<commit_before>---
layout: post
title: "FFmpeg解码视频保存图片"
subtitle: "如何使用FFmpeg解码视频"
author: "Johnny"
date: 2017-12-5 21:49:54
header-img: "img/caffe_install.jpg"
tags: 
    - FFmpeg 
---

&#160; &#160; &#160; &#160;项目需要，这几天尝试使用FFmpeg解码视频并得到图片，包括各种格式的监控视频，经过几天的努力，终于完成了，在这里做个记录。

&#160; &#160; &#160; &#160;FFmpeg是一套可以用来记录、转换数字音频、视频，并能将其转化为流的开源计算机程序。采用LGPL或GPL许可证。它提供了录制、转换以及流化音视频的完整解决方案。它包含了非常先进的音频/视频编解码库libavcodec，为了保证高可移植性和编解码质量，libavcodec里很多code都是从头开发的。FFmpeg在Linux平台下开发，但它同样也可以在其它操作系统环境中编译运行，包括Windows、Mac OS X等。这个项目最早由<NAME>发起，2004年至2015年间由<NAME>主要负责维护。许多FFmpeg的开发人员都来自MPlayer项目，而且当前FFmpeg也是放在MPlayer项目组的服务器上。项目的名称来自MPEG视频编码标准，前面的"FF"代表"Fast Forward"。

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

## 1.安装FFmpeg ##


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

1. 官网提供的安装是按照软件使用者的方式安装，默认不编译生成动态链接库.so文件，所以在编译安装过程中很多命令都有类似`--disable-shared`的参数。为了开发使用，在编译的过程中去掉所有的类似命令，有的还需要加入`--enable-shared`命令。其中一个库还要加入`--enable-fPIC`命令，如果不加入会报错。-fPIC命令在编译C/C++时是一个很常用的选项，-fPIC表明使用地址无关代码。（PIC：Position Independent Code. ）Linux下编译共享库时，必须加上-fPIC参数，否则在链接时会有错误提示。具体有关-fPIC的知识请参阅文后的链接[2]。
2. 如果使用源码编译安装的方式安装以上各个依赖库，其中有一个库libvpx，是VP8/VP9格式的视频的编码器和解码器，它的下载链接是googlesource.com。由于众所周知的原因，它这个链接在大陆是打不开的，需要你使用一些其他的方法才能下载到，下载方法我就不赘述了，身为一个程序员这应该是必备技能。

## 2.FFmpeg解码视频保存图片 ##

&#160; &#160; &#160; &#160;笔者主要研究的也不是视频编解码方向，做这个东西主要是用来解码图片方便后续项目使用，所以也就没打算对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;
	}

&#160; &#160; &#160; &#160;当然了，要想使用FFmpeg最好还是要了解一点FFmpeg的知识，比如解码的流程，需要调用哪些函数，上面那个工程里的代码为什么这样写，哪些自己用不到是可以删掉的，哪些是必须的…… 了解这些知识最佳途径是看雷神雷霄骅的博客[6]。说到这里不得不提一下雷神，雷神是做视频编解码的尤其是做FFmpeg的大家对雷霄骅的敬称，雷霄骅生前是中国传媒大学的通信与信息系统专业博士生，把雷神称为是国内FFmpeg的第一人一点儿都不为过，他在当今音视频编解码封闭技术领域，专注，勤奋，分享，传播，奉献。在中文音视频技术圈留下他深深的印记。可惜天妒英才，2016年7月17日凌晨雷神猝死在学校主楼五层，知乎上有人说：**上帝也想玩一把直播，就把雷神招进去了....** 原雷神在天堂安息！<commit_msg>fix bug in ffmpeg post<commit_after>---
layout: post
title: "FFmpeg解码视频保存图片"
subtitle: "如何使用FFmpeg解码视频"
author: "Johnny"
date: 2017-12-5 21:49:54
header-img: "img/caffe_install.jpg"
tags: 
    - FFmpeg 
---

&#160; &#160; &#160; &#160;项目需要，这几天尝试使用FFmpeg解码视频并得到图片，包括各种格式的监控视频，经过几天的努力，终于完成了，在这里做个记录。

&#160; &#160; &#160; &#160;FFmpeg是一套可以用来记录、转换数字音频、视频，并能将其转化为流的开源计算机程序。采用LGPL或GPL许可证。它提供了录制、转换以及流化音视频的完整解决方案。它包含了非常先进的音频/视频编解码库libavcodec，为了保证高可移植性和编解码质量，libavcodec里很多code都是从头开发的。FFmpeg在Linux平台下开发，但它同样也可以在其它操作系统环境中编译运行，包括Windows、Mac OS X等。这个项目最早由<NAME>发起，2004年至2015年间由<NAME>主要负责维护。许多FFmpeg的开发人员都来自MPlayer项目，而且当前FFmpeg也是放在MPlayer项目组的服务器上。项目的名称来自MPEG视频编码标准，前面的"FF"代表"Fast Forward"。

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

## 1.安装FFmpeg ##


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

1. 官网提供的安装是按照软件使用者的方式安装，默认不编译生成动态链接库.so文件，所以在编译安装过程中很多命令都有类似`--disable-shared`的参数。为了开发使用，在编译的过程中去掉所有的类似命令，有的还需要加入`--enable-shared`命令。其中一个库还要加入`--enable-fPIC`命令，如果不加入会报错。-fPIC命令在编译C/C++时是一个很常用的选项，-fPIC表明使用地址无关代码。（PIC：Position Independent Code. ）Linux下编译共享库时，必须加上-fPIC参数，否则在链接时会有错误提示。具体有关-fPIC的知识请参阅文后的链接[2]。
2. 如果使用源码编译安装的方式安装以上各个依赖库，其中有一个库libvpx，是VP8/VP9格式的视频的编码器和解码器，它的下载链接是googlesource.com。由于众所周知的原因，它这个链接在大陆是打不开的，需要你使用一些其他的方法才能下载到，下载方法我就不赘述了，身为一个程序员这应该是必备技能。

## 2.FFmpeg解码视频保存图片 ##

&#160; &#160; &#160; &#160;笔者主要研究的也不是视频编解码方向，做这个东西主要是用来解码图片方便后续项目使用，所以也就没打算对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;
	}

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

&#160; &#160; &#160; &#160;愿雷神在天堂安息！
{'fraction_non_alphanumeric': 0.1258164317634926, 'fraction_numerical': 0.0446888965280165, 'mean_word_length': 16.014619883040936, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 9, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '413113', 'n_tokens_mistral': 4673, 'n_tokens_neox': 5214, 'n_words': 160}