本周的学习是从解码器开始的,临时去分析了JM的DCT,并发了一篇说明蝶形算法的文章。以前看JM代码的时候,这个部分一直掠过,因为书上和网络上都没有说得很清楚,一个忽然而来的念头决定搞清楚这问题。翻书把信号处理处理的相FFT蝶形算法关知识复习了一遍,依然觉得不得要领,然后再看推导过程,再翻阅代码,终于有所领悟,于是都写在前一篇文章(H.264整数DCT公式推导和蝶形图分析)当中了。顺便看了DCT在JMVC的相关代码,在Transform.cpp文件中,这里实现的依然是基于蝶形算法的FDCT。
回到JMVC解码器的问题,其参考代码可以从H264AVCEncoderLibTestStaticd.exe进行测试,解码不需要配置文件,运行的方式已经在软件说明书写清楚了:
H264AVCDecoderLibTestStatic <str> <rec> <numViews>
str: bitstream file (input)
rec: reconstructed video sequence (output)
numViews: number of view in bitstream
|
从解码器入手的目的是可以对照标准协议对照具体的解码过程,在进入细节之前,对全局的过程有所了解。解码器的输入的是用MVCBitStreamAssemblerStaticd.exe编过的合成流,或viewId = 0的这个单视点流(纯AVC流)。rec最好写成*.yuv的文件,否则可能会造成错误,我的实验主要是基于ballroom的640x480码流,使用前三个视点。
解码部分在协议中比较引人注意的是参考帧重排和关于序列子集的处理,此外,在代码中的错误隐藏也是很有趣的课题。
1. 在参考帧重排方面,按标准文档,增加了“Reference picture list MVC modification syntax”,这个实际上就是以前我们经常听到的参考帧重排的扩展。
根据以上的hierarchical B结构图,这里的参考帧构成除了Inter,还有inter-view的成分。按照对JMVC代码的实验分析,只有在对视点s1这样的Inter-view视点解码的时候,才会调用参考帧重排的动作。重排序相关的代码在FrameMng::xReferenceListRemapping(),这个函数将根据modification_of_pic_nums_idc的值来判断要进行参考帧调整的类型,然后调用相应的调整过程。从下面展示的实验结果可以分析参考帧重排序的一些规律,参考帧的list0和list1被初始化的最大缓存分别是64帧,在代码中硬编码了,序列的view1的第4,2,6,1帧的解码情况被打印出来(按这个view的解码顺序),他们的参考帧排列如下。
( 1) Frame 4 ( LId 0, TL X, QL 0, MVC-B, BId-1, AP 0, QP 40 )
*************before******************
bufsize of list0: 3
poc of ref= 0 8 4
ViewId of ref= 1 1 0
***********************************
*************before******************
bufsize of list1: 3
poc of ref= 8 0 4
ViewId of ref= 1 1 2
***********************************
bufsize of list0: 3
poc of ref= 0 4 8
ViewId of ref= 1 0 1
bufsize of list1: 3
poc of ref= 8 4 0
ViewId of ref= 1 2 1
( 1) Frame 2 ( LId 0, TL X, QL 0, MVC-B, BId-1, AP 0, QP 41 )
*************before******************
bufsize of list0: 4
poc of ref= 0 4 8 2
ViewId of ref= 1 1 1 0
***********************************
*************before******************
bufsize of list1: 4
poc of ref= 4 8 0 2
ViewId of ref= 1 1 1 2
***********************************
bufsize of list0: 4
poc of ref= 0 2 4 8
ViewId of ref= 1 0 1 1
bufsize of list1: 4
poc of ref= 4 2 8 0
ViewId of ref= 1 2 1 1
( 1) Frame 6 ( LId 0, TL X, QL 0, MVC-B, BId-1, AP 0, QP 41 )
*************before******************
bufsize of list0: 5
poc of ref= 4 2 0 8 6
ViewId of ref= 1 1 1 1 0
***********************************
*************before******************
bufsize of list1: 5
poc of ref= 8 4 2 0 6
ViewId of ref= 1 1 1 1 2
***********************************
bufsize of list0: 5
poc of ref= 4 6 2 0 8
ViewId of ref= 1 0 1 1 1
bufsize of list1: 5
poc of ref= 8 6 4 2 0
ViewId of ref= 1 2 1 1 1
( 1) Frame 1 ( LId 0, TL X, QL 0, MVC-B, BId-1, AP 0, QP 42 )
*************before******************
bufsize of list0: 6
poc of ref= 0 2 4 6 8 1
ViewId of ref= 1 1 1 1 1 0
***********************************
*************before******************
bufsize of list1: 6
poc of ref= 2 4 6 8 0 1
ViewId of ref= 1 1 1 1 1 2
***********************************
bufsize of list0: 6
poc of ref= 0 1 2 4 6 8
ViewId of ref= 1 0 1 1 1 1
bufsize of list1: 6
poc of ref= 2 1 4 6 8 0
ViewId of ref= 1 2 1 1 1 1
分析以上实验,可以给出的结论是:
1.参考帧列表是以inter预测在hierarchical B结构的最直接的相关帧开始的,比如帧2的两边分别是0和4.然后是本视点其它已解码帧(按解码先后顺序排列,较近解码的排较靠前),然后才是相邻视点同一采集时点的帧。
2.重排工作发生在inter-view帧,工作过程是将相邻视点同一采集时点的帧在列表中的位置调整至inter预测最直接的相关帧后??挥诒臼拥闫渌?囊呀饴胫≈?啊?lt;/p>
3. MVC中依然维系多参考帧预测。
2.序列子集的处理,这一部分是按需要提取序列,H264AVCEncoderLibTestStaticd.exe的操作没有成功,原因是输入的序列流没有相关的SEI。从标准文档的学习中,关注的重点是8.5.3的子序列的提出过程,后面的8.3.4说明了主视点(全AVC视点)的指定。8.3.5说明了当没有主视点的序列集和如何创建主视点。(to do:将在SEI只是进一步熟悉的时候重新安排H264AVCEncoderLibTestStaticd的实验)
3.错误隐藏方面在在CommonDefs.h定义了基本的代码框架。
typedef enum
{
EC_NONE = 100,
EC_BLSKIP, //从base layer拷贝运动信息
EC_RECONSTRUCTION_UPSAMPLE, //上采样重构
EC_FRAME_COPY, //帧拷贝
EC_TEMPORAL_DIRECT, //时间域帧间隐藏
EC_INTRA_COPY //帧内隐藏
} ERROR_CONCEAL;
各枚举值的定义我已经给出了基本注释,根据代码的学习情况,当前代码实现的有EC_BLSKIP和EC_TEMPORAL_DIRECT被调用的迹象,更多的是EC_TEMPORAL_DIRECT分别被用于MotionCompensation::compensateDirectBlock和MotionCompensation::compensateMb当中。要加深对H.264错误隐藏的了解可以参考《JM86之误码掩盖参考代码完全剖析》,文章作者非常用功,给出了基本错误隐藏的图解。(to do:这个方面要继续深入,进行丢包实验)
本周还看了一些相关论文,下周一定要注意记录。下周(2009.5.25-2009.5.31)将开始重要部分-运动估计的学习。
(mvbdser) |