1. 程式人生 > >如何從JM8.6的編碼端和解碼端提取濾波前的畫素值?

如何從JM8.6的編碼端和解碼端提取濾波前的畫素值?

        先來看看H.264編碼器和解碼器的示意圖:

 

    

         在H.264的編碼端和解碼端都會有一幀影象的濾波前的畫素值,而且必然是相等的. 與濾波前的畫素值對應的一個概念是濾波後的畫素值,濾波後的畫素值又叫做重建值. 值得一提的是:H.264幀內預測的參考幀是濾波前的,而幀間預測的參考幀是濾波後的, 至於為什麼,之前的博文中也早就討論過, 在此就不再細說.

 

        在程式中,要找到某個量,一般的方法有兩個.其一:看變數是從何而來;其二:看變數何去何從. 打個非常簡單的比方,有一個壞人要從A地到B地作案,警察既可以在壞人剛出A門時將其抓獲,也可以在壞人剛到B門是將其抓獲, 警察也要斟酌,到底是在A處好還是在B處好呢?

       根據該思路,我們分析一下,濾波前的指從何而來?這個很好確定,就是max(0, min(殘差 + 預測值, 255)), 所以在這個地方必定可以守株待兔地抓到濾波前值. 當然我們也可以看看,濾波前值將何去何從,濾波前值的下一步步驟當然是要進行濾波操作啊, 所以在濾波之前也可以守株待兔地抓到濾波前值. 那麼,在哪一處下手比較好呢?前者也可以,後者也可以,只不過前者處畫素值沒有儲存成矩陣(陣列)的形式,而後者處已經儲存成了矩陣(陣列)的形式,所以,在後者處下手比較方便.

       下面先在JM8.6的編碼端提取濾波前值: (編碼端的濾波前值和解碼端的濾波前值必定完全一樣)

       觀察一下lencod工程中的檔名,發現了loopFilter.c, 就是這個了. 進入其中,發了好幾個重要的函式,大致看看即可. 發現了其中有DeblockFrame函式,函式的名稱真的很重要啊,見名知意. 其中的imgY就表徵了一幀的亮度,對於176*144的qcif視訊來說,最右下角的那個畫素對應的濾波前值是imgY[143][175], 其餘位置,依次類推, 便不多說. 用H.264visa讀取碼流,可以看到看到濾波前值,對比後發現,兩處的結果完全一致.

void DeblockFrame(ImageParameters *img, byte **imgY, byte ***imgUV)
{
  unsigned i;

  for (i=0; i<img->PicSizeInMbs; i++)
  {
    DeblockMb( img, imgY, imgUV, i ) ;
  }
}

       接著在JM8.6的解碼端來提取濾波前值,同上,在ldecod工程中找到了loopFilter.c, 發現了DeblockPicture函式,其中的p->imgY正是濾波前值,對於176*144的qcif視訊來說,最右下角的那個畫素對應的濾波前值是imgY[143][175], 其餘位置,依次類推, 便不多說. 用H.264visa讀取碼流,可以看到看到濾波前值,對比後發現,兩處的結果完全一致.

void DeblockPicture(ImageParameters *img, StorablePicture *p)
{
  unsigned i;

  for (i=0; i<p->PicSizeInMbs; i++)
  {
    DeblockMb( img, p, i ) ;
  }
} 

       JM8.6編碼端和解碼端得到的濾波前值高度一致,都等於H.264visa顯示的濾波前值.