h264检测是I帧还是P帧,解决录像第一帧有马赛克问题
H264帧边界识别简介

H264帧边界识别简介在Symbian平台上实现H264的RTSP流的播放原文:/asddg67/archive/2009/03/23/4017251. aspx 在Symbian平台上实现H264的RTSP流的播放/linzhiji/archive/2010/02/24/5323622.as px H264的数据读取最关键的地方就是如何识别一帧,因为ffmpeg的H264解码是按照一帧一帧解码的,如果送去解码的数据不是完整的一帧可能导致解码失败或者产生马赛克的情况。
以下是我在一个文档中摘取关于帧边界识别的一段,可以方便的解决相关的问题:帧边界识别简介H.264 将构成一帧图像所有nalu 的集合称为一个AU,帧边界识别实际上就是识别AU。
因为H.264 取消帧级语法,所以无法简单地从码流中获取AU。
解码器只有在解码的过程中,通过某些语法元素的组合才能判断一帧图像是否结束。
一般来说,解码器必须在完成一帧新图像的第一个slice_header 语法解码之后,才能知道前一帧图像已经结束。
因此,最严谨的AU 识别步骤如下:步骤1 对码流实施“去03 处理”。
步骤2 解析nalu 语法。
步骤3 解析slice_header 语法。
步骤4 综合判断前后两个nalu 以及对应的slice_header 中的若干个语法元素,看是否发生变化。
如果发生变化,则说明这两个nalu 属于不同的帧,否则说明这两个nalu 属于同一帧。
----结束显然,在解码前完成上述的AU 识别消耗许多CPU 资源,因此不推荐使用AU 方式解码为了提供一种简单的AU 识别方案,H.264 规定一种类型为09 的nalu,即编码器在每次完成一个AU 编码后,在码流中插入一个类型为09 的nalu,在这个前提下,解码器只需要从码流中搜索类型为09 的nalu 即可获得一个AU。
H.264 并不强制要求编码器插入类型为09 的nalu,因此并非所有的码流都具备这种特征。
H.264AVC中的SPSI帧技术

M89MC VAQPA 8K -./7. DEN= 0=#&( Q9 -*2 , -34 5+367( , +89: !"7;<4= .JE S8@A RE8:O9E QR *+7R98SEK @K :J8: @MEA:@N8F *+7 R98SEK N8A WE 9ENQAK:9ON:EM ETEA PJEA M@RRE9EA: 9ERE9EANE R98SEK 89E OKEM RQ9 :JE@9 L9EM@N:@QA= ?E 8FKQ @ANFOME 8 MEKN9@L:@QA QR *-7R98SEKC PJ@NJ 89E OKEM @A NQAXOAN:@QA P@:J *+7R98SEK= .JE L9QLE9:G QR *+7R98SEK 8FFQPK :JES :Q 9ELF8NE -7R98SEK @A 8LLF@N8:@QAK KONJ 8K W@:K:9E8S KP@:NJ@AB &KLF@N@ABC 8AM 98AMQS 8NNEKK= Y@A8FFGC K@SOF8:@QA 9EKOF:K KJQP :J8: *+7R98SEK J8TE K@BA@R@N8A:FG WE::E9 NQM@AB ERR@N@EANG :J8A -7R98SEK PJ@FE L9QT@M@AB K@S@F89 ROAN:@QA8F@:@EK=
%E99&#_%9EN$%L9EM&#
H264编码详细说明

序列、图像(存储单元)、宏块、像素一个序列的第一个图像叫做IDR 图像(立即刷新图像),IDR 图像都是I 帧图像。
H.264 引入IDR 图像是为了解码的重同步,当解码器解码到IDR 图像时,立即将参考帧队列清空,将已解码的数据全部输出或抛弃,重新查找参数集,开始一个新的序列。
●I帧(帧内编码帧)是一种自带全部信息的独立帧,无需参考其它图像便可独立进行解码。
视频序列中的第一个帧始终都是I帧。
I帧可以用来实现快进、快退以及其它随机访问功能。
如果新的客户端将参与查看视频流,编码器将以相同的时间间隔或者根据要求自动插入I帧。
I帧的缺点在于它们会占用更多的数据位,但I帧不会产生可觉察的模糊现象。
●P帧(帧间预测编码帧)需要参考前面的I帧和/或P帧的不同部分才能进行编码。
与I帧相比,P帧通常占用更少的数据位,但其缺点是,由于P帧对前面的P和I参考帧有着复杂的依赖性,因此对传输错误非常敏感。
●B帧(双向预测编码帧)需要同时以前面的帧和后面的帧作为参考帧。
不是参考帧,不会造成解码错误的扩散。
运算比较复杂,CPU占用较高。
I、B、P各帧是根据压缩算法的需要人为定义的,它们都是实实在在的物理帧。
一般来说,I帧的压缩率是7(跟JPG差不多),P帧是20,B帧可以达到50。
网络打包、网络抽象层单元(NALU)、片NALU的网络打包:(1) 额外开销要少,使MTU尺寸在100~64k字节范围都可以;(2) 不用对包内的数据解码就可以判别该包的重要性;(3) 载荷规范应当保证不用解码就可识别由于其他的比特丢失而造成的包不可解码;(4) 支持将NALU分割成多个RTP包;(5) 支持将多个NALU汇集在一个RTP包中。
●灵活宏块次序(FMO) 可以通过设置宏块次序映射表(MBAmap)来任意地指配宏块到不同的片组,FMO模式打乱了原宏块顺序,降低了编码效率,增加了时延,但增强了抗误码性能。
划分图像的模式各种各样,主要的有棋盘模式、矩形模式等。
论坛最近经常有人问H264的效果等问题

论坛最近经常有人问H.264的效果等问题,我实在是没时间一一做答,再者各人观点不同,干脆给出个测试报告,大家自己评价吧。
测试条件:1、赛扬1G,256MB SDRAM,Win98SE2、H.264只支持16x16、8x8、4x4模式,部分MMX优化(量化等耗时部分没有优化)3、只测试 300 kbps、500 kbps、1000 kbps、1500 kbps几种环境4、MPEG4为半点MV,H.264为1/4点MV5、I帧间隔一律为646、帧率均设置为25 Hz7、MPEG4为了提高PSNR,没有使用MMX/SSE等简化算法测试序列:A、电影中截取的250帧,含有渐亮、渐暗、场景渐渐切换、全屏横向运动等复杂环境备注:1、MPEG4编码器输出的总PSNR均值和YUV分量和的均值不同,所以我重新计算了一下,新的值比编码器给出的大约大1左右;2、H.264编码器没有码率控制,只好使用修改Qp来控制了,在实际使用中由于有码率控制,所以效果应该比我的测试结果好。
3、H.264由于是简化版本,所以其编码速度约为1 fps4、H.264的码率只能精确到整数部分,小数部分均设为0了5、为了便于比较,H.264部分增测了一些码率测试结果(均为平均值):1、MPEG4部分视频序列A、H263量化方式:379.00 kbps: PSNR=39.767(Y=37.040, U=40.998, V=41.262) 559.22 kbps: PSNR=42.480(Y=40.432, U=43.298, V=43.709) 1073.48 kbps: PSNR=44.714(Y=42.861, U=45.415, V=45.865) 1583.01 kbps: PSNR=45.634(Y=43.598, U=46.378, V=46.926)视频序列A、MPEG4量化方式:375.12 kbps: PSNR=39.954(Y=37.059, U=41.297, V=41.505) 562.53 kbps: PSNR=42.647(Y=40.355, U=43.554, V=44.033) 1054.25 kbps: PSNR=45.140(Y=43.157, U=45.852, V=46.411) 1539.31 kbps: PSNR=46.311(Y=44.318, U=46.961, V=47.653) 2541.80 kbps: PSNR=47.082(Y=45.049, U=47.727, V=48.470)2、H.264部分视频序列A、2参考帧、CAVLC:295.00 kbps: PSNR=41.375(Y=38.805, U=42.424, V=42.894)489.00 kbps: PSNR=43.923(Y=42.187, U=44.500, V=45.081)533.00 kbps: PSNR=44.512(Y=42.664, U=45.151, V=45.720)1027.00 kbps: PSNR=46.866(Y=45.672, U=47.114, V=47.811)视频序列A、5参考帧、CAVLC:322.00 kbps: PSNR=41.855(Y=39.297, U=42.854, V=43.413)488.00 kbps: PSNR=43.896(Y=42.122, U=44.504, V=45.060)1024.00 kbps: PSNR=46.860(Y=45.650, U=47.118, V=47.813)视频序列A、2参考帧、CABAC:265.00 kbps: PSNR=41.925(Y=39.461, U=42.875, V=43.439)359.00 kbps: PSNR=43.362(Y=41.347, U=44.088, V=44.651)510.00 kbps: PSNR=44.712(Y=43.246, U=45.155, V=45.736)1015.00 kbps: PSNR=47.198(Y=46.067, U=47.406, V=48.122)视频序列A、5参考帧、CABAC:164.00 kbps: PSNR=39.635(Y=36.014, U=41.295, V=41.597)262.00 kbps: PSNR=41.855(Y=39.297, U=42.854, V=43.413)505.00 kbps: PSNR=44.722(Y=43.253, U=45.172, V=45.740)1008.00 kbps: PSNR=47.193(Y=46.050, U=47.419, V=48.110)视频序列A、1参考帧、CAVLC、2个B帧:536.00 kbps: PSNR=41.794(Y=39.420, U=42.723, V=43.239)。
视频编码之I帧、P帧、B帧

视频编码之I帧、P帧、B帧
视频传输原理
视频是利⽤⼈眼视觉暂留的原理,通过播放⼀系列的图⽚,使⼈眼产⽣运动的感觉。
单纯传输视频画⾯,视频量⾮常⼤,对现有的⽹络和存储来说是不可接受的。
为了能够使视频便于传输和存储,⼈们发现视频有⼤量重复的信息,如果将重复信息在发送端去掉,在接收端恢复出来,这样就⼤⼤减少了视频数据的⽂件,因此有了H.264视频压缩标准。
在H.264压缩标准中I帧、P帧、B帧⽤于表⽰传输的视频画⾯。
I帧⼜称帧内编码帧,是⼀种⾃带全部信息的独⽴帧,⽆需参考其他图像便可独⽴进⾏解码,可以简单理解为⼀张静态画⾯。
视频序列中的第⼀个帧始终都是I帧,因为它是关键帧。
2、P帧
P帧⼜称帧间预测编码帧,需要参考前⾯的I帧才能进⾏编码。
表⽰的是当前帧画⾯与前⼀帧(前⼀帧可能是I帧也可能是P帧)的差别。
解码时需要⽤之前缓存的画⾯叠加上本帧定义的差别,⽣成最终画⾯。
与I帧相⽐,P帧通常占⽤更少的数据位,但不⾜是,由于P帧对前⾯的P 和I参考帧有着复杂的依耐性,因此对传输错误⾮常敏感。
B帧⼜称双向预测编码帧,也就是B帧记录的是本帧与前后帧的差别。
也就是说要解码B帧,不仅要取得之前的缓存画⾯,还要解码之后的画⾯,通过前后画⾯的与本帧数据的叠加取得最终的画⾯。
B帧压缩率⾼,但是对解码性能要求较⾼。
总结:
I帧只需考虑本帧;P帧记录的是与前⼀帧的差别;B帧记录的是前⼀帧及后⼀帧的差别,能节约更多的空间,视频⽂件⼩了,但相对来说解码的时候就⽐较⿇烦。
因为在解码时,不仅要⽤之前缓存的画⾯,⽽且要知道下⼀个I或者P的画⾯,对于不⽀持B帧解码的播放器容易卡顿。
数字视频压缩技术H264详解

数字视频压缩技术H264详解一个基于分组方式的接口,打包和相应的信令属于NAL的一部分。
这样,高编码效率和网络友好性的任务分别由VCL和NAL来完成。
VCL层包括基于块的运动补偿混合编码和一些新特性。
与前面的视频编码标准一样,H.264没有把前处理和后处理等功能包括在草案中,这样可以增加标准的灵活性。
NAL负责使用下层网络的分段格式来封装数据,包括组帧、逻辑信道的信令、定时信息的利用或序列结束信号等。
例如,NAL支持视频在电路交换信道上的传输格式,支持视频在Internet上利用RTP/UDP/IP传输的格式。
NAL包括自己的头部信息、段结构信息和实际载荷信息,即上层的VCL数据。
(如果采用数据分割技术,数据可能由几个部分组成)。
(2)高精度、多模式运动估计H.264支持1/4或1/8像素精度的运动矢量。
在1/4像素精度时可使用6抽头滤波器来减少高频噪声,对于1/8像素精度的运动矢量,可使用更为复杂的8抽头的滤波器。
在进行运动估计时,编码器还可选择“增强”内插滤波器来提高预测的效果。
在H.264的运动预测中,一个宏块(MB)可以按图2被分为不同的子块,形成7种不同模式的块尺寸。
这种多模式的灵活和细致的划分,更切合图像中实际运动物体的形状,大大提高了运动估计的精确程度。
在这种方式下,在每个宏块中可以包含有1、2、4、8或16个运动矢量。
在H.264中,允许编码器使用多于一帧的先前帧用于运动估计,这就是所谓的多帧参考技术。
例如2帧或3帧刚刚编码好的参考帧,编码器将选择对每个目标宏块能给出更好的预测帧,并为每一宏块指示是哪一帧被用于预测。
(3)4某4块的整数变换H.264与先前的标准相似,对残差采用基于块的变换编码,但变换是整数操作而不是实数运算,其过程和DCT基本相似。
这种方法的优点在于:在编码器中和解码器中允许精度相同的变换和反变换,便于使用简单的定点运算方式。
也就是说,这里没有“反变换误差”。
变换的单位是4某4块,而不是以往常用的8某8块。
H.264参考帧

H264 中的参考帧列表H264中允许从多至15个帧里面选择1帧或者2帧出来作为参考进行预测,所以必须引入一个列表来管理这些参考图像,对与P slice而言,对应 list0,对于B slice 而言,还需要多一个 list1,因为 B slice 是进行的两次预测!(一个前向一个后向\两个前向\两个后向)参考帧分为 long term / short term 两种,即所谓的长期参考帧和短期参考帧。
其中长期参考帧用 LongTermPicNum来进行索引,而短期参考帧则利用 frame_num 或者 POC 来进行索引(默认索引顺序即初始化顺序),再具体一点:P slice 的短期参考利用 frame_num 来进行索引,且按照降序排列(即离当前图像最近的前向图像排在第0位)B slice 的短期参考利用 POC 来进行索引,对其List0而言,先按照POC降序排列处于其前向的参考帧然后再按照POC升序排列处于其后向的参考帧;对其List1而言,先按照POC升序排列处于其后向的参考帧然后再按照POC降序排列处于其前向的参考帧。
对于每个MB而言,在mb_pred()中会传输其参考索引,以表明该MB从list0\list1中选择哪一个作为参考,而对于一个Slice 而言,可能存在该 Slice 内部大多数MB都选择了某一个索引号较大的参考帧,如设定list0中的索引从0~5,而大多数MB都选择了5,在用哥伦布码进行编码时,将会消耗较多的bit!所以在初始化排序好后,会根据当前 slice 的具体情况,对列表进行重排序,如将此时排在索引5位置的POC与排在0位置的POC进行交换,那么mb_pred()中传输参考索引所需的bit数就大大减少了!其中参考索引重排的语法在ref_pic_list_reordering()中有详细介绍!那么当一帧解完后,如何处理该帧呢?需不需要将其放入参考列表中?所以在h264的bit stream中还传输了dec_ref_pic_marking(),通过mmco这个玩意告诉我们当前的一帧接完后如何处理参考列表!TBD:剩下的一个问题就是,为什么要分长期参考和短期参考呢?以下是来自网上的答案,因为short term参考帧以frame_num做为索引,而frame_num是有最大值的,达到最大值后会进行取模,所以短期参考帧不能长期存在于参考列表中,因为一旦frame_num达到最大值后取模为0,该索引就失去意义了,而长期参考帧则不同!/********************************************************I guess there are two primary differences.1) Short-term reference pictures are indexed by referring to variablesthat are a function of their frame_num value. But frame_num is a modulocounter that wraps over periodically. Therefore there is a limit on howlong a short-term reference picture can remain in the buffer -- itcannot remain there after the frame_num value has wrapped all the wayaround and crossed over the same value again. In contrast, long-termreference pictures are referenced by an index that is explicitlyassigned to them by syntax -- their long-term frame index. So along-term reference picture can stay in the decoded picture buffer aslong as the encoder wants it to.2) There is no use of temporal (picture order count) relationships whenreferencing long-term reference pictures in the decoding process.**********************************************************/。
H.264讲解

帧内预测
图4
帧内预测 16×16亮度预测模式
– 宏块的全部16×16亮度成分可以整体预测,有4种 预测模式,如表2和图5所示。
图5 16×16预测模式
帧内预测
表2 16×16预测模式
描 模式
述
模式0(垂直) 模式1(水平) 模式2(DC) 模式3(平面)
由上边像素推出相应像素值
由左边像素推出相应像素值
H.264/AVC编解码器 H.264解码器
– 由 图 1 可 知 , 由 编 码 器 的 NAL 输 出 一 个 压 缩 后 的 H.264压缩比特流。由图2,经熵解码得到量化后的 一组变换系数 X,再经反量化、反变换,得到残差 Dn’。利用从该比特流中解码出的头信息,解码器 就产生一个预测块PRED,它和编码器中的原始PRED 是相同的。当该解码器产生的PRED与残差Dn’相加 后,就产生 uFu’ ,再经滤波后,最后就得到滤波 后的Fn’,这个Fn’就是最后的解码输出图像。
这样表示9中预测模式只需要8个值 (0 to 7)
帧内预测
帧间预测
树状结构运动补偿
– 每个宏块(16×16像素)可以4种方式分割:一个 16×16,两个16×8,两个8×16,四个8×8。其运 动补偿也相应有四种。而8×8分割还可以有四种方 式的分割:一个8×8,两个4×8或两个8×4及4个 4×4。这种分割下的运动补偿则称为树状结构运动 补偿。
当A (或者 B)的预测模式不可用时,
prediction mode of A= 2.
例如 A 和 B块的预测模式分别为 3 和1
most probable mode for block C =1
帧内预测
编码器为每个4x4 块发送一个标记 flag,解码器按照如下方式 解码 If flag==1, prediction mode=most_probable_mode If flag==0 If rem_intra4×4_pred_mode< most_probable_mode prediction mode=rem_intra4×4_pred_mode else prediction mode=rem_intra4×4_pred_mode+1
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
h264检测是I帧还是P帧,解决录像第一帧有马赛克问题
最近使用h264码流数据进行录像,但是录出来的第一帧有马赛克,究其原因是录像的第一帧不是关键帧,所以需要录像是需要判断第一帧是否是关键帧,方法有两种,第一种是原码流的基础上查找,第二种是将原码流传递给ffmpeg让ffmpeg判断key_frame,第二种相对简单,但是由于这样一来录像和解码视频切合的太紧密,之后修改比较麻烦,所以选择第一种方案,查看注释1可以明白如何检测h264码流的关键帧,下面是我截取原码流的关键帧和p帧
0000000 :是sps
0000000 : 是pps
0000000 : 是帧类型
关键帧类型:
1.<span style="color:#FF0000;"><span style="font-size:24px;">000000
0: <span style="color:#CCCCCC;">0000 0001 6742 401f 9654 0501 ed0
0 f39e ....gB@..T......
2.0000010: a</span><span style="color:#3366FF;">000 0000 0168 ce38
80</span>00 0000 01<span style="color:#000000;">65</span> 8880 .
....h.8.....e..
3.0000020: 4001 8231 2000 4f11 d84d 5fff fb3b c28a @..1 .O..M_..;.
.
4.0000030: 00bc fc83 03db b3e3 8603 9c59 fa0f a82c ...........Y...
,
5.0000040: df55 fdf6 8414 032a e766 bd4b fbea 05af .U.....*.f.K...
.</span>
6.</span>
P帧类型:
1.0000000: <span style="color:#C0C0C0;">0000 0001 6742 401f 9654 05
01 ed00 f39e ....gB@..T......
2.0000010: a</span><span style="color:#3366FF;">000 0000 0168 ce38
80</span>00 0000 01<span style="color:#000000;">41</span> 9a02 .
....h.8.....A..
3.0000020: 0586 7cb9 9125 5788 8f90 7f1f 1930 7eef ..|..%W......0~
.
4.0000030: 6383 bebd 2cc5 3627 92c3 390b 46dc d4a5 c...,.6'..9.F..
.
5.0000040: 774b 3484 57f8 9840 fba3 1dd6 800f 2242 wK4.W..@......"
B
6.0000050: 8816 080f 8f8d 84c6 09aa cda6 363d 00da ............6=.
.
7.0000060: b563 4392 bc65 93e2 63bb 6d30 472e 3ef1 .cC..e..c.m0G.>
.
8.0000070: 545d 6a3f 36c3 2f7d 6b1e 3c91 d15d d687 T]j?6./}k.<..].
.
所以在代码中需要检索第29个字节,来判断是65还是41,
1.public static String byteToHexString(byte src){
2. StringBuilder stringBuilder = new StringBuilder("");
3. int v = src & 0xFF;
4. String hv = Integer.toHexString(v);
5.if (hv.length() < 2) {
6. stringBuilder.append(0);
7. }
8. stringBuilder.append(hv);
9.return stringBuilder.toString();
10. }
11.p rivate boolean isFirstIFrame = true;
12.p rivate String IFrame = "65";//关键帧是0x65
13.//<span style="font-size:16px"></span>bArrayImage是存放h264原码流
字节数组
14.i f (是在录像) {
15.if (isFirstIFrame) {
16. String type = byteToHexString(bArrayImage[29]
);
17.if (type.equals(IFrame)) { //第29个字符是
判断帧的类型
18. isFirstIFrame = false;
19. ShootingVideoData(bArrayImage, Video_Data
_iVideoLen);//录制第一帧:关键帧
20. }
21. }else {
22. ShootingVideoData(bArrayImage, Video_Data_iVi
deoLen);
23. }
24. }
这样在录制出的第一帧录像就没有马赛克了。
注释1:检测h264中I帧,P帧
今天在网上找了一些资料,知道了如何检测h264中的帧类型,在这里记录下来。
首先,贴出nal单元类型定义(图从《新一代视频压缩编码标准H.264》摘录):
假设一段h264的码流为:00 00 00 01 41 E6 60……
其中的00 00 00 01为起始码,而起始码之后的下一个字节就可以检测出这一帧的类型。
在上面的码流中起始码之后的字节位0x41,换算成二进制为0100 0001。
注:我解读顺序为从左往右算。
(1)第1位禁止位,值为1表示语法出错
(2)第2~3位为参考级别
(3)第4~8为是nal单元类型,在此处为0 0001换算成十进制为1。
根据上图可知道这段码流是【不分区、非IDR图像的片】,新濠天地娱乐场 在baseline的档次中就是P帧,因为baseline没有B帧。
如果是另一段码流:00 00 00 01 65 E8……
那么根据0x65字节(0110 0101)根据后5位换算十进制为5,也就是【IDR图像中的片】,即I帧。
用代码的方式可以这样写,int type = 0x65 & 0x1f,然后根据type在表中查找即可获得需要的结果。