FFmpeg的入门

引言H264编码使用

VideoToolbox硬编码录制H264视频

从iOS8开始,苹果将VideoToolbox.framework开放了出来,使开发者可以使用iOS设备内置的硬件设备来进行视频的编码和解码工作。硬件编解码的好处是,复杂的计算由专门的硬件电路完成,往往比使用cpu计算更高效,速度更快,功耗也更低。

VideoToolbox 工作流程大致为:

创建Session ->设置编码相关参数 ->开始编码

—> 循环输入源数据(yuv类型的数据,直接从摄像头获取)

—> 获取编码后的h264数据

结束编码

以下为详细代码,内有详细注释,完整工程在文章末尾。


FFmpeg的入门_第1张图片
FFmpeg的入门_第2张图片
FFmpeg的入门_第3张图片
FFmpeg的入门_第4张图片
FFmpeg的入门_第5张图片

编码保存的h264数据保存到Document目录下,在Info.plist文件中添加Application supports iTunes file sharing ,并设置为YES,即可通过iTunes直接导出来,然后使用VLC播放器即可直接播放。 

FFmpeg的入门_第6张图片

正文H.265编码格式

视频流媒体中程中视频数据的传输占据了绝大部分的带宽,如何提升编码效率,使用更少的带宽,提供更优质的画面质量,是音视频开发人员一直努力的重点。HEVC(High Efficiency Video Coding,也叫H.265)编码格式的推出,给这一方向带来了突破点,但由于其算法复杂度较高,前期未曾得到普遍应用,而随着移动设备计算能力的提高和越来越多的设备开始支持HEVC的硬件编/解码,直播平台也开始逐渐引入HEVC视频格式。

HEVC属视频编码层面标准,如果在视频流媒体中进行应用,还需要相应的封装格式和流媒体协议的支持。鉴于直播的大部分推拉流协议是基于RTMP的,本文主要介绍如何在RTMP协议中增加对HEVC视频编码格式的支持,其他协议或私有协议,

1. 背景介绍

典型的直播框架通常包括三大部分,如下图所示:

1. 推流端:负责音视频数据的采集、处理、编码及封装后将数据推送至源站;

2. 服务端:涵盖源站和CDN,接收来自推流端的音视频数据,然后将数据分发至各播放端;

3. 播放端:从CDN拉取直播数据,解复用、解码后渲染音视频数据;

FFmpeg的入门_第7张图片

图1. 直播框架图

引入HEVC编码,涉及到的变动部分如上图中红色字体所标注:

1. 编码模块:需要支持HEVC格式的编解码,该部分不属于本文的介绍范畴,我们有在其它文章中介绍如何在iOS11上进行HEVC的硬编硬解,感兴趣的朋友可自行查阅;

4. 封装/传输模块:RTMP、HTTP-FLV流媒体协议需要增加对HEVC视频编码格式的支持,该部分是本文介绍的重点。

相信广大的音视频开发者对于FFmpeg并不陌生,由于它在多媒体处理上提供的强大功能以及开源易于修改维护的特性,使得其被广泛应用于各音视频相关软件中。官方FFmpeg中,并没有对RTMP/FLV中进行HEVC的相关扩展,我们基于此作出了修改。本文后面介绍的就是如何在FFmpeg中,对RTMP进行HEVC扩展。如果您的开发工程中并没有用到FFmpeg,可直接阅读第四章节,也能够很轻松的在您的代码中增加这部分内容。

本文我们会着重介绍如果在iOS11上使用系统API进行265硬编硬解功能,读者需要有使用VideoToolBox进行H.264硬编/解码的相关经验。

一、什么是HEVC(H.265)

HEVC全称High Efficiency Video Coding(高效率视频编码),是比H.264更加优秀的一种视频压缩标准(也称为H.265)。HEVC在低码率视频压缩上,提升质量、减少容量和节省带宽方面都有突出表现,因此除了拍摄占用的容量减少外,在视频通话时也能更加流畅清晰。据9to5Mac的测试结果,原来的H.264标准需要需要60MB才能达到的画质,HEVC仅需要33MB。从下图的压缩效果可以看出,HEVC的压缩算法更加智能,虽然图片细节丢失的情况更高,但是却不会严重影响视频的画质。


H.264与H.265的压缩效果对比.png

需要注意的是,H.265的硬编/解功能,并不是ios的所有设备升级到新系统上都可以使用,目前苹果公布可使用HEVC编/解码的移动设备要求如下:

iOS 11 HEVC Encode


H.265硬编.png

iOS 11 HEVC Decode


FFmpeg的入门_第8张图片

H.265硬解.png

二、VideoToolBox编码

使用VideoToolBox进行H.264和H.265编码的流程完全相同,只在创建和配置编码器上存在少量差异,下面以VideoToolBox的编码流程为线索,说明使用两种编码格式时的区别。

1. 创建VTCompressionSession



FFmpeg的入门_第9张图片

如果使用H.264编码功能,参数codecType需要设置为kCMVideoCodecType_H264;

如果使用H.265编码功能,参数codecType需要设置为kCMVideoCodecType_HEVC;

其他参数在使用两种编码格式时没有区别。

2. 设置编码相关参数


FFmpeg的入门_第10张图片

3. 启动编码



4. 循环输入源数据(yuv类型)


FFmpeg的入门_第11张图片

5. 获取编码后的数据

通过在创建VTCompressionSession传入回调函数,获取编码后的数据。


FFmpeg的入门_第12张图片

至此针对使用VideoToolBox进行H.264/H.265编码的基本流程已经介绍完毕。

三、VideoToolBox解码

VideoToolBox的解码主要涉及以下几个函数:

VTDecompressionSessionCreate 创建解码session

VTDecompressionSessionDecodeFrame 解码一个frame

VTDecompressionSessionInvalidate 销毁解码session

其中VTDecompressionSessionCreate创建session时需要CMVideoFormatDescriptionRef类型的视频格式描述,而对于CMVideoFormatDescriptionRef,VideoToolBox中提供了多个方法可以创建:

CMVideoFormatDescriptionCreateCMVideoFormatDescriptionCreateForImageBufferCMVideoFormatDescriptionCreateFromH264ParameterSets

在iOS11中新增了一个方法:

CMVideoFormatDescriptionCreateFromHEVCParameterSets

用以创建H.265视频格式的描述。

对于H.264和H.265的解码,在VideoToolBox层面的操作完全一致,唯一不同的就是视频格式的描述类型不同。最常使用也最容易理解的为后两个通过ParameterSets来创建的函数,前两个函数的创建方式未作详细了解。

至此,对使用VideoToolBox解码H.265视频的重点就放在如何获取ParameterSets(即VPS、SPS和PPS)上。

3.1 H.265 NALU类型

同H.264一样,H.265数据也是以NALU的形式组织起来,区别在于H.264的NALU Header为一个字节,而H.265的为两个字节,其结构如下:


FFmpeg的入门_第13张图片

H265 nalu header

所以,H.265编码格式的NALU类型判断方式如下,code为NALU Header的第一个字节:

int type = (code &0x7E)>>1;

其中type类型为32、33、34的NALU分别为VPS、SPS和PPS,其他类型参见H.265规范《T-REC-H.265-201304-I!!PDF-E》。

3.2 HEVCDecoderConfigurationRecord

使用ffmpeg读取MP4文件后,视频的AVCodecContext结构的extradata存储的即为包含有SPS、PPS信息的数据结构。

对于H.264格式的视频来说,为AVCDecoderConfigurationRecord,该结构在标准文档《ISO-14496-15 AVC file format》中有详细说明。

对于H.265格式的视频来说,为HEVCDecoderConfigurationRecord,此结构的定义目前未找到官方的定义,参考https://lists.matroska.org/pipermail/matroska-devel/2013-September/004567.html及ffmpeg中hevc.c文件中的实现,该结构详细如下:


FFmpeg的入门_第14张图片
FFmpeg的入门_第15张图片

其中最后的nalUnit存储的即为VPS、SPS和PPS信息。

获取到VPS、SPS和PPS之后,就可以通过

CMVideoFormatDescriptionCreateFromHEVCParameterSets

来创建H.265视频格式的描述信息,再创建解码session即可使用VideoToolBox进行解码。

3.3 说明

iOS 11 beta2的版本中

VTDecompressionSessionWaitForAsynchronousFrames

此函数调用会失败,目前不确定是beta系统的问题还是什么其他原因,在该版本的iOS系统上使用ijkplayer VideoToolBox解码会发现播放卡顿,就是因为该函数的问题导致,留待后续版本观察(7月10日已经推出beta3版本,还未确认)

你可能感兴趣的:(FFmpeg的入门)