H.264---(I、P、B幀)(I幀和IDR幀)(DTS和PTS、time_base)


1、I、P、B幀

1.1 I幀

I幀表示關鍵幀,你可以理解為這一幀畫面的完整保留;解碼時只需要本幀數據就可以完成(因為包含完整畫面)

1.2 P幀

P幀表示的是這一幀跟之前的一個關鍵幀(或P幀)的差別,解碼時需要用之前緩存的畫面疊加上本幀定義的差別,生成最終畫面。(也就是差別幀,P幀沒有完整畫面數據,只有與前一幀的畫面差別的數據)

1.3 B幀

B幀是雙向差別幀,也就是B幀記錄的是本幀與前后幀的差別(具體比較復雜,有4種情況),換言之,要解碼B幀,不僅要取得之前的緩存畫面,還要解碼之后的畫面,通過前后畫面的與本幀數據的疊加取得最終的畫面。B幀壓縮率高,但是解碼時CPU會比較累~。

1.4 I P B幀編碼順序(解碼順序)與顯示順序

轉自http://blog.sina.com.cn/s/blog_7ebe66420101tt38.html

僅僅使用前一個顯示的基准幀來編碼的幀被稱為“P幀”,同時使用前一個顯示幀和未來幀作為基准幀進行編碼的幀稱為“B幀”。在通常的場景中,編解碼器編碼一個I幀,然后向前跳過幾個幀,用編碼I幀作為基准幀對一個未來P幀進行編碼,然后跳回到I幀之后的下一個幀。編碼的I幀和P幀之間的幀被編碼為B幀。之后,編碼器會再次跳過幾個幀,使用第一個P幀作為基准幀編碼另外一個P幀,然后再次跳回,用B幀填充顯示序列中的空隙。這個過程不斷繼續,每12到15個P幀和B幀內插入一個新的I幀。例如,圖1種給出了一個典型的視頻幀序列。

通常,更換場景后的第一幀就是I幀,I幀應當全幀傳送。從壓縮的程度來看,I畫面的壓縮量最少;P畫面次之,它是以I畫面為基礎;B畫面壓縮最多。為了加大壓縮比,通常在I幀后面相隔2幀(最多3幀)設置1個P幀,在I、P幀之間都是B幀,在兩個P幀之間也是設置2~3幀B幀。B幀傳送它與I幀或P幀之間的差值信息,或者P幀與后面P幀或I幀之間的差值信息,或者它與前后I、P幀或P、P幀平均值之間的差值信息。當主體內容變化愈大時,兩個I畫面之間的幀數值越小;當主體內容變化小時,I面畫的間隔可以適當大一些。或者說,B幀、P幀所占比例越大,圖像壓縮比越高。一般兩個I畫面相隔13~15幀,相隔幀數不宜再多。

下面以15幀為例,說明VCD圖像幀的排列順序。I、P、B三種畫面的典型設置方式,對NTSC制共約需半秒時間。節目輸入順序是按實際出現順序排列的,即I、B、B、P、B、B、P、B、B……I、B、B、P……;但為了解碼時便於從I、P畫面插補得到B畫面,在編碼錄制節目時,將順序改變了,即按照I、P、B、B……順序,即改為按原來0、3、1、2、6、4、5、9、7、8…的畫面順序。解碼時先解出0幀、3幀,再由其插補預測計算得出1幀、2幀等等。為此,須在解碼器內設置動態存儲器,將I、P幀先解碼並存儲,再計算出各個B幀。不過最后輸出時,還是應當按照實際播放順序重組讀出,按正確順序輸出。

I B B P B B P…B B I    I P B B P B B … I B B
1 2 3 4 5 6 7 …        1 4 2 3 7 5 6 …
  (a) 顯示順序          (b) 編解碼順序
                  圖 1
        在此有兩個問題需要說明:首先是插多少B 幀最合適?理論上說I、P之間插入的B幀越多,壓縮比越高,但是編解碼器所需的幀存儲器也越大,因此實際應用中一般最多兩個。其次,B幀的引入會增加編解碼端的延遲,如果追求網絡監視的時延,最好是不使用B幀。

 

2、I幀和IDR幀

轉自https://blog.csdn.net/heanyu/article/details/6255111

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圖像之間的圖像做運動參考。一個序列中可以有很多的I圖像,I圖像之后的圖象可以引用I圖像之間的圖像做運動參考。
      對於IDR幀來說,在IDR幀之后的所有幀都不能引用任何IDR幀之前的幀的內容,與此相反,對於普通的I-幀來說,位於其之后的B-和P-幀可以引用位於普通I-幀之前的I-幀。從隨機存取的視頻流中,播放器永遠可以從一個IDR幀播放,因為在它之后沒有任何幀引用之前的幀。但是,不能在一個沒有IDR幀的視頻中從任意點開始播放,因為后面的幀總是會引用前面的幀。

 

 

3、DTS和PTS、time_base

轉自https://blog.csdn.net/bixinwei22/article/details/78770090

PTS:Presentation Time Stamp。PTS主要用於度量解碼后的視頻幀什么時候被顯示出來
DTS:Decode Time Stamp。DTS主要是標識讀入內存中的bit流在什么時候開始送入解碼器中進行解碼

也就是pts反映幀什么時候開始顯示,dts反映數據流什么時候開始解碼

怎么理解這里的“什么時候”呢?如果有某一幀,假設它是第10秒開始顯示。那么它的pts是多少呢。是10?還是10s?還是兩者都不是。

為了回答這個問題,先引入FFmpeg中時間基的概念,也就是time_base。它也是用來度量時間的。
如果把1秒分為25等份,你可以理解就是一把尺,那么每一格表示的就是1/25秒。此時的time_base={1,25}
如果你是把1秒分成90000份,每一個刻度就是1/90000秒,此時的time_base={1,90000}。
所謂時間基表示的就是每個刻度是多少秒
pts的值就是占多少個時間刻度(占多少個格子)。它的單位不是秒,而是時間刻度。只有pts加上time_base兩者同時在一起,才能表達出時間是多少。
好比我只告訴你,某物體的長度占某一把尺上的20個刻度。但是我不告訴你,這把尺總共是多少厘米的,你就沒辦法計算每個刻度是多少厘米,你也就無法知道物體的長度。
pts=20個刻度
time_base={1,10} 每一個刻度是1/10厘米
所以物體的長度=pts*time_base=20*1/10 厘米

在ffmpeg中。av_q2d(time_base)=每個刻度是多少秒
此時你應該不難理解 pts*av_q2d(time_base)才是幀的顯示時間戳。

下面理解時間基的轉換,為什么要有時間基轉換。
首先,不同的封裝格式,timebase是不一樣的。另外,整個轉碼過程,不同的數據狀態對應的時間基也不一致。拿mpegts封裝格式25fps來說(只說視頻,音頻大致一樣,但也略有不同)。非壓縮時候的數據(即YUV或者其它),在ffmpeg中對應的結構體為AVFrame,它的時間基為AVCodecContext 的time_base ,AVRational{1,25}。
壓縮后的數據(對應的結構體為AVPacket)對應的時間基為AVStream的time_base,AVRational{1,90000}。
因為數據狀態不同,時間基不一樣,所以我們必須轉換,在1/25時間刻度下占10格,在1/90000下是占多少格。這就是pts的轉換。

根據pts來計算一楨在整個視頻中的時間位置:
timestamp(秒) = pts * av_q2d(st->time_base)

duration和pts單位一樣,duration表示當前幀的持續時間占多少格。或者理解是兩幀的間隔時間是占多少格。一定要理解單位。
pts:格子數
av_q2d(st->time_base): 秒/格

計算視頻長度:
time(秒) = st->duration * av_q2d(st->time_base)

ffmpeg內部的時間與標准的時間轉換方法:
ffmpeg內部的時間戳 = AV_TIME_BASE * time(秒)
AV_TIME_BASE_Q=1/AV_TIME_BASE

av_rescale_q(int64_t a, AVRational bq, AVRational cq)函數
這個函數的作用是計算a*bq / cq來把時間戳從一個時間基調整到另外一個時間基。在進行時間基轉換的時候,應該首先這個函數,因為它可以避免溢出的情況發生。
函數表示在bq下的占a個格子,在cq下是多少。

關於音頻pts的計算:
音頻sample_rate:samples per second,即采樣率,表示每秒采集多少采樣點。
比如44100HZ,就是一秒采集44100個sample.
即每個sample的時間是1/44100秒

一個音頻幀的AVFrame有nb_samples個sample,所以一個AVFrame耗時是nb_samples*(1/44100)秒
即標准時間下duration_s=nb_samples*(1/44100)秒,
轉換成AVStream時間基下
duration=duration_s / av_q2d(st->time_base)
基於st->time_base的num值一般等於采樣率,所以duration=nb_samples.
pts=n*duration=n*nb_samples

補充:
next_pts-current_pts=current_duration,根據數學等差公式an=a1+(n-1)*d可得pts=n*d



免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM