Chinaunix首页 | 论坛 | 博客
  • 博客访问: 2278583
  • 博文数量: 668
  • 博客积分: 10016
  • 博客等级: 上将
  • 技术积分: 8588
  • 用 户 组: 普通用户
  • 注册时间: 2008-05-29 19:22
文章分类

全部博文(668)

文章存档

2011年(1)

2010年(2)

2009年(273)

2008年(392)

分类:

2009-08-14 10:44:36

14.2.1  MPEG-4编/解码设计与剖析(1)

XviD CODEC以动态库和静态库的形式供应用程序使用。这里以静态库为对象,展现视频编码和解码的设计过程。通过代码分析深入掌握视频编/解码的工作原理。XviD的MPEG-4算法的视频编码和解码在同一个工程中。视频编码使用一个函数,根据传入的参数决定初始化、编码和销毁编码器,视频解码函数调用与之类似。

1.MPEG-4视频编码

XviD的MPEG-4视频编码支持档级,并且绝大部分的视频应用不超过720像素 576像素的分辨率,尽管XviD最高可支持4096像素 4096像素分辨率的视频编码。而实际上在视频监控应用中,CIF(352像素 288像素)分辨率更常用。另外,尽管XviD CODEC支持高档应用:B帧编码、1/4精度像素和全局运动补偿GMC。但是在使用如DSP硬件编码时,这些功能是简化了的,即实现MPEG-4的SP档级。而在PC上开发XviD MPEG-4算法时,这些高档应用可以考虑打开,但是大量额外的计算量与获得的编码性能并不成比例。所以在后面的介绍中及在实际的应用中也确实如此,以MPEG-4的SP档级为主要介绍对象。

MPEG-4视频编码是典型的混合编码技术,即使用变换、量化和编码三步骤对图像数据或图像差值作处理。I帧(关键帧Key Frame)是帧内编码,即对图像数据做编码,利用了图像的空间冗余;P帧编码主要是利用前向预测,对宏块差值编码,利用了图像的时间冗余。统计来看,P帧编码是主流,因为I帧有一定的间隔。P帧编码中的技术核心是搜索与当前宏块的最佳匹配块,即运动估计,搜索的窗口越大,宏块越匹配,但随之运算量也就越大。运动估计技术(Motion Estimation,ME)是任何视频编码算法的核心。这里以图像大小为352像素 288像素、格式为I420、编码I、P帧为例介绍MPEG-4视频编码流程,如图14-1所示。

 
(点击查看大图)图14-1  MPEG-4视频编码流程框图

每个模块的功能简要介绍如下。

从文件中读取一帧图像,大小为352像素×288像素×3/2(包含了亮度和色度)。

以宏块为单位进行编码,一帧图像中所有宏块编码完成,也就完成了对当前帧的编码。

对当前宏块进行运动估计(如果是I帧,则不用),根据SAD值决定匹配块。

对8 8块进行编码,按照其在宏块中排列的顺序进行。首先将当前宏块同参考宏块作差值,然后再对差值进行编码(I帧不用)。

对当前编码块(或者经过运动补偿的差值)进行DCT变换。

对DCT变换后的系数进行量化。

反量化模块是量化模块的逆过程。

反DCT模块是DCT模块的逆过程。

AC/DC预测,即在编码I帧时,对当前宏块的第一行或者第一列系数同它周围的某一块作一个差值,进一步增加零系数,降低比特率。

反DCT后的宏块作运动补偿得到当前宏块的重建值,称为重建宏块。

码流合并模块,形成最后的视频编码码流。码流由码流头开始,然后是具体的帧。在编码之前,模块首先向输出流文件中写入码流头信息。然后写入第一帧的内容,每一帧同样由帧头信息开始,帧头信息同当前的编码内容是紧密相关的,后面的帧数据必须完全符合它规定的一些特性,譬如当前帧的量化值、运动补偿的搜索范围等。接下来是具体的帧数据,并且是按照宏块组织的。宏块内容包含当前宏块的编码信息,例如当前宏块是否编码、编码类型等,接着是运动矢量的数据,最后是具体的6个块的数据。

XviD CODEC为了检测运行平台的CPU,在编/解码器初始化前,给开发者提供了可以指定平台的接口,另外程序也能够自动检测CPU。然后针对不同的平台初始化核心模块的函数指针,编码和解码前都要做该项工作。

     //………………
xvid_gbl_init.cpu_flags = 0; //程序自动检测
xvid_global(NULL, XVID_GBL_INIT, &xvid_gbl_init, NULL);
//………………
int xvid_global(void *handle, int opt, void *param1, void *param2)
{
switch(opt) {
case XVID_GBL_INIT :   //初始化内部的函数指针、VLC码表和图像空间转换函数
return xvid_gbl_init((xvid_gbl_init_t*)param1);
case XVID_GBL_INFO :  //返回编码器的一些信息通知给主机
return xvid_gbl_info((xvid_gbl_info_t*)param1);
case XVID_GBL_CONVERT :  //颜色转换
return xvid_gbl_convert((xvid_gbl_convert_t*)param1);
default :
return XVID_ERR_FAIL;
}
}

上述代码在调用初始化编码前调用一次,主要是初始化内部的函数指针,如通过检测CPU平台,使用MMX或SSE指令优化的函数初始化函数指针,创建VLC熵编码的码表等。主要函数为xvid_gbl_init。

XviD的MPEG-4编码算法实现以一个函数及其3个不同的参数传递来完成。

/*------------------------------编码器操作-------------------------------*/
#define XVID_ENC_CREATE  0 /* 创建编码器实例;0代表成功*/
#define XVID_ENC_DESTROY 1 /* 销毁编码器实例;0代表成功*/
#define XVID_ENC_ENCODE  2 /* 编码一帧图像:返回编码后的字节数
* 0表示该帧不用写入文件(如编码器滞后或延迟) */
/*-----------------------------编码器入口函数-----------------------------*/
extern int xvid_encore(void *handle, int opt, void *param1, void *param2);
编码器的入口函数xvid_encore的实现如下:
int xvid_encore(void *handle, int opt, void *param1, void *param2)
{
switch (opt) {
case XVID_ENC_ENCODE:    //XviD编码一帧图像
return enc_encode((Encoder *) handle,(xvid_enc_frame_t *)
param1,(xvid_enc_ stats_t *) param2);
case XVID_ENC_CREATE:    //XviD创建编码器
return enc_create((xvid_enc_create_t *) param1);
case XVID_ENC_DESTROY:   //XviD销毁编码器
return enc_destroy((Encoder *) handle);
default:
return XVID_ERR_FAIL;
}
}

阅读(1421) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~