原本我在想要不要放出这篇文章来的,因为这篇文章不成熟,都是在编译ffmpeg---即使有前人放出来的源代码,但还是出现种种问题了----历经的各种坑,各种bug,但是其实一想,这些问题不会只有我一个人遇到的,放出来起码能让其他人做出参考。
在编译ffmpeg这期间,其实很耗时间,主要是不熟c++、cmake、makefile这些,还有几篇文章也是草稿类型,也是同时期涂鸦的:
都是废稿,不过可以说明一下ffmpeg不是拿一个源代码包编译就可以的:
[运维] ubuntu等linux下编译配置ffmpeg以供c++调用[草稿]
[运维] ubuntu等linux下编译配置ffmpeg以供c++调用
下面是正文:
前前言
我也不想有这个前前言的,然而,人工手动编译ffmpeg的难度已经超过我的想象了,即使有前人的智慧,但是我还是各种地雷,这个只是用来做踩坑用的一篇小笔记,如果正式要编译的话,那么直接看正式篇吧,这篇踩坑篇用来做什么?用来记录还有告诉其他人,你遇到的坑已经有人填过了。
前言
因为要涉足音视频的开发,所以,需要编译一下ffmpeg为静态库然后用c++调用。
然后,这种编译我重复了多次还是没办法成功---光是依赖都一大堆,而且要逐个编译--整个人都崩溃了,不过,好在看到了其他兄弟的编译脚本,尚算有一丝希望。
可以参考这个兄弟的:
https://github.com/zimbatm/ffmpeg-static
稍后我会将这个项目打包方便下载。先看看说明:
打开相关项目一看:
欸,原来这个东西是用这脚本编译的?再看看编译代码:
build-ubuntu.sh
#!/bin/bash sudo apt-get install build-essential curl tar pkg-config sudo apt-get -y --force-yes install \ autoconf \ automake \ build-essential \ cmake \ frei0r-plugins-dev \ gawk \ libass-dev \ libfreetype6-dev \ libopencore-amrnb-dev \ libopencore-amrwb-dev \ libsdl1.2-dev \ libspeex-dev \ libssl-dev \ libtheora-dev \ libtool \ libva-dev \ libvdpau-dev \ libvo-amrwbenc-dev \ libvorbis-dev \ libwebp-dev \ libxcb1-dev \ libxcb-shm0-dev \ libxcb-xfixes0-dev \ libxvidcore-dev \ pkg-config \ texi2html \ zlib1g-dev # For 12.04 # libx265 requires cmake version >= 2.8.8 # 12.04 only have 2.8.7 ubuntu_version=`lsb_release -rs` need_ppa=`echo $ubuntu_version'<=12.04' | bc -l` if [ $need_ppa -eq 1 ]; then sudo add-apt-repository ppa:roblib/ppa sudo apt-get update sudo apt-get install cmake fi ./build.sh "$@"
然后build.sh里面的内容:截取部分图片:
... 一直在下载源代码然后编译然后再编译ffmpeg?
看来要自己慢慢摸索估计每天就一个依赖就重新编译一次会崩溃的。。。
好了,尝试执行脚本一下:
....我太难了。。。。下载不成功自己退出来了。。。欸,看来要改造一下这个脚本,方便进行编译了。
坑人不断
这里先提一下一些比较重要的bug。
librtmp的 In function ‘DHInit’ dereferencing pointer to incomplete type ‘DH {aka struct dh_st}’
这个问题让在下非常疑惑,编译到rtmpdump的时候就出现了,死活不过:
后来查阅资料:
有这问题的兄弟不少,都在问了:
https://owenashurst.com/?p=242
原因是:
https://github.com/puma/puma/issues/1136
解决方案一:卸载新版,安装旧版本
嗯,那么根据这说法的其中一个解决方案是什么呢?
sudo apt-get purge libssl-dev sudo apt-get install libssl1.0-dev
卸载新版本的lbssl-dev,安装旧版本-1.0的。
解决方案二、新旧版本并存,指定编译时候的版本:
看这里:
https://github.com/xbmc/inputstream.rtmp/issues/31
我采用的解决方案是--不想麻烦,直接装旧版本的,装完之后再编译librtmp,你会发现:
编译成功!
最后,连同ffmpeg也编译了,然后可以得到:
查看一下编译过后的target目录,有:
好了,基本都齐全了,不过编译后的文件都在:
/home/too-white/ffmpeg-build/target/
ffmpeg开启了相应模块但是没有编译进去的问题
先说一下碰到的问题:
1、链接编译通过,但是执行的时候出现了问题:
黑人脸:我见都没见过libopencore-amr,它是怎么出来的?
它是这样出来的---亲手放出来的:
在编译ffmpeg的时候有些参数会开启功能,所以,解决方案是:
去这里看看:
https://sourceforge.net/projects/opencore-amr/files/
估计其中几个是要安装的:
于是,编译ffmpeg的源代码里面又多了下面三个兄弟:
这篇文章基本在解释为什么要编译xxx库,当然,我最后放出去的打包工具会将所有的源代码、库都放好的,
不会让大家重新再走一遍这无底深坑。
特别标明:
amrwb-11编译时候它会自行下载一个文件然后解压缩再编译,
https://www.3gpp.org/ftp/Specs/archive/26_series/26.204/26204-b00.zip
然后实在有点慢了,而且解压缩时候会出现:
又是一个bug。。
https://blog.csdn.net/zqj6893/article/details/84748214
其他人也遇到了。。
amrwb-11的修正方案
修正有两点:1、修正unzip报错的问题,2、不从网上下载,直接在本地解压缩。
首先,将从网上下载好的文件解压缩之后【正常能解压缩的,就是在makefile里面调用unzip就不行】,然后分别压缩为tar文件
这样做是因为等下要从脚本用/bin/tar代替 unzip来解压缩
第二,修改 prepare_sources.sh.in 文件:
如下图:
因为等下configure的时候会生成prepare_source.sh文件,内容是将@unzip替换成真正的unzip执行命令路径,
我们先下手为强,直接修改为tar的执行路径,代码如下:
##fixed unzip bug /bin/tar xf 26204-b00_ANSI-C_source_code.tar.xz mv 26204-b00_ANSI-C_source_code/c-code ./ rm -rf 26204-b00_ANSI-C_source_code
虽然粗糙,不过在这个版本下好使。
第三:将makefile.in 和 makefile.am都修改一下,修改的地方都一样:
第2段代码删除或者注释掉【因为这是从远程下载文件的,我们文件都下载好了】,第一段代码改为:
$(top_srcdir)/26204-b00_ANSI-C_source_code.zip $(top_srcdir)/26204-b00.doc: $(top_srcdir)/26204-b00.tar.xz rm -f $(top_srcdir)/26204-b00_ANSI-C_source_code.zip $(top_srcdir)/26204-b00.doc chmod +w $(top_srcdir) ##fixed 额,既然unzip没办法解压缩,那么就用tar吧。 # $(UNZIP) -d $(top_srcdir) $< rm -rf 26204-b00 /bin/tar xf $< mv 26204-b00/26204-b00.doc ./ mv 26204-b00/26204-b00_ANSI-C_source_code.zip ./ rm -rf 26204-b00 chmod og-w $(top_srcdir)/26204-b00.doc
重新打包,我这里打包为,然后将放到ffmpeg的构建工具的第三方源码里面去,方便到时候在新电脑上面重新编译代码。
最后的编译结果:
编译通过。
amrnb-11修正方案
安装amrnb的时候同样有类似的问题,譬如:它要下载:
http://www.3gpp.org/ftp/Specs/archive/26_series/26.104/26104-b00.zip
这个文件,然后unzip文件又报错。方案是类似的:
prepare_souce.sh.in修改:
makefile.in makefile.am修改:
编译结果:
手动修改时候请小心目录路径,里面的文件名称有多有少,也有很接近都是文件名称都是不一样的。容易出问题。
rtmpdump中的librtmp没办法生成动态库的问题
光是编译一个ffmpeg就有这么多问题,引用到的rtmp竟然编译不出来一个动态库,就有静态库。下面就这个问题进行追踪跟进。
先看看build的时候使用到的makefile【这是librtmp的】:
VERSION=v2.3 prefix=/home/too-white/ffmpeg-build/target INC=-I$(prefix)/include CC=$(CROSS_COMPILE)gcc LD=$(CROSS_COMPILE)ld AR=$(CROSS_COMPILE)ar SYS=posix CRYPTO=OPENSSL #CRYPTO=GNUTLS DEF_POLARSSL=-DUSE_POLARSSL DEF_OPENSSL=-DUSE_OPENSSL DEF_GNUTLS=-DUSE_GNUTLS DEF_=-DNO_CRYPTO REQ_GNUTLS=gnutls REQ_OPENSSL=libssl,libcrypto LIBZ=-lz LIBS_posix= LIBS_mingw=-lws2_32 -lwinmm -lgdi32 LIB_GNUTLS=-lgnutls -lgcrypt $(LIBZ) LIB_OPENSSL=-lssl -lcrypto $(LIBZ) LIB_POLARSSL=-lpolarssl $(LIBZ) CRYPTO_LIB=$(LIB_$(CRYPTO)) $(LIBS_$(SYS)) CRYPTO_REQ=$(REQ_$(CRYPTO)) CRYPTO_DEF=$(DEF_$(CRYPTO)) SO_posix=so.0 SO_mingw=dll SO_EXT=$(SO_$(SYS)) SHARED=yes SODEF_yes=-fPIC SOLIB_yes=librtmp.$(SO_EXT) SOINST_yes=install_$(SO_EXT) SO_DEF=$(SODEF_$(SHARED)) SO_LIB=$(SOLIB_$(SHARED)) SO_INST=$(SOINST_$(SHARED)) DEF=-DRTMPDUMP_VERSION=\"$(VERSION)\" $(CRYPTO_DEF) $(XDEF) OPT=-O2 CFLAGS=-Wall $(XCFLAGS) $(INC) $(DEF) $(OPT) $(SO_DEF) incdir=$(prefix)/include/librtmp bindir=$(prefix)/bin libdir=$(prefix)/lib mandir=$(prefix)/man BINDIR=$(DESTDIR)$(bindir) INCDIR=$(DESTDIR)$(incdir) LIBDIR=$(DESTDIR)$(libdir) MANDIR=$(DESTDIR)$(mandir) OBJS=rtmp.o log.o amf.o hashswf.o parseurl.o all: librtmp.a $(SO_LIB) clean: rm -f *.o *.a *.so *.$(SO_EXT) librtmp.a: $(OBJS) $(AR) rs $@ $? librtmp.$(SO_EXT): $(OBJS) $(CC) -shared -Wl,-soname,$@ $(LDFLAGS) -o $@ $^ $> $(CRYPTO_LIB) ln -sf $@ librtmp.so log.o: log.c log.h Makefile rtmp.o: rtmp.c rtmp.h rtmp_sys.h handshake.h dh.h log.h amf.h Makefile amf.o: amf.c amf.h bytes.h log.h Makefile hashswf.o: hashswf.c http.h rtmp.h rtmp_sys.h Makefile parseurl.o: parseurl.c rtmp.h rtmp_sys.h log.h Makefile librtmp.pc: librtmp.pc.in Makefile sed -e "s;@prefix@;$(prefix);" -e "s;@VERSION@;$(VERSION);" \ -e "s;@CRYPTO_REQ@;$(CRYPTO_REQ);" librtmp.pc.in > $@ install: install_base $(SO_INST) install_base: librtmp.a librtmp.pc -mkdir -p $(INCDIR) $(LIBDIR)/pkgconfig $(MANDIR)/man3 cp amf.h http.h log.h rtmp.h $(INCDIR) cp librtmp.a $(LIBDIR) cp librtmp.pc $(LIBDIR)/pkgconfig cp librtmp.3 $(MANDIR)/man3 install_so.0: librtmp.so.0 cp librtmp.so.0 $(LIBDIR) cd $(LIBDIR); ln -sf librtmp.so.0 librtmp.so install_dll: librtmp.dll cp librtmp.dll $(BINDIR)
光是看makefile就感觉很正常了,该有的有了,那么看看实际上调用gcc时候编译的命令:
就是这一行:
gcc -Wall -I/home/too-white/ffmpeg-build/target/include -DRTMPDUMP_VERSION=\"v2.3\" -DUSE_OPENSSL -O2 -fPIC -c -o rtmp.o rtmp.c
这个可能有点问题,因为gcc生成动态库的时候有这些注意事项:
经过分析之后,很有可能就是:
这段代码或者这段规则没有运行。从命令行也可以看出来:
圈出来的第一段命令以及第二段命令分别对应于makefile的:
librtmp.a 规则 ar执行,以及 librtmp.pc的sed的执行都对上了,中间的librtmp.so规则没有任何输出,gcc也不执行,那就奇怪了。
后来确实证实了librtmp.so.0这个规则不执行,因为我在makefile强行修改了规则librtmp.a,在他后面顺便编译so动态库:
结果是执行的,但是报错了:
转入对openssl的编译,我反复比对openssl的makefile文件,甚至尝试手动修改gcc参数,但是没想到答案竟然如此简单,首先看看openssl的config文件的内容:
里面有一个shared或者no-shared,对吧,那么在config的时候添加shared参数试试:
添加了,然后编译一次,再看看编译后的lib目录:
libssl.so已经出来了---成败往往只有一步。人家原来已经弄好了,就一个参数的事。
然后再尝试编译librtmp,看到编译结果里面出现librtmp.so了,成功第一步:
然后去target/lib里面看看,有没有.so文件:
没有,发生什么问题了---去编译的源文件目录看看:
有编译过的动态库,这是没有复制文件的问题了。
我们看看makefile代码:
makefile里面是有规则指定复制 librtmp.so.0到lib的目录下面的,而这个规则或者任务就叫【install_so.0】当然,这个任务要依赖于子任务:【librtmp.so.0】,这跟gradle的任务依赖很像啊。而上面的另一个任务 isntall_base 又依赖于 librtmp.a librtmp.pc 这两个任务,我们来看看调用方式:
也就是说make的时候指定了执行任务install_base======!!!诶?从这里已经可以知道为什么之前的分析是始终不执行librtmp.so.0这个任务来生成so动态库了,因为人家调用的任务里面不包含librtmp.so.0这任务啊!可见makefile的语法基础是何等重要,现在踩恍然大悟,所以,我们不需要强行修改任务了,只需要在make的时候执行两个任务,分别是 isntall_base install_so.0即可。
修改为:
执行结果:
librtmp的动态库编译完成。
经过逐个逐个源码包的编译,最后,连同ffmpeg的源码包共26个包编译完成,静态库以及动态库都在:
有兴趣的朋友可以看我放出来的ffmpeg源码编译工具。
来源:CSDN
作者:码农下的天桥
链接:https://blog.csdn.net/cdnight/article/details/104082724