https://iamkate.com/code/binary-file-viewer/
1 YCbCr
亮度Y是不同权重的RGB平均值:
Y = Kr x R + Kg x G + Kb x B
Cb = B - Y
Cr = R - Y
Cg = G - Y
2 H264
2.1 40nm
H264 IP core: ME/MC, Quantize, CAVLC, CABAC
macro block includes 16x16 Y, 8x8 Cb, then split 16x16 Y to 16 4x4, and split 8x8 Cb to to 4 4x4, using DCT transformer for each 4x4.
2.2 NALU
H264的H是ITU-T标准中按照字母排序的规范,正好将H264排到了字母H。
Annex-B H264文件格式 = ANNEX_B + NALU + ANNEX_B + NALU + …
1)其中ANNEX_B等于0x000001或0x00000001,NALU由1个字节header和RBSP(Raw Byte Sequence Payload)组成。buffer中的每一个字节与0比较,如果相等,zero_cnt++;如果不相等,那么zero_cnt = 0;假如zero_cnt == 3并且当前的字节等于1,表明下一个字节是NALU的开始。
2)NALU header的b4...b0表示32种数据类型,1表示P或者B,5表示IDR(I帧,H264 FPS等于每秒传输的I帧的数目),6表示SEI,7表示SPS(NALU前3个hex格式字节67 64 00),8表示PPS,其中SPS和PPS存放解码关键信息,包括视频宽高等,SPS的第一个字节profile_idc表明使用的是哪种profile,例如Base Profile/Main Profile/High Profile。一般每个IDR前面都有SPS和PPS,可以参考AVB的pcap文件。
H264 GOP = 1 I-frame (IDR), GOP value is set to H264 codec register.
width = (pic_width_in_mbs_minus1 + 1) x 16 - frame_crop_left_offset x 2 - frame_crop_right_offset x 2;
height = (pic_height_in_map_units_minus1 + 1) x 16 x (2 - frame_mbs_only_flag) - frame_crop_top_offset x 2 - frame_crop_bottom_offset x 2;
fps = time_scale / num_units_in_tick;
3)当AVB或者RTP对NALU进行分段传输时(Fragmentation Unit),用FU indentifier和FU header两个字节替换了1字节的NALU header,第一个字节FU indentifier的bit4...bit0表示type,28为FU-A,29为FU-B;第二个字节FU header的bit7等于1时表示分片start_bit,第二个字节FU header的bit6等于1时表示分片end_bit,第二个字节FU header的bit4...bit0等于NALU header中的type。接收AVB CVF时NALU header = (fu_ind & 0xe0) | (fu_hdr & 0x1f)。需要注意的是raw socket编程时,读取到的buffer中不包含4 bytes vlan。
4)以太网帧MTU的长度范围在[46, 1500],也就是除去14字节MAC头(不包括4字节VLAN)和4字节FCS后支持的数据长度范围,Ethernet Inter frame Gap (IFG) is 12 bytes。提取AVB CVF帧到文件中时,如果CVF帧除去头部28字节后的payload长度小于等于18,那么先写入一个ANNEX_B到文件中,接着写CVF帧payload[1]开始的数据到文件中,并且写入文件的数据长度等于CVF帧的payload[0]。
5) H264 File Name Extension: .h264, PotPlayer 64 bit or VLC can play it.
2.3 H264多NALU编码
当一帧YUV数据过大时,单线程编码就不太现实,因此codec通常将一帧YUV数据切割成几个大块,然后由多个线程同时编码成多个NALU单元。
例如:SPS PPS I I I SPS PPS I I I SPS...
这个例子中就是3个I帧表示一个camera frame,通常见到的都是一个I帧表示一个YUV帧。
NALU payload首字节(1字节NALU header之后的第一个字节)开始的第一个字段是first_mb_in_slice,表示一个YUV帧的第一个切片,使用ue(v)解码。first_mb_in_slice等于0表示一个YUV帧的开始。
2.4 UVC H264
Each length of urb.number_of_packets is equal to iTD.Transaction X Length, the maximum is 3 x 1024 bytes.
Check UVC video format through PotPlayer. Intel Integrated Camera uses packed YUY2 (4:2:2) format.
UVC H264 12字节头偏移地址为1的1个字节bmHeaderInfo,其bit0在每个帧开始时会有从0到1或者从1到0的切换。其bit1为1时表示一帧的结束。
micro_frame ISO (including burst) = 12-byte header + (SCP + SPS) + (SCP + PPS) + (SCP + SEI) + (SCP + part of IDR), SCP means Start_Code_Prefix.
Refer to ELP_H264_UVC (Shenzhen Ailipu) and USB_Video_Payload_H264_1.5.pdf.
2.5 SMDK6410 MFC
读出H264文件头部的SPS/PPS/SEI一起赋值给MFC buffer去初始化解码器,然后顺序读出NALU I帧给解码器buffer,每解码完一帧YUV,函数就返回成功。
2.6 FFMPEG H264
发送H264 packet后,如果数据不足以组成完整的一帧YUV,解码器会缓存数据,此时avcodec_receive_frame返回AVERROR(EAGAIN),需要更多输入数据。
发送packet1 - > receive返回EAGAIN(数据不足)
发送packet2 - > receive返回EAGAIN(还不够)
发送packet3 - > receive成功,输出frame1
- > receive成功,输出frame2(一个packet产生多帧)
- > receive返回EAGAIN(需要更多输入数据)
3 28nm H265
3.1 NALU
1)H265 NALU header由2字节组成,第一个字节的bit0表示字段F,一般其值为0,第一字节的bit6...bit1表示64种类型,1表示TRAIL_R(P帧),19表示IDR_W_RADL(I帧),32表示VPS(NALU前四个hex格式字节40 01 0c 01),33表示SPS,34表示PPS,39表示SEI,一般每个IDR_W_RADL前面都有VPS、SPS和PPS;第一个字节的bit7和第二个字节的bit4...bit0表示字段LayerId,一般其值为0,第二个字节的bit7...bit5表示字段TID,一般其值为1。
将H265 NAL头中type为1的改成19后,会导致H265的视频变成慢镜头。
width = pic_width_in_luma_samples;
height = pic_height_in_luma_samples;
fps = vui_time_scale / vui_num_units_in_tick;
2)当AVB或者RTP对NALU进行分段传输时(Fragmentation Unit),用2字节FU indentifier和1字节FU header替换了2字节的NALU header,当FU indentifier的第一字节的bit6...bit1为49时,表示分段FU;第三个字节FU header的bit7等于1时表示分片start_bit,第三个字节FU header的bit6等于1时表示分片end_bit,第三个字节FU header的bit5...bit0等于NALU header中的type。接收AVB CVF时NALU header的第一个字节 = (fu_ind[0] & 0x81) | ((fu_hdr & 0x3f) << 1)。
3) H265 File Name Extension: .h265, PotPlayer 64 bit or VLC can play it.
4) Refer to github h265nal.
3.2 H265多NALU编码
NALU payload首字节(2字节NALU header之后的第一个字节)开始的第一个字段是first_slice_segment_in_pic_flag,表示一个YUV帧的第一个切片,使用u(1)解码。
1) If you find VCL-NAL parse slice header and find value of first_slice_segment_in_pic_flag equal to 1 specifies that the slice segment is the first slice segment of the picture in decoding order.
2) Do same process until you will get next vcl nal containing first_slice_segment_in_pic_flag equal to 1. So this will indicate you this is the start of new or next frame.
VLC播放H265文件时要保证第一个报文是VPS,否则VLC无法播放。
4 SPS解析
4.1 H264 SPS解析
se(v): signed 32bit integer Exponential Golomb with the left bit first, v means variable
u(n): n bits unsigned integer
ue(v): unsigned 32bit integer Exponential Golomb with the left bit first, v means variable
codeNum = 2^LeadingZeroBits - 1 + (xxxx)
哥伦布编码以中间的1为对称轴,前缀全为0。
For example:
000010101
LeadingZeroBits = 4
codeNum = 2^4 - 1 + 101b = 16 - 1 + 5 = 20
Refer to github ELP_H264_UVC to get se(v), u(n) and ue(v) functions implementation.
In ffmpeg, sps and pps are saved in AVCodecContext.extradata.
4.2 H265 SPS解析
Refer to github ELP_H264_UVC to get se(v), u(n) and ue(v) functions implementation.
参考NXRTE网站 H265 Nalu类型判断及 sps 数据解析
4.3 Tools
H264: Elecard StreamEye. 1-byte NALU header + Slice header + Slice payload. After NALU header the first 2-byte of Slice header is first_mb_in_slice, where mb means macro block. Need use ExpGolomb to parse the first 2-byte.
H265: Elecard HEVC Analyzer (Click sps in left panel), PotPlayer64
H264 and H265
于 2022-10-24 10:15:06 首次发布
本文详细介绍了H264和H265编码格式,包括NALU结构、帧类型、GOP结构、分段传输以及SPS和PPS等关键信息。讲解了如何解析NALU头、理解视频帧的编码切片以及不同类型的NALU在解码过程中的作用。此外,还提到了H264和H265在多NALU编码时的处理方式,以及与UVCH264的关联。

246

被折叠的 条评论
为什么被折叠?



