昨天介绍了一下h264结构,介绍h264结构就是为了这一次铺垫的,我们源数据是YUV格式的,要想把YUV格式转化成H264格式,就需要用到编码技术,这个编码技术的话,还是要说到FFmpeg,FFmpeg是业界公认的比较优秀的编解码软件,现在我也是需要这个软件进行编解码,所以有必要了解一波。
8.1 编译安装FFmpeg
FFmpeg是一套可以用来记录、转换数字音频、视频,并能将其转化为流的开源计算机程序。采用LGPL或GPL许可证。它提供了录制、转换以及流化音视频的完整解决方案。它包含了非常先进的音频/视频编解码库libavcodec,为了保证高可移植性和编解码质量,libavcodec里很多code都是从头开发的。
FFmpeg在Linux平台下开发,但它同样也可以在其它操作系统环境中编译运行,包括Windows、Mac OS X等。这个项目最早由Fabrice Bellard发起,2004年至2015年间由Michael Niedermayer主要负责维护。许多FFmpeg的开发人员都来自MPlayer项目,而且当前FFmpeg也是放在MPlayer项目组的服务器上。项目的名称来自MPEG视频编码标准,前面的"FF"代表"Fast Forward"。《来自百度百科》
8.1.1 下载
总要抄一下介绍把,我感觉我写的介绍比不上百度百科的,所以还要要抄抄,这样多实际,先来一个FFmpeg官网,可以在这个官网下载,也可以通过官网了解一下其他信息,不过我现在喜欢在github下了,这是程序员的开源世界,所以在来一个github连接地址,可以在这里下载,也可以直接git clone下,不过我下的有点慢,访问国外的网站网速还是不行啊,还是乖乖的下一个压缩包。
8.1.2 编译
根据之前几篇安装redis,nginx应该对安装比较熟了吧,不过这个ffmpeg不按套路出牌,ReadMe竟然没看到安装信息,找了很久,才发现在INSTALL.md这里,看来以后还看记得看两个文件一个是Readme,一个是INSTALL。
我把INSTALL的信息粘贴出来,这个写的还是比较简单的,不过我们之前也是3步,其实最麻烦的就是第一步配置,不过看着是不需要带其他参数,暂时不带,以后有问题再看看,反正源码都在了不怕。
刚刚尝试了一下./configure ,我是Debian系统,然后就报了一个错:
nasm/yasm not found or too old. Use --disable-x86asm for a crippled build.
然后浏览了一下其他人的博客,找到了一篇介绍怎么解决的,内容:
需要安装yasm的汇编编译器
sudo apt-get install yasm
分析:yasm是汇编编译器,ffmpeg为了提高效率使用了汇编指令,如MMX和SSE等。所以系统中未安装yasm时,就会报上面错误。
如果不需要yasm也可以
./configure --disable-x86asm
原文链接:FFmpeg yasm/nasm not found or too old. Use --disable-yasm for a crippledbuild
果然安装了之后,一马平川,不过这个编译,安装时间有点久,可以等等。
make install之后,会把库和头文件拷贝到/usr/local/这个目录,这个是configure默认的,在配置的时候其实我们可以自己配置的,只不过我比较偷懒就没有配。
后面补加:
不知道是不是写代码的习惯,都不喜欢把前面的东西删除掉,都是比较喜欢在后面添加,这次也不例外,前面的我就不修改了,记得看这个补加的。
其实上面的安装步骤并没有错,问题是ffmpeg中自带h264的解码,但是没有包含编码,所以再执行后面的编码demo程序一直没找到h264编码,这也是为什么我后来才补加的,就是因为在测试demo程序的时候才发现有问题,所以我们需要额外添加x264支持h264的编码。
安装x264
可以到x264安装路径 下载x264的库,然后解压。
也可以通过git来安装:git clone git://git.videolan.org/x264.git
安装x264的操作我直接贴出来:
1. ./configure --enable-static --enable-share
2.make
3.sudo make install
比较简单,直接按照命令执行即可。
重新编译安装ffmpeg
竟然需要重新打开libx264的功能,就需要重新编译安装ffmpeg,安装步骤也直接贴出来
1. 配置ffmpeg时,加上x264,如:
./configure --enable-gpl --enable-libx264
2. make clean
3. make
4. make install
这个重新装的过程参考了这篇文章:ffmpeg推流时,可能出现错误:Unknown encoder ‘libx264’
8.1.3 测试
ffmpeg本来就是编解码使用的,所以我们只要把一个视频文件然后进行编解码测试就可以了,
ffmpeg -i 720x480_25fps.mp4 -vcodec copy -acodec copy out.flv
测试的方式就是把MP4文件转化成flv格式,然后在使用vlc播放器播放,可以播放就说明安装成功了。
8.2 运行编码demo
8.2.1 编译demo
这个版本的demo好像移动了文件夹,在doc/examples中,还是老习惯,第一个看Readme,
这次的README没有让我失望,就是我需要的,里面介绍了两种方法,不过我选择第二种,因为我都是把源码拖下来了,就不必在重新到其他目录去了,所以只需要make examples就可以了。
8.2.2 运行demo
编译完成后,很多可执行文件,现在比较关心编码这一块,所以列出编码部分文件
之前就是在这里运行demo的时候,发现不能h264编码,所以看到这里的如果没有h264编码的,需要回去看我补加的内容,这样就支持h264编码了。
运行的命令:
./encode_video 1.h264 libx264
因为我们用的是libx264的库,所以需要选择libx264的编码,下面就是demo执行成功进行编码的打印。
我们打开编码的文件1.h264
这个就是demo视频录制的h264格式的视频,我也不知道为什么录的是这么多颜色,不过待会可以浏览一下代码。
然后我们在用雷神的h264分析工具看一看:
毫无违和感,哈哈。
8.3 简单分析代码
这里只是简单分析一个encode_video.c的代码,让我们有一点初始编解码的感觉,具体的源码目前不分析,以后分不分析看情况,哈哈哈。源文件我就不复制出来了,这里还是启用写重要函数的方式。
1、avcodec_find_encoder_by_name(codec_name) `//通过我们输入的名字寻找编码器,这里传参的是libx264
2、avcodec_alloc_context3(codec); //就相当于编码器的一个全局的控制块,后面就是堆编码控制块进行初始化
3、av_packet_alloc(); //申请一个packet,在编码完成之后接收数据使用
4、avcodec_open2(c, codec, NULL); //context全局控制块已经准备好了,然后进行打开编码器的操作
5、av_frame_alloc(); //申请一帧的空间,这个就是我们准备的一帧数据,丢给编码器编码使用
6、av_frame_get_buffer(frame, 0); //为上面申请的帧frame申请内存空间
7、av_frame_make_writable(frame); //抱枕frame的数据是可写的
8、//demo程序使用的是手动填充YUV数据,强,下一节我介绍的是通过读取文件的方式
9、avcodec_send_frame(enc_ctx, frame);
//把原始数据发送给编码器,进行编码,然后下面在接收通过编码器编完码之后的数据,
//不过现在这个接口可能要废弃了,不过使用到还可以使用,新接口用这种了avcodec_encode_video2
10、avcodec_receive_packet(enc_ctx, pkt); //接收编码器回来的数据
11、fwrite(pkt->data, 1, pkt->size, outfile); //把接收到的数据写入到文件中
12、av_packet_unref(pkt); //清楚的包
13、avcodec_free_context(&c); //释放context
14、av_frame_free(&frame); //释放帧缓冲
15、av_packet_free(&pkt); //释放packet
差不多就这么多步骤,解码的话,我这里就不写了,因为看着也差不多其实,大家有空去看看。