从动手到放弃之我不要自己编译ffmpeg了 【踩坑+草稿篇】

这一生的挚爱 提交于 2020-01-25 12:17:16

原本我在想要不要放出这篇文章来的,因为这篇文章不成熟,都是在编译ffmpeg---即使有前人放出来的源代码,但还是出现种种问题了----历经的各种坑,各种bug,但是其实一想,这些问题不会只有我一个人遇到的,放出来起码能让其他人做出参考。

 

在编译ffmpeg这期间,其实很耗时间,主要是不熟c++、cmake、makefile这些,还有几篇文章也是草稿类型,也是同时期涂鸦的:

都是废稿,不过可以说明一下ffmpeg不是拿一个源代码包编译就可以的:

[运维] ubuntu等linux下编译配置ffmpeg以供c++调用[草稿]

[运维] ubuntu等linux下编译配置ffmpeg以供c++调用

下面是正文:

 

 前前言

我也不想有这个前前言的,然而,人工手动编译ffmpeg的难度已经超过我的想象了,即使有前人的智慧,但是我还是各种地雷,这个只是用来做踩坑用的一篇小笔记,如果正式要编译的话,那么直接看正式篇吧,这篇踩坑篇用来做什么?用来记录还有告诉其他人,你遇到的坑已经有人填过了。

前言

因为要涉足音视频的开发,所以,需要编译一下ffmpeg为静态库然后用c++调用。

然后,这种编译我重复了多次还是没办法成功---光是依赖都一大堆,而且要逐个编译--整个人都崩溃了,不过,好在看到了其他兄弟的编译脚本,尚算有一丝希望。

可以参考这个兄弟的:

https://github.com/zimbatm/ffmpeg-static

稍后我会将这个项目打包方便下载。先看看说明:

屏幕截图_381.png

打开相关项目一看:

屏幕截图_382.png

欸,原来这个东西是用这脚本编译的?再看看编译代码:

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里面的内容:截取部分图片:

屏幕截图_384.png

屏幕截图_385.png

屏幕截图_386.png

屏幕截图_387.png

 

... 一直在下载源代码然后编译然后再编译ffmpeg?

看来要自己慢慢摸索估计每天就一个依赖就重新编译一次会崩溃的。。。

好了,尝试执行脚本一下:

屏幕截图_380.png

 

....我太难了。。。。下载不成功自己退出来了。。。欸,看来要改造一下这个脚本,方便进行编译了。

 

 

坑人不断

这里先提一下一些比较重要的bug。

 

librtmp的 In function ‘DHInit’ dereferencing pointer to incomplete type ‘DH {aka struct dh_st}’

 

这个问题让在下非常疑惑,编译到rtmpdump的时候就出现了,死活不过:

2020-01-19_19-11.png

 

后来查阅资料:
有这问题的兄弟不少,都在问了:

https://owenashurst.com/?p=242

2020-01-19_19-15.png

2020-01-19_19-15_1.png

原因是:

https://pastebin.com/Ghr20JVz

https://github.com/puma/puma/issues/1136

 

2020-01-19_19-19.png

2020-01-19_19-19_1.png

 

解决方案一:卸载新版,安装旧版本

 

嗯,那么根据这说法的其中一个解决方案是什么呢?

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

 

2020-01-19_19-28.png

2020-01-19_19-28_1.png

 

我采用的解决方案是--不想麻烦,直接装旧版本的,装完之后再编译librtmp,你会发现:

2020-01-19_19-52.png

编译成功!

 

最后,连同ffmpeg也编译了,然后可以得到:

2020-01-19_20-58.png

查看一下编译过后的target目录,有:

2020-01-19_20-59.png

2020-01-19_20-59_1.png

 

2020-01-19_20-59_2.png

 

好了,基本都齐全了,不过编译后的文件都在:

/home/too-white/ffmpeg-build/target/

 

 

ffmpeg开启了相应模块但是没有编译进去的问题

 

先说一下碰到的问题:

1、链接编译通过,但是执行的时候出现了问题:

2020-01-20_12-13.png

 

黑人脸:我见都没见过libopencore-amr,它是怎么出来的?

 

它是这样出来的---亲手放出来的:

 

2020-01-20_12-11.png

 

在编译ffmpeg的时候有些参数会开启功能,所以,解决方案是:

安装amr转mp3所需的库

 

去这里看看:

https://sourceforge.net/projects/opencore-amr/files/

估计其中几个是要安装的:

2020-01-20_12-19.png

 

于是,编译ffmpeg的源代码里面又多了下面三个兄弟:

2020-01-20_12-26.png

 

这篇文章基本在解释为什么要编译xxx库,当然,我最后放出去的打包工具会将所有的源代码、库都放好的,

不会让大家重新再走一遍这无底深坑。

 

特别标明:

amrwb-11编译时候它会自行下载一个文件然后解压缩再编译,

https://www.3gpp.org/ftp/Specs/archive/26_series/26.204/26204-b00.zip  

 

然后实在有点慢了,而且解压缩时候会出现:

2020-01-20_12-58.png

 

又是一个bug。。

 

https://blog.csdn.net/zqj6893/article/details/84748214

其他人也遇到了。。

 

amrwb-11的修正方案

 

修正有两点:1、修正unzip报错的问题,2、不从网上下载,直接在本地解压缩。 

首先,将从网上下载好的文件解压缩之后【正常能解压缩的,就是在makefile里面调用unzip就不行】,然后分别压缩为tar文件

 

这样做是因为等下要从脚本用/bin/tar代替 unzip来解压缩

 

第二,修改 prepare_sources.sh.in 文件:

如下图:

2020-01-20_16-07.png

因为等下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

2020-01-20_16-10.png

虽然粗糙,不过在这个版本下好使。

 

第三:将makefile.in 和 makefile.am都修改一下,修改的地方都一样:

2020-01-20_16-12.png

 

第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

 

2020-01-20_16-16.png

 

重新打包,我这里打包为,然后将放到ffmpeg的构建工具的第三方源码里面去,方便到时候在新电脑上面重新编译代码。

2020-01-20_16-20.png

最后的编译结果:

2020-01-20_16-21.png

编译通过。

 

amrnb-11修正方案

安装amrnb的时候同样有类似的问题,譬如:它要下载:

http://www.3gpp.org/ftp/Specs/archive/26_series/26.104/26104-b00.zip

这个文件,然后unzip文件又报错。方案是类似的:

2020-01-20_16-33.png

prepare_souce.sh.in修改:

2020-01-20_16-50_1.png

makefile.in makefile.am修改:

2020-01-20_16-39_1.png

编译结果:

2020-01-20_16-50.png

 

手动修改时候请小心目录路径,里面的文件名称有多有少,也有很接近都是文件名称都是不一样的。容易出问题。

 

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时候编译的命令:

2020-01-23_12-01.png

 

就是这一行:

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生成动态库的时候有这些注意事项:

 

2020-01-23_12-03.png

 

经过分析之后,很有可能就是:

2020-01-23_12-16.png

这段代码或者这段规则没有运行。从命令行也可以看出来:

2020-01-23_12-23.png

 

圈出来的第一段命令以及第二段命令分别对应于makefile的:

2020-01-23_12-25.png

librtmp.a 规则 ar执行,以及 librtmp.pc的sed的执行都对上了,中间的librtmp.so规则没有任何输出,gcc也不执行,那就奇怪了。

 

后来确实证实了librtmp.so.0这个规则不执行,因为我在makefile强行修改了规则librtmp.a,在他后面顺便编译so动态库:

2020-01-24_09-31.png

结果是执行的,但是报错了:

2020-01-24_09-31_1.png

 

转入对openssl的编译,我反复比对openssl的makefile文件,甚至尝试手动修改gcc参数,但是没想到答案竟然如此简单,首先看看openssl的config文件的内容:

2020-01-24_18-35_1.png

里面有一个shared或者no-shared,对吧,那么在config的时候添加shared参数试试:

2020-01-24_18-35.png

添加了,然后编译一次,再看看编译后的lib目录:

2020-01-24_18-34.png

libssl.so已经出来了---成败往往只有一步。人家原来已经弄好了,就一个参数的事。

然后再尝试编译librtmp,看到编译结果里面出现librtmp.so了,成功第一步:

2020-01-24_18-40.png

然后去target/lib里面看看,有没有.so文件:

2020-01-24_18-43_1.png

没有,发生什么问题了---去编译的源文件目录看看:

2020-01-24_18-43.png

 

有编译过的动态库,这是没有复制文件的问题了。

我们看看makefile代码:

2020-01-24_18-57.png

makefile里面是有规则指定复制 librtmp.so.0到lib的目录下面的,而这个规则或者任务就叫【install_so.0】当然,这个任务要依赖于子任务:【librtmp.so.0】,这跟gradle的任务依赖很像啊。而上面的另一个任务 isntall_base 又依赖于 librtmp.a librtmp.pc 这两个任务,我们来看看调用方式:

2020-01-24_18-57_1.png

也就是说make的时候指定了执行任务install_base======!!!诶?从这里已经可以知道为什么之前的分析是始终不执行librtmp.so.0这个任务来生成so动态库了,因为人家调用的任务里面不包含librtmp.so.0这任务啊!可见makefile的语法基础是何等重要,现在踩恍然大悟,所以,我们不需要强行修改任务了,只需要在make的时候执行两个任务,分别是 isntall_base install_so.0即可。

修改为:

2020-01-24_19-04_1.png

执行结果:

2020-01-24_19-04.png

librtmp的动态库编译完成。

 

经过逐个逐个源码包的编译,最后,连同ffmpeg的源码包共26个包编译完成,静态库以及动态库都在:

2020-01-24_19-36.png

2020-01-24_19-35.png

有兴趣的朋友可以看我放出来的ffmpeg源码编译工具。

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!