H.264中IDR帧和I帧区别

IDR(Instantaneous Decoding Refresh)--即时解码刷新。
      I和IDR帧都是使用帧内预测的。它们都是同一个东西而已,在编码和解码中为了方便,要首个I帧和其他I帧区别开,所以才把第一个首个I帧叫IDR,这样就方便控制编码和解码流程。IDR帧的作用是立刻刷新,使错误不致传播,从IDR帧开始,重新算一个新的序列开始编码。而I帧不具有随机访问的能力,这个功能是由IDR承担。IDR会导致DPB(DecodedPictureBuffer参考帧列表——这是关键所在)清空,而I不会。IDR图像一定是I图像,但I图像不一定是IDR图像。一个序列中可以有很多的I图像,I图像之后的图像可以引用I图像之前的图像做运动参考。  
      对于IDR帧来说,在IDR帧之后的所有帧都不能引用任何IDR帧之前的帧的内容,与此相反,对于普通的I-帧来说,位于其之后的B-和P-帧可以引用位于普通I-帧之前的I-帧。从随机存取的视频流中,播放器永远可以从一个IDR帧播放,因为在它之后没有任何帧引用之前的帧。但是,不能在一个没有IDR帧的视频中从任意点开始播放,因为后面的帧总是会引用前面的帧。

普通I帧与IDR(Instantaneous Decoding Refresh,瞬时解码刷新)帧为均采用帧内预测技术的视频帧,同属于I帧。

区别是:采用IDR帧编码,会导致DPB(Decoded Picture Buffer,直译为解码图像缓冲区,即指参考帧列表)完成一次清空处理,而普通I帧不会。

那么,这样带来的直接结果是怎样的呢?
即,当前IDR帧后面的帧不会将当前IDR帧之前已经编码的帧作为参考帧;而当前普通I帧之后的帧有可能将当前I帧之前的帧作为参考帧。

那么,这样带来的直接效果是怎样的呢?
即,播放视频的时候,可以直接从IDR帧开始播放,因为IDR帧之前的帧与当前IDR帧和之后的帧再也没有直接地关联;而普通I帧则不行。

可以看到,一般来讲,一段视频的第0帧(也即首帧)是I帧,那么它算不算是IDR帧呢?答:算。

所以,IDR帧一定是I帧,反之不成立。
在H.264标准参考软件(JM)下,通过IDRIntraEnable来设置是否支持IDR帧。



 在H.264编码中为了提高编码效率,采用了与传统MPEG-2编码不同的帧预测方式,在H.264编码中的B、P帧与MPEG-2中的B、P帧具有不同的帧间预测特性,H.264中的B、P帧能以多个视频帧做为参考帧,以获取更高的压缩比,正是这些新的特性进一步提高了H.264编码的压缩效率。为此,也在H.264编码中引入了一个关键帧的概念即IDR帧。
  IDR帧是一个GOP(Group of Pictures)中的首个I帧,即从IDR帧开始,重新开始一个新的序列编码,它的作用是使解码器立即刷新,从而使预测错误不致传播,并提供随机访问的能力。一个GOP中可以有很多的I帧,但只能有一个IDR帧。IDR帧一定是I帧,但I帧不一定是IDR帧。对IDR帧的编码处理与I帧的处理相同:(1)进行帧内预测,决定所采用的帧内预测模式。(2)像素值减去预测值,得到残差。(3)对残差进行变换和量化。(4)变长编码和算术编码。(5)重构图像并滤波,得到的图像作为其它帧的参考帧。
  H.264与MPEG-2编码的不同是,相对普通的I帧,位于其之后的B帧和P帧可以引用位于其之前的图像帧最为参考,而对于IDR帧来说,在IDR帧之后的所有帧都不能引用其之前的帧的内容。由此可以看出,从随机存取的视频流中,播放器永远可以从一个IDR帧播放,因为在它之后没有任何帧引用之前的帧。但是,不能在一个没有IDR帧的视频中从任意点开始播放,因为后面的帧总是会引用前面的帧进行帧间预测。
IDR就是这样一种特殊的I帧,它确保后面的任何帧一定不参考其前面的帧,可以放心地作为关键帧,而将快编后的重新编码计算量限定在编辑点前后2个GOP之内。
  通过IDR帧的原理,我们可以看出,如果一个视频流的GOP的第一帧不是IDR帧而是普通I帧,会因为H.264采用了多帧预测,有可能I帧后的P、B会参考I帧前的帧,这样在编辑时如果以任意帧为编辑点,则随后的帧都应重新进行预测编码,这无疑会增加设备的运算量,降低编辑效率。
  一幅图像根据概念来分可以分为两种:IDR图像和非IDR图像。一幅图像是否是IDR图像是由组成该图像的NALU值决定的,如果组成该图像的NALU如“图1”语法结构中nal_unit_type值为5,则该图像为IDR帧,否则为非IDR帧。由此我们可以得出这样的结论:
  (1)nal_unit_type值为5的NALU只会出现在IDR帧中,而IDR帧中的所有NALU都是nal_unit_type 值为5的NALU;
  (2)我们以组成一幅图像的帧的类型来区分该图像是否是IDR图像是不对的。一个图像序列中的所有帧都是I帧并不代表这个图像就是IDR图像。因为I帧也可以从属于nal_unit_type值为1的NALU。
  可见,在编码器设置中进行参数设定,适时指定IDR帧十分重要。


 H.264中普通I帧和IDR帧究竟有什么区别?(不要与MPEG2中的I帧搞混淆了) 
分类: 视频相关研究
2012-11-16 16:12 1780人阅读 评论(0) 收藏 举报
       纠结概念的人不少,这是个好事,但有时用实验的方法自己亲自分析一下会更好. 一次刻骨铭心的体验胜过千百次的说教, 闲话少扯,进入正题.
       在MPEG2中,有个重要的概念叫GOP(group of pictures),假设编码的帧类型为:IBBPBBPBBPBBIBBPBBPBBPBBI..., 那么这个IBBPBBPBBPBB就叫一个GOP. 由于误差会积累,但MPEG2中的I帧可以阻断误差的积累,也就是说,在MPEG中I帧后面的帧永远不会参考I帧前面的帧,也就是说,一个GOP中的帧永远不会参考前一个GOP中的帧.(另外说句题外话:B帧可以参考下一个GOP的I帧,但在MPEG2中,B帧不会作为参考帧,所以B帧不会导致误差积累)
 
       在H.264中就不同了.很多人说,在H.264中没有I帧这个概念了,当然这也是有道理的,标准中的确没有这么叫,但是,为了方便,也可以延续I帧这个概念,那么H.264中什么叫I帧呢?
       定义:H.264中的I帧是指帧中的宏块都是采用帧内预测方式,在H.264中有两种I帧: 普通I帧和IDR帧(特殊I帧).
       在H.264中,是IDR帧阻断了误差的积累, IDR帧后面的帧都不能参考该IDR帧前面的帧. 在H.264中,普通的I帧并没有阻断误差的积累,那就是说普通I帧后面的帧就可以参考该I帧之前的帧么?事实正是如此. 下面用H.264visa加以分析验证.
再次总结:在H.264中,I帧分为普通I帧和IDR帧(特殊I帧); 在H.264中,是IDR帧阻断了误差的积累, IDR帧后面的帧都不能参考该IDR帧前面的帧, 普通的I帧并没有阻断误差的积累,普通I帧后面的帧可以参考该I帧之前的帧. 在MPEG2中,I帧阻断了误差的积累,I帧后面的帧不可以参考该I帧之前的帧. 从这个意义上说,H.264中的IDR帧颇有MPEG2中I帧的味道.


I帧和IDR帧的区别
分类:H.264
2006-08-15 14:34
阅读(761)评论(0)
    看代码看得头昏脑胀,有时会上网搜索一些自己比较困扰的问题,觉得大家好强啊。其实,任何成功的人都是一步步走到今天的,小贝也是每日苦练才踢出著名香蕉球的啊。可是,我常想我会有这样的一天吗?……好奇妙的感觉,怀着80%的担心和20%的欣喜。算了,不要胡思乱想了。


    看一个问题:


I帧和IDR帧的区别:


    IDR帧属于I帧。解码器收到IDR frame 时,将所有的参考帧队列丢弃(用x264_reference_reset函数实现——在encoder.c文件中)。这点是所有I帧共有的特性,但是收到IDR帧时,解码器另外需要做的工作就是:把所有的PPS和SPS参数进行更新。由此可见,在编码器端,每发一个IDR,就相应地发一个 PPS&SPS_nal_unit


    这是网上搜索到的一个答案,有一定参考价值吧。


先说明:所有的IDR帧都是I帧,但是并不是所有I帧都是IDR帧。就是说,IDR帧是I帧的子集。(我们程序中设定的是每250帧出现一个IDR帧)


我们用的程序是这样的:


    /* ------------------- Setup frame context ----------------------------- */


    /* 5: Init data dependant of frame type */


    if( h->fenc->i_type == X264_TYPE_IDR )


    {


        /* reset ref pictures */


        x264_reference_reset( h );


        i_nal_type    = NAL_SLICE_IDR;


        i_nal_ref_idc = NAL_PRIORITY_HIGHEST;


        i_slice_type = SLICE_TYPE_I;


    }


    else if( h->fenc->i_type == X264_TYPE_I )


    {


        i_nal_type    = NAL_SLICE;


        i_nal_ref_idc = NAL_PRIORITY_HIGH; /* Not completely true but for now it is (as all I/P are kept as ref)*/


        i_slice_type = SLICE_TYPE_I;


    }


    else if( h->fenc->i_type == X264_TYPE_P )


    {


        i_nal_type    = NAL_SLICE;


        i_nal_ref_idc = NAL_PRIORITY_HIGH; /* Not completely true but for now it is (as all I/P are kept as ref)*/


        i_slice_type = SLICE_TYPE_P;


    }


    else if( h->fenc->i_type == X264_TYPE_BREF )


    {


        i_nal_type    = NAL_SLICE;


        i_nal_ref_idc = NAL_PRIORITY_HIGH; /* maybe add MMCO to forget it? -> low */


        i_slice_type = SLICE_TYPE_B;


    }


    else    /* B frame */


    {


        i_nal_type    = NAL_SLICE;


        i_nal_ref_idc = NAL_PRIORITY_DISPOSABLE;


        i_slice_type = SLICE_TYPE_B;


}


    x264_reference_reset函数的定义如下:(其实,因为这个代码是通用的,所以应该是参考帧队列。但是,我们只用一个参考帧,“队列”并没有意义。)


static inline void x264_reference_reset( x264_t *h )


{


    int i;


    /* reset ref pictures */


    for( i = 1; i < h->frames.i_max_dpb; i++ )


    {


        h->frames.reference[i]->i_poc = -1;


    }


    h->frames.reference[0]->i_poc = 0;


}


    看来,好像是遇到IDR帧时才会将所有的参考帧队列丢弃(x264_reference_reset( h );)。其实,我们的程序默认只用一个参考帧,这个问题就不是十分有意义了。


    多参考帧情况下。


    举个例子:有如下帧序列:IPPPPIPPPP……(我们程序没有B帧,所以帧序列简单些,但道理是一样的)。按照3个参考帧编码。


    因为“按照3个参考帧编码”,所以参考帧队列长度为3。


    遇到绿色的I时,并不清空参考帧队列,把这个I帧加入参考帧队列(当然I编码时不用参考帧。)。再检测到红色的P帧时,用到的就是PPI三帧做参考了。




    不怕自己罗嗦(好记性不如烂笔头),再强调一个:一个参考帧,就是参考当前帧的前面的那帧(因为没涉及到B帧,所以“前面的那帧”既是播放顺序的,也是编码顺序的)。多个参考帧是一个道理。(我以前一直误解为从前面的几帧中找到最合适的一个参考帧)


    最后,“但是收到IDR帧时,解码器另外需要做的工作就是:把所有的PPS和SPS参数进行更新。由此可见,在编码器端,每发一个IDR,就相应地发一个 PPS&SPS_nal_unit”应该是对的吧。先这样认为:)


偶然机会,查到:IDR-instantaneous decoding refresh (IDR)picture; 
      A coded picture in which all slices are I or SI slices that causes the decoding process to mark all reference pictures as "unused for reference" immediately after decoding the IDR picture. After the decoding of an IDR picture all following coded pictures in decoding order can be decoded without inter prediction from any picture decoded prior to the IDR picture. The first picture of each coded video sequence is an IDR picture. 
    “也就是说,IDR的出现其实是相当于向解码器发出了一个清理reference buffer的信号吧,上面说前于这一帧的所有已编码帧不能为inter做参考帧了。” 

还有:“因为264采用了多帧预测,就有可能在display order下I帧后的P会参考I帧前的帧,这样在random access时如果只找I帧,随后的帧的参考帧可能unavailable,IDR就是这样一种特殊的I帧,把它定义为确保后面的P一定不参考其前面的帧,可以放心地random access。 ”

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/383285.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

c++中的IO流(流的概念和流类库的结构,标准的输入输出流)

流的概念和流类库的结构 程序的输入指的是从输入文件将数据传送给程序&#xff0c;程序的输出指的是从程序将数据传送给输出文件 c输入输出包含以下三个方面的内容 对系统指定的标准设备的输入输出。即从键盘输入数据&#xff0c;输出到显示器屏幕&#xff0c;这种输入输出称…

MTD应用学习札记

今天做升级方案用到了mtd-utils中的flash_eraseall和flash_cp两个工具&#xff0c;在进行方案验证的时候&#xff0c;遭遇到各种不解和疑惑&#xff0c;因对MTD的原理不熟悉&#xff0c;所以只能多次尝试&#xff0c;虽然最后把方案搞定了&#xff0c;不过觉得MTD中的mtd和mtdb…

c++中的文件读写的操作

写文件 ofstreamopen指定打开方式isopen判断是否打开成功ifs<<“数据”ofs.close&#xff08;&#xff09; 读文件 ifstream ifs 指定打开方式ios::in isopen判断是否打开成功 读取有三种方式 #include<iostream>using namespace std;//文件读写头文件#incl…

udhcpc命令

由于要使用网络通讯&#xff0c;所以不可避免的要用到dhcp。理想的网络通讯方式是下面3种都要支持: 1,接入已有网络。这便要求可以作为dhcp客户端。 2,作为DHCP服务器&#xff0c;动态分配IP。 3,指定固定IP 第3种情况没有什么好说的&#xff0c;简单说下前2种情况。 使用步骤&…

c++的STL--1概念通述

STL的概念 什么是STL? STL(standard template libaray-标准模板库)&#xff1a;是C标准库的重要组成部分&#xff0c;不仅是一个可复用的组件库&#xff0c;而且 是一个包罗数据结构与算法的软件框架。 STL从广义上分为&#xff1a;容器(container)&#xff0c;算法(algorit…

socket通信和异常处理札记

Linux socket通信出现CLOSE_WAIT状态的原因与解决方法 这个问题之前没有怎么留意过&#xff0c;是最近在面试过程中遇到的一个问题&#xff0c;面了两家公司&#xff0c;两家公司竟然都面到到了这个问题&#xff0c;不得不使我开始关注这个问题。说起CLOSE_WAIT状态&#xff0c…

mac 下使用wireshark监听网络上的数据

分三个步骤&#xff1a; 1.wireshark安装 wireshark运行需要mac上安装X11&#xff0c;mac 10.8的系统上默认是没有X11的。先去http://xquartz.macosforge.org/landing/下载最新的 xquartz安装&#xff0c;安装好就有X11了。 wireshark的下载&#xff0c;网…

c++的vector容器

vector容器概念 vector是表示可变大小数组的序列容器。就像数组一样&#xff0c;vector也采用的连续存储空间来存储元素。也就是意味着可以采用下标对vector的元素 进行访问&#xff0c;和数组一样高效。但是又不像数组&#xff0c;它的大小是可以动态改变的&#xff0c;而且它…

嵌入式Linux下3G USB Modem的使用

busybox中需打开&#xff1a;wc&#xff0c;pidof&#xff1b; busybox中shell下打开getopts 百度搜索“Serial connection established. using channel 1”包含大量问题解答 2013-12-22 0个评论 收藏 我要投稿 一.ARM-Linux ARM-Linux-2.6.17 3G USB Modem:hu…

新一代数据库技术

新一代非关系型数据库有以下5个主要类型&#xff1a; 面向文件存储&#xff1a;适用于存储海量文件&#xff0c;代表产品MongoDb 列存储(wide column store/column-family)数据库&#xff1a;快速查找相关数据&#xff0c;相关数据被放在同一列中&#xff0c;代表产品Cassandra…

c++中stack容器

Stack 简介 stack 是堆栈容器&#xff0c;是一种“先进后出”的容器。stack 是简单地装饰 deque 容器而成为另外的一种容器。#include stack没有迭代器 Stack所有元素的进出都必须符合“先进后出”的条件&#xff0c;只有stack顶端的元素&#xff0c;才有机会被外界取用&am…

详解udev

如果你使用Linux比较长时间了&#xff0c;那你就知道&#xff0c;在对待设备文件这块&#xff0c;Linux改变了几次策略。在Linux早期&#xff0c;设备文件仅仅是是一些带有适当的属性集的普通文件&#xff0c;它由mknod命令创建&#xff0c;文件存放在/dev目录下。后来&#xf…

c++中的queue容器

queue容器 队列是一种容器适配器&#xff0c;专门用于在FIFO上下文(先进先出)中操作&#xff0c;其中从容器一端插入元素&#xff0c;另一端 提取元素。 队列作为容器适配器实现&#xff0c;容器适配器即将特定容器类封装作为其底层容器类&#xff0c;queue提供一组特定的 成员…

NAU8810相关问题

1.ADC和DAC有什么区别&#xff1f; 不&#xff0c;这不是一个“愚弄人的”问题或脑筋急转弯&#xff0c;并且我认为我们的读者都非常清楚模数转换器(ADC)及数模转换器(DAC)的基本功能。 但在如何使用这些转换器以及人们的认知度上也存在着哲理性区别。用最简单的话讲&#xff0…

c++中list容器

list概念 list是可以在常数范围内在任意位置进行插入和删除的序列式容器&#xff0c;并且该容器可以前后双向迭代。list的底层是双向链表结构&#xff0c;双向链表中每个元素存储在互不相关的独立节点中&#xff0c;在节点中通过指针指向 其前一个元素和后一个元素。list与for…

Linux中rc的含义

在Linux中&#xff0c;最为常用的缩略语也许是“rc”&#xff0c;它是“runcomm”的缩写――即名词“run command”(运行命令)的简写。rc”是任何脚本类文件的后缀&#xff0c;这些脚本通常在程序的启动阶段被调用&#xff0c;通常是Linux系统启动时。如/etc/rc&#xff08;连接…

c++中的set容器和multiset容器

set容器基本概念 set的特性是&#xff0c;所有元素都会根据元素的键值自动被排序。set的元素不像map那样可以同时拥有实值和键值&#xff0c;set的元素即是键值又是实值。set不允许两个元素又相同的键值。我们不可以通过set的迭代器改变set元素的值&#xff0c;因为set元素值就…

linux下的僵尸进程处理SIGCHLD信号

什么是僵尸进程&#xff1f; 首先内核会释放终止进程(调用了exit系统调用)所使用的所有存储区&#xff0c;关闭所有打开的文件等&#xff0c;但内核为每一个终止子进程保存了一定量的信息。这些信息至少包括进程ID&#xff0c;进程的终止状态&#xff0c;以及该进程使用的CPU时…

c++中的map容器

map/multimap基本概念 Map的特性是&#xff0c;所有元素都会根据元素的键值自动排序。Map所有的元素都是pair&#xff0c;同时拥有实值和键值&#xff0c;pair的第一元素被视为键值&#xff0c;第二元素被视为实值&#xff0c;map不允许两个元素有相同的键值我们可以通过map的…

mknod指令详解

mknod - make block or character special files mknod [OPTION]... NAME TYPE [MAJOR MINOR] option 有用的就是 -m 了 name 自定义 type 有 b 和 c 还有 p 主设备号 次设备号 主设备号是由linux/major.h定义的&#xff0c;如下定义了一个DOC设备&am…