《H.264/AVC視訊編解碼技術詳解》視訊教程已經在“CSDN學院”上線,視訊中詳述了H.264的背景、標準協議和實現,並通過一個實戰工程的形式對H.264的標準進行解析和實現,歡迎觀看!

“紙上得來終覺淺,絕知此事要躬行”,只有自己按照標準文件以程式碼的形式操作一遍,才能對視訊壓縮編碼標準的思想和方法有足夠深刻的理解和體會!

連結地址:H.264/AVC視訊編解碼技術詳解

GitHub程式碼地址:點選這裡

在本系列的博文18中,我們討論了算術編碼的基本原理,以及實現一個簡單的算術編碼器核心的方法:

而在博文19和21中我們根據H.264對於CABAC的規定,討論了語法元素二值化以及上下文概率模型的相關演算法:

通過前面的研究我們已經瞭解,由於視訊資料特殊的統計特性和對編碼效能的高指標要求,CABAC的演算法遠遠比博文18中描述的基本模型更加複雜。儘管如此,CABAC在算術編碼的最核心層面依然遵循了博文18中所講的根本原理,這一點在本文對標準協議文件的解讀中也可以獲得明確的證實。

一、CABAC解析(解碼)的總流程

CABAC的解碼過程定義與標準協議文件的9.3.3.2節。CABAC解碼過程所需要的輸入資料包括前一章所推匯出的上下文模型索引ctxIdx、旁路模式標誌bypassFlag,以及解碼器引擎的狀態。下圖表示了CABAC解碼過程的概念框圖:

在上圖中可以看出,根據引數的不同,CABAC解碼總共可能有三種執行流程:

  • DecodeBypass: 當旁路模式標誌bypassFlag為1時執行,表示旁路模式的解析過程;
  • DecodeDecision: 當bypassFlag為0且ctxIdx不為276時執行,表示CABAC解析過程;
  • DecodeTerminate: 當bypassFlag為0且ctxIdx==276時執行,表示解析終結碼的過程;

在這三種執行流程中最重要的就是第二種——DecodeDecision。接下來本文將從DecodeDecision開始分析這三種解析過程。

二、CABAC算術編碼的解碼(解析)過程

本節描述的即是DecodeDecision部分的方法。這一部分也是CABAC演算法中最為重要的部分,H.264的main、high profile中的多數語法元素都是通過該過程進行解析的。該部分在標準協議文件的9.3.3.2.1中定義。

從標準協議中的該節內容中可知,該過程所需要的資料有ctxIdx, codIRange 和 codIOffset,其中ctxIdx由前一章《CABAC的上下文概率模型》中的方法推導,codIRange 和 codIOffset的初始值由CABAC解碼器引擎的初始化確定。輸出的資料包括解析出來的語法元素位元位值binVal,以及更新過的codIRange 和 codIOffset。

該過程的整體流程如下圖所示:

2.1 計算 codIRangeLPS

計算 codIRangeLPS 的過程遵循以下流程:

  1. 根據當前的codIRange值,計算qCodIRangeIdx的值:
    • qCodIRangeIdx =( codIRange >> 6 ) & 3
  2. 通過 qCodIRangeIdx 和 pStateIdx,計算 codIRangeLPS 的值:
    • 通過查表獲取:codIRangeLPS = rangeTabLPS[ pStateIdx ][ qCodIRangeIdx ]
    • rangeTabLPS為預定義的表,在表9-44中指定;

2.2 更新 codIRange

更新 codIRange 的方法為:

codIRange = codIRange - codIRangeLPS;

更新完成後,判斷 codIOffset,如果 codIOffset >= codIRange,輸出位元位值binVal賦值為1 - valMPS,並且codIOffset自減去codIRange的值,然後codIRange的值賦值為codIRangeLPS;否則,輸出位元位值binVal賦值為valMPS。

2.3 狀態轉移過程

在CABAC編碼或解碼語法元素的某一個bit,編碼/解碼器將隨之更新編解碼器的狀態。狀態轉移過程定義於標準的9.3.3.2.1.1節。該過程根據當前的上下文模型索引和解碼的位元值,來更新上下文模型索引以及LPS/MPS的定義。

狀態轉移過程可以下式表示:

if( binVal = = valMPS )
    pStateIdx = transIdxMPS( pStateIdx )
else {
    if( pStateIdx = = 0 ) {
        valMPS = 1 − valMPS   
    }
    pStateIdx = transIdxLPS( pStateIdx )
}

在編碼過程中上下文模型索引的更新同樣以查表的形式實現,該表格在9-45中規定。

2.4 歸一化過程

在第18篇博文“算術編碼的基本原理中”已經討論過算術編碼器的歸一化。在H.264實際定義的CABAC演算法中,歸一化同樣也是必備過程。CABAC的歸一化過程定義於9.3.3.2.2節,流程圖以下圖表示:

進行歸一化的本質含義是更新codIRange和codIOffset的值,所需要的資料包括當前CABAC的codIRange和codIOffset以及當前的二進位制位元流資料。主要步驟為:

  • 判斷如果codIRange不小於256,那麼不需要進行歸一化;
  • 如果codIRange小於256,則進行歸一化過程,方法為:
    1. codIRange和codIOffset分別自乘以2;
    2. 在碼流中讀取 1 bit,並與codIOffset按位取或運算並更新到codIOffset;

三、CABAC的bypass解析方法

本節描述的是CABAC的DecodeBypass方法,即旁路解析模式,在bypass值設為1時執行。DecodeBypass相比DecodeDecision方法的特點是編碼效率較低但運算遠比DecodeDecision簡單。與DecodeDecision過程相比,DecodeBypass不需要ctxIdx,只需要codIRange和codIOffset兩個值。

DecodeBypass過程的流程圖如下:

解析過程為:

  1. 首先codIOffset自增一倍,並且從碼流中讀取1 bit與之求按位或操作;
  2. codIOffset與codIRange對比:
    • 若codIOffset小於codIRange,輸出二進位制位0;
    • 否則,輸出二進位制位1,且codIOffset自減去codIRange的值;

四、CABAC的終止符解析

CABAC的終止符解析即DecodeTerminate過程,主要用於解析end_of_slice和ctxIdx值為276的元素。解析的方法類似於DecodeBypass過程,流程如下:

  1. 首先codIOffset自減2;
  2. codIOffset與codIRange對比:
    • 若codIOffset小於codIRange,輸出二進位制位0,並執行解碼器的歸一化過程;
    • 否則,輸出二進位制位1;