--- trunk/xvidcore/src/divx4.c 2002/04/27 23:51:59 142 +++ trunk/xvidcore/src/divx4.c 2002/04/28 16:15:51 143 @@ -1,7 +1,7 @@ /************************************************************************** * * XVID MPEG-4 VIDEO CODEC - * opendivx api wrapper + * OpenDivx API wrapper * * This program is an implementation of a part of one or more MPEG-4 * Video tools as specified in ISO/IEC 14496-2 standard. Those intending @@ -39,12 +39,8 @@ * *************************************************************************/ -#ifndef FREEBSD -#include -#else #include -#endif -#include // memset +#include #include "xvid.h" #include "divx4.h" @@ -53,7 +49,17 @@ #define EMULATED_DIVX_VERSION 20011001 -// decore +/************************************************************************** + * Divx Instance Structure + * + * This chain list datatype allows XviD do instanciate multiples divx4 + * sessions. + * + * ToDo : The way this chain list is used does not guarantee reentrance + * because they are not protected by any kind of mutex to allow + * only one modifier. We should add a mutex for each element in + * the chainlist. + *************************************************************************/ typedef struct DINST @@ -66,11 +72,386 @@ } DINST; - +/************************************************************************** + * Global data (needed to emulate correctly exported symbols from divx4) + *************************************************************************/ + +/* This is not used in this module but is required by some divx4 encoders*/ +int quiet_encore = 1; + +/************************************************************************** + * Local data + *************************************************************************/ + +/* The Divx4 instance chainlist */ static DINST * dhead = NULL; +/* Divx4 quality to XviD encoder motion flag presets */ +static int const divx4_motion_presets[7] = { + 0, + + PMV_QUICKSTOP16, + + PMV_EARLYSTOP16, + + PMV_EARLYSTOP16 | PMV_HALFPELREFINE16, + + PMV_EARLYSTOP16 | PMV_HALFPELREFINE16 | + PMV_EARLYSTOP8 | PMV_HALFPELDIAMOND8, + + PMV_EARLYSTOP16 | PMV_HALFPELREFINE16 | + PMV_EARLYSTOP8 | PMV_HALFPELDIAMOND8, + + PMV_EARLYSTOP16 | PMV_HALFPELREFINE16 | + PMV_EXTSEARCH16 | PMV_EARLYSTOP8 | + PMV_HALFPELREFINE8 | PMV_HALFPELDIAMOND8 +}; + + +/* Divx4 quality to general encoder flag presets */ +static int const divx4_general_presets[7] = { + 0, + XVID_H263QUANT, + XVID_H263QUANT, + XVID_H263QUANT | XVID_HALFPEL, + XVID_H263QUANT | XVID_INTER4V | XVID_HALFPEL, + XVID_H263QUANT | XVID_INTER4V | XVID_HALFPEL, + XVID_H263QUANT | XVID_INTER4V | XVID_HALFPEL +}; + +/* + * Current divx4 encoder quality + * ToDo : this data should not be shared between encoder instances + */ +static int quality; + +/************************************************************************** + * Local Prototypes + *************************************************************************/ + +/* Chain list helper functions */ +static DINST * dinst_find(unsigned long key); +static DINST * dinst_add(unsigned long key); +static void dinst_remove(unsigned long key); + +/* Converts divx4 colorspaces codes to xvid codes */ +static int xvid_to_opendivx_dec_csp(int csp); +static int xvid_to_opendivx_enc_csp(int csp); + +/************************************************************************** + * decore part + * + * decore is the divx4 entry point used to decompress the mpeg4 bitstream + * into a user defined image format. + *************************************************************************/ + +int +decore(unsigned long key, unsigned long opt, void * param1, void * param2) +{ + + int xerr; + + switch (opt) { + + case DEC_OPT_MEMORY_REQS : + { + memset(param2, 0, sizeof(DEC_MEM_REQS)); + return DEC_OK; + } + + case DEC_OPT_INIT : + { + XVID_INIT_PARAM xinit; + XVID_DEC_PARAM xparam; + DINST * dcur; + DEC_PARAM * dparam = (DEC_PARAM *)param1; + + /* Find the divx4 instance */ + if ((dcur = dinst_find(key)) == NULL) + { + dcur = dinst_add(key); + } + + /* + * XviD initialization + * XviD will detect the host cpu type and activate optimized + * functions according to the host cpu features. + */ + xinit.cpu_flags = 0; + xvid_init(NULL, 0, &xinit, NULL); + + /* XviD decoder initialization for this instance */ + xparam.width = dparam->x_dim; + xparam.height = dparam->y_dim; + dcur->xframe.colorspace = + xvid_to_opendivx_dec_csp(dparam->output_format); + + xerr = decoder_create(&xparam); + + /* Store the xvid handle into the divx4 instance chainlist */ + dcur->handle = xparam.handle; + + break; + } + + case DEC_OPT_RELEASE : + { + DINST * dcur; + + /* Find the divx4 instance into the chain list */ + if ((dcur = dinst_find(key)) == NULL) + { + return DEC_EXIT; + } + + /* Destroy the XviD decoder attached to this divx4 instance */ + xerr = decoder_destroy(dcur->handle); + + /* Remove the divx4 instance from the chainlist */ + dinst_remove(key); + + break; + } + + case DEC_OPT_SETPP : + { + DINST * dcur; + + /* Find the divx4 instance into the chain list */ + if ((dcur = dinst_find(key)) == NULL) + { + return DEC_EXIT; + } + + /* + * We return DEC_OK but XviD has no postprocessing implemented + * in core. + */ + return DEC_OK; + } + + case DEC_OPT_SETOUT : + { + DINST * dcur; + DEC_PARAM * dparam = (DEC_PARAM *)param1; + + if ((dcur = dinst_find(key)) == NULL) + { + return DEC_EXIT; + } + + /* Change the output colorspace */ + dcur->xframe.colorspace = + xvid_to_opendivx_dec_csp(dparam->output_format); + + return DEC_OK; + } + + case DEC_OPT_FRAME: + { + int csp_tmp = 0; + DINST * dcur; + DEC_FRAME * dframe = (DEC_FRAME *)param1; + + if ((dcur = dinst_find(key)) == NULL) + { + return DEC_EXIT; + } + + /* Copy the divx4 fields to the XviD decoder structure */ + dcur->xframe.bitstream = dframe->bitstream; + dcur->xframe.length = dframe->length; + dcur->xframe.image = dframe->bmp; + dcur->xframe.stride = dframe->stride; + + /* Does the frame need to be skipped ? */ + if (!dframe->render_flag) + { + /* + * Then we use the null colorspace to force XviD to + * skip the frame. The original colorspace will be + * restored after the decoder call + */ + csp_tmp = dcur->xframe.colorspace; + dcur->xframe.colorspace = XVID_CSP_NULL; + } + + /* Decode the bitstream */ + xerr = decoder_decode(dcur->handle, &dcur->xframe); + + /* Restore the real colorspace for this instance */ + if (!dframe->render_flag) + { + dcur->xframe.colorspace = csp_tmp; + } + + break; + } + + case DEC_OPT_FRAME_311 : + /* XviD does not handle Divx ;-) 3.11 yet */ + return DEC_EXIT; + + case DEC_OPT_VERSION: + return EMULATED_DIVX_VERSION; + + default : + return DEC_EXIT; + } + + + /* XviD error code -> Divx4 */ + switch(xerr) + { + case XVID_ERR_OK : + return DEC_OK; + case XVID_ERR_MEMORY : + return DEC_MEMORY; + case XVID_ERR_FORMAT : + return DEC_BAD_FORMAT; + default : + return DEC_EXIT; + } +} -DINST * dinst_find(unsigned long key) +/************************************************************************** + * Encore Part + * + * encore is the divx4 entry point used to compress a frame to a mpeg4 + * bitstream. + *************************************************************************/ + +#define FRAMERATE_INCR 1001 + +int +encore(void * handle, int opt, void * param1, void * param2) +{ + + int xerr; + + switch(opt) { + case ENC_OPT_INIT : + { + ENC_PARAM * eparam = (ENC_PARAM *)param1; + XVID_INIT_PARAM xinit; + XVID_ENC_PARAM xparam; + + /* Init XviD which will detect host cpu features */ + xinit.cpu_flags = 0; + xvid_init(NULL, 0, &xinit, NULL); + + /* Settings are copied to the XviD encoder structure */ + xparam.width = eparam->x_dim; + xparam.height = eparam->y_dim; + if ((eparam->framerate - (int)eparam->framerate) == 0) + { + xparam.fincr = 1; + xparam.fbase = (int)eparam->framerate; + } + else + { + xparam.fincr = FRAMERATE_INCR; + xparam.fbase = (int)(FRAMERATE_INCR * eparam->framerate); + } + xparam.rc_bitrate = eparam->bitrate; + xparam.rc_reaction_delay_factor = 16; + xparam.rc_averaging_period = 100; + xparam.rc_buffer = 100; + xparam.min_quantizer = eparam->min_quantizer; + xparam.max_quantizer = eparam->max_quantizer; + xparam.max_key_interval = eparam->max_key_interval; + quality = eparam->quality; + + /* Create the encoder session */ + xerr = encoder_create(&xparam); + + eparam->handle = xparam.handle; + + break; + } + + case ENC_OPT_RELEASE : + { + xerr = encoder_destroy((Encoder *) handle); + break; + } + + case ENC_OPT_ENCODE : + case ENC_OPT_ENCODE_VBR : + { + ENC_FRAME * eframe = (ENC_FRAME *)param1; + ENC_RESULT * eresult = (ENC_RESULT *)param2; + XVID_ENC_FRAME xframe; + XVID_ENC_STATS xstats; + + /* Copy the divx4 info into the xvid structure */ + xframe.bitstream = eframe->bitstream; + xframe.length = eframe->length; + + xframe.motion = divx4_motion_presets[quality]; + xframe.general = divx4_general_presets[quality]; + + xframe.image = eframe->image; + xframe.colorspace = + xvid_to_opendivx_enc_csp(eframe->colorspace); + + if (opt == ENC_OPT_ENCODE_VBR) + { + xframe.intra = eframe->intra; + xframe.quant = eframe->quant; + } + else + { + xframe.intra = -1; + xframe.quant = 0; + } + + /* Encode the frame */ + xerr = encoder_encode((Encoder *) handle, &xframe, (eresult ? &xstats : NULL) ); + + /* Copy back the xvid structure to the divx4 one */ + if (eresult) + { + eresult->is_key_frame = xframe.intra; + eresult->quantizer = xstats.quant; + eresult->total_bits = xframe.length * 8; + eresult->motion_bits = xstats.hlength * 8; + eresult->texture_bits = eresult->total_bits - eresult->motion_bits; + } + + eframe->length = xframe.length; + + break; + } + + default: + return ENC_FAIL; + } + + /* XviD Error code -> Divx4 error code */ + switch(xerr) + { + case XVID_ERR_OK : + return ENC_OK; + case XVID_ERR_MEMORY : + return ENC_MEMORY; + case XVID_ERR_FORMAT : + return ENC_BAD_FORMAT; + default : + return ENC_FAIL; + } +} + +/************************************************************************** + * Local Functions + *************************************************************************/ + +/*************************************** + * DINST chainlist helper functions * + ***************************************/ + +/* Find an element in the chainlist according to its key value */ +static DINST * dinst_find(unsigned long key) { DINST * dcur = dhead; @@ -87,7 +468,8 @@ } -DINST * dinst_add(unsigned long key) +/* Add an element to the chainlist */ +static DINST * dinst_add(unsigned long key) { DINST * dnext = dhead; @@ -105,7 +487,8 @@ } -void dinst_remove(unsigned long key) +/* Remove an elmement from the chainlist */ +static void dinst_remove(unsigned long key) { DINST * dcur = dhead; @@ -134,9 +517,13 @@ } } +/*************************************** + * Colorspace code converter * + ***************************************/ -int xvid_to_opendivx_dec_csp(int csp) +static int xvid_to_opendivx_dec_csp(int csp) { + switch(csp) { case DEC_YV12 : @@ -170,293 +557,22 @@ } } - -int decore(unsigned long key, unsigned long opt, - void * param1, void * param2) +static int xvid_to_opendivx_enc_csp(int csp) { - int xerr; - switch (opt) + switch (csp) { - case DEC_OPT_MEMORY_REQS : - { - memset(param2, 0, sizeof(DEC_MEM_REQS)); - return DEC_OK; - } - - case DEC_OPT_INIT : - { - DEC_PARAM * dparam = (DEC_PARAM *)param1; - XVID_INIT_PARAM xinit; - XVID_DEC_PARAM xparam; - DINST * dcur = dinst_find(key); - if (dcur == NULL) - { - dcur = dinst_add(key); - } - - xinit.cpu_flags = 0; - xvid_init(NULL, 0, &xinit, NULL); - - xparam.width = dparam->x_dim; - xparam.height = dparam->y_dim; - dcur->xframe.colorspace = xvid_to_opendivx_dec_csp(dparam->output_format); - - xerr = decoder_create(&xparam); - - dcur->handle = xparam.handle; - - break; - } - - case DEC_OPT_RELEASE : - { - DINST * dcur = dinst_find(key); - if (dcur == NULL) - { - return DEC_EXIT; - } - - xerr = decoder_destroy(dcur->handle); - - dinst_remove(key); - - break; - } - - case DEC_OPT_SETPP : - { - // DEC_SET * dset = (DEC_SET *)param1; - DINST * dcur = dinst_find(key); - if (dcur == NULL) - { - return DEC_EXIT; - } - - // dcur->xframe.pp = dset->postproc_level; - - return DEC_OK; - } - - case DEC_OPT_SETOUT : - { - DEC_PARAM * dparam = (DEC_PARAM *)param1; - DINST * dcur = dinst_find(key); - if (dcur == NULL) - { - return DEC_EXIT; - } - - dcur->xframe.colorspace = xvid_to_opendivx_dec_csp(dparam->output_format); - - return DEC_OK; - } - - case DEC_OPT_FRAME: - { - int csp_tmp = 0; - - DEC_FRAME * dframe = (DEC_FRAME *)param1; - DINST * dcur = dinst_find(key); - if (dcur == NULL) - { - return DEC_EXIT; - } - - dcur->xframe.bitstream = dframe->bitstream; - dcur->xframe.length = dframe->length; - dcur->xframe.image = dframe->bmp; - dcur->xframe.stride = dframe->stride; - - if (!dframe->render_flag) - { - csp_tmp = dcur->xframe.colorspace; - dcur->xframe.colorspace = XVID_CSP_NULL; - } - - xerr = decoder_decode(dcur->handle, &dcur->xframe); - - if (!dframe->render_flag) - { - dcur->xframe.colorspace = csp_tmp; - } - - break; - } - - - case DEC_OPT_FRAME_311 : - return DEC_EXIT; - - - case DEC_OPT_VERSION: - return EMULATED_DIVX_VERSION; + case ENC_CSP_RGB24 : + return XVID_CSP_VFLIP | XVID_CSP_RGB24; + case ENC_CSP_YV12 : + return XVID_CSP_YV12; + case ENC_CSP_YUY2 : + return XVID_CSP_YUY2; + case ENC_CSP_UYVY : + return XVID_CSP_UYVY; + case ENC_CSP_I420 : + return XVID_CSP_I420; default : - return DEC_EXIT; - } - - - switch(xerr) - { - case XVID_ERR_OK : return DEC_OK; - case XVID_ERR_MEMORY : return DEC_MEMORY; - case XVID_ERR_FORMAT : return DEC_BAD_FORMAT; - default : // case XVID_ERR_FAIL : - return DEC_EXIT; - } -} - - - - -// encore - -#define FRAMERATE_INCR 1001 - -int divx4_motion_presets[7] = { - 0, - PMV_QUICKSTOP16, - PMV_EARLYSTOP16, - PMV_EARLYSTOP16 | PMV_HALFPELREFINE16, - PMV_EARLYSTOP16 | PMV_HALFPELREFINE16 | PMV_EARLYSTOP8 | PMV_HALFPELDIAMOND8, - PMV_EARLYSTOP16 | PMV_HALFPELREFINE16 | PMV_EARLYSTOP8 | PMV_HALFPELDIAMOND8, - PMV_EARLYSTOP16 | PMV_HALFPELREFINE16 | PMV_EXTSEARCH16 | PMV_EARLYSTOP8 | PMV_HALFPELREFINE8 | PMV_HALFPELDIAMOND8 -}; - - -int divx4_general_presets[7] = { - 0, - XVID_H263QUANT, - XVID_H263QUANT, - XVID_H263QUANT | XVID_HALFPEL, - XVID_H263QUANT | XVID_INTER4V | XVID_HALFPEL, - XVID_H263QUANT | XVID_INTER4V | XVID_HALFPEL, - XVID_H263QUANT | XVID_INTER4V | XVID_HALFPEL -}; - -int quality; - -int encore(void * handle, int opt, void * param1, void * param2) -{ - int xerr; - - switch(opt) - { - case ENC_OPT_INIT : - { - ENC_PARAM * eparam = (ENC_PARAM *)param1; - XVID_INIT_PARAM xinit; - XVID_ENC_PARAM xparam; - - xinit.cpu_flags = 0; - xvid_init(NULL, 0, &xinit, NULL); - - xparam.width = eparam->x_dim; - xparam.height = eparam->y_dim; - if ((eparam->framerate - (int)eparam->framerate) == 0) - { - xparam.fincr = 1; - xparam.fbase = (int)eparam->framerate; - } - else - { - xparam.fincr = FRAMERATE_INCR; - xparam.fbase = (int)(FRAMERATE_INCR * eparam->framerate); - } - xparam.rc_bitrate = eparam->bitrate; - xparam.rc_reaction_delay_factor = 16; - xparam.rc_averaging_period = 100; - xparam.rc_buffer = 100; - xparam.min_quantizer = eparam->min_quantizer; - xparam.max_quantizer = eparam->max_quantizer; - xparam.max_key_interval = eparam->max_key_interval; - quality = eparam->quality; - - xerr = encoder_create(&xparam); - - eparam->handle = xparam.handle; - - break; - } - - case ENC_OPT_RELEASE : - { - xerr = encoder_destroy((Encoder *) handle); - break; - } - - case ENC_OPT_ENCODE : - case ENC_OPT_ENCODE_VBR : - { - ENC_FRAME * eframe = (ENC_FRAME *)param1; - ENC_RESULT * eresult = (ENC_RESULT *)param2; - XVID_ENC_FRAME xframe; - XVID_ENC_STATS xstats; - - xframe.bitstream = eframe->bitstream; - xframe.length = eframe->length; - - xframe.motion = divx4_motion_presets[quality]; - xframe.general = divx4_general_presets[quality]; - - xframe.image = eframe->image; - switch (eframe->colorspace) - { - case ENC_CSP_RGB24 : - xframe.colorspace = XVID_CSP_VFLIP | XVID_CSP_RGB24; - break; - case ENC_CSP_YV12 : - xframe.colorspace = XVID_CSP_YV12; - break; - case ENC_CSP_YUY2 : - xframe.colorspace = XVID_CSP_YUY2; - break; - case ENC_CSP_UYVY : - xframe.colorspace = XVID_CSP_UYVY; - break; - case ENC_CSP_I420 : - xframe.colorspace = XVID_CSP_I420; - break; - } - - if (opt == ENC_OPT_ENCODE_VBR) - { - xframe.intra = eframe->intra; - xframe.quant = eframe->quant; - } - else - { - xframe.intra = -1; - xframe.quant = 0; - } - - xerr = encoder_encode((Encoder *) handle, &xframe, (eresult ? &xstats : NULL) ); - - if (eresult) - { - eresult->is_key_frame = xframe.intra; - eresult->quantizer = xstats.quant; - eresult->total_bits = xframe.length * 8; - eresult->motion_bits = xstats.hlength * 8; - eresult->texture_bits = eresult->total_bits - eresult->motion_bits; - } - - eframe->length = xframe.length; - - break; - } - - default: - return ENC_FAIL; - } - - switch(xerr) - { - case XVID_ERR_OK : return ENC_OK; - case XVID_ERR_MEMORY : return ENC_MEMORY; - case XVID_ERR_FORMAT : return ENC_BAD_FORMAT; - default : // case XVID_ERR_FAIL : - return ENC_FAIL; + return -1; } } -