织梦CMS - 轻松建站从此开始!

罗索

MVC学习的第七周小结(2009.6.22-2009.6.28)-YUV数据流

jackyhwei 发布于 2010-01-28 20:02 点击:次 
本周将查看JMVC的数据流动,认识在本模型代码中那些存储数据的类。
TAG:

本周将查看JMVC的数据流动,认识在本模型代码中那些存储数据的类。

1. I/O文件

做编码实验的时候,不能直接编码有interview依赖关系的视频,例如双视点实验中,在没有编主视点0的时候,不能直接编辅视点1。观察一下载双视点编码中的输入输出文件(根据真实JMVC代码实验):

(1) rcFilename=D:\workspace\project\jmvc\bin\recon_1.yuv
(2) rcFilename=D:\workspace\264\ballroom\ballroom_1.yuv
(3) rcFilename=D:\workspace\project\jmvc\bin\output1.264
(4) rcFilename=D:\workspace\project\jmvc\bin\recon_0.yuv

如上是被编码辅视点1时先后初始化的文件,除了本视点外,还有主视点0的重构文件被应用recon_0.yuv。给出以上四种情况的调用关系:

(1) H264AVCEncoderTest::init()-> WriteYuvToFile::create()->WriteYuvToFile::xInit()

(2) H264AVCEncoderTest::init()->ReadYuvFile::init()

(3) H264AVCEncoderTest::init()->WriteBitstreamToFile::init()

(4)H264AVCEncoderTest::go()->CreaterH264AVCEncoder::init()->  MultiviewReferencePictureManager :: AddVectorOfFilesToUseAsReference()-> MultiviewReferencePictureManager::AddViewFileToUseAsReference() <_references.push_back()> -> ReadYuvFile::init()

重点看以下(4),在PicEncoder中,会有个专门做inter-view管理的对象(MultiviewReferencePictureManager) m_MultiviewRefPicManager,在PicEncoder::process()的参考组织过程中,m_MultiviewRefPicManager. AddMultiviewReferencesPicturesToBuffer()负责把inter-view的帧放入相应的list0或list1中,便于以后的时差估计使用,这就是JMVC的独特之处。

 

                                           图1 H.264编码流程

图1展示了H.264编码流程,JMVC把重构帧(就是入如上图1经过DCT、量化和他们的逆过程,做了运动补偿形成的帧)记录到文件中,在以后的依赖视点编码时,可以直接读入使用。使用重构帧为运动/视差估计是应为在解码端只能获得重构帧。

2. H264AVCEncoderTest::go()分析

这里是编码测试的入口,略过前面对SEI信息的处理。可以看到的是代码将逐帧从YUV文件读取数据。YUV数据在文件中按Y,U,V的顺序一帧帧的紧接存放,没有冗余数据,如下是对4:2:0的176x144帧数据举例:

          176
     +-------------+
     |                      |
     |     Y              | 144
     |                      |
     |                      |
     +-------------+
       88
     +------+
     |  U      |
     |           |72
     +------+
     |  V      |
     | -------   |72
代码是用ReadYuvFile::xReadPlane()把帧的每个分量数据读入内存。类PicBuffer的对象apcOriginalPicBuffer将存放读入一帧的YUV原始数据。m_pcH264AVCEncoder->process()进行具体的编码过程,在之后的PicEncoder::process()中,调用了RecPicBuffer:: initCurrRecPicBufUnit(),该函数将输入的YUV数据转变存储到类RecPicBufUnit对象pcRecPicBufUnit中,作为数据块被传入xEncodePicture()做具体编码。类RecPicBufUnit把YUV数据和POC,VIEWID等其他相关的上下文信息结合起来,形成有管理的帧数据。

 

下面来看看这个帧数据是如何分离成运动矢量和残差、如何进行输出重构帧,又如何管理参考帧的。

3.参考帧分析

编码端的参考帧管理在PicEncoder::xEncodePicture()-> PicEncoder::xStartPicture()->RecPicBuffer::getRefLists()。在这里根据帧类型,进行list0和list1的初始化,填值(包括了inter和inter-view过程)和重排序,下面的实验将调研标准hierarchical B结构(GOP=8)在编码端的参考帧管理。hierarchical B结构(GOP=8)在“MVC学习的第二周小结(2009.5.18-2009.5.24)-mvc解码概况和参考帧分析”中有附图,那里还实验分析了解码端的参考帧管理。

¥¥¥¥¥¥¥¥¥¥JMVC编码端参考帧实验¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥

如附图实验三视点情况。0为主视点,2为第一辅视点,1为第二辅视点。考虑到篇幅限制,这里只给出视点1的数据,既包含帧间也包含inter-view的典型例子。在***内部的是xRefListRemapping()前的参考帧情况。实验数据的答应顺序是printf( " %d/%d", rcList[uiIndex]->getViewId(), rcList[uiIndex]->getPOC() );


viewID=1


ViewCodingOrder: 0 2 1

*************before******************
List 0 = 0/0
***********************************
*************before******************
List 1 = 0/0
***********************************
List 0 = 0/0
List 1 = 2/0
encode time: 58.219 second
   0 B IDR            0  QP 37  Y 32.3800 dB  U 37.7089 dB  V 37.6010 dB   bits   26184


*************before******************
List 0 = 0/8
***********************************
*************before******************
List 1 = 0/8
***********************************
List 0 = 0/8
List 1 = 2/8
encode time: 58.062 second
   1 B REF            8  QP 37  Y 32.3354 dB  U 37.8172 dB  V 37.7190 dB   bits   25672


*************before******************
List 0 = 1/0 1/8 0/4
***********************************
*************before******************
List 1 = 1/0 1/8 0/4
***********************************
List 0 = 1/0 0/4
List 1 = 1/8 2/4
encode time: 111.594 second
   2 B REF            4  QP 40  Y 32.3518 dB  U 37.8689 dB  V 37.5807 dB   bits    5144


*************before******************
List 0 = 1/0 1/4 1/8 0/2
***********************************
*************before******************
List 1 = 1/0 1/4 1/8 0/2
***********************************
List 0 = 1/0 0/2
List 1 = 1/4 2/2
encode time: 106.875 second
   3 B REF            2  QP 41  Y 32.1857 dB  U 37.9306 dB  V 37.4947 dB   bits    4008


*************before******************
List 0 = 1/4 1/2 1/0 1/8 0/6
***********************************
*************before******************
List 1 = 1/4 1/2 1/0 1/8 0/6
***********************************
List 0 = 1/4 0/6
List 1 = 1/8 2/6
encode time: 108.204 second
   4 B REF            6  QP 41  Y 32.1311 dB  U 37.8020 dB  V 37.5645 dB   bits    3856


*************before******************
List 0 = 1/0 1/2 1/4 1/6 1/8 0/1
***********************************
*************before******************
List 1 = 1/0 1/2 1/4 1/6 1/8 0/1
***********************************
List 0 = 1/0 0/1
List 1 = 1/2 2/1
encode time: 103.281 second
   5 B                1  QP 42  Y 32.0451 dB  U 37.8979 dB  V 37.3828 dB   bits    2904

*************before******************
List 0 = 1/2 1/0 1/4 1/6 1/8 0/3
***********************************
*************before******************
List 1 = 1/2 1/0 1/4 1/6 1/8 0/3
***********************************
List 0 = 1/2 0/3
List 1 = 1/4 2/3
encode time: 103.422 second
   6 B                3  QP 42  Y 32.0795 dB  U 37.9575 dB  V 37.4602 dB   bits    2864

 
*************before******************
List 0 = 1/4 1/2 1/0 1/6 1/8 0/5
***********************************
*************before******************
List 1 = 1/4 1/2 1/0 1/6 1/8 0/5
***********************************
List 0 = 1/4 0/5
List 1 = 1/6 2/5
encode time: 102.312 second
   7 B                5  QP 42  Y 32.1537 dB  U 37.9360 dB  V 37.5200 dB   bits    2448

*************before******************
List 0 = 1/6 1/4 1/2 1/0 1/8 0/7
***********************************
*************before******************
List 1 = 1/6 1/4 1/2 1/0 1/8 0/7
***********************************
List 0 = 1/6 0/7
List 1 = 1/8 2/7
encode time: 101.75 second
   8 B                7  QP 42  Y 32.0916 dB  U 37.8796 dB  V 37.5812 dB   bits    2504


¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥

从以上的实验结果来看,xRefListRemapping()不仅是重排序参考帧而且精简了参考帧,只留下hierarchical B结构中有直接关系的帧。重排序的控制和解码端一致符合标准文档中的状态控制

enum RplrOp
{
  RPLR_NEG   = 0,
  RPLR_POS   = 1,
  RPLR_LONG  = 2,
  RPLR_END   = 3,
  // JVT-V043
  RPLR_VIEW_NEG =4,
  RPLR_VIEW_POS =5,
};

标准模型只做了很基础的参考帧控制以符合hierarchical B结构,没有进行复杂的优化,而在运动估计中也没有对同一宏块可以从两个前向或后向的参考帧同时取得预测信息,所以给大家留下了很多优化的空间。

4. 运动矢量和残差分离

在SliceEncoder::encodeSlice()中,有两个重要的编码端函数。MbEncoder::encodeMacroblock()是进行帧内、帧间和视差预测,并进行DCT变换和量化,而MbCoder::encode()将对码表里的组织数据进行熵编码(残差熵编码在MbEncoder::encodeMacroblock()中完成),它将根据配置文件选择使用cabac和cavlc(代码里的UvlcWriter类)完成具体编码。

在MbEncoder::encodeMacroblock()里,根据宏块模式,将进行xEstimateMb***或xEstimateMbIntra***系列的函数,进行运动视差估计或帧内估计。还是从最熟悉的xEstimateMb16x16()入手分析,在完成运动估计提取运动矢量之后,xSetRdCostInterMb()函数随之被调用,在该函数中将利用m_pcMotionEstimation->compensateMb()通过运动矢量和参考帧匹配求出残差值,然后在MbEncoder::xEncode4x4InterBlock()中进行残差值编码,最重要的就是要进行DCT整数变换和量化。这部分是在xEncode4x4InterBlock()中完成的。

其中,Transform::transform4x4Blk()被调用作为变换和量化,并且反变换和分量化重构帧的宏块成分。之后的MbCoder::xScanLumaBlock()就已经去读取残差的变换量化后的输出系数并做熵编码了。DCT整数变化使用蝶形图方法,已经在我5月的文章“H.264整数DCT公式推导和蝶形图分析”里有所叙述,量化部分留待以后分析。(todo: 量化部分分析

在xEstimateMb16x16()的最后一个被调用函数是xCheckInterMbMode8x8(),该函数运用xSetRdCost8x8InterMb(),使用8x8的DCT。将其RDCost和4x4的比较,选择其最小值的模式作为最终DCT模式。从RDcost的定义公式可以知道,它完整的计算除了SAD部分还有数据编码的代价部分,在这里对每一种宏块分割模式严格使用经过DCT,量化和熵编码的实际值进行衡量,其计算代价相当高。是否可以通过SATD可以预测出一种最佳模式,再进行DCT,量化和熵编码过程?以后再查看X264相关代码时要注意。(todo:是否可以用简单运算SATD先预测最佳宏块分割

本周把JMVC按图1的H.264编码数据流过程大致走了一遍,分析了编码参考帧,系统的I/O文件和运动估计后对残差的获得与处理。余下一些具体的帧内预测编码,熵编码运算和量化过程分析,将在下周(2009.6.29-2009.7.5)继续探讨。

(jacky)
本站文章除注明转载外,均为本站原创或编译欢迎任何形式的转载,但请务必注明出处,尊重他人劳动,同学习共成长。转载请注明:文章转载自:罗索实验室 [http://www.rosoo.net/a/201001/8432.html]
本文出处:网络博客 作者:jacky
顶一下
(3)
100%
踩一下
(0)
0%
------分隔线----------------------------
发表评论
请自觉遵守互联网相关的政策法规,严禁发布色情、暴力、反动的言论。
评价:
表情:
用户名: 验证码:点击我更换图片
栏目列表
将本文分享到微信
织梦二维码生成器
推荐内容