H264的解码解析

概念简介:

1:nal的作用:简称网络抽象层,负责H264的格式化数据并且提供头信息,以保证数据适合各种信和存储介质上的传输。

nal的结构是:

NAL头+RBSP(所谓的RBSP是原始编码数据后面加了结尾比特) =1帧数据

RBSP为数据块:数据块分为

A:SODB最原始的编码数据,

B:RBSP原始编码数据后面添加了结尾比特。

    数据内部可以分为:

    1:参数集:PS:序列的全局信息:图像尺寸,视频格式等

    2:增强信息:SEI:视频序列解码的增强信息

    3:图像界定符:PD:视频图像的边界

    4:编码片:SLICE:编码片的头信息和数据

    5:数据分割:DP片层的数据,用于恢复错误解码

    6:序列结束符:表明一个序列的结束,下一个图像为IDR图像

    7:流结束符:表明流中没有图像。

C:EBSP加了防校验字符。:

H264分为两层:视频编码层(VCL)和网络提取层(NAL)VCL书记为被压缩编码后的视频数据序列,在VCL数据封装到NAL单元之后,才可以用来传输

始码StartCodePrefix,如果该NALU对应的slice为一帧的开始则用4位字节表示,ox00000001,否则用3位字节表示ox000001(是一帧的一部分)。另外,为了使NALU主体中不包括与开始码相冲突的,在编码时,每遇到两个字节连续为0,就插入一个字节的0x03。解码时将0x03去掉。也称为脱壳操作。

1个nal数据结构的基本单元:

**********************************************
NALU单元的开始 00 00 00 01 (nal的分隔符)+nal_header头
(RBSP结构)SPS+SEI+PPS+I片+图像界定符(PD视频图像边界)
SEI添加自定义信息  (视频序列解码增强信息)00 00 00 01 06

编码片SLICE  (编码片的头信息和数据)

一些主要数据结构的结构头例程

SPS 00 00 00 01 67(序列参数集SPS)
PPS 00 00 00 01 68(图像参数集PPS)
IDR 00 00 00 01 65(IDR图像的片,I帧,参考帧)
 

***************************************


       数据分割:组成片的编码数据存放在 3 个独立的 DP(数据分割,A、B、C)中,各自包含一个编码片的子集。

       分割A包含片头和片中每个宏块头数据。

       分割B包含帧内和 SI 片宏块的编码残差数据。

       分割 C包含帧间宏块的编码残差数据。

       每个分割可放在独立的 NAL 单元并独立传输。

(一般是P帧,B帧的分割传输)

 

编码器将每个NAL各自独立、完整地放入一个分组,因为分组都有头部,解码器可以方便地检测出NAL的分界,并依次取出NAL进行解码。

每个NAL前有一个起始码 0x00 00 01(或者0x00 00 00 01),解码器检测每个起始码,作为一个NAL的起始标识,当检测到下一个起始码时,当前NAL结束。同时H.264规定,当检测到0x000000时,也可以表征当前NAL的结束。那么NAL中数据出现0x000001或0x000000时怎么办?H.264引入了防止竞争机制,如果编码器检测到NAL数据存在0x000001或0x000000时,编码器会在最后个字节前插入一个新的字节0x03

注意:解码器在解码时,首先逐个字节读取NAL的数据,统计NAL的长度,然后再开始解码。

 

2:   H264的分块

 

场帧的概念:,视频中的一场一帧可以产生一个编码图片    。

一帧是有一片或者多个片组成,一片由1个或者多个宏块组成

一个编码图像通常划分为若干个宏块组成,一个宏块由一个16*16的亮度像素和附加的一个8*8Cb和一个8*8的cr彩色像素块组成

16*16的YUV数据组成,宏块作为H264编码的基本单位

片可以分为I片(只包含I宏块)。B片(B和I宏块),P片(P和I宏块)和其他一些片

I宏块利用当前片中已解码的像素作为参考进行帧内预测。

P宏块:利用前面已编码的图像作为参考进行帧内预测

B宏块:利用双向的参考图像进行帧内预测。

3:nal头结构

1个字节:forbidden_bit(1bit) + nal_reference_bit(2bit) + nal_unit_type(5bit)

 

1.forbidden_bit:                             禁止位,初始为0,当网络发现NAL单元有比特错误时可设置该比特为1,以便接收方纠错或丢掉该单元。

2.nal_reference_bit:                   nal重要性指示,标志该NAL单元的重要性,值越大,越重要,解码器在解码处理不过来的时候,可以丢掉重要性为0的NALU。

nal_unit_type 值为 5 的NALU 为IDR帧

nal_unit_type中的1(非IDR图像的编码条带)、2(编码条带数据分割块A)、3(编码条带数据分割块B)、4(编码条带数据分割块C)、5(IDR图像的编码条带)种类型

0:未规定 
1:非IDR图像中不采用数据划分的片段 
2:非IDR图像中A类数据划分片段 
3:非IDR图像中B类数据划分片段 
4:非IDR图像中C类数据划分片段 
5:IDR图像的片段 
6:补充增强信息 (SEI) 
7:序列参数集 
8:图像参数集 
9:分割符 
10:序列结束符 
11:流结束符 
12:填充数据 
13 – 23:保留 
24 – 31:未规定

所谓参考帧,就是在其他帧解码时需要参照的帧。比如一个I帧可能被一个或多个B帧参考,一个B帧可能被某个P帧参考。

       从这个表我们也可以看出来,DIR的I帧是非常重要的,他一丢,那么这个序列的所有帧都没办法解码了;

       序列参数集和图像参数集也很重要,没有序列参数集,这个序列的帧就没法解;

       没有图像参数集,那用到这个图像参数集的帧都没法解。

4:比较重要的两个序列参数集:SPS,PPS(需要解析这两个参数用来解码数据流)

H264中将原本的序列和图像头部的大部分元素有力出来形成序列参数集和图像参数集,其余的部分则放入片内。

参数集是一个独立的数据单位,不依赖参数集外的其他句法元素,一个参数集不对应 某一个特定的图像或者序列,同一个序列参数集可以被多个图像参数集引用,用一个图像参数集可以被多个图像所引用,

*****************************************(比较重要)

只有在编码器需要更新参数集的内容是,才会发出新的参数集

eg:I  P  P  P  P 是一个序列

在H264中图像以序列进行组织,一个序列的第一个图像叫做IDR图像(立即刷新图像),IDR图像都是I帧图像,H264引入IDR是为了引入解码的重同步,当解码到IDR图像时,立即将参考帧队列清空,将已解码的数据全部输出或者抛弃,重新查找参数集,开始一个新的序列。

***************************************

1:序列参数集(SPS):

传送以次参数集为参考的NAL单元之前传送,nal单元有专门的表示,如果标识相同,则序列参数集相同

   SPS 包含的是针对一连续编码视频序列的参数,如标识符 seq_parameter_set_id、帧数及 POC 的约束、参考帧数目、解码图像尺寸和帧场编码模式选择标识等等。

2:图像参数集(PPS):

   其参数如标识符 pic_parameter_set_id、可选的 seq_parameter_set_id、熵编码模式选择标识、片组数目、初始量化参数和去方块滤波系数调整标识等等。

 

注意关于序列参数及和图像参数集:

1.序列参数集NAL单元       

必须在传送所有以此参数集为参考的其他NAL单元之前传送,不过允许这些NAL单元中间出现重复的序列参数集NAL单元。

所谓重复的详细解释为:序列参数集NAL单元都有其专门的标识,如果两个序列参数集NAL单元的标识相同,就可以认为后一个只不过是前一个的拷贝,而非新的序列参数集。
      

 

2.图像参数集NAL单元      

 

必须在所有以此参数集为参考的其他NAL单元之前传送,不过允许这些NAL单元中间出现重复的图像参数集NAL单元,这一点与上述的序列参数集NAL单元是相同的。

3.不同基本编码图像中的片段(slice)单元和数据划分片段(data partition)单元在顺序上不可以相互交叉,即不允许属于某一基本编码图像的一系列片段(slice)单元和数据划分片段(data partition)单元中忽然出现另一个基本编码图像的片段(slice)单元片段和数据划分片段(data partition)单元。

 

4.参考图像的影响:如果一幅图像以另一幅图像为参考,则属于前者的所有片段(slice)单元和数据划分片段(data partition)单元必须在属于后者的片段和数据划分片段之后,无论是基本编码图像还是冗余编码图像都必须遵守这个规则。

 

5.基本编码图像的所有片段(slice)单元和数据划分片段(data partition)单元必须在属于相应冗余编码图像的片段(slice)单元和数据划分片段(data partition)单元之前。

       

6.如果数据流中出现了连续的无参考基本编码图像,则图像序号小的在前面。

        

7.如果arbitrary_slice_order_allowed_flag置为1,一个基本编码图像中的片段(slice)单元和数据划分片段(data partition)单元的顺序是任意的,如果arbitrary_slice_order_allowed_flag置为零,则要按照片段中第一个宏块的位置来确定片段的顺序,若使用数据划分,则A类数据划分片段在B类数据划分片段之前,B类数据划分片段在C类数据划分片段之前,而且对应不同片段的数据划分片段不能相互交叉,也不能与没有数据划分的片段相互交叉。

 

8.如果存在SEI(补充增强信息)单元的话,它必须在它所对应的基本编码图像的片段(slice)单元和数据划分片段(data partition)单元之前,并同时必须紧接在上一个基本编码图像的所有片段(slice)单元和数据划分片段(data partition)单元后边。假如SEI属于多个基本编码图像,其顺序仅以第一个基本编码图像为参照。

 

9.如果存在图像分割符的话,它必须在所有SEI 单元、基本编码图像的所有片段slice)单元和数据划分片段(data partition)单元之前,并且紧接着上一个基本编码图像那些NAL单元。

        

10.如果存在序列结束符,且序列结束符后还有图像,则该图像必须是IDR(即时解码器刷新)图像。序列结束符的位置应当在属于这个IDR图像的分割符、SEI 单元等数据之前,且紧接着前面那些图像的NAL单元。如果序列结束符后没有图像了,那么它的就在比特流中所有图像数据之后。

      

11.流结束符在比特流中的最后。

*********************************************************************

在写程序是用到的两个序列集SPS序列参数集 PPS 图像参数集(参数集的获取和解析)

从H264码流中获取.在H264码流中,都是以"0x00 0x00 0x01"或者"0x00 0x00 0x00 0x01"为开始码的,找到开始码之后,使用开始码之后的第一个字节的低5位判断是否为7(sps)或者8(pps), 及data[4] & 0x1f == 7 || data[4] & 0x1f == 8.然后对获取的nal去掉开始码之后进行base64编码,得到的信息就可以用于sdp.sps和pps需要用逗号分隔开来

SDP中的H.264的SPS和PPS串,包含了初始化H.264解码器所需要的信息参数,包括编码所用的profile,level,图像的宽和高,deblock滤波器等。
由于SDP中的SPS和PPS都是BASE64编码形式的,不容易理解,附件有一个工具软件可以对SDP中的SPS和PPS进行解析。
用法是在命令行中输入:
spsparser sps.txt pps.txt output.txt

例如sps.txt中的内容为:
Z0LgFNoFglE=
pps.txt中的内容为:
aM4wpIA=

最终解析的到的结果为:

Start dumping SPS:
  profile_idc = 66
  constrained_set0_flag = 1
  constrained_set1_flag = 1
  constrained_set2_flag = 1
  constrained_set3_flag = 0
  level_idc = 20
  seq_parameter_set_id = 0
  chroma_format_idc = 1
  bit_depth_luma_minus8 = 0
  bit_depth_chroma_minus8 = 0
  seq_scaling_matrix_present_flag = 0
  log2_max_frame_num_minus4 = 0
  pic_order_cnt_type = 2
  log2_max_pic_order_cnt_lsb_minus4 = 0
  delta_pic_order_always_zero_flag = 0
  offset_for_non_ref_pic = 0
  offset_for_top_to_bottom_field = 0
  num_ref_frames_in_pic_order_cnt_cycle = 0
  num_ref_frames = 1
  gaps_in_frame_num_value_allowed_flag = 0
  pic_width_in_mbs_minus1 = 21
  pic_height_in_mbs_minus1 = 17
  frame_mbs_only_flag = 1
  mb_adaptive_frame_field_flag = 0
  direct_8x8_interence_flag = 0
  frame_cropping_flag = 0
  frame_cropping_rect_left_offset = 0
  frame_cropping_rect_right_offset = 0
  frame_cropping_rect_top_offset = 0
  frame_cropping_rect_bottom_offset = 0
  vui_parameters_present_flag = 0

Start dumping PPS:
  pic_parameter_set_id = 0
  seq_parameter_set_id = 0
  entropy_coding_mode_flag = 0
  pic_order_present_flag = 0
  num_slice_groups_minus1 = 0
  slice_group_map_type = 0
  num_ref_idx_l0_active_minus1 = 0
  num_ref_idx_l1_active_minus1 = 0
  weighted_pref_flag = 0
  weighted_bipred_idc = 0
  pic_init_qp_minus26 = 0
  pic_init_qs_minus26 = 0
  chroma_qp_index_offset = 10
  deblocking_filter_control_present_flag = 1
  constrained_intra_pred_flag = 0
  redundant_pic_cnt_present_flag = 0
  transform_8x8_mode_flag = 0
  pic_scaling_matrix_present_flag = 0
  second_chroma_qp_index_offset = 10

/////////////////////////////////////////////////////////////////////////////////////////////////
这里需要特别提一下这两个参数
pic_width_in_mbs_minus1 = 21
  pic_height_in_mbs_minus1 = 17
分别表示图像的宽和高,以宏块(16x16)为单位的值减1

 

因此,实际的宽为 (21+1)*16 = 352

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值