JM代码分析(三)

请添加图片描述


printf颜色打印

\033[显示方式;前景色;背景色m

显示方式: 0(默认值)、1(高亮)、22(非粗体)、4(下划线)、24(非下划线)、5(闪烁)、25(非闪烁)、7(反显)、27(非反显)
前景色: 30(黑色)、31(红色)、32(绿色)、 33(黄色)、34(蓝色)、35(洋红)、36(青色)、37(白色)
背景色: 40(黑色)、41(红色)、42(绿色)、 43(黄色)、44(蓝色)、45(洋红)、46(青色)、47(白色)

\033[0m 默认
\033[1;32;40m 绿色
033[1;31;40m 红色

printf( “\033[1;31;40m 输出红色字符 \033[0m” )

//红色高亮
printf("\033[1;31m tmp_test===============%s %d %s======= \033[0m \n",__FILE__,__LINE__,__FUNCTION__);
//黄色高亮
printf("\033[1;33m tmp_test===============%s %d %s======= \033[0m \n",__FILE__,__LINE__,__FUNCTION__);

JM编码过程

encode_one_frame
perform_encode_field 场编码
perform_encode_frame 帧编码

frame_picture
code_a_picture
code_a_plane
while循环中编码
encode_one_slice

ReportI 输出I帧信息

Annex B & RTP输出格式

字节流格式(Annex B)和RTP格式流浅析
AnnexB(附录B)格式:NALU数据+开始前缀(00000001或000001),针对H.320电话会议。
RTP格式:NALU数据+20个字节的类似的并不符合RTP协议的RTP头。针对IP网络的RTP打包方式。为原始的NAL打包格式,就是开始的若干字节(1,2,4字节)是NAL的长度,而不是start_code,此时必须借助某个全局的数据来获得编码器的profile,level,PPS,SPS等信息才可以解码。

H.264协议只规定了字节流格式,没有规定 RTP 格式。可能也是因为这个原因,JM 的 RTP 格式没有被用到任何场合场合中,成为了摆设。
一共有两种起始码:3字节的0x000001和4字节的0x00000001 3字节的0x000001只有一种场合下使用,就是一个完整的帧被编为多个slice的时候,包含这些slice的nalu使用3字节起始码。其余场合都是4字节的。
H.264 的两种码流格式:

GetAnnexbNALU 处理字节流格式的码流
GetRTPNALU 处理 RTP 格式码流

字节流格式的码流主要用于存储,例如制作 DVD(当然现在的 DVD 还不是用 H.264)
RTP 格式码流主要用于网络传送,例如在线看电影

率失真优化 RDO

率失真优化(Rate–distortion optimization,简称RDO)是一种提升视频压缩性能的最优化方法。其原理是对视频的有损(画面质量)与比特率(编码所需的数据量)同时进行最优化,以求达到一个最佳的平衡点。虽然此算法一开始是在视频压缩的编码器中被使用,但也可以用于各种多媒体编码包含视频、视频、音频等等,只要编码时会同时考虑到质量及文件大小皆可使用。
率失真优化会较大部分其他区块比对的衡量方法来得慢,譬如绝对值差和(SAD)和转换后绝对值差和(SATD)。因此率失真优化通常只在动作补偿的最后一个步骤才会被使用,像是在H.264/AVC中最后需要对各种分区模式下决定的时候。

YUV格式

YUV420格式的理解:
在YUV420中,一个像素点对应一个Y,一个2X2的小方块对应一个U和V。对于所有YUV420图像,它们的Y值排列是完全相同的,因为只有Y的图像就是灰度图像。YUV420sp与YUV420p的数据格式它们的UV排列在原理上是完全不同的。420p它是先把U存放完后,再存放V,也就是说UV它们是连续的。而420sp它是UV、UV这样交替存放的。(见下图)
有了上面的理论,我就可以准确的计算出一个YUV420在内存中存放的大小。
width * hight =Y(总和)
U = Y / 4
V = Y / 4

所以YUV420 数据在内存中的长度是 width * hight * 3 / 2,
假设一个分辨率为8X4的YUV图像,它们的格式如下图:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-k6WppvFu-1672565231066)(null)]

另附:
这里写图片描述

宏块类型的介绍 B_Skip、P_Skip、CBP

1 CBP表示残差的编码状态,CBP一共6bit,低4位表示4个亮度8x8块,第4位表示U,第五位表示V,如果相应的位为"1", 表示此块有残差系数,反之没有残差,此宏块没有被编码.

2 direct 是帧间宏块的一种预测模式,而不是宏块类型,而 Skip 是帧间宏块的一种类型,而不是预测模式。skip 类型宏块采用的是direct 预测模式。

3 B_Skip类型宏块: 无像素残差,无运动矢量残差(MVD)。解码时,通过Direct预测模式(时间或空间)计算出前、后向MV后,直接利用前、后向MV得到像素预测值。像素重构值=像素预测值
P_Skip类型宏块: 也就是COPY宏块。无像素残差,无运动矢量残差(MVD)。直接利用预测MV得到像素预测值。像素重构值=像素预测值 (不使用Direct预测模式)
B_Direct_1616类型宏块: 有像素残差,无运动矢量残差(MVD)。解码时,通过Direct预测模式(时间或空间)计算出前、后向MV后,利用前、后向MV得到像素预测值。然后,像素重构值=像素预测值+像素残差解码值 .
Skip类型的两种宏块,都是无残差、无MVD
B_Direct分为对16
16和88,都是有残差、无MVD
B_Skip 类型宏块(大小为 16
16)
B_Direct_88 类型块(大小为 88)
B_Direct 类型宏块(大小为 16*16)都采用的是 Direct 预测模式

	对于mb_type为P8*8的16*16宏块,里面可能存在B_Direct模式的8*8子快。跟B_Direct_16*16类型宏块一样有像素残差,无运动矢量残差(MVD)。 区别是对于B_Direct_16*16,其4个8*8子块都采用direct模式;但对于B_Direct_8*8,其所属的16*16宏块中剩余的8*8块却不一定要采用direct模式。

4 如果满足以下三个条件则将宏块按 Skip 类型进行编码:
(1)最佳模式选择为Inter16×16;
(2)MC得到的最终运动矢量等于预测运动矢量,即运动矢量的残差为0;
(3)变换系数均被量化为0。

参考:Skip宏块与Direct预测模式浅析

P帧中,有3种基本的宏块:I宏块,skip形式的P宏块和非skip形式的P宏块

帧间预测过程

普通的(非skip)帧间预测, 先得到MVPRED, 然后搜索得到最佳匹配块. (判断最佳的方法…是可能使用MAD作为判断标准…) 然后把模式, 运动残差(MVD), CBP, 和像素残差一起编码传输 (或者还有其他一些flags)

JM:从264流中读取MVD过程

1、码流中读取MVD
readMBMotionVectors 熵编码时读取帧间宏块的运动矢量残差,调用过程如下:

#0  readMBMotionVectors (currSE=0xbfffdde8, dP=0x81ab8c8, currMB=0x814f434, list=0, step_h0=2, step_v0=2, offset=1)	at src/macroblock.c:431
#1  0x08093fc1 in read_motion_info_from_NAL_p_slice (currMB=0x814f434) at src/macroblock.c:1269
#2  0x0809c71e in read_P8x8_macroblock (currMB=0x814f434, dP=0x81ab8c8, currSE=0xbfffde98) at src/mb_read.c:1123
#3  0x0809d42a in read_one_macroblock_p_slice_cavlc (currMB=0x814f434) at src/mb_read.c:1532
#4  0x0806554f in decode_one_slice (currSlice=0x81a68d8) at src/image.c:2540
#5  0x08060e94 in decode_slice (currSlice=0x81a68d8, current_header=2) at src/image.c:748
#6  0x0806169d in decode_one_frame (pDecoder=0x810d170) at src/image.c:943
#7  0x08087376 in DecodeOneFrame (ppDecPicList=0xbfffdfe4) at src/ldecod.c:1254
#8  0x08054fd3 in main (argc=1, argv=0xbffff174) at src/decoder_test.c:282

nalu->buf 存放着EBSP起始的第一个位

2、写MVD到码流中
writeMotionVector8x8

#0  writeMotionVector8x8 (currMB=0x8238378, i0=0, j0=0, i1=2, j1=2, refframe=0, list_idx=0, mv_mode=4, bipred_me=0, 
    Extraction=0) at src/macroblock.c:3087
#1  0x0812b88a in rdcost_for_8x8blocks (currMB=0x8238378, dataTr=0x8c55df0, cnt_nonz=0xbfffea60, cbp_blk=0xbfffeac0, 
    lambda=2505, block=0, mode=4, part=0xbfffeabb, min_rdcost=356116) at src/rdopt.c:830
#2  0x080fb713 in submacroblock_mode_decision_b_slice (currMB=0x8238378, enc_mb=0xbfffecc8, dataTr=0x8c55df0, 
    cofACtr=0x8c4e730, block=0, cost=0xbfffec48) at src/mode_decision_P8x8.c:519
#3  0x080c0f5d in encode_one_macroblock_high (currMB=0x8238378) at src/md_high.c:207
#4  0x0814da9b in encode_one_slice (p_Vid=0x81d5020, SliceGroupId=0, TotalCodedMBs=0) at src/slice.c:515
#5  0x0806cfe5 in code_a_plane (p_Vid=0x81d5020, p_Inp=0x81e9c88) at src/image.c:219
#6  0x0806d32e in code_a_picture (p_Vid=0x81d5020, pic=0x836ac80) at src/image.c:306
#7  0x08070e2c in frame_picture (p_Vid=0x81d5020, frame=0x836ac80, imgData=0x81d50ec, rd_pass=0) at src/image.c:1664
#8  0x0806eaa1 in perform_encode_frame (p_Vid=0x81d5020) at src/image.c:818
#9  0x0807010b in encode_one_frame (p_Vid=0x81d5020, p_Inp=0x81e9c88) at src/image.c:1300
#10 0x0808e43b in encode_sequence (p_Vid=0x81d5020, p_Inp=0x81e9c88) at src/lencod.c:1106
#11 0x0808c504 in main (argc=1, argv=0xbffff164) at src/lencod.c:392

对码流的分析

1 首先给出一张264码流的二进制文件,如下:
这里写图片描述

0x00 00 00 01 or 0x00 00 01是NALU的前缀编码,在get_annex_b_NALU 中将其识别,并去掉,而将一个NALU给nalu->buf
从后面的67~80是NALU单元,(代表着一个SPS),而NALU中的第一个字节0x67,是NALU的head,其后才是一个RBSP数据.

2 现在研究一个PPS
PPS的码流数据为: {0xcb, 0xe3, 0xcb, 0x22, 0xc0} 不包括0x68的NALU head
先语法元素用掉了33位(p_Dec->UsedBits存储了一个NALU语法元素的位数),那么0xcb, 0xe3, 0xcb, 0x22, + 1 = 33bit 而后面的100 0000是RBSP trailing bits (第一位是1,后跟0,直到补齐一个字节)

H264码流分析

NAL+VCL
NAL全称Network Abstract Layer, 即网络抽象层。
在H.264/AVC视频编码标准中,整个系统框架被分为了两个层面:视频编码层面(VCL)和网络抽象层面(NAL)。其中,前者负责有效表示视频数据的内容,而后者则负责格式化数据并提供头信息,以保证数据适合各种信道和存储介质上的传输。因此我们平时的每帧数据就是一个NAL单元(SPS与PPS除外)。
一个frame是可以分割成多个Slice来编码的,而一个Slice编码之后被打包进一个NAL单元,另外NAL单元中也存放着SPS/PPS/SEI等信息.
Slice是片的意思,264中把图像分成一帧(frame)或两场(field),而帧又可以分成一个或几个片(Slilce);片由宏块(MB)组成。宏块是编码处理的基本单元。

SODB:最原始的编码数据,没有任何附加数据
RBSP:在 SODB 的基础上加了rbsp_stop_ont_bit(bit 值为 1)并用 0 按字节补位对齐
EBSP:在 RBSP 的基础上增加了防止伪起始码字节(0X03)

对于RBSP NALU的介绍和理解:
H.264中NALU、RBSP、SODB的关系

JM8.6中NALU(此处指非VCL式的NALU,如SPS和PPS)是如何写进码流的?
JM8.6中NALU(此处指VCL式的NALU)是如何写进码流的?

通过使用h264bitstream-0.1.9分析了H264的码流的NAL数据(未对V),以下是一部分输出的NAL数据。

/************************************************
* SPS
* **********************************************/
!! Found NAL at offset 4 (0x0004), size 23 (0x0017) 
XX 00 00 00 01 67 64 00 0B AC D9 42 C4 E8 40 00 00 
==================== NAL ====================
 forbidden_zero_bit : 0 
 nal_ref_idc : 3 
 nal_unit_type : 7 ( Sequence parameter set ) 
======= SPS =======
 profile_idc : 100 
 constraint_set0_flag : 0 
 constraint_set1_flag : 0 
 constraint_set2_flag : 0 
 constraint_set3_flag : 0 
 constraint_set4_flag : 0 
 constraint_set5_flag : 0 
 reserved_zero_2bits : 0 
 level_idc : 11 
 seq_parameter_set_id : 0 
 chroma_format_idc : 1 
 residual_colour_transform_flag : 0 
 bit_depth_luma_minus8 : 0 
 bit_depth_chroma_minus8 : 0 
 qpprime_y_zero_transform_bypass_flag : 0 
 seq_scaling_matrix_present_flag : 0 
 log2_max_frame_num_minus4 : 0 
 pic_order_cnt_type : 0 
   log2_max_pic_order_cnt_lsb_minus4 : 2 
   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 : 4 
 gaps_in_frame_num_value_allowed_flag : 0 
 pic_width_in_mbs_minus1 : 10 
 pic_height_in_map_units_minus1 : 8 
 frame_mbs_only_flag : 1 
 mb_adaptive_frame_field_flag : 0 
 direct_8x8_inference_flag : 1 
 frame_cropping_flag : 0 
   frame_crop_left_offset : 0 
   frame_crop_right_offset : 0 
   frame_crop_top_offset : 0 
   frame_crop_bottom_offset : 0 
 vui_parameters_present_flag : 1 
=== VUI ===
 aspect_ratio_info_present_flag : 0 
   aspect_ratio_idc : 0 
     sar_width : 0 
     sar_height : 0 
 overscan_info_present_flag : 0 
   overscan_appropriate_flag : 0 
 video_signal_type_present_flag : 0 
   video_format : 0 
   video_full_range_flag : 0 
   colour_description_present_flag : 0 
     colour_primaries : 0 
   transfer_characteristics : 0 
   matrix_coefficients : 0 
 chroma_loc_info_present_flag : 0 
   chroma_sample_loc_type_top_field : 0 
   chroma_sample_loc_type_bottom_field : 0 
 timing_info_present_flag : 1 
   num_units_in_tick : 1 
   time_scale : 50 
   fixed_frame_rate_flag : 1 
 nal_hrd_parameters_present_flag : 0 
 vcl_hrd_parameters_present_flag : 0 
   low_delay_hrd_flag : 0 
 pic_struct_present_flag : 0 
 bitstream_restriction_flag : 1 
   motion_vectors_over_pic_boundaries_flag : 1 
   max_bytes_per_pic_denom : 0 
   max_bits_per_mb_denom : 0 
   log2_max_mv_length_horizontal : 9 
   log2_max_mv_length_vertical : 9 
   num_reorder_frames : 2 
   max_dec_frame_buffering : 4 
=== HRD ===
 cpb_cnt_minus1 : 0 
 bit_rate_scale : 0 
 cpb_size_scale : 0 
   bit_rate_value_minus1[0] : 0 
   cpb_size_value_minus1[0] : 0 
   cbr_flag[0] : 0 
 initial_cpb_removal_delay_length_minus1 : 0 
 cpb_removal_delay_length_minus1 : 0 
 dpb_output_delay_length_minus1 : 0 
 time_offset_length : 0 

/************************************************
* PPS
* **********************************************/
!! Found NAL at offset 31 (0x001F), size 6 (0x0006) 
XX 00 00 00 01 68 CB E3 CB 22 C0 
==================== NAL ====================
 forbidden_zero_bit : 0 
 nal_ref_idc : 3 
 nal_unit_type : 8 ( Picture parameter set ) 
======= 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 : 2 
 num_ref_idx_l1_active_minus1 : 0 
 weighted_pred_flag : 1 
 weighted_bipred_idc : 2 
 pic_init_qp_minus26 : -3 
 pic_init_qs_minus26 : 0 
 chroma_qp_index_offset : -2 
 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 : 0 

/************************************************
* SEI
* **********************************************/
!! Found NAL at offset 40 (0x0028), size 672 (0x02A0) 
XX C0 00 00 01 06 05 FF FF 9C DC 45 E9 BD E6 D9 48 
==================== NAL ====================
 forbidden_zero_bit : 0 
 nal_ref_idc : 0 
 nal_unit_type : 6 ( Supplemental enhancement information (SEI) ) 
======= SEI =======
=== User data unregistered ===
 payloadType : 5 
 payloadSize : 666 
 payload : 
DC 45 E9 BD E6 D9 48 B7 96 2C D8 20 D9 23 EE EF 
........ 
61 71 3D 31 3A 31 2E 30 30 00 

/************************************************
* 帧数据1
* **********************************************/
!! Found NAL at offset 715 (0x02CB), size 5142 (0x1416) 
XX 80 00 00 01 65 88 84 01 7B A7 CD 83 87 14 00 04 
==================== NAL ====================
 forbidden_zero_bit : 0 
 nal_ref_idc : 3 
 nal_unit_type : 5 ( Coded slice of an IDR picture ) 
======= Slice Header =======
 first_mb_in_slice : 0 
 slice_type : 7 ( I slice only ) 
 pic_parameter_set_id : 0 
 frame_num : 0 
 field_pic_flag : 0 
 bottom_field_flag : 0 
 idr_pic_id : 0 
 pic_order_cnt_lsb : 0 
 delta_pic_order_cnt_bottom : 0 
 redundant_pic_cnt : 0 
 direct_spatial_mv_pred_flag : 0 
 num_ref_idx_active_override_flag : 0 
 num_ref_idx_l0_active_minus1 : 0 
 num_ref_idx_l1_active_minus1 : 0 
 cabac_init_idc : 0 
 slice_qp_delta : 1 
 sp_for_switch_flag : 0 
 slice_qs_delta : 0 
 disable_deblocking_filter_idc : 0 
 slice_alpha_c0_offset_div2 : 0 
 slice_beta_offset_div2 : 0 
 slice_group_change_cycle : 0 
=== Prediction Weight Table ===
 luma_log2_weight_denom : 0 
 chroma_log2_weight_denom : 0 
=== Ref Pic List Reordering ===
 ref_pic_list_reordering_flag_l0 : 0 
 ref_pic_list_reordering_flag_l1 : 0 
=== Decoded Ref Pic Marking ===
 no_output_of_prior_pics_flag : 0 
 long_term_reference_flag : 0 
 adaptive_ref_pic_marking_mode_flag : 0 

/************************************************
* 帧数据2
* **********************************************/
!! Found NAL at offset 5861 (0x16E5), size 2213 (0x08A5) 
XX 00 00 00 01 41 9A 22 6C 13 E2 83 E1 44 23 ED EA 

从中可以看到码流由SPS+PPS+SEI+帧数据构成…
而用HEX打开该H264的视频中可看到16进制的信息。
1、SPS信息
这里写图片描述

2、PPS信息
这里写图片描述

3、SEI增强信息
这里写图片描述
这里写图片描述

4、帧数据
这里写图片描述

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值