H.264 ,MPEG-2,MPEG-1,H.263,MPEG-4系列

1 encoder

 

3 analyse

(函数调用从左到右,下同;图片显示不全时,请下载显示)

 

2 P帧运动估计流程图

3 B帧运动估计流程图

 

 

4 decoder

 

 

ffmpeg的mpeg2编码I帧代码解读

首先说一下编码的函数层次:
MPV_encode_picture
—encode_thread
———encode_mb_hq
————encode_mb(编码一个宏块)
——————encode_mb_internal(编码I帧宏块,在这个函数里面选择不同的宏块编码器)
————————mpeg1_encode_mb(由于YUV的比例不一样,4:4:4或者4:2:0,进行宏块编码)
——————————mpeg1_encode_mb_internal(对宏块进行编码)
————————————mpeg1_encode_block(对一个block进行编码,注意这里面的宏块都是经过DCT和量化之后的数据):这个函数就是最需要看的咯:包括DC编码和AC编码,会选择不同的码表进行编码(详细过程看代码)

其次,所有的编码后的数据都是通过函数put_bits写到比特流中

第三,以上的代码解读都不包括诸如图片头之类的编码,相应的格式编码可以在相应层次中的函数里面找到。

第 四,libavcodec/mpegvideo_enc.c里面MPV_encode_init对编码进行初始化,主要是初始化,根据 avctx->codec_id选择不同的编码标准,进行不同的初始化,在656行,根据s->dct_quantize选择了DCT系数和 量化器(因为不同的编码标准,量化器是不一样的),然而在程序里面,统一由函数指针指向的函数dct_quantize完成

第五,在encode_mb_internal里面首先,进行了DCT和量化,然后进行霍夫曼编码——根据(s->codec_id)选择不同的编码器。DCT & quantize在1629行。

第五,在 简单的说一下编码的过程:
1.初始化,包括选择DCT和量化器等等
2.编码一个图像(picture),将picture分成若干的mb(MacroBlock),这个时候要写入相应的图片头信息
3. 编码I帧MacroBlock,将MacroBlock分成若个小的block,由于YUV的比例不一样,因此每次需要编码的block的数量也是不一样 的,在函数mpeg1_encode_mb里面,就区分了CHROMA_420和其他格式拥有不同的block数量。
4.编码block,一个block包含三个编码对象:DC系数,AC系数(level)和游程长度。DC系数单独用差分编码,AC和run
联合在一起编码。这个过程都是在函数mpeg1_encode_block里面完成的。

  1.MpegEncContext这个struct类型,一定要吃透,虽然代码是用C写得,但是写得很C++,这个MpegEncContext其实可以看做一个C++的类,里面定义了很多指针,这些指针指又指向了一些strcut,而这个struct其实相当于C++的成员函数,成员函数的初始化,一般是在XX_init函数里面初始化的。这一点,可以在后面的叙述中体现出来。

2.再说一下编码的过程,encode_mb_internal函数,做了MarcoBlock的编码,在1629行,开始做DCT&quant,1686行,开始做霍夫曼编码,而霍夫曼编码,对不同的标准来说,码表是不一样的,因此在1687行做了一个switch的选择,mpeg1和mpeg2,都是用的相同的mpeg1_encode_mb函数进行block的编码,而block内的编码,在以前的笔记中已经提到,过程这里不重复。

3.现在说DCT&quant,其中,1635行s->block_last_index[i] = s->dct_quantize(s, s->block[i], i, s->qscale, &overflow);,就是做DCT&quant。正如第1点中说的,dct_quantize本来只是MpegEncContext中的一个元素,类型为指针,指向一个struct,而这个struct就相当于C++里面的成员函数。现在,我们知道了在这个地方,相当于调用了一个成员函数,做了DCT&quant这件事情,接下来,讨论这个成员函数在哪里初始化的。

4.在Mpegvideo.c的MPV_encode_init函数里面,对编码所需要的一些“成员函数”进行了初始化。前面一堆东西,是做编码器的选择。在第656行,dct_quant这成员函数被初始化为dct_quant_c这个函数。于是,接下去找dct_quant_c这个函数的定义。发现,3649行,又调用了dsp.fdct这个成员函数,做离散余弦变换。接下来找dsp.fdct这个成员函数的初始化地方。
这个非常费劲,我找了半天才找到——在函数dsputil_init里面做了fdct的初始化,一步一步的跟踪调用关系,可以发现过程是这样的:
MPV_encode_init调用MPV_common_init,再调用dsputil_init,在dsputil_init里面初始化了fdct,而MPV_encode_init紧接着,执行前面提到的dct_quantize的初始化。
至此,整个初始化完成。

  1.完整的初始化过程,函数调用关系如下:

   

  1.首先编码的是DC系数,在函数

MPEG-4 AVC/H.264 信息

 

本FAQ系列由(haibara)翻译,期间受到kaito_mkid(pcicp)帮助,在此感谢,由于Newbie的关系,如有翻译错误,还请各位指出,由Doom9的bond编撰的原文

译者注:基本专业名称我都以小括 形式加以解释,详细信息请自行查阅资料。

什么是MPEG-4/span>

MPEG-4(ISO 14496)是由制定了我们熟知的MPEG-1(MP3, VCD)和MPEG-2(DVD, SVCD)标准,并力于使各种音频/视频压缩格式和更多内容标准化的国际标准化组织(International Organization for Standardization/ISO)的工作组,即运动图像专家组(Moving Picture Experts Group/MPEG)发展的广泛的开放标准。
本质上MPEG-4标准不仅把目标定为标准化某些有发展前途的产品(例如达到DVD性能),而且含盖了一个能让产品供应商根据需要选择适当标准去执行的广泛的次级标准。

声明:本站部分文章及图片源自用户投稿,如本站任何资料有侵权请您尽早请联系jinwei@zod.com.cn进行处理,非常感谢!

上一篇 2013年11月22日
下一篇 2013年11月22日

相关推荐