H264 NALU分析

作者&投稿:缑林 (若有异议请与网页底部的电邮联系)
~

NALU(Network Abstract Layer Unit)

⾳视频编码在流媒体和⽹络领域占有重要地位;流媒体编解码流程⼤致如下图所示:

H.264从1999年开始,到2003年形成草案,最后在2007年定稿有待核实。在ITU的标准⾥称为H.264,在MPEG的标准⾥是MPEG-4的⼀个组成部分–MPEG-4 Part 10,⼜叫AdvancedVideo Codec,因此常常称为MPEG-4 AVC或直接叫AVC。

在⾳视频传输过程中,视频⽂件的传输是⼀个极⼤的问题;⼀段分辨率为1920 1080,每个像素点为RGB占⽤3个字节,帧率是25的视频,对于传输带宽的要求是:1920 1080 3 25/1024/1024=148.315MB/s,换成bps则意味着视频每秒带宽为1186.523Mbps,这样的速率对于⽹络存储是不可接受的。因此视频压缩和编码技术应运⽽⽣。

对于视频⽂件来说,视频由单张图⽚帧所组成,⽐如每秒25帧,但是图⽚帧的像素块之间存在相似性,因此视频帧图像可以进⾏图像压缩;H264采⽤了16*16的分块⼤⼩对,视频帧图像进⾏相似⽐较和压缩编码。如下图所示:

H26使⽤帧内压缩和帧间压缩的⽅式提⾼编码压缩率;H264采⽤了独特的I帧、P帧和B帧策略来实现,连续帧之间的压缩;

如上图所示:

H264除了实现了对视频的压缩处理之外,为了⽅便⽹络传输,提供了对应的视频编码和分⽚策略;类似于⽹络数据封装成IP帧,在H264中将其称为组(GOP, group of pictures)、⽚(slice)、宏块(Macroblock)这些⼀起组成了H264的码流分层结构; H264将其组织成为序列(GOP)、图⽚(pictrue)、⽚(Slice)、宏块(Macroblock)、⼦块(subblock)五个层次

GOP (图像组)主要⽤作形容⼀个IDR帧 到下⼀个IDR帧之间的间隔了多少个帧。

H264将视频分为连续的帧进⾏传输,在连续的帧之间使⽤I帧、P帧和B帧。同时对于帧内⽽⾔,将图像分块为⽚、宏块和字块进⾏分⽚传输;通过这个过程实现对视频⽂件的压缩包装。

IDR(Instantaneous Decoding Refresh,即时解码刷新)

⼀个序列的第⼀个图像叫做 IDR 图像 ⽴即刷新图像 ),IDR 图像都是 I 帧图像。I和IDR帧都使⽤ 帧内预测 。I帧不⽤参考任何帧,但是之后的P帧和B帧是有可能参考这个I帧之前的帧的。

⽐如(解码的顺序):

IDR1 P4 B2 B3 P7 B5 B6 I10 B8 B9 P13 B11 B12 P16 B14 B15 这⾥的B8可以跨过I10去参考P7

原始图像: IDR1 B2 B3 P4 B5 B6 P7 B8 B9 I10

IDR1 P4 B2 B3 P7 B5 B6 IDR8 P11 B9 B10 P14 B11 B12 这⾥的B9就只能参照IDR8和P11,不可以参考 IDR8 前⾯的帧

其核⼼作⽤是,是为了解码的重同步,当解码器解码到 IDR 图像时, ⽴即将参考帧队列清空 ,将已解码的数据全部输出或抛弃,重新查找参数集,开始⼀个新的序列。这样,如果前⼀个序列出现重⼤错误,在这⾥可以获得重新同步的机会。IDR图像之后的图像永远不会使⽤IDR之前的图像的数据来解码。

下⾯是⼀个H264码流的举例(从码流的帧分析可以看出来B帧不能被当做参考帧)

GOP 指的就是两个I帧之间的间隔. ⽐较说GOP为120,如果是720 p60 的话,那就是2s⼀次I帧.在视频编码序列中,主要有三种编码帧:I帧、P帧、B帧,如下所示:

在视频编码序列中,GOP即Group of picture(图像组) ,指两个I帧之间的距离,Reference(参考周期)指两个P帧之间的距离。⼀个I帧所占⽤的字节数⼤于⼀个P帧,⼀个P帧所占⽤的字节数⼤于⼀个B帧。

所以在码率不变的前提下, GOP值越⼤,P、B帧的数量会越多 ,平均每个I、P、B帧所占⽤的字节数就越多,也就更容易获取较好的图像质量;Reference越⼤,B帧的数量越多,同理也更容易获得较好的图像质量。

需要说明的是,通过提⾼GOP值来提⾼图像质量是有限度的,在遇到场景切换的情况时,H.264编码器会⾃动强制插⼊⼀个I帧,此时实际的GOP值被缩短了。另⼀⽅⾯,在⼀个GOP中, P、B帧是由I帧预测得到的,当I帧的图像质量⽐较差时,会影响到⼀个GOP中后续P、B帧的图像质量,直到下⼀个GOP开始才有可能得以恢复,所以GOP值也不宜设置过⼤ 。同时,由于P、B帧的复杂度⼤于I帧,所以过多的P、B帧会影响编码效率,使编码效率降低。另外,过⻓的GOP还会影响Seek操作的响应速度,由于P、B帧是由前⾯的I或P帧预测得到的,所以Seek操作需要直接定位,解码某⼀个P或B帧时,需要先解码得到本GOP内的I帧及之前的N个预测帧才可以,GOP值越⻓,需要解码的预测帧就越多,seek响应的时间也越⻓。

H.264原始码流(裸流)是由⼀个接⼀个NALU组成,它的功能分为两层,VCL(视频编码层)和NAL(⽹络提取层):

在VCL进⾏数据传输或存储之前,这些编码的VCL数据,被映射或封装进NAL单元。(NALU)

NALU结构单元的主体结构如下所示;⼀个原始的H.264 NALU单元通常由[StartCode] [NALU Header] [NALU Payload]三部分组成,其中 Start Code ⽤于标示这是⼀个NALU 单元的开始,必须是"00 00 00 01" 或"00 00 01",除此之外基本相当于⼀个NAL header + RBSP;

(对于FFmpeg解复⽤后, MP4 ⽂件读取出来的packet是不带 startcode ,但 TS⽂件 读取出来的packet 带了startcode

每个NAL单元是⼀个⼀定语法元素的可变⻓字节字符串,包括包含⼀个字节的头信息(⽤来表示数据类型),以及 若⼲整数字节的负荷数据

NALU头信息( ⼀个字节 ):

其中:

nal_unit_type:这个NALU单元的类型,1~12由H.264使⽤,24~31由H.264以外的应⽤使⽤

forbidden_zero_bit: 在 H.264 规范中规定了这⼀位必须为 0.

H.264标准指出,当数据流是储存在介质上时,在每个NALU 前添加起始码:0x000001 或0x00000001,⽤来指示⼀个NALU 的起始和终⽌位置:

在这样的机制下,在码流中检测起始码,作为⼀个 NALU得 起始 标识,当检测到下⼀个起始码时,当前NALU 结束 **。

3字节的 0x000001 只有⼀种场合下使⽤,就是 ⼀个完整的帧被编为多个slice(⽚)的时候 ,包含这些slice的NALU 使⽤3字节起始码。其余场合都是 4 字节 0x00000001 的。

H264有两种封装

很多解码器只⽀持annexb这种模式,因此需要将mp4做转换:在ffmpeg中⽤h264_mp4toannexb_filter可以做转换

在H264中的图像以序列为单位进⾏组织, ⼀个序列是⼀段图像编码后的数据流 ,以I帧开始, 到下⼀个I帧结束。

IDR图像:⼀个序列的第⼀个图像叫做IDR图像(⽴即刷新图像),IDR 图像都是I帧图像。 H.264引⼊IDR图像是为了解码的重同步,当解码器解码到IDR图像时,⽴即将参考帧队列清 空,将已解码的数据全部输出或抛弃,重新查找参数集,开始⼀个新的序列。这样,如果前⼀个序列出现重⼤错误,在这⾥获得重新同步的机会。IDR图像之后的图像永远不会使⽤IDR之 前的图像数据来解码。

⼀个序列就是⼀段内容差别不是很⼤的图像编码后⽣成的⼀串数据流。当 运动变化⽐较少 的时 候,⼀个序列可以很⻓,因为运动变化的少就代表图像画⾯的内容变动很⼩,所以就可以编⼀ 个I帧,然后⼀直P帧、B帧了。 当运动变化多时,可能⼀个序列就⽐较短了 ,⽐如就包含⼀个I 帧和3、4个P帧。

const AVBitStreamFilter *bsfilter = av_bsf_get_by_name("h264_mp4toannexb"); h264_mp4toannexb Filter




弋阳县19359507091: H264码流解析 -
却容复方: 00 00 00 01是Start code后面的ox67为 0110 0111 forbidden_zero_bit 是禁止位,应该是第一位即f(1)=0,1为语法有错误 nal_ref_idc是参考级别,代表被其它帧参考情况,u(2)= 11 = 3最(0为无参考,详见规范) nal_unit_type是该帧的类型,为剩...

弋阳县19359507091: 请教一个关于h.264解码的问题
却容复方: H264的话,你可以通过判断NALU类型来确定是不是关键帧,并且你送到ffmpeg解码的时候第一帧必须是关键帧,否则是解不出来的(即使解出来也全是马赛克).

弋阳县19359507091: 用什么工具查看h264帧的参考关系 -
却容复方: 目前视频编解码分析领域,最权威的工具就是Elecard出品的.分析H264的话,可以用Elecard Stream Analyzer (分析码流结构),Elecard Stream Eye(分析帧结构和编码细节如宏块收敛等)

弋阳县19359507091: 如何把H264文件的数据一帧一帧的读出来 -
却容复方: 这其实是一个协议分析过程,每一帧H264数据都是可以通过观察二进制码流分析出来的.根据协议说明,每一帧图像一般在开头有一个单元分隔符NAL,两个单元分隔符之间的数据包就是一帧图像.就是00 00 01 09,这个09就是单元分隔符的标志.不过协议并没有说NAL流必须如此组织,可能还有其它的组织形式.我手头的H264文件都是这样组织的.

弋阳县19359507091: 谁能给我说说 darwin 的h264编码的mp4 流 的解析过程啊 还有包的格式 我怎么找资料都解不开这个包. -
却容复方: 首先你要确定是裸数据流还是已经文件封装的了,如果是裸流就直接解析(网上有N多H264解析的),如果是文件封装,就要根据文件类型解了文件头再解裸流

弋阳县19359507091: 如何在H264数据中获取PTS -
却容复方: xH264的ES原始数据一般是以NAL(Network Abstract Layer)的格式存在.可以直接用于文件存储和网络传输.每一个NALU(Network Abstract Layer Unit)数据,是由数据头+RBSP数据组成. 首先需要将数据流,分割成一个一个独立的NALU数据...

弋阳县19359507091: linux下有没有比较方便的对yuv文件或者H264文件进行分析比较的 -
却容复方: YUV格式通常有两大类:打包(packed)格式和平面(planar)格式.前者将YUV分量存放在同一个数组中,通常是几个相邻的像素组成一个宏像素(macro-pixel);而后者使用三个数组分开存放YUV三个分量,就像是一个三维平面一样. 在摄...

弋阳县19359507091: 除了VUI还有没有方法可以计算出H264的帧率 -
却容复方: 在H264文件里面,直接描述帧率的只有VUI,VUI一般是最标准的计算帧率的方法,精确到小数.不过确实有的H264的SPS里面没有VUI,此时可以通过统计每10秒有多少帧,大致计算出帧率.具体方法如下:从第一个I帧开始,把这个I帧的PTS作为基准时间记录.每次读一个帧,都看下PTS,直到PTS时间间隔到达10秒.然后看下总共多少帧,除以10,基本就是帧率了.也可以用更长的时间间隔,这样统计的更准确.

弋阳县19359507091: wireshark怎么分析h264 -
却容复方: 没什么关系的.以前H263的rtp包算得还不错,不过H264的时候感觉wireshark的分析就没什么用了.没什么关系的.以前H263的rtp包算得还不错,不过H264的时候感觉wireshark的分析就没什么用了.

弋阳县19359507091: 如何用C语言取出H.264ES文件里的nal信息 -
却容复方: 读文件,找到nal头,根据nal规则读规定位进行运算!具体的可以参考H264编解码标准!如果不会自己写轮子,可以使用ffmpeg库或者直接使用x264开源库来操作.

本站内容来自于网友发表,不代表本站立场,仅表示其个人看法,不对其真实性、正确性、有效性作任何的担保
相关事宜请发邮件给我们
© 星空见康网