FFmpeg解码视频保存图片

如何使用FFmpeg解码视频

Posted by Johnny on December 5, 2017

       项目需要,这几天尝试使用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”。

       FFmpeg其实使用非常广泛,国内包括暴风影音、QQ影音,以及国外的KMPPlayer等,还有转码工具格式工厂等,都使用了FFmpeg的解码器和代码。由于FFmpeg是在LGPL/GPL协议下发布的(如果使用了其中一些使用GPL协议发布的模块则必须使用GPL协议),任何人都可以自由使用,但必须严格遵守LGPL/GPL协议。有很多播放软件都使用了FFmpeg的代码,但它们并没有遵守LGPL/GPL协议,没有公开任何源代码。所以这些软件后来被FFmpeg开源项目加入了FFmpeg官网上的耻辱柱。作为一个开源爱好者,我对上述软件使用FFmpeg的源代码或者核心组件而不按照协议公开源码的行为表示可耻。

1.安装FFmpeg

       FFmpeg依赖很多库,所以需要安装很多库,包括NASM、YASM、libx64、libx265、libvpx、libopus等,还好FFmpeg官网上提供了FFmpeg的安装指导,我的系统是Ubuntu,所以我使用的是参考文献1里安装指导。如果有root权限,指导里很多库都可以使用sudo apt-get install命令进行安装,如果像我一样没有root权限,那就都使用源码编译的安装方式。使用源码编译安装有两个注意事项:

1)官网提供的安装方法不会生成.so动态链接库

       官网提供的安装是按照软件使用者的方式安装,默认不编译生成动态链接库.so文件,所以在编译安装过程中很多命令都有类似--disable-shared的参数。为了开发使用,在编译的过程中去掉所有的类似命令,有的还需要加入--enable-shared命令。其中一个库还要加入--enable-fPIC命令,如果不加入会报错。-fPIC命令在编译C/C++时是一个很常用的选项,-fPIC表明使用地址无关代码。(PIC:Position Independent Code. )Linux下编译共享库时,必须加上-fPIC参数,否则在链接时会有错误提示。具体有关-fPIC的知识请参阅文后的链接2。具体需要修改的编译配置选项如下:

  • 在配置libx264编译选项时,需要加入–enable-shared选项;
  • 在编译libx265时需要把编译选项中的-DENABLE_SHARED:bool=off改为-DENABLE_SHARED:bool=true;
  • 在编译libvpx时在配置编译选项时,加入选项–enable-shared –enable-pic;
  • 在编译libfdk-aac时把编译选项中的–disable-shared去掉,改为–enable-shared;
  • 在编译libmp3lame时把编译选项中的–disable-shared去掉,改为–enable-shared;
  • 在编译libopus时把编译选项中的–disable-shared去掉,改为–enable-shared;
  • 在最后编译FFmpeg配置编译选项时,加入–enable-shared选项。

2)libvpx的源码需要FQ下载

       如果使用源码编译安装的方式安装以上各个依赖库,其中有一个库libvpx,是VP8/VP9格式的视频的编码器和解码器,它的下载链接是googlesource.com。由于众所周知的原因,它这个链接在大陆是打不开的,需要你使用一些其他的方法才能下载到,下载方法我就不赘述了,FQ应该是一个技术人员的必备技能。

2.FFmpeg解码视频保存图片

       笔者主要研究的也不是视频编解码方向,做这个东西主要是用来解码图片方便后续项目使用,所以也就没打算对FFmpeg做深入的研究。经过笔者在GitHub上费了点儿时间的搜索,找到了一个FFMpeg解码视频保存图片的项目,项目地址见参考资料3。这个项目是Windows下的一个项目,并且使用的是较为老版本的FFmpeg,有些函数的名字已经有所改变,为了能在Linux下使用还是需要进行一些修改。比如PIX_FMT_BGR24需要改为AV_PIX_FMT_BGR24,av_close_input_file改为avformat_close_input等。而且这个项目保存的是bmp格式的图片,里面调用了Windows的API,我要的是Linux下的代码,所以需要对以上这些进行了修改。保存.jpg图片最常见方法是把解码出的YUV图像转为RGB图片,再使用libjpeg库把RGB数据按照JPEG格式写成图片。但是呢,我比较懒,我不想写这么一大坨东西,我选择使用OpenCV的cv::imread函数把RGB图像写入硬盘保存为.jpg图片,该函数的优点是可以根据写入文件名的后缀自动选择编码格式,.jpg和.bmp图片都可以保存,所以我参考文献4和文献5把保存图片函数改为:

bool Save(const std::string & pFileName, AVFrame * frame, const int & w, const int & h){
	cv::Mat img_mat(h, w , CV_8UC3, frame->data[0]);
	cv::imwrite(pFileName, img_mat);
	return true;
}

       当然了,要想使用FFmpeg最好还是要了解一点FFmpeg的知识,比如解码的流程,需要调用哪些函数,上面那个工程里的代码为什么这样写,哪些自己用不到是可以删掉的,哪些是必须的…… 了解这些知识最佳途径是看雷神雷霄骅的博客6。说到这里不得不提一下雷神,雷神是做视频编解码的尤其是做FFmpeg的大家对雷霄骅的敬称,雷霄骅生前是中国传媒大学的通信与信息系统专业博士生,把雷神称为是国内FFmpeg的第一人一点儿都不为过,他在当今音视频编解码封闭技术领域,专注,勤奋,分享,传播,奉献。在中文音视频技术圈留下他深深的印记。可惜天妒英才,2016年7月17日凌晨雷神猝死在学校主楼五层,知乎上有人说:上帝也想玩一把直播,就把雷神招进去了….

       愿雷神在天堂安息!

3.源代码

       代码我已经整理好放到GitHub上了,地址在这里。如果这个小工程帮到你了,还望你在GitHub上给个star。

参考资料

  1. Compile FFmpeg on Ubuntu, Debian, or Mint
  2. Linux共享对象之编译参数fPIC
  3. FFMpeg-decode-example
  4. ffmpeg AVFrame to opencv Mat conversion
  5. How to capture frame from RTSP Stream witg FFMPEG Api, OpenCV
  6. FFmpeg源代码简单分析–雷霄骅

// mathjax