从事音视频技术开发对FFmpeg都不会感到陌生,通过它可以完成音视频采集、编解码、转码、后处理以及流媒体服务等诸多的功能,可以说涵盖了音视频开发中绝大多数的领域。金山云多媒体SDK团队在移动直播、短视频等项目中遇到了许多问题,本文为《FFmpeg从入门到出家》系列的第一篇上半部分,由LiveVideoStack审校整理,希望能让大家对FFmpeg有更深入了解。
文 / 施雪梅
视频流媒体中程中视频数据的传输占据了绝大部分的带宽,如何提升编码效率,使用更少的带宽,提供更优质的画面质量,是音视频开发人员一直努力的重点。HEVC(High Efficiency Video Coding,也叫H.265)编码格式的推出,给这一方向带来了突破点,但由于其算法复杂度较高,前期未曾得到普遍应用,而随着移动设备计算能力的提高和越来越多的设备开始支持HEVC的硬件编/解码,直播平台也开始逐渐引入HEVC视频格式。
HEVC属视频编码层面标准,如果在视频流媒体中进行应用,还需要相应的封装格式和流媒体协议的支持。鉴于直播的大部分推拉流协议是基于RTMP的,本文主要介绍如何在RTMP协议中增加对HEVC视频编码格式的支持,其他协议或私有协议,可参考本文自行添加。此外,除推流端和播放端要做出修改,用到的RTMP Server部分也要同步进行相应修改,才能够保证HEVC在直播中的正常使用。
1.背景介绍
典型的直播框架通常包括三大部分,如下图所示:
推流端:负责音视频数据的采集、处理、编码及封装后将数据推送至源站;
服务端:涵盖源站和CDN,接收来自推流端的音视频数据,然后将数据分发至各播放端;
播放端:从CDN拉取直播数据,解复用、解码后渲染音视频数据;
图1. 直播框架图
引入HEVC编码,涉及到的变动部分如上图中红色字体所标注:
编码模块:需要支持HEVC格式的编解码,该部分不属于本文的介绍范畴,我们有在其它文章中介绍如何在iOS11上进行HEVC的硬编硬解,感兴趣的朋友可自行查阅;
封装/传输模块:RTMP、HTTP-FLV流媒体协议需要增加对HEVC视频编码格式的支持,该部分是本文介绍的重点。
相信广大的音视频开发者对于FFmpeg并不陌生,由于它在多媒体处理上提供的强大功能以及开源易于修改维护的特性,使得其被广泛应用于各音视频相关软件中。但官方FFmpeg中没有对RTMP FLV中进行HEVC的相关扩展,这是因为FLV与RTMP是Adobe发行的标准,而Adobe暂停了对FLV与RTMP标准的更新,HEVC的相关扩展属于私有标准,所以为了减少国际上不必要的不兼容性麻烦,官方FFmpeg并不会对FLV与RTMP中扩展HEVC进行支持。经过CDN联盟讨论,我们制定了相关的协议扩展规范,并在FFmpeg中完成了相关代码实现。
本文后面介绍的就是如何在FFmpeg中,对RTMP进行HEVC扩展。如果您的开发工程中并没有用到FFmpeg,可直接阅读第四章节,也能够很轻松的在您的代码中增加这部分内容。
2.FFmpeg简析
FFmpeg从无到有,发展至今,功能日益强大,代码也越来越多,很多初学者都被其众多的源文件、庞大的结构体和复杂的算法打消了继续学习的念头。本章节将从总体对FFmpeg进行简单的解析,教您如何阅读FFmpeg源码。
2.1总体说明
FFmpeg包含如下类库:
libavformat - 用于各种音视频封装格式的生成和解析,包括获取解码所需信息、读取音视频数据等功能。各种流媒体协议代码(如rtmpproto.c等)以及音视频格式的(解)复用代码(如flvdec.c、flvenc.c等)都位于该目录下。
libavcodec - 音视频各种格式的编解码。各种格式的编解码代码(如aacenc.c、aacdec.c等)都位于该目录下。
libavutil - 包含一些公共的工具函数的使用库,包括算数运算,字符操作等。
libswscale - 提供原始视频的比例缩放、色彩映射转换、图像颜色空间或格式转换的功能。
libswresample - 提供音频重采样,采样格式转换和混合等功能。
libavfilter - 各种音视频滤波器。
libpostproc - 用于后期效果处理,如图像的去块效应等。
libavdevice - 用于硬件的音视频采集、加速和显示。
如果您之前没有阅读FFmpeg代码的经验,建议优先阅读libavformat、libavcodec以及libavutil下面的代码,它们提供了音视频开发的最基本功能,应用范围也是最广的。
2.2常用结构
FFmpeg里面最常用的数据结构,按功能可大致分为以下几类(以下代码行数,以branch: origin/release/3.4为准):
1. 封装格式
AVFormatContext - 描述了媒体文件的构成及基本信息,是统领全局的基本结构体,贯穿程序始终,很多函数都要用它作为参数;
AVInputFormat - 解复用器对象,每种作为输入的封装格式(例如FLV、MP4、TS等)对应一个该结构体,如libavformat/flvdec.c的ff_flv_demuxer;
AVOutputFormat - 复用器对象,每种作为输出的封装格式(例如FLV, MP4、TS等)对应一个该结构体,如libavformat/flvenc.c的ff_flv_muxer;
AVStream - 用于描述一个视频/音频流的相关数据信息。
2. 编解码
AVCodecContext - 描述编解码器上下文的数据结构,包含了众多编解码器需要的参数信息;
AVCodec - 编解码器对象,每种编解码格式(例如H.264、AAC等)对应一个该结构体,如libavcodec/aacdec.c的ff_aac_decoder。每个AVCodecContext中含有一个AVCodec;
AVCodecParameters - 编解码参数,每个AVStream中都含有一个AVCodecParameters,用来存放当前流的编解码参数。
3. 网络协议
AVIOContext - 管理输入输出数据的结构体;
URLProtocol - 描述了音视频数据传输所使用的协议,每种传输协议(例如HTTP、RTMP)等,都会对应一个URLProtocol结构,如libavformat/http.c中的ff_http_protocol;
URLContext - 封装了协议对象及协议操作对象。
4. 数据存放
AVPacket