VC++实现 低比特率视听会议压缩编码标准H.263
转载请标明是引用于 http://blog.csdn.net/chenyujing1234
欢迎大家提出意见,一起讨论!
需要源码的请与我联系。
1、H.263编码技术
H.263是国际电联ITU-T的一个标准草案,是为低码流通信而设计的。但实际上这个标准可用在很宽的码流范围,
而非只用于低码流应用。H.263的编码算法与H.261一样,但做了一些改善和改变,以提高性能和纠错能力。
H.263标准在低码率下能够提供比H.261更好的图像效果,两者的区别有:
(1)H.263的运动补偿使用半象素精度,而H.261则用全象素精度和循环滤波;
(2)数据流层次结构的某些部分在H.263中是可选的,使得编解码可以配置成更低的数据率或更好的纠错能力;
(3)H.263包含四个可协商的选项以改善性能;
(4)H.263采用无限制的运动向量以及基于语法的算术编码;
(5)采用事先预测和与MPEG中的P-B帧一样的帧预测方法;
(6)H.263支持5种分辨率,即除了支持H.261中所支持的QCIF和CIF外,还支持SQCIF、4CIF和16CIF,SQCIF。
H.263是为了满足诸如视频会议、视频电子邮件和可视电话等视频通信业务发展的需要,并且克服公用电话交换网(PSTN)和
无线网络传输速率的瓶颈制定的视频编码标准。
网络应用最重要的目标之一就是进行多媒体通信。多媒体信息主要包括图像、声音和文本三大类,其中视频、音频等信号的信息量非常大,
因此对这些数据进行有效的表达和适当处理是非常重要的。
尽管H.263编码的主体框架仍然延续H.261标准编码的主要框架,但在许多方面对H.261进行了改进和扩充,在编码算法复杂度增加很少的情况下,
能提供更好的图像质量、更低的速率。
1、1 H.263编码结构说明H.263定义了视频编码的数据结构,以便解码器能从接收到的码流中根据数据结构的定义进行解码重建图像。
这种数据结构是一种分级的数据结构,从大到小依次是图像帧、块组、宏块和块这4层结构。
以CIF图像帧(352X288)为例:
一帧图像可以分为12个块组,分别为GOB0-GOB11。
GOB0GOB1GOB2GOB3GOB4GOB5GOB6GOB7GOB8GOB9GOB10GOB11
每一个GOB又分为33个宏块。
MB0MB1MB2MB3MB4MB5MB6MB7MB8MB9MB10MB11MB12MB13MB14MB15MB16MB17MB18MB19MB20MB21MB22MB23MB24MB25MB26MB27MB28MB29MB30MB31MB32
每一宏块由4个亮度块(Y0-Y3)和2个色差块(CrCb)组成,块的大小是8X8,块是DCT变换的最小单元。
综上的分解应该得到: 352X288=101376 12 X 33 X(8X8X2+16*16*4)=456192
为什么本该理论本该相等的地方却相差四倍。
视频编码器生成的编码是自我格式化的。该数据流可以和其他多种源信号混合传输。视频解码器执行与视频编码器相逆的过程。
如下图所示,H.263对视频输出比特率没有进行限制,输出比特率既可以是恒定的,也可以是变化的。输入的图像信号可以在多种频率下采样处理,这一
采样频率和传输网络的数字时钟是异步的。
H.263采用的是混合编码技术,即用帧间预测减少时域冗余,用变换编码减少残差信号的空域冗余,相应的解码器具有运用补偿能力。
H.263采用的是半像素精度,与H.261采用的全像素精度和一个环路滤波器的设计不同。
被发送的各种符号采用可变长编码技术。
当H.263标准不采用任何高级选项时,称为H.263的基本编码模式,或称为H.263的缺省编码模式。其信源编码器仍然采用可减少时间冗余的帧间编码预测和
可减少空间冗余的DCT变换编码相结合的混合编码方法。
H.263比H.261在以下几个方面做了改进,以便适应极低码率的传输要求:
(1) H.263中包含4个基本模式:非限制运行矢量模式、基于语法的算术编码模式、高级预测模式、PB帧模式。
(2) H.263编码器除了支持H.261中的图像格式CIF和QCIF之外,还增加了另外3种图像格式sub-QCIF、4CIF、16CIF,从而使H.263具有更广的应用范围。
对每种图像采用YUV4:2:0的图像格式。即图像各分量的采样分辩率如下:如果亮度分量按照dx个像素点,每帧dy行采样,则每个色度分量按每行dx/2个像素点,
每帧dy/2行采样。整理成表如下:
图像格式
每行亮度
图样像素(Y)
每帧图像亮度行数(Y)
每行色差取样像素(U、V)每帧图像色差行数(U、V)Sub-QCIF(亚1/4的公共中间格式)128966448QCIF(1/4的公共中间格式)1761448872CIF(公共中间格式)3522881761444CIF(4倍公共中间格式)70457635228816QCIF(16倍公共中间格式)14081152704576
H.263解码器要求能对Sub-QCIF、QCIF格式的图像码流进行解码,但是不强求能对CIF、4CIF、14CIF图像模式的码流进行解码。同样,
H.263编码器应该能够对Sub-QCIF和QCIF中任一格式的图像进行编码,是否支持其它格式由用户自己决定。
视频编码器框图如下,主要包括预测、分块变换和量化几部分。
H.263是基于块的运动编码标准,它采用减少时间冗余的帧间编码技术和减少空间冗余的DCT变换技术,
以获得较高压缩比,它的重要部分有基于块的DCT变换、量化、运动估计与帧间预测及VLC熵编码。
(1)块组(Group Of Block, GOB)、宏块(macroblock)和块(block)。
每帧图像又可以分为多个块组,每个块组包含kX16行,k的取值依赖于图像的格式,(对Sub-QCIF、QCIF、CIF格式,k=1;对于4CIF,k=2;
对于16CIF格式,k=4)。每帧图像包含的块组个数分别是:
Sub-QCIF格式为6;
QCIF格式为9;
CIF、4CIF、16CIF格式为18;
块组的标号顺序是自上而下的,由0开始。
每个块组分成多个宏块,每个宏块中亮度信号Y的分辨率为16*16,色度信号的分辨率为8*8。
每个宏块包含4个亮度块和2个色度块。宏块的标号顺序是先自左向右,再自上而下。宏块数据按宏块顺序发送,块数据也按块顺序发送。
(2)预测。
帧间预测是指图像间的预测,它可以通过运行补偿加以实现。采用了帧间预测方法的编码是帧间编码,没有采用帧间预测编码的为帧内预测。
H.263校标允许在图像层选择编码模式,此时,采用帧内编码模式的图像称为I帧,采用帧间编码模式的图像称为P帧;
P帧图像中还可以在宏块层选择编码,即允许宏块采用帧间编码和帧内编码。
在PB模式下,B帧图像中的所有宏块都采用帧间编码方式,而且部分宏块可以采用双向预测技术,采用双向预测技术的宏块称为B宏块。
(3)运动补偿。
在编码标准的默认框架下,每个宏块使用一个运动矢量作运行补偿,在高级预测模式下,一个宏块可以使用1个或4个运动矢量做运行补偿。
如果启用了PB模式,则每个宏块还要增加一个偏差矢量,用以估计B宏块的运动矢量。
宏块的运动矢量采用了差分编码技术。差分编码值是当前宏块的运动矢量和预测因子之差,而预测因子取自3个候选预测因子中的中值。
3个候选预测因子指3个相临宏块的运行矢量。
(4)量化
量化是指用规定范围内的一个值表示值的一个范围。例如把实数转成最接近的一个整数即是一种量化。量化范围可以被精确地表示成一个整数码,
该整数码在解码过程中用来恢复被量化的那个值,实际值与量化值之间的差值称为量化噪声。
在某些场合,人类视觉系统对量化噪声不敏感,量化噪声可以很大,因此量化可以提高编码效率。
量化在整个视频序列编码中占据很重要的地位,因为是先将DCT变换后的系数矩阵进行量化,然后再对这个量化矩阵编码,
量化后的非零系数越少,编码效果越好,而这是整个编码方案性能良好的主要原因。
也就是说,宏块经过DCT变换后,形成一个大幅度系统集中在低频区域,而高频区域系数都比较小,量化后许多高频系数0, 这使传输码率降低,从而达到压缩目的。
H.263默认框架下,帧内编码块的第一个系数使用统一的量化器,量化步长为8。其他各系数可选择的量化器有31个,但一个宏块内的量化器要统一。
1、2 H.263编码应用程序设计及源代码详细分析1、2、1 应用程序效果展示
应用程序采用单文档框架。
开始编码时先弹出第1帧的lum、Cb、Cr峰值信噪比
转化过程:
转化结束:
首先介绍程序中定义的重要结构体Struct类型的数据结构,
其中MotionVector表示运动矢量,PictImage包含一帧图像的数据,MB_structure包含一个宏块的数据,这些数据结构与H.263标准中的图像构成要素直观地对应,方便了视频数据的读入与处理;
还有一些与控制相关的数据结构,如Pict。
执行编码的主要函数是CodeYUV()。它默认按CIF格式进行编码。它主要完成以下几个工作:
(1) 初始化界面,包括进度条
(2) 打开文件、建立输出文件
(3) 初始化帧间编码参数,为接受YUV文件中的数据的空间、Pict空间、 Bits空间申请空间,
初始化Pict:包括 PB帧中的B-MBs 量化器、运动矢量搜索窗口(即搜索距离)、指明不插入扩展的同步、
图像编码为帧内编码、编码格式为CIF、帧内初始化因子(为8)
(4) 从文件中读取352*288*3/2个数据
(5) 调用FillImage从文件流中先读取一帧图像数据。
(6) 对第一帧数据进行帧内编码,比较原始图像与构建后的图像寻找到信噪比,并显示信噪比 。
(7) 对所有帧数据根据条件选择帧内编码或帧间编码进行编码,并把数据转化为H.263保存在文件中。
判断采用帧内编码或帧间编码的方法是: if(((frame_no-1)%Pbetween)==0) // 帧内编码, 否则采用帧间编码
Pbetween为相邻I帧之间插入的P帧个数,在编码属性对话框中设置(默认设置为19),
这样帧号frame_no为21 41 81 161 321 、、、、、时会采用帧内编码,其它帧采用帧间编码。
如上所说,H.263编码包括帧内编码和帧间编码。现在对它们分别进行说明.
1、2、2、1 帧内编码首先对第一帧进行帧内编码,利用ReadImage()函数从原始视频文件中读入一帧数据,FillIIMage()使用上面读入的数据填充一个PictureImage结构。
文件流的分布如下图:
CodeOneIntra()函数专门对一帧图像进行帧内编码,并返回编码结果。它主要完成以下功能:
(1)申请宏块数据空间、申请存放帧内编码结果的空间、
(2)指定帧内初始化因子、计算图像帧的头大小
(3)把读入的数据分为16*16像素的宏块分别处理(重点)。
CodeOneIntra方法的代码文件为CodeOneIntra.cpp、CodeOneIntra.h
下面对CodeOneIntra()函数中几个重要的功能进行讲解:
对每一宏块,先用FillLumBlock()和FillChromBlock()填充一个MB-Structure结构中的成员变量:lum、Cr、 Cb。
把一帧图像的亮度分量Y作个示意图如下:
把一帧图像的Cr或Cb分量作个示意图如下:
MB-Encode()函数对宏块进行处理,对数据进行DCT变换并对变换系数进行量化,最后返回指向数据块的指针
(即存放在qcoeff中的64*6空间中 前面64*4是存放亮度变换后的结果系数;中间64个是存Cb变换后的结果系数;后面64个是存Cr变换后的结果系数)
CountBitsCoeff()对量化系数进行可变长编码,并把结果输出到输出流中(即输出到.H263文件中去)。
MB_Decode()负责对DCT系数进行反量化和反DCT,重新构建宏块。它的操作与MB_Encode()的操作相反。
1、2、2、2 帧间编码
void CodeOneInter(PictImage *prev,PictImage *curr,PictImage *pr,PictImage *curr_recon,int QP, int frameskip, Bits *bits, Pict *pic)
函数负责当前帧编码,它是帧间编码的核心。 它主要完成以下功能:
(1)对前一帧的编码后还原的数据中的高度数据进行图像/2插值,这是为了在运动估计时进行半像素搜索,以提高运动矢量的计算精度;
(2)初始化运动向量结果数组,为每个编码块标记MV;超出图象边界的MV置为0;
(3)把读入的数据分为16*16像素的宏块分别处理(重点)。
CodeOneInter定义了一个指向三维数组的指针MV,数组元素为MotionVector结构的数据。
后面计算得到的矢量放在这一数组中,以便图像进行预测时应用。
细心的朋友可能看出帧内编码与帧间编码在对每个宏块的处理上的区别了:
(1)在帧内编码的第一步帧内编码直接把宏块数据复制到data,所以变换并量化的数据源是宏块源数据;
而帧间编码却对宏块数据预测P-宏块,所以变换并量化的数据源是宏块数据预测的结果diff;
(2)在帧内编码时对DCT系数进行反量化和反DCT、重新构建宏块 后是直接将将重建宏块data输出到整个图像recon中;
而帧间编码却对DCT系数进行反量化和反DCT、重新构建宏块 后对反变换的结果 重建P图象,然后再将重建结果输出。
下面对帧间编码的CodeOneIntra()函数中几个重要的功能进行讲解:
1、2、2、2、1 InterpolateImage对数据image进行插值1、2、2、2、2 MotionEstimatePicture 完成运动估值
MotionEstimatePicture()计算出前一帧的重建和当前帧图像之间的运动矢量。它也是按照宏块处理的,
MotionEstimatePicture()对当前帧的一个宏块算出运动向量,再填充到前面定义的MV数组中。
计算运动矢量也称为运动估计,是H.263帧间预测编码的核心,在MotionEstimatePicture()函数中,先以要计算的宏块中心为坐标,在前一帧
重建帧中确定一个31X31的搜索区域,分别读入这些块的数据存放到两个数组中。
用SAD_Macroblock()函数计算每一个宏块与当前帧中选定宏块之间的每一像素的亮度差之和,将最小的插入变量sad中,并记录产生该值的宏块,
计算完所有宏块就可以确定宏块与它的运动矢量。
FindHalfPel()函数在整像素搜索的基础上,在上一步结果附近的几个插值点中心计算,选出最优的半像素运动矢量。
如果该宏块每一个像素的亮度分量与亮度平均值之差的绝对值的和小于某一固定值,则该宏块采用帧内编码,否则采用帧间编码方式。
1、2、2、2、3 Predict_P 预测P-宏块
Predict_P()函数利用前一帧的对应宏块与运动矢量构建当前待编码宏块的预测宏块,并将计算出待编码宏块与预测宏块对应像素的插值。
1、2、2、2、4 MB_Recon_P 重建P图象