This source file includes following definitions.
- XVID_AttachStream
- XVID_DetachStream
- XVID_GetCapabilities
- XVID_SetCapabilities
- XVID_ProcessData
- XVID_CanHandleStream
- XVID_GetCodecName
- NewXVIDDec
- DeleteXVIDDec
- QueryInterfaces
- LoadInterface
- ShutdownInterface
#include <gpac/modules/codec.h>
#include <gpac/avparse.h>
#include <gpac/constants.h>
#ifndef GPAC_DISABLE_AV_PARSERS
#if !defined(__GNUC__)
# if defined(_WIN32_WCE) || defined (WIN32)
# pragma comment(lib, "libxvidcore")
# endif
#endif
#include <xvid.h>
#ifndef XVID_DEC_FRAME
#define XVID_DEC_FRAME xvid_dec_frame_t
#define XVID_DEC_PARAM xvid_dec_create_t
#else
#define XVID_USE_OLD_API
#endif
#undef XVID_USE_OLD_API
static Bool xvid_is_init = GF_FALSE;
typedef struct
{
void *base_codec;
u16 base_ES_ID;
u32 width, height, out_size, pixel_ar;
Bool first_frame;
s32 base_filters;
Float FPS;
u32 offset;
void *depth_codec;
u16 depth_ES_ID;
char *temp_uv;
u32 yuv_size;
} XVIDDec;
#define XVIDCTX() XVIDDec *ctx = (XVIDDec *) ifcg->privateStack
static GF_Err XVID_AttachStream(GF_BaseDecoder *ifcg, GF_ESD *esd)
{
GF_M4VDecSpecInfo dsi;
GF_Err e;
void **codec;
#ifdef XVID_USE_OLD_API
XVID_DEC_FRAME frame;
XVID_DEC_PARAM par;
#else
xvid_dec_frame_t frame;
xvid_dec_create_t par;
#endif
XVIDCTX();
if (!esd->decoderConfig->decoderSpecificInfo || !esd->decoderConfig->decoderSpecificInfo->data) return GF_NON_COMPLIANT_BITSTREAM;
if (esd->dependsOnESID) {
u32 i = 0;
GF_Descriptor *d = NULL;
if (esd->dependsOnESID != ctx->base_ES_ID) return GF_NOT_SUPPORTED;
#ifdef XVID_USE_OLD_API
return GF_NOT_SUPPORTED;
#endif
while ((d = (GF_Descriptor*)gf_list_enum(esd->extensionDescriptors, &i))) {
if (d->tag == GF_ODF_AUX_VIDEO_DATA) break;
}
if (!d) return GF_NOT_SUPPORTED;
codec = &ctx->depth_codec;
ctx->depth_ES_ID = esd->ESID;
} else {
if (ctx->base_ES_ID && ctx->base_ES_ID!=esd->ESID) return GF_NOT_SUPPORTED;
codec = &ctx->base_codec;
ctx->base_ES_ID = esd->ESID;
}
if (*codec) xvid_decore(*codec, XVID_DEC_DESTROY, NULL, NULL);
e = gf_m4v_get_config(esd->decoderConfig->decoderSpecificInfo->data, esd->decoderConfig->decoderSpecificInfo->dataLength, &dsi);
if (e) return e;
if (!dsi.width || !dsi.height) return GF_NON_COMPLIANT_BITSTREAM;
memset(&par, 0, sizeof(par));
par.width = dsi.width;
par.height = dsi.height;
ctx->FPS = dsi.clock_rate;
ctx->FPS /= 1000;
if (!ctx->FPS) ctx->FPS = 30.0f;
ctx->pixel_ar = (dsi.par_num<<16) | dsi.par_den;
#ifndef XVID_USE_OLD_API
par.version = XVID_VERSION;
#endif
if (xvid_decore(NULL, XVID_DEC_CREATE, &par, NULL) < 0) return GF_NON_COMPLIANT_BITSTREAM;
ctx->width = par.width;
ctx->height = par.height;
*codec = par.handle;
memset(&frame, 0, sizeof(frame));
frame.bitstream = (void *) esd->decoderConfig->decoderSpecificInfo->data;
frame.length = esd->decoderConfig->decoderSpecificInfo->dataLength;
#ifndef XVID_USE_OLD_API
frame.version = XVID_VERSION;
xvid_decore(*codec, XVID_DEC_DECODE, &frame, NULL);
#else
xvid_decore(*codec, XVID_DEC_DECODE, &frame, NULL);
#endif
ctx->first_frame = GF_TRUE;
if (ctx->depth_codec) {
ctx->out_size = ctx->width * ctx->height * 5 / 2;
ctx->temp_uv = (char*)gf_malloc(sizeof(char)*ctx->width * ctx->height / 2);
} else {
ctx->yuv_size = ctx->out_size = ctx->width * ctx->height * 3 / 2;
}
return GF_OK;
}
static GF_Err XVID_DetachStream(GF_BaseDecoder *ifcg, u16 ES_ID)
{
XVIDCTX();
if (ctx->base_ES_ID == ES_ID) {
if (ctx->base_codec) xvid_decore(ctx->base_codec, XVID_DEC_DESTROY, NULL, NULL);
ctx->base_codec = NULL;
ctx->base_ES_ID = 0;
ctx->width = ctx->height = ctx->out_size = 0;
}
else if (ctx->depth_ES_ID == ES_ID) {
if (ctx->depth_codec) xvid_decore(ctx->depth_codec, XVID_DEC_DESTROY, NULL, NULL);
ctx->depth_codec = NULL;
ctx->depth_ES_ID = 0;
if (ctx->temp_uv) gf_free(ctx->temp_uv);
ctx->temp_uv = NULL;
}
return GF_OK;
}
static GF_Err XVID_GetCapabilities(GF_BaseDecoder *ifcg, GF_CodecCapability *capability)
{
XVIDCTX();
switch (capability->CapCode) {
case GF_CODEC_RESILIENT:
capability->cap.valueInt = 1;
break;
case GF_CODEC_WIDTH:
capability->cap.valueInt = ctx->width;
break;
case GF_CODEC_HEIGHT:
capability->cap.valueInt = ctx->height;
break;
case GF_CODEC_STRIDE:
capability->cap.valueInt = ctx->width;
break;
case GF_CODEC_FPS:
capability->cap.valueFloat = ctx->FPS;
break;
case GF_CODEC_PAR:
capability->cap.valueInt = ctx->pixel_ar;
break;
case GF_CODEC_OUTPUT_SIZE:
capability->cap.valueInt = ctx->out_size;
break;
case GF_CODEC_PIXEL_FORMAT:
capability->cap.valueInt = ctx->depth_codec ? GF_PIXEL_YUVD : GF_PIXEL_YV12;
break;
case GF_CODEC_BUFFER_MIN:
capability->cap.valueInt = 1;
break;
case GF_CODEC_BUFFER_MAX:
capability->cap.valueInt = 4;
break;
case GF_CODEC_PADDING_BYTES:
capability->cap.valueInt = 32;
break;
case GF_CODEC_REORDER:
capability->cap.valueInt = 1;
break;
case GF_CODEC_WANTS_THREAD:
{
const char *sOpt = gf_modules_get_option((GF_BaseInterface *)ifcg, "XviD", "Threaded");
capability->cap.valueInt = (sOpt && stricmp(sOpt, "yes")) ? 1 : 0;
}
break;
case GF_CODEC_CU_DURATION:
default:
capability->cap.valueInt = 0;
break;
}
return GF_OK;
}
static GF_Err XVID_SetCapabilities(GF_BaseDecoder *ifcg, GF_CodecCapability capability)
{
return GF_NOT_SUPPORTED;
}
static GF_Err XVID_ProcessData(GF_MediaDecoder *ifcg,
char *inBuffer, u32 inBufferLength,
u16 ES_ID, u32 *CTS,
char *outBuffer, u32 *outBufferLength,
u8 PaddingBits, u32 mmlevel)
{
#ifdef XVID_USE_OLD_API
XVID_DEC_FRAME frame;
#else
xvid_dec_frame_t frame;
#endif
void *codec;
s32 postproc, res;
XVIDCTX();
if (!ES_ID) {
*outBufferLength = 0;
return GF_OK;
}
if (ES_ID == ctx->depth_ES_ID) {
codec = ctx->depth_codec;
} else {
codec = ctx->base_codec;
}
if (!codec) return GF_OK;
if (*outBufferLength < ctx->out_size) {
*outBufferLength = ctx->out_size;
return GF_BUFFER_TOO_SMALL;
}
memset(&frame, 0, sizeof(frame));
frame.bitstream = (void *) (inBuffer + ctx->offset);
frame.length = inBufferLength - ctx->offset;
ctx->offset = 0;
#ifdef XVID_USE_OLD_API
frame.colorspace = XVID_CSP_I420;
frame.stride = ctx->width;
frame.image = (void *) outBuffer;
#else
frame.version = XVID_VERSION;
if (ES_ID == ctx->depth_ES_ID) {
frame.output.csp = XVID_CSP_PLANAR;
frame.output.stride[0] = ctx->width;
frame.output.plane[0] = (void *) (outBuffer + ctx->yuv_size);
frame.output.stride[1] = ctx->width/4;
frame.output.plane[1] = (void *) ctx->temp_uv;
frame.output.stride[2] = ctx->width/4;
frame.output.plane[2] = (void *) ctx->temp_uv;
} else {
frame.output.csp = XVID_CSP_I420;
frame.output.stride[0] = ctx->width;
frame.output.plane[0] = (void *) outBuffer;
}
#endif
postproc = ctx->base_filters;
switch (mmlevel) {
case GF_CODEC_LEVEL_SEEK:
case GF_CODEC_LEVEL_DROP:
#ifdef XVID_USE_OLD_API
postproc &= ~XVID_DEC_DEBLOCKY;
postproc &= ~XVID_DEC_DEBLOCKUV;
#else
postproc &= ~XVID_DEBLOCKY;
postproc &= ~XVID_DEBLOCKUV;
postproc &= ~XVID_FILMEFFECT;
#endif
break;
case GF_CODEC_LEVEL_VERY_LATE:
#ifdef XVID_USE_OLD_API
postproc &= ~XVID_DEC_DEBLOCKY;
#else
postproc &= ~XVID_FILMEFFECT;
postproc &= ~XVID_DEBLOCKY;
#endif
break;
case GF_CODEC_LEVEL_LATE:
#ifdef XVID_USE_OLD_API
postproc &= ~XVID_DEC_DEBLOCKUV;
#else
postproc &= ~XVID_DEBLOCKUV;
postproc &= ~XVID_FILMEFFECT;
#endif
break;
}
postproc = 0;
if (ctx->first_frame) {
outBuffer[0] = 'v';
outBuffer[1] = 'o';
outBuffer[2] = 'i';
outBuffer[3] = 'd';
}
res = xvid_decore(codec, XVID_DEC_DECODE, &frame, NULL);
if (res < 0) {
*outBufferLength = 0;
return GF_NON_COMPLIANT_BITSTREAM;
}
if (0 && res <= 6) {
*outBufferLength = 0;
return GF_OK;
}
switch (mmlevel) {
case GF_CODEC_LEVEL_SEEK:
case GF_CODEC_LEVEL_DROP:
if (ES_ID == ctx->base_ES_ID)
*outBufferLength = 0;
break;
default:
*outBufferLength = ctx->out_size;
if (ctx->first_frame) {
ctx->first_frame = GF_FALSE;
if ((outBuffer[0] == 'v') && (outBuffer[1] == 'o') && (outBuffer[2] == 'i') && (outBuffer[3] == 'd')) {
*outBufferLength = 0;
return GF_OK;
}
}
if (res + 6 < frame.length) {
ctx->offset = res;
return GF_PACKED_FRAMES;
}
break;
}
return GF_OK;
}
static u32 XVID_CanHandleStream(GF_BaseDecoder *dec, u32 StreamType, GF_ESD *esd, u8 PL)
{
if (StreamType != GF_STREAM_VISUAL) return GF_CODEC_NOT_SUPPORTED;
if (!esd) return GF_CODEC_STREAM_TYPE_SUPPORTED;
if (esd->decoderConfig->objectTypeIndication==GPAC_OTI_VIDEO_MPEG4_PART2) {
if (esd->decoderConfig->rvc_config || esd->decoderConfig->predefined_rvc_config) return GF_CODEC_MAYBE_SUPPORTED;
return GF_CODEC_SUPPORTED;
}
return GF_CODEC_NOT_SUPPORTED;
}
static const char *XVID_GetCodecName(GF_BaseDecoder *dec)
{
#ifdef XVID_USE_OLD_API
return "XviD Dev Version";
#else
return "XviD 1.0";
#endif
}
GF_BaseDecoder *NewXVIDDec()
{
const char *sOpt;
GF_MediaDecoder *ifcd;
XVIDDec *dec;
GF_SAFEALLOC(ifcd, GF_MediaDecoder);
GF_SAFEALLOC(dec, XVIDDec);
GF_REGISTER_MODULE_INTERFACE(ifcd, GF_MEDIA_DECODER_INTERFACE, "XviD Decoder", "gpac distribution")
ifcd->privateStack = dec;
if (!xvid_is_init) {
#ifdef XVID_USE_OLD_API
XVID_INIT_PARAM init;
init.api_version = 0;
init.core_build = 0;
init.cpu_flags = XVID_CPU_CHKONLY;
xvid_init(NULL, 0, &init, NULL);
xvid_init(NULL, 0, &init, NULL);
#else
xvid_gbl_init_t init;
init.debug = 0;
init.version = XVID_VERSION;
init.cpu_flags = 0;
xvid_global(NULL, 0, &init, NULL);
#endif
xvid_is_init = GF_TRUE;
}
dec->base_filters = 0;
sOpt = gf_modules_get_option((GF_BaseInterface *)ifcd, "XviD", "PostProc");
if (sOpt) {
#ifndef XVID_USE_OLD_API
if (strstr(sOpt, "FilmEffect")) dec->base_filters |= XVID_FILMEFFECT;
#endif
if (strstr(sOpt, "Deblock_Y")) {
#ifdef XVID_USE_OLD_API
dec->base_filters |= XVID_DEC_DEBLOCKY;
#else
dec->base_filters |= XVID_DEBLOCKY;
#endif
}
if (strstr(sOpt, "Deblock_UV")) {
#ifdef XVID_USE_OLD_API
dec->base_filters |= XVID_DEC_DEBLOCKUV;
#else
dec->base_filters |= XVID_DEBLOCKUV;
#endif
}
}
ifcd->AttachStream = XVID_AttachStream;
ifcd->DetachStream = XVID_DetachStream;
ifcd->GetCapabilities = XVID_GetCapabilities;
ifcd->SetCapabilities = XVID_SetCapabilities;
ifcd->GetName = XVID_GetCodecName;
ifcd->CanHandleStream = XVID_CanHandleStream;
ifcd->ProcessData = XVID_ProcessData;
return (GF_BaseDecoder *) ifcd;
}
void DeleteXVIDDec(GF_BaseDecoder *ifcg)
{
XVIDCTX();
if (ctx->base_codec) xvid_decore(ctx->base_codec, XVID_DEC_DESTROY, NULL, NULL);
if (ctx->depth_codec) xvid_decore(ctx->depth_codec, XVID_DEC_DESTROY, NULL, NULL);
gf_free(ctx);
gf_free(ifcg);
}
#endif
GPAC_MODULE_EXPORT
const u32 *QueryInterfaces()
{
static u32 si [] = {
#ifndef GPAC_DISABLE_AV_PARSERS
GF_MEDIA_DECODER_INTERFACE,
#endif
0
};
return si;
}
GPAC_MODULE_EXPORT
GF_BaseInterface *LoadInterface(u32 InterfaceType)
{
#ifndef GPAC_DISABLE_AV_PARSERS
if (InterfaceType == GF_MEDIA_DECODER_INTERFACE) return (GF_BaseInterface *)NewXVIDDec();
#endif
return NULL;
}
GPAC_MODULE_EXPORT
void ShutdownInterface(GF_BaseInterface *ifce)
{
switch (ifce->InterfaceType) {
#ifndef GPAC_DISABLE_AV_PARSERS
case GF_MEDIA_DECODER_INTERFACE:
DeleteXVIDDec((GF_BaseDecoder*)ifce);
break;
#endif
}
}
GPAC_MODULE_STATIC_DECLARATION( xvid )