一篇文章讲明白FFmpeg从入门到精通:SEI那些事

简介: 一篇文章讲明白FFmpeg从入门到精通:SEI那些事

本文是“FFmpeg从入门到精通”系列的第三篇,由金山云供稿,并授权LiveVideoStack发布。此前两篇为FFmpeg代码导读——基础篇和FFmpeg代码导读——HEVC在RTMP中的扩展。FFmpeg广泛应用与音视频领域,被誉为音视频开发的“瑞士军刀”。“FFmpeg从入门到精通”系列将由浅入深,解读FFmpeg的基础功能与使用技巧。

流媒体是采用流式传输方式在网络上播放的媒体格式,视频网站内容、短视频、在线直播这些视频形态,均属于流媒体的不同分支。流媒体大致包含三个层级:码流、封装和协议。从音视频编码器输出的码流,经过某种封装格式后,经过特定的协议传输、保存,构成了流媒体世界的基础功能。

在直播应用的开发过程中,如果把主播端消息事件传递到观众端,一般会以Instant Messaging(即时通讯)的方式传递过去,但因为消息分发通道和直播通道是分开的,因此消息与直播音视频数据的同步性就会出现很多问题。那么有没有在音视频内部传递消息的方法呢?答案是SEI。金山云目前推出的直播问答解决方案中,就用到了SEI,作为一名视频云架构资深开发工程师,今天就来和大家分享一下SEI的技术细节。

SEI即补充增强信息(Supplemental Enhancement Information),属于码流范畴,它提供了向视频码流中加入额外信息的方法,是H.264/H.265这些视频压缩标准的特性之一。SEI的基本特征如下:

并非解码过程的必须选项

可能对解码过程(容错、纠错)有帮助

集成在视频码流中

也就是说,视频编码器在输出视频码流的时候,可以不提供SEI信息。虽然在视频的传输过程、解封装、解码这些环节,都可能因为某种原因丢弃SEI内容,但在视频内容的生成端和传输过程中,是可以插入SEI信息的。这些插入的信息,和其他视频内容一同经过传输链路到达消费端。举例来说,当前火爆的直播问答模式,就是通过SEI传递较多和答题业务相关的信息,通过SEI承载的信息,极大地优化了题目显示和观众音视频观看的同步性。

那么在SEI中可以添加哪些信息呢?以下是一些用户场景可任意扩展的例子:

传递编码器参数

传递视频版权信息

传递摄像头参数

传递内容生成过程中的剪辑事件(引发场景切换)

对于SEI如何应用,我们先以H.264/AVC这一视频编码标准为例。在这一标准中,整个系统框架分为两层:视频编码层面(Video Coding Layer,简称VCL)和网络抽象层面(Network Abstraction Layer,简称NAL)。VCL负责表示有效视频数据的内容,NAL负责格式化数据并提供头信息,以保证数据适合各种信道和存储介质上的传输。NAL unit是NAL的基本语法结构,它包含一个字节的头信息(NAL header)和一系列来自VCL的原始数据字节流(RBSP)。

H.264/AVC中的情况

NAL unit type储存在NAL header中,在H.264/AVC标准中,可用的NAL unit type一共有17种,作用是告诉解码器,承载的数据是视频关键帧,还是视频解码器的配置参数信息。其中值为6时表征SEI内容。比较常见的类型如下表所示:

NAL unit type NAL unit content

H.264/AVC中完整的NAL unit类型定义请参考《ISO/IEC 14496-10:2014》,这是MPEG专家组为AVC编解码器制定的标准,H.264/AVC中NAL unit类型完整定义都在该标准的7-1表中,标准一共预留了32种类型,在NAL header里面,用5 bits表征NAL unit type。

H.264/AVC中的NAL unit type

如上图所示,在8 bits的NAL header中:

第0位是禁止位0,值为1时表示语法出错

第1~2位是参考级别(NRI,NAL ref idc)

第3~7位是NAL unit type

需要注意的是,当NRI取值为"00"(二进制)时,表征NAL unit不参与重建参考图像,这时的NAL unit是可以丢弃的。大于"00"(二进制)时,NAL unit不能被丢弃。

H.265/HEVC中的情况

《ISO/IEC 23008-2:2015》是MPEG专家组为HEVC编解码器制定的标准,H.265/HEVC中NAL unit类型完整定义都在该标准的7-1表中,可用的NAL unit type一共有40种之多,其中39和40都表征SEI内容。因为标准一共预留64种类型,所以在NAL header里面,用6 bits表征NAL unit type。

H.265/HEVC中的NAL unit type

如上图所示,在16 bits的NAL header中:

第0位是禁止位0,值为1时表示语法出错

第1~6位是NAL unit type

第7~12位是NUH layer id

第13~15位是temporal_id

SEI 类型

在H.264/AVC视频编码标准中,并没有规定SEI payload type的范围,所以表征payload type的字节数是浮动的。

语法分析如下所示,当开始解析类型为SEI的NAL时,持续读取8bit,直到非0xff为止,然后把读取的数值累加,累加值即为SEI payload type。

sei_message(){undefined

payloadType = 0

while( next_bits(8) == 0xFF){undefined

ff_byte

payloadType += 255

}

last_payload_type_byte

payloadType += last_payload_type_byte

}//代码效果参考:http://www.ezhiqi.com/zx/art_2236.html

读取SEI payload size和payload type逻辑类似,仍然是读取到0xff为止,这样可以支持任意长度的SEI payload添加。

sei_message(){undefined

payloadSize = 0

while( next_bits(8) == 0xFF){undefined

ff_byte

payloadSize += 255

}//代码效果参考:http://www.ezhiqi.com/bx/art_123.html

last_payload_size_byte

payloadSize += last_payload_size_byte

}

当获取了SEI payload类型和大小后,就进入了实际的SEI内容读取。

当前《ISO/IEC 14496-10:2014》Annex D.1.1提供了最大到181的payload类型处理规范,由于类型可以指定任意大小,给SEI的添加、处理创造了很大的自由空间。

其中SEI payload类型值为5时,指定的处理方法叫user_data_unregistered(),字面含义为未注册的用户数据,常用于存储编码器的编码参数信息,是比较常见的payload类型。

读取payload type为5时,具体的语法解析流程如下:

function DisplayWindowSize(){undefined

var w=window.innerWidth

|| document.documentElement.clientWidth

|| document.body.clientWidth;

}//代码效果参考:http://www.ezhiqi.com/bx/art_3703.html

其中uuid_iso_iec_11578的详细定义在《ISO/IEC 11578:1996》 Annex A中,大致规定了使用128 bits(16个字节)来指定UUID。此处UUID可以表征写入SEI payload的角色ID,或者表征其他业务用途。剩下的payloadSize -16字节,即是业务层传递的具体内容了。

通过user_data_unregistered()语法解析可以看出,当使用SEI payload type为5时,注意事项如下:

payload size应该大于16;

uuid可能出现0x000000/0x000001/0x000002,需要插入0x03做防竞争处理;

构成RBSP时,都需要做RBSP拖尾处理。拖尾处理对所有SODB方式都一致。rbsp_trailing_bits()语法逻辑如下:

rbsp_trailing_bits( ){undefined

rbsp_stop_one_bit

while( !byte_aligned( ) )

rbsp_alignment_zero_bit

}

SEI例子

从video.js的示例中下载oceans.mp4并提取出H.264码流如下:

bitstream from oceans.mp4

NAL header

起始码(暗红底色)"0x00000001"分割出来的比特流即是NAL unit,起始码紧跟的第一个字节(墨绿底色)是NAL header。上图“NAL header”一共出现了四个数值:

"0x06",此时NRI为"00B",NAL unit type为SEI类型。

“0x67”,此时NRI为“11B”,NAL unit type为SPS类型。

“0x68”,此时NRI为“11B”,NAL unit type为PPS类型。

“0x65”,此时NRI为“11B”,NAL unit type为IDR图像。

SEI payload type

"0x06"后一个字节为“0x05”(淡黄底色)是SEI payload type,即表征SEI payload分析遵循user_data_unregistered()语法。

SEI payload size

“0x05”后一个字节为“0x2F”(淡蓝底色)是SEI payload size,此时整个payload是47个字节。

SEI payload uuid

"0x2F"随后的16个字节即为uuid,此时uuid为

<p style="margin-left: 16

相关文章
|
7月前
|
Web App开发 编解码 安全
视频会议技术 入门探究:WebRTC、Qt与FFmpeg在视频编解码中的应用
视频会议技术 入门探究:WebRTC、Qt与FFmpeg在视频编解码中的应用
693 4
|
编解码 API 开发工具
FFmpeg入门及编译 1
FFmpeg入门及编译
186 1
|
C++ Windows
FFmpeg入门及编译 3
FFmpeg入门及编译
117 0
|
7月前
|
存储 编解码 缓存
FFmpeg编程入门
FFmpeg编程入门
94 1
|
3月前
|
内存技术
速通FFmpeg入门
速通FFmpeg入门
42 5
|
6月前
|
存储 编解码 Linux
rodert教你学FFmpeg实战这一篇就够了 - 音视频处理入门篇
rodert教你学FFmpeg实战这一篇就够了 - 音视频处理入门篇
75 1
|
API C语言 C++
FFmpeg入门及编译 2
FFmpeg入门及编译
158 0
ffmpeg入门小结(三)—— 傅里叶变换之美
ffmpeg入门小结(三)—— 傅里叶变换之美
146 0
ffmpeg入门小结(三)—— 傅里叶变换之美
|
存储 编解码 编译器
ffmpeg入门小结(一)—— YUV格式示例
ffmpeg入门小结(一)—— YUV格式示例
396 0
ffmpeg入门小结(一)—— YUV格式示例
|
存储 缓存 编解码
ffmpeg入门小结(二)——音视频同步
ffmpeg入门小结(二)——音视频同步
392 0

相关实验场景

更多