xvid的中文简介
XviD是一款开源的MPEG-4视频编解码器。XviD的API接口定义得非常清晰,其三个核心接口函数(xvid_global(),xvid_decore()和xvid_encore())和插件函数都具有统一的形式,大大简化了程序员的工作。本文将简单介绍XviD的三个核心API接口函数,对于Xvid的插件函数未做说明,计划在本文下一版中增加。
1 版本
XviD的版本号定义为$major.$minor.$patch的形式。当版本更新时:
如果API接口没有发生改变,则增加$patch;
如果API接口发生了改变,但仍然向后兼容,则增加$minor;
如果API接口发生了重大变化,则增加$major。
很多XviD结构体都包含一个version成员,用于指定所采用的XviD的版本。正确的初始化方法是:先将结构体全部清空为0,然后再设置version成员。如下所示:
memset(&struct,0,sizeof(struct));
struct.version = XVID_VERSION;
与XviD版本有关的宏定义为:
#define XVID_MAKE_VERSION(a,b,c) ((((a)&0xff)<<16) | (((b)&0xff)<<8) | ((c)&0xff))
#define XVID_VERSION_MAJOR(a) ((char)(((a)>>16) & 0xff))
#define XVID_VERSION_MINOR(a) ((char)(((a)>> 8) & 0xff))
#define XVID_VERSION_PATCH(a) ((char)(((a)>> 0) & 0xff))
#define XVID_MAKE_API(a,b) ((((a)&0xff)<<16) | (((b)&0xff)<<0))
#define XVID_API_MAJOR(a) (((a)>>16) & 0xff)
#define XVID_API_MINOR(a) (((a)>> 0) & 0xff)
#define XVID_VERSION XVID_MAKE_VERSION(1,1,2)
#define XVID_API XVID_MAKE_API(4, 1)
XviD中存在两个版本,一个是XviD库本身的版本,即XVID_VERSION;另一个是
XviD应用编程接口(API)简介(v0.1) - 2 -
XviD的API接口的版本,即XVID_API。XVID_VERSION定义为一个24位的无符号整数;XVID_API定义为一个16位的无符号整数。
XVID_MAKE_VERSION(a,b,c)宏的作用是生成XVID_VERSION,其中a、b、c分别是XviD版本号中的$major、$minor和$patch。
XVID_VERSION_MAJOR(a)用于从XVID_VERSION中抽取出$major;XVID_VERSION_MINOR(a)用于从XVID_VERSION中抽取出$minor;XVID_VERSION_PATCH(a)用于从XVID_VERSION中抽取出$patch。
2 错误码
所有XviD函数都以返回小于0的值表明出现了错误。定义的错误码如下:
#define XVID_ERR_FAIL -1 /* general fault */
#define XVID_ERR_MEMORY -2 /* memory allocation error */
#define XVID_ERR_FORMAT -3 /* file format error */
#define XVID_ERR_VERSION -4 /* structure version not supported */
#define XVID_ERR_END -5 /* encoder only; end of stream reached */
XVID_ERR_FAIL表示一般性错误;XVID_ERR_MEMORY表示内存分配错误;XVID_ERR_FORMAT表示文件格式错误;XVID_ERR_VERSION表明程序中使用了不再被支持的结构体版本;XVID_ERR_END是编码器独有的错误码,表示已经到达流末尾。
3 色场空间
XviD中定义的色场空间如下:
#define XVID_CSP_PLANAR (1<< 0) /* 4:2:0 planar (==I420, except for pointers/strides) */
#define XVID_CSP_USER XVID_CSP_PLANAR
#define XVID_CSP_I420 (1<< 1) /* 4:2:0 planar */
#define XVID_CSP_YV12 (1<< 2) /* 4:2:0 planar */
#define XVID_CSP_YUY2 (1<< 3) /* 4:2:2 packed */
#define XVID_CSP_UYVY (1<< 4) /* 4:2:2 packed */
#define XVID_CSP_YVYU (1<< 5) /* 4:2:2 packed */
#define XVID_CSP_BGRA (1<< 6) /* 32-bit bgra packed */
#define XVID_CSP_ABGR (1<< 7) /* 32-bit abgr packed */
#define XVID_CSP_RGBA (1<< 8) /* 32-bit rgba packed */
#define XVID_CSP_ARGB (1<<15) /* 32-bit argb packed */
#define XVID_CSP_BGR (1<< 9) /* 24-bit bgr packed */
#define XVID_CSP_RGB555 (1<<10) /* 16-bit rgb555 packed */
#define XVID_CSP_RGB565 (1<<11) /* 16-bit rgb565 packed */
#define XVID_CSP_SLICE (1<<12) /* decoder only: 4:2:0 planar, per slice rendering */
#define XVID_CSP_INTERNAL (1<<13) /* decoder only: 4:2:0 planar, returns ptrs to internal buffers */
#define XVID_CSP_NULL (1<<14) /* decoder only: dont output anything */
#define XVID_CSP_VFLIP (1<<31) /* vertical flip mask */
尽管XviD定义的色场空间比较多,但实际上常用的只有XVID_CSP_I420、XVID_CSP_YV12、XVID_CSP_BGR、XVID_CSP_RGB555、XVID_CSP_RGB565这样几种。
作者个人的观点:XVID_CSP_PLANAR、XVID_CSP_USER、XVID_CSP_I420、XVID_CSP_YV12都属于YUV4:2:0色场空间,采用YUV平面格式存放;XVID_CSP_YUY2、XVID_CSP_UYVY、XVID_CSP_YVYU都属于YUV4:2:2色场空间,采用YUV紧缩格式存放。XviD似乎没有提供对YUV4:4:4和YUV4:1:1色场空间的支持——也可能是MPEG-4标准不支持。无论如何,常用的YUV色场空间是YUV4:2:0。
4 profile和level定义
XviD中定义了对三种MPEG-4 Profile@Level组合的支持:Simple(S)、Advanced Realtime Simple(ARTS)、Advanced Simple(AS)。
#define XVID_PROFILE_S_L0 0x08 /* simple */
#define XVID_PROFILE_S_L1 0x01
#define XVID_PROFILE_S_L2 0x02
#define XVID_PROFILE_S_L3 0x03
#define XVID_PROFILE_ARTS_L1 0x91 /* advanced realtime simple */
#define XVID_PROFILE_ARTS_L2 0x92
#define XVID_PROFILE_ARTS_L3 0x93
#define XVID_PROFILE_ARTS_L4 0x94
#define XVID_PROFILE_AS_L0 0xf0 /* advanced simple */
#define XVID_PROFILE_AS_L1 0xf1
#define XVID_PROFILE_AS_L2 0xf2
#define XVID_PROFILE_AS_L3 0xf3
#define XVID_PROFILE_AS_L4 0xf4
XviD没有定义对MPEG-4中其它Profile@Level组合的支持。
5 像素幅型比(Pixel Aspect Ration)
像素幅型比表示的是屏幕上一个像素点的宽度和高度的比值,简写为PAR(即Pixel Aspect Ratio的缩写)。XviD定义了对如下几种标准的像素幅型比的支持:
#define XVID_PAR_11_VGA 1 /* 1:1 vga (square), default if supplied PAR is not a valid value */
#define XVID_PAR_43_PAL 2 /* 4:3 pal (12:11 625-line) */
#define XVID_PAR_43_NTSC 3 /* 4:3 ntsc (10:11 525-line) */
#define XVID_PAR_169_PAL 4 /* 16:9 pal (16:11 625-line) */
#define XVID_PAR_169_NTSC 5 /* 16:9 ntsc (40:33 525-line) */
#define XVID_PAR_EXT 15 /* extended par; use par_width, par_height */
视频应用中常见的像素幅型比有两种:4:3和16:9,后者更具有剧场效果。PAL和NTSC是两种电视标准(另外一种电视标准是SECAM),这两种电视标准都是隔行扫描时代的产物。PAL规定的场率是50场/秒(即25帧/秒),扫描线行数是525行;NTSC规定的场率是60场/秒(即30帧/秒),扫描线行数是625行。
6 帧类型
XviD定义了如下帧类型:
#define XVID_TYPE_VOL -1 /* decoder only: vol was decoded */
#define XVID_TYPE_NOTHING 0 /* decoder only (encoder stats): nothing was decoded/encoded */
#define XVID_TYPE_AUTO 0 /* encoder: automatically determine coding type */
#define XVID_TYPE_IVOP 1 /* intra frame */
#define XVID_TYPE_PVOP 2 /* predicted frame */
#define XVID_TYPE_BVOP 3 /* bidirectionally encoded */
#define XVID_TYPE_SVOP 4 /* predicted+sprite frame */
在解码的时候,常见的做法是根据帧类型的不同而进行不同的处理。XVID_TYPE_VOL、XVID_TYPE_IVOP、XVID_TYPE_PVOP、XVID_TYPE_BVOP较常用。作者暂不清楚XVID_TYPE_SVOP的含义。
7 xvid_global()函数
函数原型:
int xvid_global(void *handle, int opt, void *param1, void *param2);
功能:
全局初始化;
获取XviD和硬件功能信息(全局信息);
色场空间转换。
参数:
handle,是一个句柄,代表着一个xvid global操作实例,
opt,指定要执行的操作,对应于上面三种功能,opt分别可取XVID_GBL_INIT、XVID_GBL_INFO、XVID_GBL_CONVERT这样三个值;
param1,是对应操作的入口参数或者出口参数。当opt为XVID_GBL_INIT时,param1是入口参数,应当为一个xvid_gbl_init_t类型的指针;当opt为XVID_GBL_INFO时,param1是出口参数,应当为一个xvid_gbl_info_t类型的指针;当opt为XVID_GBL_CONVERT时,param1是入口参数,应当为一个xvid_gbl_convert_t类型的指针;
param2,这个参数将被忽略,通常应当设置为NULL。
返回值:
成功:返回0;
失败:返回相应错误码(<0)。
7.1 全局初始化
当xvid_global()函数的第二个参数opt为XVID_GBL_INIT时,xvid_global()函数对整个XviD进行初始化。初始化的内容包括要用到CPU的哪些功能以及要采用哪一个调试级别。XviD的灵活之处在于:它既可以自行确定使用CPU的哪些功能,也能够让编程者来决定如何发掘CPU的处理能力。
opt参数为XVID_GBL_INIT时,xvid_global()函数的param1参数应该为一个xvid_gbl_init_t类型的指针。xvid_gbl_init_t定义为:
/* XVID_GBL_INIT param1 */
typedef struct {
int version;
unsigned int cpu_flags; /* [in:opt] zero = autodetect cpu; */ /* XVID_CPU_FORCE|{cpu features} = force cpu features */
int debug; /* [in:opt] debug level */
} xvid_gbl_init_t;
前面说过,XviD的API接口中所有的结构体类型都包含一个version成员,应当将其设置为所采用的XviD的版本。
对于cpu_flags成员,当其值为0时,将由XviD自动探测所用CPU的处理能力。当想强制使用CPU的某种特殊功能时,必须同时为cpu_flags指定XVID_CPU_FORCE标志和相关的功能标志,比如,要强制使用IA32体系结构的MMX指令,就必须将cpu_flags进行如下设置:
struct.cpu_flags = XVID_CPU_FORCE | XVID_CPU_MMX;
XviD支持的CPU功能列表如下所示,其中,XVID_CPU_ALTIVEC是专门针对PPC体系结构的。其它的大部分功能都是针对IA32体系结构的。
#define XVID_CPU_FORCE (1<<31) /* force passed cpu flags */
#define XVID_CPU_ASM (1<< 7) /* native assembly */
/* ARCH_IS_IA32 */
#define XVID_CPU_MMX (1<< 0) /* mmx : pentiumMMX,k6 */
#define XVID_CPU_MMXEXT (1<< 1) /* mmx-ext : pentium2, athlon */
#define XVID_CPU_SSE (1<< 2) /* sse : pentium3, athlonXP */
#define XVID_CPU_SSE2 (1<< 3) /* sse2 : pentium4, athlon64 */
#define XVID_CPU_3DNOW (1<< 4) /* 3dnow : k6-2 */
#define XVID_CPU_3DNOWEXT (1<< 5) /* 3dnow-ext : athlon */
#define XVID_CPU_TSC (1<< 6) /* tsc : Pentium */
/* ARCH_IS_PPC */
#define XVID_CPU_ALTIVEC (1<< 0) /* altivec */
xvid_gbl_init_t结构体中的debug成员用来表明XviD的调试级别,不同的调试级别表明了不同的出错原因。实际上,这和Linux内核编程中的打印函数printk()很相似。XviD定义了如下调试级别:
#define XVID_DEBUG_ERROR (1<< 0)
#define XVID_DEBUG_STARTCODE (1<< 1)
#define XVID_DEBUG_HEADER (1<< 2)
#define XVID_DEBUG_TIMECODE (1<< 3)
#define XVID_DEBUG_MB (1<< 4)
#define XVID_DEBUG_COEFF (1<< 5)
#define XVID_DEBUG_MV (1<< 6)
#define XVID_DEBUG_RC (1<< 7)
#define XVID_DEBUG_DEBUG (1<<31)
由于每一种调试级别实际上都是以一个标志位来表示的,因此实际上可以指定多重调试级别。
下面是一个采用xvid_global()函数进行全局初始化的示例代码:
xvid_gbl_init_t xvid_gbl_init;
/* Clear the structure with zeros */
memset(&xvid_gbl_init, 0, sizeof(xvid_gbl_init_t));
/* Version */
xvid_gbl_init.version = XVID_VERSION;
/* CPU setting */
xvid_gbl_init.cpu_flags = XVID_CPU_FORCE | XVID_CPU_MMX;
/* Debug setting */
xvid_gbl_init.debug = XVID_DEBUG_ERROR | XVID_DEBUG_COEFF;
/* Take in effect */
xvid_global(NULL, XVID_GBL_INIT, &xvid_gbl_init, NULL);
简单说明一下上述代码:首先将xvid_gbl_init结构体清零;然后依次设置版本、CPU功能、调试级别,也就是分别给三个结构体成员赋值。这里,指定采用CPU的MMX指令,同时,指定了两个调试级别:XVID_DEBUG_ERROR和XVID_DEBUG_COEFF。最后,调用xvid_global()使这些设置生效。注意到xvid_global()函数的第一个参数handle和最后一个参数param2都被置为NULL指针。
7.2 获取全局信息
当xvid_global()函数的第二个参数opt为XVID_GBL_INFO时,xvid_global()函数将用于获取xvid处理器硬件信息。xvid_global()函数的第三个参数param1为出口参数,指向一个xvid_gbl_info_t类型的结构体。
/* XVID_GBL_INFO param1 */
typedef struct {
int version;
int actual_version; /* [out] returns the actual xvidcore version */
const char * build; /* [out] if !null, points to description of this xvid core build */
unsigned int cpu_flags; /* [out] detected cpu features */
int num_threads; /* [out] detected number of cpus/threads */
} xvid_gbl_info_t;
在调用xvid_global()函数获取信息之前,应该设置xvid_gbl_info_t结构体的version成员为当前的XviD版本,而在实际的输出结果中,actual_version表示的是XviD的实际版本;如果build指针不为空,则是指向一个描述字符串以表明xvid的构建版本;cpu_flags用于表明CPU能够支持的功能集合;num_threads表示线程数(作者未能搞清楚这个变量的含义)。
一个通过xvid_global()函数获取XviD版本信息和CPU信息的示例程序如下所示:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "xvid.h"
int
main(void)
{
xvid_gbl_info_t xvid_gbl_info;
/* Clear xvid_gbl_info with 0s */
memset(&xvid_gbl_info, 0, sizeof(xvid_gbl_info_t));
/* Version */
xvid_gbl_info.version = XVID_VERSION;
/* Take effect */
xvid_global(NULL, XVID_GBL_INFO, &xvid_gbl_info, NULL);
/* print */
printf("actual version: %d.%d.%d\n",
XVID_VERSION_MAJOR(xvid_gbl_info.actual_version),
XVID_VERSION_MINOR(xvid_gbl_info.actual_version),
XVID_VERSION_PATCH(xvid_gbl_info.actual_version));
if (xvid_gbl_info.cpu_flags | XVID_CPU_MMX)
printf("CPU: MMX\n");
if (xvid_gbl_info.build)
printf("build: %s\n", xvid_gbl_info.build);
printf("threads: %d\n", xvid_gbl_info.num_threads);
return (0);
}
编译上述程序,运行结果如下:
[root@cyc test]# ./xvid_test
actual version: 1.1.2
CPU: MMX
build: xvid-1.1.2
threads: 0
7.3 色场空间转换
个功能是完成色场空间的转换。此时 xvid_global()函数的第二
个参数 opt 为 XVID_GBL_CONVERT,第三个参数 param1 应指向一个 xvid_gbl_convert_t
类型
xvid_global()函数的第三
的结构体。xvid_gbl_convert_t定义为:
/* X */
VID_GBL_CONVERT param1
typedef struct {
int version;
xvid_image_t input; /* [in] input image & colorspace */
xvid_image_t output; /* [in] output image & colorspace */
int width; /* [in] width */
int height; /* [in] height */
int interlacing; /* [in] interlacing */
} id_gbl_convert_t; xv
解释一下xvid_gbl_covert_t的各个成员:ver n sion 的含义不用再解释了,前面已多次说
以及相应的色场空间;output 表示输出图像以及相应的色场空间;
width 表示要转换的图像的宽度;height 表示要转换的图像的高度;interlacing 是一个标志,
用来
明;input表示输入图像
表明图像是否是隔行扫描图像。xvid_gbl_convert_t中的所有成员都是输入参数。input和output都是xvid_image_t类型的变量,在XviD中将xvid_image_t结构体定义为:
type
def struct { int csp; /* [in] colorspace; or with XVID_CSP_VFLIP to perform vertical fl
ip */
void * plane[4]; /* [in] image plane ptrs */
int stride[4]; /* [in] image stride; "bytes per row"*/ } xvid_image_t;
xvid_image_t结构体的第一个成员csp表示色场空间,第二个成员 plane 是一个 4 元素
中的每一个指针指向一个输出色场平面;第四个参数 stride 也是一个 4 元
素的数组,数组中的每一个元素都用于指明在相应色场平面上的步长为多少,所谓步长实际
上就
8 xvid_decore 函数
ecore()。xvid_decore()的函数原型如下:
的指针数组,数组
是指一行像素点的个数。(示例程序暂略)
()
XviD解码的核心函数是xvid_d
int xvid_decore(void *handle, int opt, void *param1, void *param2);
xvid_decore()函数的几个参数的含义分别是:
。opt 可取如下值之一:
XVID_DEC_CREATE、XVID_DEC_DESTROY、XVID_DEC_DECODE。和
XviD 解码实例
DE),在解码
)。
比
handle,是一个句柄,用来代表一个XviD解码操作实例;
opt,指定xvid_decore()函数要执行的操作
xvid_global()函数不同,在执行解码操作时,必须先创建一个
(XVID_DEC_CREATE),然后进入解码循环(XVID_DEC_DECO循环完成之后应当销毁一开始创建的XviD解码实例(XVID_DEC_DESTROYparam1,是一个通用指针类型,具体应该指向什么根据opt参数的取值而定,如,当opt的值为XVID_DEC_CREATE时,param1应该指向一个xvid_dec_create_t类型的结构体。对于opt为XVID_DEC_CREATE和XVID_DEC_DECODE的情
形,param1都是必要参数。对于opt为XVID_DEC_DESTROY的情况,param1参数将被忽略,通常设置为NULL即可。
下面就 的。
8.1 创建
在使用 XviD 进行解码之前,必须先创建 XviD 解码实例。创建 xvid 解码实例的具体做
te_t 类型的结构体,然后将其地址做为 param1 参数传
递给 xvid_decore()函数,其中,opt 参数指定为 XVID_DEC_CREATE。第一个参数 handle
和 param
param2,是一个可选参数,只在opt为XVID_DEC_DECODE的时候有效,指向一个xvid_dec_stats_t类型的结构体。依次来看看xvid_decore()函数都是如何调用
xvid解码实例
法是:首先初始化一个xvid_dec_crea
2参数都可以指定为NULL。在xvid中,xvid_dec_create_t定义如下: /* XVID_DEC_CREATE param 1
age w hen the dimensions are
imidth & height may be specified here w
know in ad n vance. */
typedef struct {
int version;
int width; /* [in:opt] image width */
int height; /* [in:opt] image width */
void * handle; /* [out] decore context handle */
} xvid_dec_create_t;
在xvid_dec_creat_t的几个成员中: e
采用的 XviD 的版本,按照前面的方式初始化即可;
width,是解码后的图像的宽度,如果解码之前已经事先知道,可设置,否则设
;
xvid_decore()
成之后再从 xvid_dec_create_t 的 handle 成员
示例:
version,是
置为0即可。width是输入参数
height,是解码后的图像的高度,如果解码之前已经事先知道,可设置,否则设
置为0即可。height是输入参数; handle,是一个句柄。之所以有这个成员,其原因是:通常在调用
函数创建XviD解码实例的时候,都将xvid_decore()函数的第一个参数handle设置为NULL,在创建xvid解码实例完
中得到这个句柄。此后在调用xvid_decore()函数进行解码的时候就可以使用这个句柄了。Handle成员是输出参数。
xvid_dec_create_t xvid_dec_create;
void *d ndle = NULL;
ec_ha
/* Reset the structure with zeros */
memset(&xvid_dec_create, 0, sizeof(xvid_dec_create_t));
/* Version */
xvid_dec_create.version = XVID_VERSION;
/*
* Image dimensions -- set to 0, xvidcore will resize when ever it is
* needed
*/ xvid_dec_create.width = 0;
xvid_dec_create.height = 0;
ret = xvid_decore(NULL, XVID_DEC_CREATE, &xvid_dec_create, NULL);
dec_handle = xvid_dec_create.handle;
上面的这段示例代码定义了一个句柄 dec_handle(其实是一个无类型指针),在调用
vid_decore()函数完成 XviD 解码实例的创建工作之后,通过
x
dec_handle = xvid_dec_create.handle;
将创建的句柄指定给了dec_handle。
8.2 解码
开始真正的解码了。解码也是通过 xvid_decore()
函数来完成的。解码要用到两个结构体类型:xvid_dec_frame_t 和 xvid_dec_stats_t,
c_fram _t 指 定 给 xvid_decore() 函 数 的 param1 参 数 , xvid_dec_stats_t 指 定 给
数的 param2 参数。尽管 param2 是可选参数,但是通常情况下都是应该指定
的,因为通过它才能知道解码过程的状态。此外,xvid_decore()函数的第一个参数 handle 应
该为
_
在创建了解码实例之后,接下来就是
xvid_deexvid_decore()函
创建XviD解码实例时返回的xvid_dec_create_t类型的结构体中的handle成员。在进行解码操作时,xvid_decore()函数的opt参数应当设置为XVID_DEC_DECODE。XviD对xviddec_frame_t类型的定义如下: typedef struct { int version; int general; /* [in:opt] general flags */
from)*/
void *bitstream; /* [in] bitstream (read
int length; /* [in] bitstream length */
xvid_image_t output; /* [in] output image (written to) */
/* ------- v1.1.x ------- */
int brightness; /* [in] brightness offset (0=none) */
} id_dec_frame_t; xv
xvid_dec_frame_t中各个成员的作用简单说明如下:
general,是一个可选输入参数。这个参数的取值可以是下面这些标志取或的结果:
/* general flags */
#define XVID_LOWDELAY (1<<0) /* lowdelay mode */
#def break in stream */
ine XVID_DISCONTINUITY (1<<1) /* indicates
#defin V
e XID_DEBLOCKY (1<<2) /* perform luma deblocking */
#define XVID_DEBLOCKUV (1<<3) /* perform chroma deblocking */
#define XVID_FILMEFFECT (1<<4) /* adds film grain */
#define XVID_DERINGUV (1<<5) /* perform chroma deringing, requires debloc
king to work */
#define XVID_DERINGY (1<<6) /* perform luma deringing, requires deblocki
ng to work */
#define XVID_DEC_FAST (1<<29) /* disable postprocessing to decrease cpu usa
ge *todo* */ #define XVID_DEC_DROP (1<<30) /* drop bframes to decrease cpu usage *todo
* */ #define XVID_DEC_PREROLL (1<<31) /* decode as fast as you can, don't even sh
ow output *todo* */
这些标志控制着解码器的某些功能:
XVID_LOWDELAY 以低延迟模式解码;
XVID_DEBLOCKY 去除亮度块状化(猜测);
除色差块状化(猜测);
;
图像畸变),要求开启去除
去除块状化标志;
用,暂未实现;
EROLL 尽可能快地解码,甚至不显示输出。
通常 的 些
it
n
ut id 的输出流,
XVID_DISCONTINUITY 以非连续模式解码;
XVID_DEBLOCKUV 去
XVID_FILMEFFECT 添加影片效果(猜测)
XVID_DERINGUV 去除色差“振铃”(一种
块状化标志;
XVID_DERINGY 去除亮度“振铃”,要求开启
XVID_DEC_FAST 禁用后处理以减少CPU使
XVID_DEC_DROP 丢弃B帧以减少CPU使用,暂未实现; XVID_DEC_PR
情况下,如果不需要上面这功能,可以将general设置为0。
bstream,是一个输入参数,指向要解码的输入流;
legth,是一个输入参数,表明bitstream所指向的输入码流的长度;
oput,输入参数,是一个xv_image_t类型的变量,用来指定解码后
xvid_image_t类型前面已有说明,这里再次列举如下:
typedef struct {
in sp
t c; /* [in] colorspace; or with XVID_CSP_VFLIP to perform vertical fl
ip */
void *
plane[4]; /* [in] image plane ptrs */
int stride[ [in] image stride; "bytes per row"*/ 4]; /*
} xvid_image_t;
csp,是一个输入参数,指明输出应当采用的色场空间,如果想将输入图像进
行垂直翻转,那么可以将 csp 指定为 XVID_CSP_VFLIP;
指向要输出的颜色平面——最多可以有
个输出缓冲区,用于存放相
色彩平面。如果解码后的输出图像只有一个色彩平面,那么只使用
plane[0];
个平面,可以为
xvid_deco
plane,输入参数,是一个数组,用来
4个输出平面。实际上,一个plane元素就指向一
应的
stride,输入参数,也是一个数组,用来指出每一个平面的步长,简单说步长就是一行像素点所占的空间大小,以字节为单位。如果有多
每个平面设置一个步长值。re()函数的另一个可选参数为xvid_dec_stats_t类型的指针:
/* XVID_DEC param2 :: optional */ _DECODE
typedef struct
{
int versio
n;
t
int type; /* [ou] output data type */
union{
struct { /* type>0 {XVID_TYPE_IVOP,XVID_TYPE_PVOP,X
VID_TYPE_BVOP,XVID_TYPE_SVOP} */
int general; /* [out] flags */
int time_base; /* [out] time base */
int time_increment; /* [out] time increment */
/* XXX: external deblocking stuff */ int * qscale; /* [out] pointer to quantizer table */
int qscale_stride; /* [out] quantizer scale stride */
} p; vo
stru/* XVID_TYPE_ */ ct { VOL
int general; /* [out] flags */
int width; /* [out] width */
int height; /* [out] height */ int par; /* [out] pixel aspect ratio (refer to XVID_PAR_xxx a
bove) */
int par_width; /* [out] aspect ratio width [1..255] */
int par_height; /* [out] aspect ratio height [1..255] */
} l; vo } ta; da
} idec_stats_t; xv _d
xvid_dec_stats_t 类型中最重要的部分是 data,这是一个联合,联合的两个成员分别是两
结 体 结 体 vol 则描述
类型中,type 成员的作用是用来确定解出来的帧的类型,有关帧的类型
type 的值为 XVID_TYPE_VOL 时,data 联合中存放的是 vol;当 type 的
VOP、XVID_TYPE_PVOP、XVID_TYPE_BVOP、XVID_TYPE_SVOP
之一时,data 联合中存放的是 vop。
以像素为单位,
的 NTSC 或者 PAL 幅型比,则 par_width 和 par_height
对 v
隔;
长(具体含义未搞清楚)。
图像的大小,可以在创建 XviD 解码实例的时候指定
解码后 图 可以在解码的过程中知道解出
来的图像的大小,这就是通过 xvid_dec_stats_t 中的 vol 结构体来实现的。
示例代码:
个构,构体vop描述了一个视频对象平面(Video Object Plane);而结构
了一个视频对象层(Video Object Layer)。
xvid_dec_stats_t
前面已做说明。当
值为XVID_TYPE_I
首先来解释vol结构体中的各个成员: general中保存的是解码器解码时所采用的标志; width是解码出来的图像的宽度,
height是解码出来的图像的高度,以像素为单位; par是解码出来的图像的像素幅型比; 如果解码后的图像不是标准
就是实际所采用的像素幅型比。
于op结构体中的各个成员:
general中保存的是解码器解码时所采用的标志;
time_base是相对于开始解码时的时间长度(猜测);
time_increment是相对于上一帧的时间间
qscale指向外部提供的量化表(猜测); qscale_stride代表量化器的缩放步
前面说过,如果事先知道解出来的
的像的大小;如果不知道的话,也没有关系,XviD
#defin
e IN_BITSTREAM_SIZE 1024
#define
OUT_BITSTREAM_SIZE 1024
#define STRIDE 352
unsigned char istream[IN_BITSTREAM_SIZE]; unsigned char ostream[OUT_BITSTREAM_SIZE];
int i IN_BITSTREAM_SIZE;
stream_size =
xvid_dec_frame_t xvid_dec_frame;
xvid_dec_stats_t xvid_dec_stats;
/* Reset all structures */
memset(&xvid_dec_frame, 0, sizeof(xvid_dec_frame_t));
memset(&xvid_dec_stats, 0, sizeof(xvid_dec_stats_t));
/* Set version */
xvid_dec_frame.version = XVID_VERSION;
xvid_dec_stats.version = XVID_VERSION;
/* No general flags to set */
xvid_dec_frame.general = 0;
/* Input stream */
xvid_dec_frame.bitstream = istream;
xvid_dec_frame.length = istream_size;
/* Output frame structure */
xvid_dec_frame.output.plane[0] = ostream;
xvid_dec_frame.output.stride[0] = STRIDE;
xvid_dec_frame.output.csp = XVID_CSP_UYVY;
/* submit to xvide decode core */
xvid_decore(dec_handle, XVID_DEC_DECODE, &xvid_dec_frame, &xvid_dec_stats);
在 xvid_decore()函数中,dec_handle 是上一节创建 XviD 解码实例时得到的那个句柄。
文件或者其它媒介(比如网络)读取输入码流的过程,解码得
:2:2 紧缩格式),采用单平面输出。另外,通常
据解码的状态决定对解码得到的码流如何处理,
显示设备输出或者保存到文件中。而如果
码得到的是 vol,那么可能会根据需要调整输出图像缓冲区的大小,等等。
上面的实例代码中没有加入从
到的图像采用的是UYVY格式(一种YUV 4
情况下的做法是在一个循环中不断解码,根
比如,如果解码正常,那么可能会将得到图像通过
解
8.3 销毁xvid解码实例
销毁XviD解码实例比较简单。方法如下:将xvid_decore()函数的第一个参数handle设为创建XviD解码实例后得到的句柄;第二个参数opt设置为XVID_DEC_DESTROY;参数param1和param2都设为NULL。销毁XviD解码实例之后,不能再通过其对输入码流进行解码。示例代码:
xvid_decore(dec_handle, XVID_DEC_DESTROY, NULL, NULL);
上述代码中的第一个参数 dec_handle 是创建 XviD 解码实例之后得到的。
9 xvid_encore()函数
-4 标准规定的码流。与
xvid_decore()函数的工作流程一样:xvid_encore()函数的使用方法也是先创建一个 XviD 编码
实例 建的 XviD
编码实例。不过,与 xvid_decore()相比,xvid_encore()函数的使用要复杂一些,主要原因是
vid_encore()函数原型定义如下:
xvid_encore()是对输入的原始图像进行编码,输出符合MPEG
;然后执行实际的编码操作;最后,在所有的解码过程都结束之后,销毁所创
编码过程的参数设置要麻烦一些。x
int xvid_encore(void *handle, int opt, void *param1, void *param2);
xvid_encore()函数的几个参数的含义分别是: handle,编码实例的句柄,用来代表一个xvid编码操作实例; opt,指定xvid_encore()函数要执行的操作。opt可取如下值之一:XVID_ENC_CREATE、XVID_ENC_DESTROY、XVID_ENC_ENCODE。在执行
编码操作时,必须先创建一个 编码实例( CREATE),然后进
应当销毁所创建的
)。
,是一个通用指针类型,具体应该指向什么根据 opt 参数的取值而定。当
XVID_ENC_CREATE 时,param xv nc_create_t 类
ODE 的情形,
xvid_dec_sta
返 值
函数返回输出的字节数表示执行成功;
示执行失败,对于 opt 为
XVID_ENC_ENCODE 的情形,xvid_encore()函数返回 0 表示该帧不应该被写入;
下面就来依次看看
9.1 创建
在 创 建 数 设 为一 个
xvid_enc_c
XviDXVID_ENC_入编码循环(XVID_ENC_ENCODE),在编码循环完成之后
XviD编码实例(XVID_ENC_DESTROY
param1opt的值为1应该指向一个id_e
型的结构体。对于opt为XVID_ENC_CREATE和XVID_ENC_ENCparam1都是必要参数。对于opt为XVID_ENC_DESTROY的情况,param1应当为NULL。param2,是一个可选参数,只在opt为XVID_ENC_ENCODE的时候有效,指向一个ts_t类型的结构体。
回: 成功:对于opt为XVID_ENC_CREATE和XVID_ENC_DESTROY的情形,xvid_encore()函数返回0表示成功,对于opt为XVID_ENC_ENCODE的情形,xvid_encore()
失败:对于opt为XVID_ENC_CREATE和XVID_ENC_DESTROY的情形,xvid_encore()函数返回小于0的错误码表
xvid_encore()函数是如何完成不同的功能的。xvid编码实例
XviD编码实例时,应当将xvid_encore()函数的param1参reate_t类型的结构体的地址。xvid_enc_create_t类型定义如下:
/*--------
--------------------------------------------------------------------
* xvid_enc_create_t structure definition
*
* T
his structure ispassed as param1 during an instance creation (operation * XVID_ENC_CREATE)
*--------------------------------------------------------------------------*/
typedef struct {
int version;
int profile; /* [in] profile@level; refer to XVID_PROFILE_xxx */
int width; /* [in] frame dimensions; width, pixel units */
int height; /* [in] frame dimensions; height, pixel units */
int num_zones; /* [in:opt] number of bitrate zones */
xvid_enc_zone_t * zones; /* ^^ zone array */
int num_plugins; /* [in:opt] number of plugins */
xvid_enc_plugin_t * plugins; /* ^^ plugin array */
int num_threads; /* [in:opt] number of threads */
int max_bframes; /* [in:opt] max sequential bframes (0=disable bframe
s) */
int global; /* [in:opt] global flags; controls encoding behavior */
/* --- vol-based stuff; included here for convenience */
int fincr; /* [in:opt] framerate increment; set to zero for variabl
e merate */ fra
int fbase; /* [in] framerate base frame_duration = fincr/fbase se
conds*/
/* ---------------------------------------------- */
/* --- vop-based; included here for convenience */
int max_key_interval; /* [in:opt] the maximum interval between key frames */ int frame_drop_ratio; /* [in:opt] frame dropping: 0=drop none... 100=drop a
ll */
int bquant_ratio; /* [in:opt] bframe quantizer multipier/offeset; used to
dede bframes quant when bquant==-1 */ ci
int bquant_offset; /* bquant = (avg(past_ref_quant,future_ref_quant)*bqua
nt_ratio + bquant_offset) / 100 */
int min_quant[3]; /* [in:opt] */ int max_quant[3]; /* [in:opt] */
/* ---------------------------------------------- */
void *handle; /* [out] encoder instance handle */
} id_enc_create_t; xv
下面对 xvid_enc_create_t 中的成员逐一进行简要说明:
同前;
level 组合,XviD 编码器将据此决定如
间进行折衷。关于 profile 和 level 的定
设定为 XVID_PROFILE_S_L0,就表明
码。profile 是一个
width,为输入帧的宽度,以像素为单位。width 是一个输入参数;
,这是一个可选输入参数;
num_threads,线程数,(作用未知),这是一个可选输入参数;
es,最大 B 帧数,设为 0 禁用 B 这是一个可选输入参数;
global,全局标志位,这些标志位控制着 XviD 编码器的行为。这是一个可选输
version,应当设置为所用的xvid的版本,
profile,应当设置为准备采用的profile和
何在编码质量和压缩效率以及运算强度之义在前面已有说明。比如,如果将profile
希望XviD编码器按照MPEG-4 Simple profile的level 0进行编
输入参数;
height,为输入帧的高度,以像素为单位。height是一个输入参数;
num_zones,似乎是码流zone数目(作用未搞清楚)
zones,似乎是zone数组(作用未搞清楚),这是一个可选输入参数; num_plugins,插件数目,这是一个可选输入参数; plugins,插件数组,这是一个可选输入参数;
max_bfram帧,
入参数,当不需要控制编码器的行为时,将其设为0即可。global中允许的标志
位如下(作者窃以为这些标志都是为视频编码专家准备的):
/*----- --
---------------------------------------------------------------------
* "G al"
lob flags
*
* Thes ags are used for xvid_enc_create_t->global field during instance
e fl
* cre n
atio (operation XVID_ENC_CREATE)
*----- ---
------------------------------------------------------------------*/
#define XV eam */ ID_GLOBAL_PACKED (1<<0) /* packed bitstr
#define XVID_GLOBAL_CLOSED_GOP (1<<1) /* closed_gop: was DX50BVOP
dx50 bvop compatibility */
#define XVID_GLOBAL_EXTRASTATS_ENABLE (1<<2)
#if 0
#define XVID_GLOBAL_VOL_AT_IVOP (1<<3) /* write vol at every ivop: WIN
32/divx compatibility */ #define XVID_GLOBAL_FORCE_VOL
(1<<4) /* when vol-based parameters ar
e changed, insert an ivop NOT recommended */ #
endif #define XVID_GLOBAL_DIVX5_USERDATA (1<<5) /* write divx5 userdata stri
ng this is implied if XVID_GLOBAL_PACKED is set */
fincr,帧率增量,设为0时为可变帧率(作用未完全搞清楚),这是一个可选输
入参数;
员用于确定帧之间的间隔时间,计算公式为:帧间间隔=fincr/fbase
e)与关键帧之间的最大间隔,单位为帧。
比如,如果设为 50,就表示两个关键帧之间应该有 50 个 P 帧或者 B 帧。这是一
o,B 帧量化器 multipier(作用未搞清楚),这是一个可选输入参数;
(past_ref_quant,future_ref_quant)*bquant_ratio + bquant_offset) / 100 计算 B
,可选输入参数;
尽 x
参数仅 面
例代码(未
fbase,这个成
秒; max_key_interval,关键帧(即Intra fram
个可选输入参数;
frame_drop_ratio,为丢弃帧占总帧数的比例,取值为0到100之间,为0时不丢
弃帧,为100时丢弃所有帧。这是一个可选输入参数; bquant_rati
bquant_offset,B帧量化器偏移(作用未搞清楚)。似乎是通过下面的公式bquant = (avg
帧的量化器系数,在此公式中用到了bquant_ratio和bquant_offset; min_quant[3],最小量化系数(作用未知),可选输入参数; max_quant[3],最大量化系数(作用未知)
handle,在创建xvid编码实例之后,xvid_encore()函数将通过这个成员返回一个编码实例的句柄。这个成员是一个输出参数。
管vid_enc_create_t中需要设置的参数比较多,但是很多都是可选参数,必须设置的
下这样几个:version、profile、width、height。因此,下面就给出一个最简单的示经过验证):
#define C
IF_ROW 352
#define CIF_CO 8 L 28
void * enc
_handle = NULL;
xvid_enc_create_t xvid_enc_create;
/* V
ersion again */ memset(&xvid_enc_create, 0, sizeof(xvid_enc_create_t)); xvid_enc_create.version = XVID_VERSION;
/* Width and Height of input frames */
xvi
d_enc_create.width = CIF_ROW;
xvid_enc_create.height = CIF_COL;
xvid_enc_create.profile = XVID_PROFILE_S_L0;
xvid_encore(NULL, XVID_ENC_CREATE, &xvid_enc_create, NULL);
/* Retrieve the encoder instance from the structure */
enc_handle = xvid_enc_create.handle;
在调用xvid_encore()函数创建XviD编码实例的时候,第一个参数 handle 指定为 NULL
API 函数忽略掉),在创建完成之后,从 xvid_enc_create
c_handle。此后,在编码过程中或者在销毁编码实例的
enc_handle。
.2 编码
行真正的编码工作了,这也是通过
码过程,xvid_encore()函数的 param1 参数应当设定为
一个指向 xvid_enc_frame_t 类型的结构体,可选参数 param2 可以指向一个 xvid_enc_stats_t
类型
xvid_enc_frame_t 是 param1 参数应当指向的类型,xvid_enc_frame_t 在 XviD 中定义为:
(实际上即使指定了值也会被XviD的
中取出创建的编码实例的句柄赋给en
时候,都应该将xvid_encore()函数的handle参数指定为
9
在创建了XviD编码实例之后,紧接着的事情就是进
xvid_encore()函数完成的。为了完成编
的结构体,如果不关心编码状态,也可以将param2设置为NULL。xvid_encore()函数的第一个参数handle通常应当设置为创建XviD编码实例之后得到的句柄,而opt参数应该指定为XVID_ENC_ENCODE。当xvid_encore()函数调用成功时,将返回编码后输出的字节数,如果返回0则表明当前所在的帧不应该写入。
/*----------------------------------------------------------------------------
* xvid_enc_frame_t structure definition
*
* This structure is passed as param1 during a frame encoding (operation * XVID_ENC_ENCODE) *--------------------------------------------------------------------------*/ /* out value for the frame structure->type field * unlike stats output in param2, this field is not asynchronous and tells
* t
he client app, if the frame written into the stream buffer is an ivop
* usually used for indexing purpose in the container */
#define XVID_KEYFRAME (1<<1)
/* The structure */
typedef struct {
int version;
/* VOL related stuff
* unless XVID_FORCEVOL is set, the encoder will not react to any changes
* here until the next VOL (keyframe). */
int vol_flags; /* [in] vol flags */
unsigned char *quant_intra_matrix; /* [in:opt] custom intra qmatrix */
unsigned char *quant_inter_matrix; /* [in:opt] custom inter qmatrix */
int par; /* [in:opt] pixel aspect ratio (refer to XVID_PAR
_xxx above) */
int par_width; /* [in:opt] aspect ratio width */
int par_height; /* [in:opt] aspect ratio height */
/* Other fields that can change on a frame base */
int fincr; /* [in:opt] framerate increment, for variable fram
erate only */
int vop_flags; /* [in] (general)vop-based flags */
int motion; /* [in] ME options */
xvid_image_t input; /* [in] input image (read from) */
int type; /* [in:opt] coding type */
int quant; /* [in] frame quantizer; if <=0, automatic (rateco
ntrol) */
int bframe_threshold;
void *bitstream; /* [in:opt] bitstream ptr (written to)*/
int length; /* [in:opt] bitstream length (bytes) */
int out_flags; /* [out] bitstream output flags */
} id_enc_frame_t; xv
在xvid_enc_frame_t中,各个成员的含义如下所示:
version,前面已多次说明,应设为当前所用的 XviD 版本;
vol_flags,包含vol标志位,vol_flags是一个输入参数。xvid支持的标志位如下:
/*----------------------------------------------------------------------------
* "VOL" flags
*
*hese flags are used for xvid_enc_frame_t->vol_flags field during frame T
* encoding (operation XVID_ENC_ENCODE)
*--------------------------------------------------------------------------*/ #define XVID_VOL_MPEGQUANT (1<<0) /* enable MPEG type quantization */
#define XVID_VOL_EXTRASTATS (1<<1) /* enable plane sse stats */
#define X RTERPEL (1<<2) /* ena le quarterpel: frames will encode
VID_VOL_QUAb
d as quarte
rpel */
#defin
e XVID_VOL_GMC (1<<3) /* enable GMC; frames will be checked
for gmc suitability */
#define XVID_VOL_REDUCED_ENABLE (1<<4) /* enable reduced resolution vops: f
rames will be checked for rrv suitability */
/*NOTE: thereducedresolutionfeatureisnot
supported anymore. This flag will have no effect! */
#define XVID_VOL_INTERLACING (1<<5) /* enable interlaced encoding */
quant_intra_matrix,是一个可选输入参数,可以将其指向一个自定义的帧内(intra)
帧间(inter)
个可选输入参数,用于指定像素幅型比,其取值应该是几个标准的像
一个可选输入参数,用于指定像素幅型比的宽度;
于 VOP 的标志位。允许的标志位定
量化矩阵;
quant_inter_matrix,是一个可选输入参数,可以将其指向一个自定义的
量化矩阵; par,是一
素幅型比宏定义中的一个(XVID_PAR_xxx); par_width,是
par_height,是一个可选输入参数,用于指定像素幅型比的高度;
fincr,是一个可选输入参数,指定帧率增量,只适用于可变帧率的情形; vop_flags,是一个输入参数,其中保存着基
义如下所示:
/*----- --
---------------------------------------------------------------------
* "VOP" flags
*
* These fl for xvid_enc_frame_t->vop_flags field during frame
ags are used
* encoding (operation VID_ENC_ENCODE) X
*----- ---
------------------------------------------------------------------*/
/* Alw s
ayvalid */
#define EBUG (1<< 0) /* print debug messa es in frames
XVID_VOP_Dg
*/
#defin V
e XID_VOP_HALFPEL (1<< 1) /* use halfpel interpolation */
#defin V
e XID_VOP_INTER4V (1<< 2) /* use 4 motion vectors per MB */
#define XVID_VOP_TRELLISQUANT (1<< 3) /* use trellis based R-D "optimal"
quantization */
#define XVID_VOP_CHROMAOPT (1<< 4) /* enable chroma optimization pre-fi
lter */
#define XVID_VOP_CARTOON (1<< 5) /* use 'cartoon mode' */
#define XVID_VOP_GREYSCALE (1<< 6) /* enable greyscale only mode (eve
n for color input material chroma is ignored) */
#define XVID_VOP_HQACPRED (1<< 7) /* high quality ac prediction */
#define XVID_VOP_MODEDECISION_RD (1<< 8) /* enable DCT-ME and use it for
mode decision */
#define XVID_VOP_FAST_MODEDECISION_RD (1<<12) /* use simplified R-D mode decision */
#define XVID_VOP_RD_BVOP (1<<13) /* enable rate-distortion mode decisi
on in b-frames */ /* Only valid for vol_flags|=XVID_VOL_INTERLACING */
#define XVID_VOP_TOPFIELDFIRST (1<< 9) /* set top-field-first flag */ #define XVID_VOP_ALTERNATESCAN (1<<10) /* set alternate vertical scan flag */
/* only valid for vol_flags|=XVID_VOL_REDUCED_ENABLED */ #define XVID_VOP_REDUCED (1<<11) /* reduced resolution vop */
/*NOTE:reducedresolutionfeatureisnots
upported anymore. This flag will have no effect! */
motion,是一个输入参数,其中保存着用于运动估计的标志位。允许的标志位定
义如下:
/*---------------------------------------------------------------------------- * "Motion" flags
*
* These flags are used for xvid_enc_frame_t->motion field during frame
* encoding (operation XVID_ENC_ENCODE)
*--------------------------------------------------------------------------*/
/* Motion Estimation Search Patterns */
#define XVID_ME_ADVANCEDDIAMOND16 (1<< 0) /* use advdiamonds instead of
diamonds as search pattern */ #define XVID_ME_ADVANCEDDIAMOND8 (1<< 1) /* use advdiamond for XVID_
ME_EXTSEARCH8 */
#defin
e XVID_ME_USESQUARES16 (1<< 2) /* use squares instead of diam
onds as sea */ rch pattern
#define XVID_ME_USESQUARES8 (1<< 3) /* use square for XVID_ME_E
XTSEARCH8 */
/* SAD operator based flags */
#define XVID_ME_HALFPELREFINE16 (1<< 4)
#define XVID_ME_HALFPELREFINE8 (1<< 6)
#define XVID_ME_QUARTERPELREFINE16 (1<< 7)
#define XVID_ME_QUARTERPELREFINE8 (1<< 8)
#define XVID_ME_GME_REFINE (1<< 9)
#define XVID_ME_EXTSEARCH16 (1<<10) /* extend PMV by more search
es */
#define XVID_ME_EXTSEARCH8 (1<<11) /* use diamond/square for extended 8x8 search */
#define XVID_ME_CHROMA_PVOP (1<<12) /* also use chroma for P_VOP/S_VOP ME */
#define XVID_ME_CHROMA_BVOP (1<<13) /* also use chroma for B_VOP ME */
#define XVID_ME_FASTREFINE16 (1<<25) /* use low-complexity refineme
nt functions */
#define XVID_ME_FASTREFINE8 (1<<29) /* low-complexity 8x8 sub-bloc
k refinement */
/* Rate Distortion based flags
* Valid when XVID_VOP_MODEDECISION_RD is enabled */
#define XVID_ME_HALFPELREFINE16_RD (1<<14) /* perform RD-based halfpel refinement */
#define XVID_ME_HALFPELREFINE8_RD (1<<15) /* perform RD-based halfpel refinement for 8x8 mode */
#define XVID_ME_QUARTERPELREFINE16_RD (1<<16) /* perform RD-based qpel refinement */
#define XVID_ME_QUARTERPELREFINE8_RD (1<<17) /* perform RD-based qpel refinement for 8x8 mode */
#define XVID_ME_EXTSEARCH_RD (1<<18) /* perform RD-based search usi ng square pattern enable XVID_ME_EXTSEARCH8 to do this in 8x8 search as well */
#define XVID_ME_CHECKPREDICTION_RD (1<<19) /* always check vector equal t o prediction */
/* Other */
#define XVID_ME_DETECT_STATIC_MOTION (1<<24) /* speed-up ME by detecting st
ationary scenes */ #define XVID_ME_SKIP_DELTASEARCH (1<<26) /* speed-up by skipping b-fram
e delta search */ #define XVID_ME_FAST_MODEINTERPOLATE (1<<27) /* speed-up by partly skipping
interpolate mode */ #define XVID_ME_BFRAME_EARLYSTOP (1<<28) /* speed-up by early exiting b-
search */
/* Unused */ #define XVID_ME_UNRESTRICTED16 (1<<20) /* unrestricted ME, not implem
ented */ #define XVID_ME_OVERLAPPING16 (1<<21) /* overlapping ME, not implem
ented */
#define XVID_ME_UNRESTRICTED8 (1<<22) /* unrestricted ME, not implem
ented */
#define XVID_ME_OVERLAPPING8 (1<<23) /* overlapping ME, not implemented */
input,是一个xvid_image_t类型的输入参数,代表着输入流,其中不仅指定了输入流的输入
数据,也指定了输入流采用的色场空间; type,是一个可选的输入参数,用于指定编码的类型,通常可以指定为
XVID_TYPE_AUTO;
nt,是一个输入参数,表示帧量化器,如果取值小于等于 0,则自动选择(码
bitstream,是一个可选输入参数,指向编码后的输出缓冲区;
长度,单位为字节;
当执行编码操作时,xvid_encore()函数的 param2 参数可以指向一个 xvid_enc_stats_t 类
型的结构体。xvid_enc_stats_t 类型定义如下:
qua
率控制);
bframe_threshold,(作用未知);
length,是一个可选输入参数,表明输出缓冲区(即bitstream所指向的空间)的
out_flags,是一个输出参数,包含输出码流的相关标志。
/*------------
----------------------------------------------------------------
* xv n
id_ec_stats_t structure
*
* Used in:
* -
xvid_plg_data_t structure
* - optio xvid_encore() function nal parameter in
*
* .codi g_
ntype = XVID_TYPE_NOTHING if the stats are not given
*------------ ---------------------------------------------------*/ -----------
typedef stru
ct {
in er
t vsion;
/* encoding parameters */ int type; /* [out] coding type */
int quant; /* [out] frame quantizer */ int vol_flags; /* [out] vol flags (see above) */
int vop_flags; /* [out] vop flags (see above) */
/* bitrate
*/ int length; /* [out] f
rame length */
int hlength; /* [out] header length (bytes) */ int kblks; /* [out] number of blocks compressed as Intra */
int mblks; /* [out] number of blocks compressed as Inter */
int ublks; /* [out] number of blocks marked as not_coded */
int sse_y; /* [out] Y plane's sse */
int sse_u; /* [out] U plane's sse */
int sse_v; /* [out] V plane's sse */
} id_enc_stats_t; xv
xvid_enc_stats_t可以用作xvid_encore()函数的 既 param2 参 数 , 也 可 以 包 含 在
id vid_enc_stats_t 用作 xvid_encore()
数的 param2 参数的情形。在此种情况下,除了 version 外,xvid_enc_stats_t 中的所有成员
回编码操作执行的状态。各个成员的简单说明如下:
;
一
hlength,是一个输出参数,编码后的头部长度,单位为字节;
一 数,帧间编码压缩的宏块数目;
一个输出参数,标记为不编码的宏块数目;
示例代码:
xv_plg_data_t类型中(插件数据)。下面的讨论只针对x
函
都是输出参数,用来返
type,是一个输出参数,表明编码类型
quant,是个输出参数,表明采用的量化器;
vol_flags,是一个输出参数,表明为编码器指定的vol标志;
vop_flags,是一个输出参数,表明为编码器指定的vop标志;
length,是一个输出参数,编码的一帧的长度;
kblks,是一个输出参数,帧内编码压缩的宏块数目;
mblks,是个输出参数,是一个输出参
ublks,是
sse_y,是一个输出参数,Y平面上的sse值(SSE表示总方误差); sse_u,是一个输出参数,U平面上的sse值; sse_v,是一个输出参数,V平面上的sse值。
#defin
e CIF_ROW 352
#defin
e CIF_COL 288
#define CSP XVID_CSP_I420
#defin B
e PP 1
unsigned char
image[CIF_ROW * CIF_COL * BPP];
unsigned [1024]; char bitstream
xvid_e
nc_frame_t xvid_enc_frame;
xvid_enc_st id_enc_stats;
ats_t xv
/* Ver
sionfor the frame and the stats */
memset(&xvid_enc_frame, 0, sizeof(xvid_enc_frame_t));
xvid_enc_frame.version = XVID_VERSION;
mems x
et(&vid_enc_stats, 0, sizeof(xvid_enc_stats_t));
xvid sion = XVID_VERSION;
_enc_stats.ver
/* Bind output buffer / *
xvid_enc_frame.bitstream = bitstream;
xvid_enc_frame.length = -1;
/* Bind input buffer */
xvid_enc_frame.input.plane[0] = image;
xvid_enc_frame.input.csp = CSP;
xvid_enc_frame.input.stride[0] = CIF_ROW;
/* Set up core's general features */
xvid_enc_frame.vol_flags = 0;
xvid_enc_frame.vop_flags = 0;
/* Set up motion estimation flags */
xvid_enc_frame.motion = 0;
/* Frame type -- let core decide for us */
xvid_enc_frame.type = XVID_TYPE_AUTO;
/* Force the right quantizer -- It is internally managed by RC plugins */
xvid_enc_frame.quant = 0;
xvid_encore(enc_handle, XVID_ENC_ENCODE, &xvid_enc_frame,
&xvid_enc_stats);
在上述示例代码中,image中保存的是输入图像;bitstream 用于保存编码后的码流;大
分 xvid_enc_frame 中的成员都采用默认设置,实际上的设置工作集中在设定输入图像和输
,调用 xvid_encore()函数,其中第一个参数 enc_handle
实例句柄,编码状态通过 xvid_enc_stats 返回。
.3 销毁 xvid 编码实例
做法如下:将 xvid_encore()函数的第一个参数 handle 设
opt 设置为 XVID_ENC_DESTROY;参数
实例之后,不能再用它进行编码。
示例代码:
部
出流上。设置好xvid_enc_frame之后
是创建XviD编码实例后返回的
9
销毁XviD编码实例非常简单。
为
创建XviD编码实例后得到的句柄;第二个参数
param1和param2都设为NULL。销毁XviD编码
xvid_encore(enc_handle, XVID_ENC_DESTROY, NULL, NULL);
上述代码中的第一个参数 enc_handle 是创建 XviD 编码实例之后得到的句柄。
有看到 的官方文档。显然,接口清晰易懂并不是不给出官方文档的理由。
程中,可以插入相关的插件完成一些额外的操作,比
将编码前后的码流转储到文件中以便于调试或者分析。
这些插件函数和前面说明的三个核心函数具有相同的接口形式。XviD 本身定义了六个标准
的插
10 总结
XviD的三个核心API接口都采用了同样的参数形式(只是形式上相同),不可否认,XviD采用这样的处理方式,使得应用程序接口非常清晰,非常便于使用。这为通过XviD编写应用程序的开发人员提供了不少方便。但是一个比较不好的地方是:到目前为止,还没XviD
另外,在通过XviD进行编码的过如通过插件对编码情况进行统计或者
件函数,用于计算psnr(Peek Signal Noise Rate,峰值信噪比,一种通用的衡量视频质量的方法)以及进行码率控制等工作。在本文中没有对这些插件函数进行说明,本文档的下一版本中也许会增加对这些插件函数的说明。