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.pswp.cn/news/383285.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/383285.shtml
英文地址,請注明出處:http://en.pswp.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…