前言:对于从未接触过音视频编解码的同学来说,使用FFmpeg的学习曲线恐怕略显陡峭。本人由于工作需要,正好需要在项目中使用。因此特地将开发过程总结下来。只当提供给有兴趣的同学参考和学习。
由于FFmpeg是使用C语言开发,所有和函数调用都是面向过程的。以我目前的学习经验来说,通常我会把一个功能的代码全部放在main函数中实现。经过测试和修改认为功能正常,再以C++面向对象的方式逐步将代码分解和封装。因此在对本套指南中我也会采用先代码实现再功能封装的步骤。
一、开发前的准备工作
开发工具为VS2013+Qt5,目录结构:
bin:工作和测试目录
doc:开发文档目录
include:ffmpeg头文件配置目录
lib:ffmpeg静态库配置目录
src:源码目录
属性页配置:
常规-输出目录:..\..\bin
调试-工作目录:..\..\bin
C/C++-常规-附加包含目录:..\..\include
链接器-常规-附加库目录:..\..\lib
链接器-系统-子系统:控制台 (/SUBSYSTEM:CONSOLE)
二、编解码基础知识
(1)封装格式
所谓封装格式是指音视频的组合格式,例如最常见的封装格式有mp4、mp3、flv等。简单来说,我们平时接触到的带有后缀的音视频文件都是一种封装格式。不同的封装格式遵循不同的协议标准。有兴趣的同学可以自行扩展,更深的东西我也不懂。
(2)编码格式
以mp4为例,通常应该包含有视频和音频。视频的编码格式为YUV420P,音频的编码格式为PCM。再以YUV420编码格式为例。我们知道通常图像的显示为RGB(红绿蓝三原色),在视频压缩的时候会首先将代表每一帧画面的RGB压缩为YUV,再按照关键帧(I帧),过渡帧(P帧或B帧)进行运算和编码。解码的过程正好相反,解码器会读到I帧,并根据I帧运算和解码P帧以及B帧。并最终根据视频文件预设的FPS还原每一帧画面的RGB数据。最后推送给显卡。所以通常我们说的编码过程就包括:画面采集、转码、编码再封装。
(3)视频解码和音频解码有什么区别
玩游戏的同学肯定对FPS不陌生,FPS太低画面会感觉闪烁不够连贯,FPS越高需要显卡性能越好。一些高速摄像机的采集速度能够达到11000帧/秒,那么在播放这类影片的时候我们是否也需要以11000帧/秒播放呢?当然不是,通常我们会按照25帧/秒或者60帧/秒设定图像的FPS值。但是由于视频存在关键帧和过渡帧的区别,关键帧保存了完整的画面而过渡帧只是保存了与前一帧画面的变化部分,需要通过关键帧计算获得。因此我们需要对每一帧都进行解码,即获取画面的YUV数据。同时只对我们真正需要显示的画面进行转码,即将YUV数据转换成RGB数据,包括计算画面的宽高等。
但是音频则不然,音频的播放必须和采集保持同步。提高或降低音频的播放速度都会让音质发生变化,这也是变声器的原理。因此在实际开发中为了保证播放的音视频同步,我们往往会按照音频的播放速度来控制视频的解码转码速度。
三、代码实现
(1)注册FFmpeg组件:注册和初始化FFmpeg封装器和网络设备
av_register_all(); avformat_network_init(); avdevice_register_all();