H.264格式 入门

H.264格式 入门
初碰这些高深莫测的名词,顿时觉得头昏脑胀:“这都是什么玩意”?先记录下来分析以下.
入门就从这里开始.

H264可以分为2层:视频编码层"VCL"和网络提取层"NAL"
VCL: Video Coding Layer,切片(slice)”、“宏块(macroblock)” 属于VCL中的概念, 压缩的概念
NAL: Network Abstraction Layer,传输的概念
写到后面我才知道两层的含义.就是数据层上加了一个byte叫网络头,这里叫网络层.好玄!


NALU: NAL unit (网络抽象层单元)
AU:  access unit (访问单元)
AUD: Access Unit delimiter(访问单元分割符)
SEI: Supplemental Enhancement Informat(附加增强信息)
primary coded picture(基本图像编码)
Redundant Coded Picture(冗余图像编码)
Instantaneous Decoding Refresh (IDR,即时解码刷新)
Hypothetical Reference Decoder (HRD,假想参考解码)
Hypothetical Stream Scheduler (HSS,假想码流调度器)

SPS:Sequence Parameter Set 序列参数集,SPS中保存了一组编码视频序列(Coded video sequence)的全局参数.
PPS: Picture Parameter Set 图像参数集,对应的是一个序列中某一副图像或者某几副图像的参数.
I帧:帧内编码,可独立解码生成完整的图片
P帧:前向预测编码帧,需要参考其前⾯的⼀个I 或者B 来⽣成⼀张完整的图⽚.
B帧: 双向预测内插编码帧,则要参考其前⼀个I或者P帧及其后⾯的⼀个P帧来⽣成⼀张完整的 图⽚.


1.文件结构
NALU 由头和体构成,头(1byte)+体
H264的源文件是由NAL单元组成,一个完整的NAL数据由起始码前缀,NAL头和RBSP三部分组成.
----------------------------------------
Start Code是Annex-B分隔NALU的办法,一般采用0x000001或0x00000001.
----------------------------------------
NAL头由一个字节组成:bit(7)+bits(6,5)+bits(4-0)
bit[7]固定为0即必须为0 表示:forbidden_zero_bit
bit[6:5]:表示:nal_ref_idc, 重要性,0 不重要,3最重要(遍查这个idc名称简写的来历没找到,猜测是id-counter之意,就是用一个唯一数代表id)
bit[4:0]:表示NAL单元的类型,nal_unit_type, 具体如下:

0    未使用    
1    非IDR图像中不采用数据划分的片段    (参考帧,重要性非0,非参考帧,重要性0)
2    非IDR图像中A类数据划分片段 (同上)    
3    非IDR图像中B类数据划分片段 (同上)    
4    非IDR图像中C类数据划分片段 (同上)    
5    IDR图像的片     (重要性 01)
6    补充增强信息单元(SEI)     (重要性 0)
7    序列参数集   (重要性 非0)
8    图像参数集       (重要性 非0)
9    分界符       (重要性 0)
10    序列结束     (重要性 0)
11    码流结束         (重要性 0)
12    填充         (重要性 0)
13…23    保留    
其中1-5是图像数据, 7,8参数集很重要.

NALU = NALU Header + SODB // 定义1
NALU = NALU Header + RBSP // 定义2
NALU = NALU Header + EBSP // 定义3


SODB string Of Data Bits,数据比特串-->最原始的编码数据
RBSP Raw Byte Sequence Payload,原始字节序列载荷-->在SODB的后面填加了结尾比特(RBSP trailing bits 一个bit“1”)若干比特“0”,以便字节对齐
EBSP Encapsulated Byte Sequence Payload 扩展字节序列载荷-->在RBSP基础上填加了仿校验字节(0X03)
它的原因是: 在NALU加到Annexb上时,需要添加每组NALU之前的开始码StartCodePrefix,如果该NALU对应的slice为一帧的开始则用4位字节表示,0x00000001,否则用3位字节表示0x000001.
为了使NALU主体中不包括与开始码相冲突的字节,在编码时,每遇到两个字节连续为0,就插入一个字节的0x03.解码时将0x03去掉.也称为脱壳操作

RBSP用来存放下表中的一种:
RBSP类型    缩写    描述
参数集        PS        序列的全局信息,如图像尺寸,视频格式等
增强信息    SEI        视频序列解码的增强信息
图像界定符    PD        视频图像的边界
编码片        SLICE    编码片的头信息和数据
数据分割            DP片层的数据,用于错误恢复解码
序列结束符            表明一个序列的结束,下一个图像为IDR图像
流结束符            表明该流中已没有图像
填充数据            亚元数据,用于填充字节

参数集:包括序列参数集(SPS), 和图像参数集(PPS)
PPS对应的是一个序列中某一幅图像或者某几幅图像,其参数如标识符 pic_parameter_set_id、可选的
    seq_parameter_set_id、熵编码模式选择标识、片组数目、初始量化参数和去方块滤波系数调整标识等等.
SPS 包含的是针对一连续编码视频序列的参数,如标识符 seq_parameter_set_id、帧数及 POC 的约束、
    参考帧数目、解码图像尺寸和帧场编码模式选择标识等等.
数据分割:组成片的编码数据存放在 3 个独立的 DP(数据分割,A、B、C)中,各自包含一个编码片的子集.
    分割A包含片头和片中每个宏块头数据.
    分割B包含帧内和 SI 片宏块的编码残差数据.
    分割C包含帧间宏块的编码残差数据.每个分割可放在独立的 NAL 单元并独立传输

常见数据帧

序列参数集 SPS----7:
图像参数集 PPS----8:
关键帧 IDR 帧----5
B/P帧 slice ----1:

搞清楚了概念,来几个实例分析一下: 这是一个真实的h264数据
00 00 00 01 09 F0    //09 分界符,RBSP数据F0
00 00 00 01 67 64 00 28 AC D9 40 78 02 27 E5 C0 5B
20 00 00 03 00 20 00 00 06 41 E3 06 32 C0 00 //67 序列参数集(重要), 直到下一个00 00 01 的均是它的数据,
                                            //数据含义需要解析,目前我还不懂.
00 00 01 68 EB EC B2 2C //68 图像参数集(重要),后面所跟数据含义还不懂.
00 00 01 06 05 FF FF AD DC 45 E9 BD E6 D9 48 B7 //06,补充增强信息SEI(0x2b4 Bytes),这个数据很多,
96 2C D8 20 D9 23 EE EF 78 32 36 34 20 2D 20 63
6F 72 65 20 31 35 39 20 2D 20 48 2E 32 36 34 2F
4D 50 45 47 2D 34 20 41 56 43 20 63 6F 64 65 63
20 2D 20 43 6F 70 79 6C 65 66 74 20 32 30 30 33
2D 32 30 31 39 20 2D 20 68 74 74 70 3A 2F 2F 77
77 77 2E 76 69 64 65 6F 6C 61 6E 2E 6F 72 67 2F
78 32 36 34 2E 68 74 6D 6C 20 2D 20 6F 70 74 69
6F 6E 73 3A 20 63 61 62 61 63 3D 31 20 72 65 66
3D 33 20 64 65 62 6C 6F 63 6B 3D 31 3A 30 3A 30
20 61 6E 61 6C 79 73 65 3D 30 78 33 3A 30 78 31
31 33 20 6D 65 3D 68 65 78 20 73 75 62 6D 65 3D
37 20 70 73 79 3D 31 20 70 73 79 5F 72 64 3D 31
2E 30 30 3A 30 2E 30 30 20 6D 69 78 65 64 5F 72
65 66 3D 31 20 6D 65 5F 72 61 6E 67 65 3D 31 36
20 63 68 72 6F 6D 61 5F 6D 65 3D 31 20 74 72 65
6C 6C 69 73 3D 31 20 38 78 38 64 63 74 3D 31 20
63 71 6D 3D 30 20 64 65 61 64 7A 6F 6E 65 3D 32
31 2C 31 31 20 66 61 73 74 5F 70 73 6B 69 70 3D
31 20 63 68 72 6F 6D 61 5F 71 70 5F 6F 66 66 73
65 74 3D 2D 32 20 74 68 72 65 61 64 73 3D 32 34
20 6C 6F 6F 6B 61 68 65 61 64 5F 74 68 72 65 61
64 73 3D 34 20 73 6C 69 63 65 64 5F 74 68 72 65
61 64 73 3D 30 20 6E 72 3D 30 20 64 65 63 69 6D
61 74 65 3D 31 20 69 6E 74 65 72 6C 61 63 65 64
3D 30 20 62 6C 75 72 61 79 5F 63 6F 6D 70 61 74
3D 30 20 63 6F 6E 73 74 72 61 69 6E 65 64 5F 69
6E 74 72 61 3D 30 20 62 66 72 61 6D 65 73 3D 33
20 62 5F 70 79 72 61 6D 69 64 3D 32 20 62 5F 61
64 61 70 74 3D 31 20 62 5F 62 69 61 73 3D 30 20
64 69 72 65 63 74 3D 31 20 77 65 69 67 68 74 62
3D 31 20 6F 70 65 6E 5F 67 6F 70 3D 30 20 77 65
69 67 68 74 70 3D 32 20 6B 65 79 69 6E 74 3D 32
35 30 20 6B 65 79 69 6E 74 5F 6D 69 6E 3D 32 35
20 73 63 65 6E 65 63 75 74 3D 34 30 20 69 6E 74
72 61 5F 72 65 66 72 65 73 68 3D 30 20 72 63 5F
6C 6F 6F 6B 61 68 65 61 64 3D 34 30 20 72 63 3D
61 62 72 20 6D 62 74 72 65 65 3D 31 20 62 69 74
72 61 74 65 3D 38 30 30 30 20 72 61 74 65 74 6F
6C 3D 31 2E 30 20 71 63 6F 6D 70 3D 30 2E 36 30
20 71 70 6D 69 6E 3D 30 20 71 70 6D 61 78 3D 36
39 20 71 70 73 74 65 70 3D 34 20 69 70 5F 72 61
74 69 6F 3D 31 2E 34 30 20 61 71 3D 31 3A 31 2E
30 30 00 80

00 00 01 65 88 84 00 18 FF FE F7 C9 EF C0 A6 DA // 65,这是IDR frame, frame slice0(重要性11), 数据太大,几千行,我只能用省略号了!
60 C6 D6 FE 4F 3D 23 F0 B2 DC FA D2 8F 84 7D EF // (10b6c字节)slice of IDR frame
A1 D8 B4 5A F5 6D 90 36 53 57 88 ......

00 00 00 01 09 F0    //09 分界符,access unit delimiter (6bytes),RBSP数据F0 跟前面一致了

00 00 00 01 41 9A 21 6C 41 8F FE D6 9E 12 01 A2 // 41, 数据片段 frame #1,重要性(10)
1B EA 6F 0A CF 60 0B C4 1A 91 24 60 C1 65 1B 94 // slice of non IDR frame(9b1字节)
D7 ED 69 26 35 86 9A 04 5F 93 74 17 ......

00 00 00 01 09 F0    //09 分界符,F0,RBSP数据, 跟前面一致了

00 00 00 01 41 9A 42 3C 21 93 29 84 18 FF FE D6 // 42, 数据片段 frame #2,重要性(10)
A5 50 01 5C 33 BF 48 E6 BE 0C 25 54 E1 47 A9 11 // slice of non IDR frame(645字节)
D3 94 FE 59 B2 18 ......
往后重复分界符和数据.

下一步,那些压缩的数据可以先不管,但这些网络层面的数据还是需要了解一下的.先搞清楚pps,sps.它们看起来比较简单(数据少)

SPS 包含了以下重要的信息:

Profile 和 Level:指定视频编码的配置和兼容性级别.
图像尺寸和宽高比:描述视频图像的尺寸和宽高比.
帧率和比特率:指定视频的帧率和比特率,影响视频的流畅度和压缩效率.
帧间预测和帧内预测设置:描述视频编码中的预测模式和帧类型.
量化参数:控制视频质量和压缩比例的参数.
熵编码模式:指定熵编码的方式,影响编码的复杂度和压缩效率.
参考帧设置:指定参考帧的配置和使用方式,用于帧间预测.
typedef struct {
    uint32_t profile_idc; //!< 当前H.264的编码配置, baseline(66) | main(77) | extended(88)
    uint32_t constraint_set0_flag;
    uint32_t constraint_set1_flag;
    uint32_t constraint_set2_flag;
    uint32_t constraint_set3_flag;
    uint32_t constraint_set4_flag;
    uint32_t constraint_set5_flag;
    uint32_t reserved_zero_2bits;
    uint32_t level_idc; //!< 编码等级 0~51
    uint32_t seq_parameter_set_id;
    //    if(profile_idc == 100 || profile_idc == 110 || profile_idc == 122 || profile_idc == 144) {
    uint32_t chroma_format_idc;
    //        if( chroma_format_idc = = 3 )
    uint32_t residual_colour_transform_flag;
    //        }
    uint32_t bit_depth_luma_minus8;
    uint32_t bit_depth_chroma_minus8;
    uint32_t qpprime_y_zero_transform_bypass_flag;
    uint32_t seq_scaling_matrix_present_flag;
    //        if (seq_scaling_matrix_present_flag)
    //            for(i = 0; i < 8; i++) {
    uint32_t seq_scaling_list_present_flag[12];
    //            }
    //        }
    //    }
    uint32_t log2_max_frame_num_minus4;
    uint32_t pic_order_cnt_type;
    //    if(pic_order_cnt_type == 0) {
    uint32_t log2_max_pic_order_cnt_lsb_minus4;
    //    }
    //    else if(pic_order_cnt_type == 1) {
    uint32_t delta_pic_order_always_zero_flag;
    int offset_for_non_ref_pic;
    int offset_for_top_to_bottom_field;
    uint32_t num_ref_frames_in_pic_order_cnt_cycle;
    int offset_for_ref_frame[256];
    //    }
    uint32_t max_num_ref_frames; //!< 参考帧的最大数目
    uint32_t gaps_in_frame_num_value_allowed_flag;
    uint32_t pic_width_in_mbs_minus1;        //!< 用于计算图像的宽度,单位为宏块个数
    uint32_t pic_height_in_map_units_minus1; //!< 度量视频中一帧图像的高度
    uint32_t frame_mbs_only_flag;
    //    if (!frame_mbs_only_flag) {
    uint32_t mb_adaptive_frame_field_flag;
    //    }
    uint32_t direct_8x8_inference_flag;
    uint32_t frame_cropping_flag;
    //    if (frame_cropping_flag) {
    uint32_t frame_crop_left_offset;
    uint32_t frame_crop_right_offset;
    uint32_t frame_crop_top_offset;
    uint32_t frame_crop_bottom_offset;
    //    }
    uint32_t vui_parameters_present_flag;
    //    if (vui_parameters_present_flag) {
    NaluSpsVuiParameters vui_parameters;
    //    }
} NaluSPS;

视频使用者信息(VUI)
(Video Usability Information)
vui_parameters 是视频编码中的一种参数,用于描述视频序列的附加信息,即视频使用者信息
vui_parameters 主要包括以下信息:

宽高比 (aspect_ratio_info):视频的显示宽高比,用于正确显示视频的宽高比例.
颜色参数 (color_primaries、transfer_characteristics、matrix_coefficients):视频的颜色空间信息,用于正确解释和显示视频的颜色.
时间相关信息 (timing_info):视频的时间参数,包括帧率和时间码等,用于正确解码和播放视频.
视频信号范围 (video_signal_type_present_flag):视频信号的范围,例如全范围或标准范围,用于正确显示视频的亮度和对比度.
音频同步信息 (nal_hrd_parameters、vcl_hrd_parameters):视频和音频之间的同步信息,确保音视频同步播放.

// Vui Parameters
typedef struct {
    uint32_t aspect_ratio_info_present_flag;
    //    if(aspect_ratio_info_present_flag) {
    uint32_t aspect_ratio_idc;
    //        if (aspect_ratio_idc == Extended_SAR) {
    uint32_t sar_width;
    uint32_t sar_height;
    //        }
    //    }
    uint32_t overscan_info_present_flag;
    //    if (overscan_info_present_flag) {
    uint32_t overscan_appropriate_flag;
    //    }
    uint32_t video_signal_type_present_flag;
    //    if (video_signal_type_present_flag) {
    uint32_t video_format;
    uint32_t video_full_range_flag;
    uint32_t colour_description_present_flag;
    //        if (colour_description_present_flag) {
    uint32_t colour_primaries;
    uint32_t transfer_characteristics;
    uint32_t matrix_coefficients;
    //        }
    //    }
    uint32_t chroma_loc_info_present_flag;
    //    if (chroma_loc_info_present_flag) {
    uint32_t chroma_sample_loc_type_top_field;
    uint32_t chroma_sample_loc_type_bottom_field;
    //    }
    uint32_t timing_info_present_flag;
    //    if (timing_info_present_flag) {
    uint32_t num_units_in_tick;
    uint32_t time_scale;
    uint32_t fixed_frame_rate_flag;
    //    }
    uint32_t nal_hrd_parameters_present_flag;
    //    if (nal_hrd_parameters_present_flag) {
    NaluSpsHrdParameters nal_hrd_parameters_present;
    //    }
    uint32_t vcl_hrd_parameters_present_flag;
    //    if (vcl_hrd_parameters_present_flag) {
    NaluSpsHrdParameters vcl_hrd_parameters_present;
    //    }
    //    if (nal_hrd_parameters_present_flag || vcl_hrd_parameters_present_flag) {
    uint32_t low_delay_hrd_flag;
    //    }
    uint32_t pic_struct_present_flag;
    uint32_t bitstream_restriction_flag;
    //    if (bitstream_restriction_flag) {
    uint32_t motion_vectors_over_pic_boundaries_flag;
    uint32_t max_bytes_per_pic_denom;
    uint32_t max_bits_per_mb_denom;
    uint32_t log2_max_mv_length_horizontal;
    uint32_t log2_max_mv_length_vertical;
    uint32_t num_reorder_frames;
    uint32_t max_dec_frame_buffering;
    //    }
} NaluSpsVuiParameters;

假想的参考解码器(HRD) Hypothetical Reference Decoder
hrd_parameters 包含了视频编码过程中的控制和管理参数,用于确保编码后的视频流在解码时能够正确恢复,并保持一定的稳定性和适应性.
它定义了视频编码的比特率、缓冲区大小和相关的时间参数.

hrd_parameters 主要包括以下信息:
    比特率 (bit_rate):视频编码的平均比特率.
    缓冲区大小 (cpb_size):解码器的缓冲区大小,用于存储已解码和待解码的视频数据.
    初始缓冲区满度 (initial_cpb_fullness):初始时解码器缓冲区的填充级别,通常以百分比表示.
    约束参数 (cpb_cnt_minus1、bit_rate_scale、cpb_size_scale):用于计算实际的缓冲区大小和填充级别.

typedef struct {
    uint32_t cpb_cnt_minus1;
    uint32_t bit_rate_scale;
    uint32_t cpb_size_scale;
    //    for( SchedSelIdx = 0; SchedSelIdx <= cpb_cnt_minus1; SchedSelIdx++ ) {
    uint32_t bit_rate_value_minus1[5];
    uint32_t cpb_size_value_minus1[5];
    uint32_t cbr_flag[5];
    //    }
    uint32_t initial_cpb_removal_delay_length_minus1;
    uint32_t cpb_removal_delay_length_minus1;
    uint32_t dpb_output_delay_length_minus1;
    uint32_t time_offset_length;
} NaluSpsHrdParameters;
这些结构代码中都有,留个概念就可以了.

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值