最近做一个东西,需要采集硬件设备的音视频数据,然后做编码。以前做过编码部分直接拽过来使用,只写硬件采集部分即可。 调查发现,硬件采集驱动过于老旧,必须使用ffmpeg3的API,而编码部分则使用了ffmpeg4。
改动编码部分降级为ffmpeg3不现实,引出来多少问题不太确定。由此设计一套方案:
- 编码部分使用ffmpeg4的动态库,链接位置自己指定
- 将硬件采集代码设计为动态库,并且将ffmpeg3的静态编译进去
- 由主体程序动态链接调用硬件采集代
静态库被编译到动态库中,相当于内部代码,与其他部分不冲突。注意不要暴露任何关于ffmpeg3到内容,否则可能引起歧义。
将以上过程抽象为如下:
static.cpp static.h --> libffmpeg3.a
capture.cpp capture.h --> libcap_dev.so
test.cpp --> test (最终可执行程序)
1. 编译生成静态库
g++ -c -fPIC static.cpp -o static.o
-fPIC是必须要添加,目的是生成与位置无关的代码
ar -r libffmpeg3.a static.o
记得调试一下库是否OK。
2. 编译生成动态库,注意需要将静态库编译进去
g++ -c -fPIC capture.cpp -o capture.o
这里需要生成动态库,就更需要-fPIC选项了。
g++ -shared capture.o -L. -lffmpeg3 -o libcap_dev.so
编译时注意使用-L -l指定和链接目标静态库,-L和-l的作用及用法请自行查询。
至此libffmpeg3.a已经被编译到libcap_dev.so中,查看一下文件大小,会发现动态库会比较大。如果链接的是ffmpeg的静态库的话,会更大,几十兆都是不是事儿。
3. 编译生成最终目标
g++ test.cpp -I./ -L./ -lcap_dev -o test
同理需要用到-L和-l。
运行目标文件,正常使用两个库中的接口。
使用方法及注意事项测试完成,下面是将其用于实战。
首先,针对第一点,需要有ffmpeg3的静态库,下载编译,注意一定要是3版本的。编译是需要添加-fPIC选项。在configure时添加如下参数:
--extra-cflags='-fPIC' --extra-cxxflags='-fPIC' --enable-static
至此生成一堆ffmpeg相关的静态库,正好对应libffmpeg3.a。
其次,针对第二点,头文件中要规避开ffmpeg的头文件,实在避不开的转化一下或者自定义也行。
最后贴出生成动态库的Makefile文件。
CC := gcc
C++ := g++
LINK := g++
# ffmpeg
FFMPEG_PATH := /usr/local/ffmpeg/3.0
# xxx driver
XXX_PATH := /usr/local/xxx_driver/include/
LIBS := -L$(FFMPEG_PATH)/lib \
-Wl,-Bstatic -Wl,-Bsymbolic\
-lavdevice -lavfilter -lpostproc \
-lavformat -lavcodec -lavutil \
-lswscale -lswresample \
-Wl,-Bdynamic -lstdc++ -ldl -lstdc++ -ldl -lm -lz -lpthread \
C++FLAGS := -g -Wall -fPIC -std=c++11 \
-D__STDC_CONSTANT_MACROS \
INCLUDES := -I$(FFMPEG_PATH)/include/ \
-I$(XXX_PATH) \
C++FILES := dev_cap.cpp \
TARGET=libdev_cap.so
OBJS = $(C++FILES:.cpp=.o)
all: $(TARGET)
$(TARGET):$(OBJS)
$(LINK) -shared $^ $(LIBS) -o $@
%.o:%.cpp
$(C++) -c $(C++FLAGS) $< $(INCLUDES) -o $@
clean:
rm -f $(TARGET) $(OBJS)
在链接ffmpeg库时遇到了如下错误:
/usr/bin/ld: /usr/local/media_http_server/ffmpeg/3.0/lib/libavcodec.a(vc1dsp_mmx.o): relocation R_X86_64_PC32 against symbol `ff_pw_9' can not be used when making a shared object; recompile with -fPIC
/usr/bin/ld: final link failed: Bad value
collect2: error: ld returned 1 exit status
make: *** [libsdi.so] Error 1
网上好多人也遇到了同样问题,需要在链接ffmpeg库是添加“-Wl,-Bsymbolic”选项。
测试一下,正常使用,可惜涉及到库代码调试起来比较费劲,美中不足。
编译时这样那样到参数问题磕巴了好久,以此记录一下。