引言

更多文章请访问 自己动手写 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相关推荐

  1. FFmpeg的H.264解码器源代码简单分析:环路滤波(Loop Filter)部分

    ===================================================== H.264源代码分析文章列表: [编码 - x264] x264源代码简单分析:概述 x26 ...

  2. FFmpeg的H.264解码器源代码简单分析:宏块解码(Decode)部分-帧间宏块(Inter)

    ===================================================== H.264源代码分析文章列表: [编码 - x264] x264源代码简单分析:概述 x26 ...

  3. FFmpeg的H.264解码器源代码简单分析:宏块解码(Decode)部分-帧内宏块(Intra)

    ===================================================== H.264源代码分析文章列表: [编码 - x264] x264源代码简单分析:概述 x26 ...

  4. FFmpeg的H.264解码器源代码简单分析:概述

    ===================================================== H.264源代码分析文章列表: [编码 - x264] x264源代码简单分析:概述 x26 ...

  5. FFmpeg的H.264解码器源代码简单分析:宏块解码(Decode)部分-帧间宏块(Inter)...

    ===================================================== H.264源代码分析文章列表: [编码 - x264] x264源代码简单分析:概述 x26 ...

  6. FFmpeg的H.264解码器源代码简单分析:宏块解码(Decode)部分-帧内宏块(Intra)...

    ===================================================== H.264源代码分析文章列表: [编码 - x264] x264源代码简单分析:概述 x26 ...

  7. FFmpeg的H.264解码器源代码简单分析:解码器主干部分

    ===================================================== H.264源代码分析文章列表: [编码 - x264] x264源代码简单分析:概述 x26 ...

  8. 视频无信号--H.265与H.264解码器连接录像机拼接电视显示画面处理

    1.录像机 录像机可以正常在电视墙上工作,则是解码器端或IP网段问题 2.解码器–调本地IP使其与解码器在同一网段 3.查看解码器出厂地址–账号密码 终端通过网页访问IP地址,或者ping 192.1 ...

  9. H.264解码器ffmpeg完整优化代码(包括PC和Windows Mobile版本)

    这里把前段时间对ffmpeg0.48进行简化和修改,包括修正内存泄漏,修改一些语句使Max Speed能够打开这些.其实代码还是比较乱的,也有很大的继续优化空间.这个工作花费了我一些休息时间,不过,我 ...

最新文章

  1. 朱俊彦团队最新论文:用GAN监督学习给左晃右晃的猫狗加表情,很丝滑很贴合...
  2. ios 添加浮动效果_iOS实现拖拽View跟随手指浮动效果
  3. node 连接mongodb
  4. cmake编译动态库和静态库
  5. DOS下文件操作命令
  6. Vmware由于centos升级内核不可运行(C header files matching your running kernel were not found)的解决方案
  7. 你努力的样子很“可耻”
  8. MTK_android11_WIFI(内网)和4G(外网)共存
  9. 日志管理(spring AOP切面拦截)
  10. 最全的WiFi速率对应表(802.11b、802.11g、802.11a、802.11n、802.11ac、802.11ax)及速率计算方法
  11. 戴尔linux改win7教程视频,戴尔笔记本win10改win7系统BIOS设置详细教程
  12. 贝叶斯基础理论及思想介绍
  13. 宽带连接显示服务器问题怎么办,宽带连接时错误678问题怎么解决【解决方法】...
  14. 汇编语言||基本传送指令MOV的用法详解
  15. Dynamics 365 设置Postman environment For WebAPI
  16. 快乐的牛奶商 c语言6,C语言程序设计基础实训手册
  17. 计算机编程语言的应用
  18. 燕窝等物品不得携带入境 具有相关检疫证书和疫苗接种证书的犬、猫等宠物
  19. 从零开始学习Hadoop--第5章 压缩
  20. 【ESP32CAM识别图形左边界】(三)识别图像左边界

热门文章

  1. opencv-python读取摄像头视频流保存为视频
  2. 【博学谷学习记录】超强总结,用心分享 | 狂野大数据 | 环境 | hive搭建
  3. openSUSE 多个GPU设置 深度学习 Caffe PyTorch 等
  4. JavaScript DOM节点
  5. 2剪切移位镜像反射旋转
  6. TypeScript基础+进阶
  7. java map扩容机制_Java HashMap的原理、扩容机制、以及性能思考
  8. Linux文件删除但空间不释放问题篇
  9. WinRAR(5.70)去广告
  10. 浏览器指纹技术与浏览器指纹破解办法