天天看點

HEVC變換編碼實作代碼詳解

作者:66

有關變換子產品

    先推薦一個特别好的部落客,可以參考他分析的HEVC,收獲頗豐,感謝前輩。

     推薦連結:http://blog.csdn.net/HEVC_CJL/article/category/1283611/3

    經預測後的殘差資料,在空域上是存在大量備援的,包含較多的平坦區域和内容變化緩慢的區域,相鄰的相近像素差距很小,經适當的變換,可以将空域的分散分布轉換到頻域的集中分布。再結合Z掃描、熵編碼等可以進行有效壓縮。

  變換到頻域的方法有許多種,DCT變換形式與輸入信号無關且存在快速實作算法,另外DCT可以将能量集中到左上角(之前看理論時從網上知道的,不明白緣由,有時間研究一下傅裡葉變換在圖形處理方面的基礎)。

在H.265中,為了适應不同預測方式下的殘差分布情況,還引入了離散餘弦變換DST。

理論部分直接網上搜尋DCT原理及特點,涉及到較多的數字信号處理内容,這裡不作贅述。

DCT的實作:

不管是h.264或h.265中,都為了提高變換速度,避免實數運算,對DCT進行了調整。h.264中,将DCT陣中調整為1、2,計算過程中僅需要加法、移位等操作。為近似為1、2所損失的精度較高(相對于h.265)。

h.265中,将DCT矩陣中的元素全部放大了64√N倍(N為變換塊大小),放大後為了保持正交性作了微量調整。先看一下h.265下的DCT變換矩陣,有4、8、16、32大小的,這裡放下4和8大小的。

const Short g_aiT4[4][4] =

{

  { 64, 64, 64, 64},

  { 83, 36,-36,-83},

  { 64,-64,-64, 64},

  { 36,-83, 83,-36}

};

const Short g_aiT8[8][8] =

{

  { 64, 64, 64, 64, 64, 64, 64, 64},

  { 89, 75, 50, 18,-18,-50,-75,-89},

  { 83, 36,-36,-83,-83,-36, 36, 83},

  { 75,-18,-89,-50, 50, 89, 18,-75},

  { 64,-64,-64, 64, 64,-64,-64, 64},

  { 50,-89, 18, 75,-75,-18, 89,-50},

  { 36,-83, 83,-36,-36, 83,-83, 36},

  { 18,-50, 75,-89, 89,-75, 50,-18}

};

這裡變換陣是有特點的,奇數行偶對稱,偶數行奇對稱。另外,8x8陣中的0、2、4、6行前四個元素組成了4x4矩陣。是以設計有統一形式的DCT蝶形算法。

整數DCT公式:

HEVC變換編碼實作代碼詳解

正常兩個4x4矩陣相乘,需要64次乘法,但DCT矩陣中對稱,每行中有一半的乘法是重複計算的,蝶形就是将他們去掉,另外代碼中計算用到了簡單的轉置,在此稍作提示:

HEVC變換編碼實作代碼詳解

整數DST公式:

僅适用于4x4變換塊

HEVC變換編碼實作代碼詳解

其中DST矩陣為:

DST矩陣如下

{ 29, 55, 74, 84

  74, 74,  0,-74

  84,-29,-74, 55

  55,-84, 74,-29}

//注意其中29 + 55 = 84,下面代碼計算過程中用到了這點。

DCT變換(16x16與32x32就不貼了,類似的):

/** 4x4 forward transform implemented using partial butterfly structure (1D)

 *  \param src   input data (residual)

 *  \param dst   output data (transform coefficients)

 *  \param shift specifies right shift after 1D transform

 */

 

void partialButterfly4(Short *src,Short *dst,Int shift, Int line)

{

  Int j;

  Int E[2],O[2];

  Int add = 1<<(shift-1);

 

  for (j=0; j<line; j++)//利用變換陣偶數行奇對稱,奇數行偶對稱的特性,将對稱部分的兩次乘合并為一次。乘法降低一半

  {    

    /* E and O */

    E[0] = src[0] + src[3];

    O[0] = src[0] - src[3];

    E[1] = src[1] + src[2];

    O[1] = src[1] - src[2];

 

    dst[0] = (g_aiT4[0][0]*E[0] + g_aiT4[0][1]*E[1] + add)>>shift;

    dst[2*line] = (g_aiT4[2][0]*E[0] + g_aiT4[2][1]*E[1] + add)>>shift;

    dst[line] = (g_aiT4[1][0]*O[0] + g_aiT4[1][1]*O[1] + add)>>shift;

    dst[3*line] = (g_aiT4[3][0]*O[0] + g_aiT4[3][1]*O[1] + add)>>shift;

 

    src += 4;//此時src按轉置陣參與計算,本為g_aiT4行乘src的列,這裡寫的是g_aiT4的行乘src的行

    dst ++;

  }

}

//8x8

void partialButterfly8(Short *src,Short *dst,Int shift, Int line)

{

  Int j,k;

  Int E[4],O[4];

  Int EE[2],EO[2];

  Int add = 1<<(shift-1);

 

  for (j=0; j<line; j++)

  {  

    /* E and O*/

    for (k=0;k<4;k++)

    {

      E[k] = src[k] + src[7-k];

      O[k] = src[k] - src[7-k];

    }    

    /* EE and EO */

    EE[0] = E[0] + E[3];//類似4x4    

    EO[0] = E[0] - E[3];

    EE[1] = E[1] + E[2];

    EO[1] = E[1] - E[2];

 

    dst[0] = (g_aiT8[0][0]*EE[0] + g_aiT8[0][1]*EE[1] + add)>>shift;

    dst[4*line] = (g_aiT8[4][0]*EE[0] + g_aiT8[4][1]*EE[1] + add)>>shift;

    dst[2*line] = (g_aiT8[2][0]*EO[0] + g_aiT8[2][1]*EO[1] + add)>>shift;

    dst[6*line] = (g_aiT8[6][0]*EO[0] + g_aiT8[6][1]*EO[1] + add)>>shift;

 

    dst[line] = (g_aiT8[1][0]*O[0] + g_aiT8[1][1]*O[1] + g_aiT8[1][2]*O[2] + g_aiT8[1][3]*O[3] + add)>>shift;

    dst[3*line] = (g_aiT8[3][0]*O[0] + g_aiT8[3][1]*O[1] + g_aiT8[3][2]*O[2] + g_aiT8[3][3]*O[3] + add)>>shift;

    dst[5*line] = (g_aiT8[5][0]*O[0] + g_aiT8[5][1]*O[1] + g_aiT8[5][2]*O[2] + g_aiT8[5][3]*O[3] + add)>>shift;

    dst[7*line] = (g_aiT8[7][0]*O[0] + g_aiT8[7][1]*O[1] + g_aiT8[7][2]*O[2] + g_aiT8[7][3]*O[3] + add)>>shift;

 

    src += 8;

    dst ++;

  }

}

 
           

DST變換:

// Fast DST Algorithm. Full matrix multiplication for DST and Fast DST algorithm

// give identical results

//DST矩陣如下

//{ 29, 55, 74, 84

//  74, 74,  0,-74

//  84,-29,-74, 55

//  55,-84, 74,-29}

//注意其中29 + 55 = 84,下面代碼計算過程中利用了這點

void fastForwardDst(Short *block,Short *coeff,Int shift)  // input block, output coeff

{

  Int i, c[4];

  Int rnd_factor = 1<<(shift-1);

  for (i=0; i<4; i++)

  {

    // Intermediate Variables

    c[0] = block[4*i+0] + block[4*i+3];

    c[1] = block[4*i+1] + block[4*i+3];

    c[2] = block[4*i+0] - block[4*i+1];

    c[3] = 74* block[4*i+2];

 

    coeff[   i] =  ( 29 * c[0] + 55 * c[1]         + c[3]               + rnd_factor ) >> shift;

    coeff[ 4+i] =  ( 74 * (block[4*i+0]+ block[4*i+1] - block[4*i+3])   + rnd_factor ) >> shift;

    coeff[ 8+i] =  ( 29 * c[2] + 55 * c[0]         - c[3]               + rnd_factor ) >> shift;

    coeff[12+i] =  ( 55 * c[2] - 29 * c[1]         + c[3]               + rnd_factor ) >> shift;

  }

}
           

(轉載請注明出處)

繼續閱讀