Feed on
Posts
Comments

jsvm

马上就要毕业了,写这篇文章的主要目的是为了纪念去年学习研究jsvm的那段时光。其中回头想想发现硕士研究生阶段好好学习的日子还真的不多:第一学期上上课就过去了,第二学期开始好好学习视频编码,第三学期忙碌着找工作,到第四学期就开始写论文搞答辩盼毕业。哎,原来自己两年来脚踏实地好好学习的时间才那么几个月……每每想到这些,心里还是忍不住要感谢实验室给我这样一个紧张的学习平台,avs会议3个月一次,每次都像打仗时的慌着做提案。虽然很累,那段日子天天晚上加班,也不记得暗地里骂了多少次,但是回头想想,不是那样一种环境,那样一种压力,自己如今可能仍然是一无所获。

以后可能不会再继续做视频压缩方面的东东了,所以在对jsvm、jm、rm、sm等暂时告别之际,不舍之情还是有一些的,平时学习的资料可能到最后压个盘,也不会再拿出来好好的研究学习了,在ksarea里面放着或许还会偶尔翻翻。不管怎样,相信这段学习的经历永远是偶一笔不小的财富。

本人学习jsvm的时间不长,但是感触还是有一些的。在正式看jsvm代码之前,做了一段时间的理论学习工作,当然主要是针对可伸缩视频编码技术。在后期看代码的时候,才发觉得前段时间的理论学习是很重要的。看jsvm的速度完全取决于你对可伸缩编码技术的了解程度和对c++编程的熟练程度,当然,后者相对而言次要些,但是如果你要在jsvm上做一定修改的话,那么后者就显得相当重要了。

下面本人就自己对jsvm的认识做一个简单的介绍。由于当时看jsvm代码也不到1个月,所以认识很浅,文字也不够深入或许还存在一些认识上的错误,但本人的初衷是好的,希望能对读者有个抛砖引玉的作用吧,呵呵。

Jsvm里面工程很多,主要包括:编码、解码、采样、码流截取等等。在此主要面向编码部分。

  • 首先从编码的配置文件说起吧,包括encoder.cfg 和 layer-i.cfg 。encoder.cfg 里面主要设置的是:输出文件名、待编码的帧数、帧率、质量增强层使用何种粒度大小、运动补偿参考帧是否采用增强层、GOP大小、I帧插入间隔、参考帧数目、基本层编码模式和运动搜索、环路滤波、空域增强层相关的配置情况等等,而layer-i.cfg主要是对空域可伸缩而言,layer0就是基本层了,其他的是逐步递增的空域增强层。其实在配置文件中,对时域、空域和质量都有设置,只是空域可伸缩的设置参数是单独拿出来的,而时域和质量的主要在encoder里面(时域->MCTF)。在layer-i.cfg中,就和普通的sm及jm的配置差不多了,基本上就是此层的输入文件大小、输入文件名、重建文件名、输入输出帧率、QP之类的,不同的是多了:NumFGSLayers、FGSMotion、InterLayerPred和BaseQuality,分别表示细粒度可伸缩层(即质量增强层)的层数、是否在FGS层中的改善运动矢量、本层是否采用向下的层间预测、本层基本质量层的质量级别(貌似是针对质量分层而言)。

 

  • 然后再说说编码器里几个主要的类的定义:

InputPicBuffer.h头文件中定义了class InputAccessUnit和class InputPicBuffer。

SequenceStructure.h头文件中定义了class FrameSpec、class FormattedStringParser 和class SequenceStructure

其中,class SequenceStructure主要包括:

{

private:

定义自己的成员变量。。。。

定义class FrameDescriptor {}

定义class SequencePart {}

定义class FrameSequencePart : public SequencePart {}

其中FrameSequencePart公有继承于SequencePart,又自己增添了一些私有成员变量:

Bool m_bInit;

FrameDescriptor* m_pacFrameDescriptor;

UInt m_uiNumberOfFrames;

UInt m_uiCurrentFrame;

UInt m_uiNumberOfRepetitions;

UInt m_uiCurrentRepetition;

UInt m_uiMinDPBSizeRef;

UInt m_uiMinDPBSizeNonRef; 和一些公有成员函数。

定义class GeneralSequencePart : public SequencePart

其中GeneralSequencePart公有继承于SequencePart,又自己增添了一些私有成员变量:

Bool m_bInit;

SequencePart** m_papcSequencePart;

UInt m_uiNumberOfParts;

UInt m_uiCurrentPart;

UInt m_uiNumberOfRepetitions;

UInt m_uiCurrentRepetition;

UInt m_uiMinDPBSizeRef;

UInt m_uiMinDPBSizeNonRef; 和一些公有成员函数。

}

在GOPEncoder.h头文件中定义了class AccessUnit、class AccessUnitList、class MCTFEncoder和class PicOutputData ,其中class PicOutputData是模板类MyList的一个实例化对象:

typedef MyList<PicOutputData> PicOutputDataList;

在 h264AVCommonIf.h 中,定义模板类MyList,公共继承于std的list类。MyList中有popBack popFront pushBack pushFront find 函数及重载了+=操作符。

template< class T >

class MyList : public std::list< T >

{

public:

typedef typename std::list<T>::iterator MyIterator;

MyList& operator += ( const MyList& rcMyList)

{

   if ( ! rcMyList.empty() )

   { insert( this->end(), rcMyList.begin(), rcMyList.end());}

   return *this;

}

T popBack()

   { T cT = this->back(); this->pop_back(); return cT; }

T popFront()

   { T cT = this->front(); this->pop_front(); return cT; }

Void pushBack( const T& rcT )

   { if( sizeof(T) == 4) { if( rcT != NULL ){ push_back( rcT);} } }

Void pushFront( const T& rcT )

   { if( sizeof(T) == 4) { if( rcT != NULL ){ push_front( rcT);} } }

MyIterator find( const T& rcT )

   { return std::find( this->begin(), this->end(), rcT ); }

};

这个模板类通用于整个编解码过程当中,通过用不同类实例化此模板,从而可以得到编解码过程中所需要的所有列表。比如:参考帧列表、输入/输出列表、质量分层列表、及SEI信息列表等等。在这里:typedef MyList<PicOutputData> PicOutputDataList; 是定义了图像输出数据的链表。

PicEncoder.h头文件中定义了class PicEncoder ;

SliceEncoder.h头文件中定义了class SliceEncoder;

MbCoder.h头文件中定义了class MbCoder;

MBEncoder.h头文件中定义了class MbEncoder

class MbEncoder : protected MbCoder , public UvlcWriter , protected BitCounter

MbEncoder 保护继承于MbCoder,MbCoder的public 和protected成员都是MbEncoder的保护成员;MbEncoder 公共继承于UvlcWriter,UvlcWriter的public 和protected成员分别是MbEncoder的公共成员和保护成员;MbEncoder 保护继承于BitCounter,BitCounter的public 和protected成员都是MbEncoder的保护成员;

CodingParameter.h头文件中定义了class CodingParameter、class EncoderConfigLineBase、class LayerParameters、class SampleWeightingParams 和class CodingParameter。

当然,jsvm里面的类是相当的多的,这里只是提出一部分比较重要的类拿出来说说。

 

  • 接下来说说JSVM编码器的一些主要函数

Main函数:  ( H264AVCEncoderLibTest.cpp )

主要部分是H264AVCEncoderTest 类对象指针pcH264AVCEncoderTest所指的go ()函数,在 H264AVCEncoderTest .cpp有函数原型。

Go函数 主要分为8部分:

1. 初始化

2. 写参数信息

3. 进入layer循环,输入必要的参数信息:

for( uiLayer = 0; uiLayer < uiNumLayers; uiLayer++ )

4. 开始一个帧一个帧的编码:

for( uiFrame = 0; uiFrame < uiMaxFrame; uiFrame++ )

{

    4-1 编码每一个帧时,layer循环 获取缓存存储图像,并且读入每个layer的帧信息:

    for( uiLayer = 0; uiLayer < uiNumLayers; uiLayer++ )

    {  m_apcReadYuv[uiLayer]->readFrame(。。。。。) }

    4-2 开始编码:m_pcH264AVCEncoder->process(。。。。。。)

    4-3 写每一帧编码后的传输单元NAL unit,并且释放临时缓存;

    4-4 写每一帧编码后的重建图像,并且释放临时缓存;

}

5. 结束编码

6. 写所有帧编码后的传输单元NAL unit,并且释放临时缓存

7. 写所有帧编码后的重建图像,并且释放临时缓存

8. 计算输出显示的参数信息,比如psnr值等等。

 

Process 函数,主要分为:  (PicEncoder.cpp)

===== fill lists =====

for( UInt uiLayer = 0; uiLayer <= uiHighestLayer; uiLayer++ )

判断编码模式,如果是AVC模式的话:(是否是AVC模式由编码配置文件encoder.cfg中的BaseLayerMode 项值决定)

则运行函数:m_pcPicEncoder ->process //见下面PicEncoder::process函数

否则:

运行函数m_pcH264AVCEncoder->process //见下面H264AVCEncoder::process函数

 

PicEncoder::process函数: (PicEncoder.cpp)

1. 输入图片信息

2. 编码图片头信息等

3. 得到下一帧

4. 初始化图像

5. 编码

6. 存储图像

 

H264AVCEncoder::process函数: (H264AVCEncoder.cpp)

1. 输入当前GOP信息

2. 编码当前GOP (运行函数:xProcessGOP)

3. 更新图像列表

 

xProcessGOP( apcPicBufferOutputList, apcPicBufferUnusedList )函数:(H264AVCEncoder.cpp)

1. 初始化GOP

2. 在GOP范围内获取每一层的可获得的信息单元,并且编码:

for( uiAUIndex = 0; uiAUIndex <= 64; uiAUIndex++ )

{

    for( uiLayer = 0;

           uiLayer < m_pcCodingParameter->getNumberOfLayers(); uiLayer ++ )

    { m_apcMCTFEncoder[uiLayer]->process(。。。。) 。。。。}

}

3. 更新图像缓存列表

for( uiLayer = 0; uiLayer < m_pcCodingParameter->getNumberOfLayers(); uiLayer++ )

{

    //—– set output list —–

    //—– update unused list —–

    //—– reset lists —–

}

MCTFEncoder::process函数: (GOPEncoder.cpp)

1. 初始化相关参数

2. 更新更高层图像(我认为:在编码一个GOP,特别是使用FGS技术时,为了提高编码效率,编码帧有时是需要参考已编码帧的高质量重建图像的,那么就需要在编码之前,整理好已编码重建帧的高质量图像,即需要更新更高层图像)

3. 编码此GOP内的anchor帧(即判断此帧是否是anchor帧,若是,则进入;若不是则进入4步骤),其中最主要的是xEncodeKeyPicture函数(后续介绍)

4. 编码此GOP内的非anchor帧,其中最主要的是xEncodeNonKeyPicture函数(后续介绍)

5. 结束GOP编码

在MCTFEncoder::xEncodeKeyPicture和MCTFEncoder::xEncodeNonKeyPicture函数中(GOPEncoder.cpp)比较主要的是xEncodeLowPassSignal、xEncodeHighPassSignal、xEncodeFGSLayer等函数。这些函数都是GOP层面的,至于其中的具体过程就不再一一的描述了。

 

在jsvm里面,虽然编码过程很复杂(因为可伸缩的算法本身就比较复杂),但是最底层的MB结构还是和普通的单层编码结构一样的,序列-->GOP-->frame-->slice-->Mb。只是在编码的过程中分了很多种情况,首先编一个frame时,除了考虑它是哪种类型(I/P/B)的帧外,还要考虑它在时域中(即GOP内)的位置情况:看它是不是anchor帧(GOP内第一个anchor帧应该是I帧,那么不参考其他帧编码,而第二个anchor帧可以是P帧或I帧,若是P帧,则要参考本GOP内前面anchor帧的重建图像),若不是anchor帧,则参考帧也必须在此GOP以内,为的是防止误差传递(这个属于参考帧管理的内容);除了考虑时域外,还要同时考虑此帧是属于哪个空域层的,编码Mb时看是否需要做层间预测(此处说的层间预测包括-宏块划分方式层间预测、运动矢量层间预测和编码残差层间预测等);最后还要考虑质量可伸缩问题(即FGS,这块本人不了解,所以就不深入了)。

 

  • 另外,对于jsvm编码后的码流大小和普通的jm码流大小基本对比如下:

    (前提条件是 参数设置基本相同)

① svc码流 (cif +qcif)

② 单层的 h264码流 (cif)

③ h264的simulcast (cif+qcif)

通常是: ① * 1.3 ≈ ③   ;   ② * 1.1 ≈①    ;   ② * 1.43 ≈③

 

先写到此为止吧,写了这么多,真够累的。

本文应该尚未结束,我想。 呵呵, 待日后更新吧。

39 条评论

  • At 2008.06.11 14:47, king said:

    太长。。。
    哈哈哈

    • At 2008.06.12 22:01, adrian said:

      对照你的描述我在JSVM软件上看了一遍流程. JSVM这代码真不是人写的,要不是没有你的指引我早就被这么多的名字给淹没了.
      在MCTFEncoder::process里(我看程序里好像写着是LayerEncoder::process,还有前面的是否是AVC模式好像是由encoder.cfg中的AVCMode参数来决定的, 也有可能是我弄错了.)你还可以写很多,呵呵,期待你继续把inter picture motion estimation/motion compensation, transform, CAVLC/CABAC, inter layer prediction…..blahblah也都写写.

      • At 2008.06.13 09:40, sha said:

        我觉得看代码之前的理论学习很重要。代码中没有明确的注释,那么很多时候都需要自己去“猜”,把自己掌握的理论和代码进行比较,这里说的“猜”也算是一种感觉吧,coding感,呵呵。而猜对猜错则就需要靠自己进一步的程序验证了。^_^

        • At 2008.06.17 20:45, adrian said:

          Sha:
          我想既然SVC都成为了H.264/AVC的extension了,那应该有了standard document,不过我怎么搜也没找到,试了下draft document也没能找到.不知道你有没有?

          • At 2008.06.18 17:46, sha said:

            adrian:好像是有的吧,但是我没有用过,因为当时看jsvm的时候,没有去找。但是后来想到jvt官方网站上有jsvm源码下,那么也应该有相应的文档吧。貌似有的,你去找找

            • At 2008.06.19 15:46, sha said:

              我貌似找到了,貌似是jsvm-9版本的补充文档:《Joint Draft 10 of SVC Amendment》,是07年California开的第23次会议的输出文档里找到的。adrian,你还要么?

              • At 2008.06.23 14:57, adrian said:

                Sha:
                我去了JVT的官方网址没有找到下JSVM源码的地方. 是不是应该有地方可以直接下载这些文档?

                • At 2008.06.23 14:58, adrian said:

                  下载JSVM这个software到是有地方可以,但里面也只有一个software manual可以读,下载the archive of standard document是没找到

                  • At 2008.06.23 15:56, adrian said:

                    Sha:
                    我在JVT2007_4_SanJose里找到了你说的joint draft 10 of SVC Amendment, 不过发现H.264/AVC 的standard document里也有SVC的描述, 想想既然SVC都已经是H.264/AVC的extension了,那标准也应该写在H.264/AVC的标准里.你觉的呢? 是看哪个?

                    • At 2008.06.24 08:42, sha said:

                      adrian: 说实话,那些文档我自己都没有好好的看过,所以我不清楚看哪个比较好,呵呵,只是以前偶尔查资料的时候会去翻翻。
                      我觉得如果你对可伸缩技术很了解的话,那么看这些文档是比较好的,两个都看看吧,一看就知道哪个对jsvm写得更深入了,毕竟是联合草案,不管看哪个都会对你有帮助的(若想把jsvm学好,那么H264/AVC也必需要很牛X,毕竟jsvm里面的基本层就是按照H264/AVC编的);如果你对可伸缩编码技术本身了解得不够深入,那么我认为从网上下一些牛人写的论文(特别是综述之类的)来看,会进度更快,当功力达到一定程度,再好好攻克一下草案, 相信你面对jsvm的代码就会唏哩哗啦的统统都可以搞定啦。^_^

                      • At 2008.07.06 21:46, binge2008 said:

                        你好!
                        看了你文章,感觉不但你的k shome,而且技术文章写得不错,呵呵
                        但要指出你的一个小错误:是否执行m_pcPicEncoder ->process 不是由encoder.cfg里的BaseLayerMode觉得,而是由MVCMode的值决定的。可惜你不再做H.264SVC(你文章上所述)了,不然,可以和你讨论讨论!

                        • At 2008.07.09 09:07, xiaoxian said:

                          hh

                          • At 2008.07.09 09:13, xiaoxian said:

                            美女,在深圳还好吧。要注意身体哦。
                            关于JSVM,请教你个问题哈。
                            这个代码有实现层次P帧的功能没?
                            我想关闭里面的层次B帧的结构(目的是关掉B帧看是否有层次结构,有的话就证明有层次P帧),但是不关掉层次结构。如果将Gopsize设为2的话,B帧的确没有了,但是时域层次也没有了,因此不能得出是否有层次P帧的结构。
                            我想请教下,是否有别的关闭层次B帧的方法(不关掉层次结构,即不用Gopsize改为2的方法)。
                            希望最后不要得出这样的结论:JSVM代码里面没有层次P帧的结构,需要自己添加。

                            • At 2008.07.11 22:36, adrian said:

                              xiaoxian:
                              我觉得如果是实现你说的这种hierachical P frame应该就是在temporal scalability中达到a structure with a structural encoder/decoder delay of zero, which means not use the future frames as reference frames. 我知道在JSVM single layer coding中的一个SequenceFormatString的parameter设置是能达到这种效果的.

                              • At 2008.07.19 22:08, adrian said:

                                Sha:
                                JSVM程序阅读还有续嘛? 期待你把jsvm中有关预测和估计的部分也写写……

                                • At 2008.07.19 23:56, sha said:

                                  好久好久好久好久没有来了……

                                  • At 2008.07.20 14:20, adrian said:

                                    Sha
                                    JSVM中对SVC motion estimation算法的实现到底在哪个位置呀??? 找了很久也没找到…..help,SOS…

                                    • At 2008.09.01 21:10, yunyun said:

                                      sha,你好,看了你的博客感觉收获很大,我现在刚开始学习jsvm,想问你一个小问题,能否给解释下anchor帧与关键帧的区别?anchor帧可是定位帧?怎么判断anchor帧?看jvt文档老是出现anchor,我不太明白到底指的哪种编码帧,如果能和你qq交流就好了,现在太需要一位贵人相助了,真是摸不着头脑啊,看了这么多文档,感觉云里雾里的,先问这个吧,希望你有空时能帮忙解答一下,在此先谢过了,希望能成为朋友,呵呵

                                      • At 2008.09.02 13:03, sha said:

                                        yunyun,你好。
                                        anchor帧一般都是I帧,但也可以是p帧,这取决于编码算法吧。
                                        对于jsvm,我好久好久都没有看过了,虽然隐约记得一些,但是准确性是不敢保证的,所以也不敢贸然的乱解释。

                                        • At 2008.09.11 22:23, adrian said:

                                          按sha的解释anchor帧就是key帧了.
                                          我在文档和程序里好像没有见过anchor帧

                                          • At 2008.09.12 08:09, sha said:

                                            在可伸缩视频编码的说明文档里,有anchor帧的概念。因为需要进行时域分级,待编码视频图像被分为一组一组的GOP,每个GOP里的帧会按照其编号进行时域层次分级编码。
                                            而每个GOP里都会有个一anchor帧,一般是第一帧。对于第一个GOP而言,其anchor帧肯定是I帧;而后面的GOP而言,anchor帧可以是I帧,也可以是P帧,(这要取决于插入I帧的间隔帧数了)但是一定不能是B帧。
                                            (第二段话有些内容不能完全确定,好久没有看了,完全是凭着记忆说的 ,不可完全相信的 ^_^)

                                            • At 2008.09.14 00:32, CF said:

                                              hehe~,偶然来到这里,先对博主的小女人情愫感到有点意思。
                                              接着又看到某位研究生毕业居然拿自己对视频编码的一点粗浅了解来卖弄,就觉得更有意思了。
                                              中国教育真是培养出太多的精英了

                                              • At 2008.09.16 17:11, sha said:

                                                呵呵,我对视频编码只是学过几个月,确实认识很粗浅。写这篇文章的初衷仅仅是对自己学习的那段时间留个脚印而已,并没有像CF描述的那样——在卖弄。呵呵。
                                                更希望CF不要因为我的blog,而含沙射影的去骂中国教育…… -_-!!

                                                • At 2008.09.16 18:22, king said:

                                                  CF:
                                                  做人要厚道,这里只是记录生活和学习的地方,没有拿出来卖弄的意思,如果你不喜欢这里,你大可绕道而行!
                                                  中国就是因为你这样的人太多了,而不能迅猛发展!

                                                  • At 2008.10.29 16:22, meng said:

                                                    强烈要求继续

                                                    • At 2008.11.03 14:57, meng said:

                                                      请问下,在JSVM里面,层间预测是在什么地方。

                                                      • At 2008.11.03 20:22, sha said:

                                                        层间预测应该是在增强层编码的时候出现,增强层编每一帧的每一个宏块时,通常会把各种编码模式都编一边,看哪一种最适合自己,就选择哪一种。其中编码模式可以是层内帧间预测、也可以是层间预测或者帧内预测。你在增强层宏块编码的函数里找,应该找得到

                                                        • At 2008.11.04 09:30, meng said:

                                                          好谢谢哦。我找到了好像是xEstimateMbIntraBL这些函数,不知道对不对,请告诉我啊。

                                                          • At 2008.11.04 09:39, sha said:

                                                            呵呵,具体的函数名我也不记得了,手头也没有jsvm的代码。你可以深入函数看看,大胆猜测,小心求证吧。

                                                            • At 2008.11.10 10:18, meng said:

                                                              《Joint Draft 10 of SVC Amendment》这个东西我没法下到。你能不能发一份给我的邮箱里。对我很重要。谢谢

                                                              • At 2008.11.11 17:44, 晴海 said:

                                                                真的超感謝你寫這篇~~~
                                                                那些代碼真的不是人看的…你的資訊真的很有用
                                                                也幫助像我這種正走進SVC領域的的人!!
                                                                謝謝!!

                                                                • At 2008.11.11 17:57, 晴海 said:

                                                                  To meng:
                                                                  我有你要的檔案
                                                                  我剛剛已經分享到免費空間裡了
                                                                  http://www.filedropper.com/jvt-w201
                                                                  請你去下載吧!!!!^o^
                                                                  沒辦法下載的話,再告訴我吧!!Good luck
                                                                  看來大家都是做JSVM的,一起加油囉~~
                                                                  (sorry 我來自台灣…但我相信繁體中文你應該也看的懂…)

                                                                  • At 2008.11.12 10:31, sha said:

                                                                    原来还是台湾的同胞啊,真难得哦~ 欢迎,欢迎
                                                                    呵呵,海峡两岸的互连在ksarea上都有所体现啦,真happy~ ^_^

                                                                    • At 2008.11.19 20:06, 晴海 said:

                                                                      Dear sha:
                                                                      我想請教您一個問題~~^o^
                                                                      承#21的回答~~anchor跟key frame是指同一個東西嗎?

                                                                      • At 2008.11.22 01:25, yapuke said:

                                                                        22楼的不用这样吧,人家又没标榜自己水平多好。你觉得粗浅,笑笑就完了,谁不是一点点的进步啊。呵呵。

                                                                        • At 2008.11.25 21:47, adrian said:

                                                                          To Meng:
                                                                          xEstimateMbIntraBL里面是有所谓的inter-layer motion estimation的

                                                                          • At 2008.12.03 11:48, asd said:

                                                                            非常感谢楼主的分享,建议楼主建个群,大家共同学习SVC!

                                                                            • At 2008.12.08 11:33, 一介书生 said:

                                                                              楼主的文章很不错,对学习JSVM是很好的参考。有空儿到“H.264乐园”(群号:12923082)和大家一起分享吧!

                                                                              • At 2008.12.21 10:33, shashali said:

                                                                                楼主继续哈

                                                                                (Required)
                                                                                (Required, will not be published)