先来看看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显示的滤波前值.