現在明白為什麼無名飛控的STM32工程裡面有個DSP檔案夾了
位元速率顯示不准問題的解決方法
FPS是影象領域中的定義,是指畫面每秒傳輸幀數,通俗來講就是指動畫或視訊的畫面數。FPS是測量用於儲存、顯示動態視訊的資訊數量。每秒鐘幀數越多,所顯示的動作就會越流暢。
視訊位元速率就是資料傳輸時單位時間傳送的資料位數,一般我們用的單位是kbps即千位每秒。通俗一點的理解就是取樣率,單位時間內取樣率越大,精度就越高,處理出來的檔案就越接近原始檔案。
1.1 逐行掃描
逐行掃描應用廣泛,在我們目前的各類電腦顯示屏、外接的顯示器上,使用的都是逐行掃描。逐行掃描非常易於理解,它就是在光柵影象下,從影象的第一行順序掃描到最後一行,也即下圖:
原始影象(左) 和 逐行掃描幀(右)
逐行掃描的結果,就是產生完整的一幀影象,因此它進行的通常是幀編碼。逐行掃描雖然現在應用廣泛,但是在最初電視機剛剛興起,還沒有電腦的時代,逐行掃描確實是不實用的。主要有以下兩點原因:
- (1)逐行掃描產生的完整的一幀影象,佔據的電視訊號的頻寬較大
- (2)在【彩色電視制】中我們知道,PAL制的幀頻為25幀每秒,NTSC的為30幀每秒。在這種情況下,如果採用逐行掃描的方式,人眼是會察覺到閃爍的。
因此聰明的人們想到,可以將一幀影象先掃描奇數場顯示在螢幕上,然後再掃描偶數場。這樣在相同的時間內,PAL制每秒可顯示50場,NTSC可顯示60場,這樣既降低了頻寬,又解決了閃爍的問題,隔行掃描也就這樣產生了。
1.2 隔行掃描
就像剛才說的那樣,隔行掃描是先掃描奇數場,然後掃描偶數場,也即頂場和底場。如下圖:
隔行掃描的經典之處,就在這個先後上!
可以想象,當從第1行隔行掃到15行,掃描完頂場後,又重頭開始掃底場,也即回到第2行開始掃,這中間是有個時間差的。這個時間差,如果站在攝像機採集影象的立場來理解,那麼就是接下來理解隔行掃描下的視訊編碼方式的關鍵。
上面我們說,逐行掃描一般進行的是幀編碼,而隔行掃描,則可以在幀編碼和場編碼之間做選擇,那選擇的依據是什麼呢?接著往下看。
2、幀編碼和場編碼
現在我們就要回到,攝像機採集影象到編碼器的階段了。我們已經知道,攝像機採集影象的掃描方式有兩種,但是因為隔行掃描的出現,它們的編碼方式卻不只兩種。我們先來介紹最容易想到的情況,那就是針對一部視訊,全部使用幀編碼或全部使用場編碼。
一般而言,對逐行掃描的視訊全部進行幀編碼。對隔行掃描的視訊,就要選擇是使用幀編碼還是場編碼,注意這裡是只選擇一次,然後整個視訊序列都採用幀編碼或場編碼。如果隔行掃描採用幀編碼,則是將頂場和底場合為一幀進行編碼。
此時對於幀編碼,在做幀間預測時,參考影象為幀影象,運動補償也為幀運動補償。對於場編碼,則是兩個場分別進行編碼,在做幀間預測時,參考影象為場影象,運動補償也為場運動補償。
以目前二者應用的場合來看:
幀編碼應用廣泛,因為目前我們無論在手機端錄的視訊、還是在電腦端、顯示器上播放的視訊,基本都是逐行掃描。因此在我們這個系列教程裡,很有可能並不會涉及到場編碼。
由隔行掃描引出的場編碼,多應用在電視業,所以對於從事網際網路的人士來說,幾乎碰不到場編碼的情況。
不過即使如此,我們還是要繼續介紹一下隔行掃描的編碼方式,因為這樣便於我們接下來理解H264中的幾個重要的句法元素。這裡我們介紹隔行掃描的前提,是整個視訊序列只採用一種編碼方式。
事實上,在整個視訊編碼中,編碼方式的選擇可以更靈活,這從我們上篇解析到的片層Slice_Header的field_pic_flag和bottom_field_flag就可以體會到。
3、 PAFF和MBAFF
【注】(Picture adaptive field-frame 和 Macro-block adaptive field-frame)
第2小節中,我們說的是整個視訊序列只採用一種編碼方式。但實際上對於隔行掃描的視訊,我們還可以更靈活,通常可以分為以下三種編碼方式:
- (1)將兩個場合為一幀進行幀編碼
- (2)兩個場分別進行場編碼
- (3)將兩個場合為一幀,但是在巨集塊級別上,兩個上下相鄰的場巨集塊組合成一個巨集塊對(MB pair,MBP),這種編碼方式也稱巨集塊級的幀場自適應,也即MBAFF,這是H264引入的一個新的編碼特性。
其中前兩點,不同於第2節的是,第1點和第2點是可以進行自適應切換的。也即在一個視訊序列中,通過對編碼效果的不同,選擇是使用幀編碼還是場編碼,因此這種方式也稱影象級的幀場自適應(PAFF)。
這就是PAFF和MBAFF,下面我們更加細緻一點來說明,為什麼有了PAFF還需要MBAFF。
3.1 使用PAFF進行編碼
在隔行掃描中,一個視訊序列的運動影象部分,和非運動影象部分的編碼,區別是很大的。
在開始時我們就說過,攝像機在進行隔行掃描時,頂場和底場的掃描時間上,是有一個時間差的。這個時間差是什麼呢?就是當攝像機掃描完頂場的最後一行後,又回過頭來掃描底場的第一行。
這樣就導致,如果將頂場和底場合為一幀,那麼頂場的第一行和底場的第一行就變成了相鄰行,而實際上相鄰行的掃描時間,整整差了一個場的掃描時間。
這對於非運動影象沒什麼,但是對於一個正在運動的影象而言,會導致合為一幀後,相鄰兩行的空間相關性比較低。所以對於運動的影象,兩個場分別進行編碼,相對合為一幀來編碼更加節省碼流。
對於非運動影象,兩個場合為一幀後,空間相關性也很大,因此合為一幀進行幀編碼更加節省碼流。
這就是PAFF的工作方式,它會根據編碼效果,調整整個影象的編碼方式。
但這同時也變成了它的缺點,因為調整整個影象的編碼方式,是個粒度非常粗的工作方式。對於視訊序列而言,可能某些影象,同時存在運動區域和非運動區域,這時PAFF的缺點就很明顯了,對這些影象使用幀編碼或場編碼似乎都不恰當,這時MBAFF就產生了。
3.2 使用MBAFF進行編碼
MBAFF將兩個場合為一幀,但是在巨集塊級別上,使用巨集塊對(MBAFF)為基本編碼單元。這樣在影象的運動區域,採用場編碼,對於非運動區域,採用幀編碼,比較兩種方式產生的碼流大小,就能在巨集塊級別選擇更節省碼流的編碼方式。
4、H264中的幀場編碼模式
前面三節,都是為這一節做鋪墊。我們已經知道了,編碼方式有幀編碼、場編碼、影象級的幀場自適應編碼和巨集塊級的幀場自適應編碼,看起來真的挺麻煩,那是因為我們沒確定我們的立場。
當我們把立場放在Slice上,一個Slice的編碼方式就只有三種:幀編碼、場編碼或MBAFF。
這就需要用到幾個句法元素,分別為:SPS中的frame_mbs_only_flag
和mb_adaptive_frame_field_flag
,Slice_Header中的field_pic_flag
和bottom_field_flag
。具體流程如下:
H264幀場編碼模式判斷
判斷出當前Slice的編碼方式後,如果是巨集塊級的幀場自適應,通常用欄位MbaffFrameFlag
等於1來表示,這也是我們在理解Slice_Header中first_mb_in_slice的語義時需要用到的欄位。