自己动手写 H.264 解码器---AnnexB 和 avcC
引言
更多文章请访问 自己动手写 H.264 解码器
目前 H.264 流行的包装方式有两种,一种叫做 AnnexB,一种叫做 avcC。对于这两种格式,各家的支持程度也不太一样,例如,Android 硬解码 MediaCodec 只接受 AnnexB 格式的数据,而 Apple 的 VideoToolBox,只支持 avcC 的格式。所以这就需要我们从业者对两种格式都有一个了解。本章,我们先来介绍 AnnexB
AnnexB
假如我们把多个 NALU 写到一个文件里面去,多个 NALU 首位相连穿成一串,因为 NALU 本身长度不一,也没有具体的标识符用来表明自己是一个独立的 NALU,那么我们在读取这个文件的时候其实并没有办法将写到一起 NALU 有效得进行区分。为了解决这个问题,我们必须给 NALU 添加上一些数据,将各个 NALU 进行分割。 AnnexB 就是用来对 NALU 层进行包装的一种格式。
AnnexB 格式的原理非常简单,就是在一个 NALU 前面加上三个或者四个字节,这些字节的内容是 0 0 0 1 或者 0 0 1。当我们读取一个 H264 流的时候,一旦遇到 0 0 0 1 或者 0 0 1,我们就认为一个新的 NALU 开始了,因此,这些用来做分隔符的字节,一般也被称为 start code, 起始码。
防竞争字节 (Emulation Prevention Bytes)
但是只在 NALU 前面加上起始码是会产生问题了,因为原始码流中,是有可能出现 0 0 0 1 或者 0 0 1 的,这样就会导致读取程序将一个 NALU 误分割成多个 NALU。为了防止这种情况发生,AnnexB 引入了防竞争字节(Emulation Prevention Bytes)的概念。
所谓防竞争字节(Emulation Prevention Bytes),就是在给 NALU 添加起始码之前,先对码流进行一次遍历,查找码流里面的存在的 0 0 0,0 0 1,0 0 2,0 0 3 的字节,然后对其进行如下修改
0 0 0 => 0 0 3 0
0 0 1 => 0 0 3 1
0 0 2 => 0 0 3 2
0 0 3 => 0 0 3 3
即在上面的 4 种情况下,在 0 0 之后,插入一个字节,内容是 3。经过这样处理的码流,就不会再和起始码(0 0 1, 0 0 0 1)重复而发生冲突。
当然,在解码过程中,通过起始码成功分割 NALU 数据之后,还要将防竞争字节去掉。
0 0 3 0 => 0 0 0
0 0 3 1 => 0 0 1
0 0 3 2 => 0 0 2
0 0 3 3 => 0 0 3
这样才能得到真正的 NALU 码流。
avcC
AnnexB 的原理是在每个 NALU 前面写上一个特殊的起始码,通过这个起始码来当做 NALU 的分隔符,从而分割每个 NALU。而 avcC 则采用了另外一种方式。那就是在 NALU 前面写上几个字节,这几个字节组成一个整数(大端字节序)这个整数表示了整个 NALU 的长度。在读取的时候,先把这个整数读出来,拿到这个 NALU 的长度,然后按照长度读取整个 NALU。
avcC 详解
在介绍 avcC 格式之前,我们先来介绍一下两个特殊的 NALU,这两个 NALU 就是 SPS 和 PPS,SPS 和 PPS 存放了解码一路 H.264 码流的必要的参数信息,也就是说,你想要解码一路 H.264,就必须首先获取到 SPS 和 PPS。在后面的课程中,我们会详细介绍 SPS 和 PPS,现在你只需要知道,SPS 和 PPS 是特殊且重要的两个 NALU。
在 AnnexB 中,SPS 和 PPS 被当做了普通的 NALU 进行处理;而在 avcC 中,SPS 和 PPS 信息被当做了特殊的信息进行了处理。
在一路采用 avcC 打包的 H.264 流之中,我们首先看到的将是一段被称之为 extradata 的数据,这段数据定义了这个 H.264 流的基本属性数据,当然,也包含了 SPS 和 PPS 数据。
我们来看一下 extradata 数据格式
bits
8 version ( always 0x01 )
8 avc profile ( sps[0][1] )
8 avc compatibility ( sps[0][2] )
8 avc level ( sps[0][3] )
6 reserved ( all bits on )
2 NALULengthSizeMinusOne // 这个值是(前缀长度-1)
3 reserved ( all bits on )
5 number of SPS NALUs (usually 1) repeated once per SPS:
16 SPS size variable SPS NALU data
8 number of PPS NALUs (usually 1) repeated once per PPS
16 PPS size variable PPS NALU data
我们注意一下这个值 NALULengthSizeMinusOne,通过将这个值加 1 ,我们就得出了后续每个 NALU 前面前缀(也就是表示长度的整数)的字节数
例如,这个 NALULengthSizeMinusOne 是 3,那么每个 NALU 前面前缀的长度就是 4 个字节。我们在读取后续数据时,可以先读 4 个字节,然后把这四个字节转成整数,就是这个 NALU 的长度了,注意,这个长度并不包含起始的4个字节,是单纯 NALU 的长度。
自己动手写 H.264 解码器---AnnexB 和 avcC相关推荐
- FFmpeg的H.264解码器源代码简单分析:环路滤波(Loop Filter)部分
===================================================== H.264源代码分析文章列表: [编码 - x264] x264源代码简单分析:概述 x26 ...
- FFmpeg的H.264解码器源代码简单分析:宏块解码(Decode)部分-帧间宏块(Inter)
===================================================== H.264源代码分析文章列表: [编码 - x264] x264源代码简单分析:概述 x26 ...
- FFmpeg的H.264解码器源代码简单分析:宏块解码(Decode)部分-帧内宏块(Intra)
===================================================== H.264源代码分析文章列表: [编码 - x264] x264源代码简单分析:概述 x26 ...
- FFmpeg的H.264解码器源代码简单分析:概述
===================================================== H.264源代码分析文章列表: [编码 - x264] x264源代码简单分析:概述 x26 ...
- FFmpeg的H.264解码器源代码简单分析:宏块解码(Decode)部分-帧间宏块(Inter)...
===================================================== H.264源代码分析文章列表: [编码 - x264] x264源代码简单分析:概述 x26 ...
- FFmpeg的H.264解码器源代码简单分析:宏块解码(Decode)部分-帧内宏块(Intra)...
===================================================== H.264源代码分析文章列表: [编码 - x264] x264源代码简单分析:概述 x26 ...
- FFmpeg的H.264解码器源代码简单分析:解码器主干部分
===================================================== H.264源代码分析文章列表: [编码 - x264] x264源代码简单分析:概述 x26 ...
- 视频无信号--H.265与H.264解码器连接录像机拼接电视显示画面处理
1.录像机 录像机可以正常在电视墙上工作,则是解码器端或IP网段问题 2.解码器–调本地IP使其与解码器在同一网段 3.查看解码器出厂地址–账号密码 终端通过网页访问IP地址,或者ping 192.1 ...
- H.264解码器ffmpeg完整优化代码(包括PC和Windows Mobile版本)
这里把前段时间对ffmpeg0.48进行简化和修改,包括修正内存泄漏,修改一些语句使Max Speed能够打开这些.其实代码还是比较乱的,也有很大的继续优化空间.这个工作花费了我一些休息时间,不过,我 ...
最新文章
- 朱俊彦团队最新论文:用GAN监督学习给左晃右晃的猫狗加表情,很丝滑很贴合...
- ios 添加浮动效果_iOS实现拖拽View跟随手指浮动效果
- node 连接mongodb
- cmake编译动态库和静态库
- DOS下文件操作命令
- Vmware由于centos升级内核不可运行(C header files matching your running kernel were not found)的解决方案
- 你努力的样子很“可耻”
- MTK_android11_WIFI(内网)和4G(外网)共存
- 日志管理(spring AOP切面拦截)
- 最全的WiFi速率对应表(802.11b、802.11g、802.11a、802.11n、802.11ac、802.11ax)及速率计算方法
- 戴尔linux改win7教程视频,戴尔笔记本win10改win7系统BIOS设置详细教程
- 贝叶斯基础理论及思想介绍
- 宽带连接显示服务器问题怎么办,宽带连接时错误678问题怎么解决【解决方法】...
- 汇编语言||基本传送指令MOV的用法详解
- Dynamics 365 设置Postman environment For WebAPI
- 快乐的牛奶商 c语言6,C语言程序设计基础实训手册
- 计算机编程语言的应用
- 燕窝等物品不得携带入境 具有相关检疫证书和疫苗接种证书的犬、猫等宠物
- 从零开始学习Hadoop--第5章 压缩
- 【ESP32CAM识别图形左边界】(三)识别图像左边界