H264码流结构讲解

所谓的码流结构就是指:视频经过编码之后所得到的数据是怎样排列的,换句话说,就是编码后的码流我们该如何将一帧一帧的数据分离开来,哪一块数据是一帧图像,哪一块是另外一帧图像,只要了解了这个,后面的事情就好办了。

1.H264帧的定义

        在H264编码中有I帧,p帧和B帧。每一帧都相当于一张静止的图像。在实际的码流传输中会利用编码器来压缩图像以减少视频的体积,其中I帧、P帧、B帧最为常见。

I 帧: I 帧通常又称之为内部画面,它通常是视频编码的第一帧。它的最大特点是自带一个完整的图像信息,在解码的过程中只需要解码本帧就可以完整地提取出一个完整的画面。假设一个视频中丢失了I 帧,则整个视频则会处于黑屏状态,后面的视频则无法正常播出。由此可见, I 帧在视频编码中扮演着相当重要的角色。但是它也有自身的缺点,那就是I 帧的体积比较大,假设在传输视频中全部采用 I 帧去传输,那整个网络链路都承受着巨大的压力。 所以,I 帧就要配合 P 帧、 B 帧等进行数据的传输。
P 帧: P 帧又称之为前向参考帧,此帧的特点是需要参考前一帧的图像信息才可以正确把图像解码出来。 P 帧指的是这一帧和前一帧的差别,并通过将图像序列中已经编码后的冗余信息充分去除来压缩传输数据量的编码图像。
B 帧: B 帧也称之为双向参考帧, B 帧的特点是以前面的帧 (I 帧或者 P ) 或者后面的帧 ( 也是 I 帧、 P ) 作为参考帧找出 B 帧的预测值,并且取预测差值和预测矢量进行传送。所以在拉流端解码B 帧的时候不仅需要获得前面的缓存视频,还需要获得后面的缓存视频才能够正常解码 B 帧。所以, B 帧虽然压缩率更高,但是更消耗CPU 资源

2.GOP(I帧间隔)

     GOP 指的是两个 I 帧之间的距离,在一个 GOP 包含了一组连续的图片。在一个 GOP 中包含了 I 帧、 P 帧、 B 帧,直到下一个 I 帧的出现,一个 GOP 才算结束。
    通常来说,I 帧所占用的字节和体积大于 P 帧、而 P 帧所占用的字节大于 B 帧。所以在码率不变的情况下,可以调整 GOP 的长度去改善画质, GOP的长度越长,所得到的P 帧和 B 帧更多,画面的质量和细节就会更好。

 

3.Slice片

        一帧图像可以分成若干片,每一片又可分成若干个宏块。宏块是视频的最小单位。

        为了并行编码,所以引入了片的概念,所谓的并行编码就是把一帧图像分成几个片,每个片相互独立进行编码。

4.H264的码流格式

        H264的码流格式可以分为两类,不同的码流格式,对于编码器的处理方式不同

        1.Annexb格式:也叫字节流格式,字节流格式使用起始码来表示一个编码数据的开始,起始码不是图像数据的一部分,只起到一个分隔图像的作用。大部分的编码器默认输出的是字节流格式的,字节流格式也叫做H264裸流。字节流格式的基本数据单元是NAL(也叫NALU)单元,为了从字节流中提取出NAL单元,协议规定,每个NAL前必须加上一个开始码

0x00000001(4字节)或0x000001(三字节)

        这里要注意一下,NAL中的h264数据也有可能包含0x00000001或0x000001,一般对NAL的这种情况会做出如下的处理:
        (1)00 00 00 修改成00 00 00 03 00

        (2)00 00 01 修改成00 00 00 03 01

        (3)00 00 02 修改成00 00 00 03 02

        (4)00 00 03 修改成00 00 00 03 03

           即只能出现连续两个字节的 00 00

 

 所以基于字节流的H264裸流=起始单元+NALU + 起始单元 + NALU +............

   2.MP4格式,MP4格式没有起始单元,但是MP4编码中使用了4字节长度作为标识,用来表示编码数据的长度。每次读取4字节数据计算出编码数据的长度,然后取出编码数据,再读取4字节,计算出数据长度,然后取出数据,这样一直计算下去就可以取出编码数据了。

5.NALU组成结构

       H264裸流分层可以分成两层,一层是VCL层(视频编码的底层),另外一层是NAL层(网络提取层也叫NALU),VCL层包含的是H264的视频内容,NALU负责的是把网络视频进行打包和传输,对于开发人员我们一般是不关心CVL层的,我们关注的重点一般都是NALU

        对于NALU,我们主要抓住的是NALU Header(1byte)和RBSP(原始字节序列载荷)

       

(1)NALU Header主要包括三部分,分别为:forbidden_zero_bitnal_ref_idcnal_unit_type,它们总共占据一个字节,也就 是说,NALU Header,在整个NALU中,占据一个字节。

        forbidden_zero_bit(禁止位)占据一个bit固定为0,当它不为0时表示在整个网络传输中,产生了错误,此时解码器可以不对此段数据进行解码

        nal_ref_idc:取值0~3,代表当前NALU的重要性,数字越大越重要,就需要被优先保护。尤其是当前NALU为图像参数集、序列参数集或IDR帧,或参考图像带(片/Slice)又或者是参考图像的带数据分割时,nal_ref_idc肯定是不为0的。

        nal_unit_type:这个表示NALU Header后面的RBSP数据的类型

       pps NALU(图像参数集):pps主要包含熵编码类型、基础QP和最大参考帧数量等基本的编码信息

       sps NALU(参数序列集):主要包含图像的宽、高、YUV格式和位深等基本的信息,如果没有pps和sps中包含的基础信息,之后的I帧P帧和B帧就无法进行解码。

       IDR NALU(及时解码刷新图像):IDR帧,即:及时解码刷新图像,它是一个序列的第一个图像,H.264引入IDR图像是为了解码的重新同步。当解码器解码到IDR图像时,立即将参考帧队列清空,将已解码的数据 全部输出或抛弃,重新查找参数集,开始一个新的序列。这样一来,如果前一个序列发生重大错误,在这里就可以获得重新同步。所以IDR图像之后的图像,永远不会引用IDR图像之前的图像来解码。并且IDR图像一定是I图像,而I图像不一定是IDR图像(H264里没有图像层,图像可以理解为帧、片或宏块)。

        如何区分这几种NALU的类型:
        

NALU = NALU Header + NALU Body       

NALU Body结构如图所示:

           NALU主体涉及三个重要的名词,分别是EBSP、RBSP和SODB。EBSP包含了RBSP,RBSP中又包含了SODB

    SODB(数据比特串):就是VCL层,是最基本的编码数据,没有包含任何的附加信息。视频解码的目的就是获取SODB

    RBSP(原始字节序列载荷):在SODB的后面加上了结尾比特,一个bit1和若干个bit0,用来字节对齐

    EBSP(扩展字节序列载荷):在RBSP的基础上添加了仿效字节(0x03).这样做的原因上面也介绍过,因为NALU的起始数据是 00 00 00 00 01或 00 00 01,防止NALU中的其他数据也出现 00 00 00 01 或 00 00 01,所以NALU会把连续的两个 00 00后插入一个0x03,在解码时,会自动的把加入的0x03丢掉,这个操作叫做脱壳操作。

所以通过以上的分析我们可以得出NALU = NALU Header + EBSP(出现连续00 00的情况)或NALU = NALU Header + =RBSP(未出现连续00 00 的情况)

通常来说,一个原始的 H.264 [StartCode] [NALU Header] [NALU Payload] 。三部分组成,其中 Start Code 用于标示这是一个 NALU 单元的开始,必须是"00 00 00 01" "00 00 01" ,具体的如下图:

如图所以,画框的都是一帧NALU单元,我们介绍一下NALU数据的特殊意义:

        00 00 00 01 06 05这是SEI数据,是视频的附加信息,包含了用户的自定义信息,比如时间戳,字幕和弹幕信息等。SEI信息一般放在编码图像之前,很多时候SEI是可以忽略的

        00 00 00 01 67这是SPS数据,这指的是序列参数集,它保存了一组编码视频序列的全局参数。编码视频序列指的是原始数据经过编码后组成的一系列序列集。

        00 00 00 01 68PPS数据,这指的是图像的参数集,主要用于保存图像序列集中一个或多个独立的图像,一般情况下,配合SPS和PPS都是H264开头的两个NALU头。

        00 00 00 01 65IDR数据,IDR指的是H264一帧完整的图像数据,也就是常说的关键帧。

        所以一个标准的H264码流结构一般是:SEI+SPS+PPS+IDR

6.I帧和IDR帧的区别和联系

        IDR属于I帧,但是I帧不一定是IDR帧。只有IDR帧,才有SPS和PPS。解码器收到IDR帧时,将缓存清空;而收到I帧不会清空缓存。也就是说,对某个IDR帧之后的帧,解码器不会参考这个IDR帧之前的任何帧做解码。对某个I帧之后的帧,解码器可能会参考这个I帧之前的帧做解码。

        

  • 4
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值