From 1d935a2e2b0709ea276d0f312c2a7218ab6928c3 Mon Sep 17 00:00:00 2001 From: Guenter Bartsch Date: Sun, 14 Oct 2001 00:43:06 +0000 Subject: libdivx4 updates from Harm van der Heijden CVS patchset: 794 CVS date: 2001/10/14 00:43:06 --- src/libdivx4/Makefile.am | 9 ++- src/libdivx4/decore-if.h | 177 ++++++++++++++++++++++++++++++++++++++++++++ src/libdivx4/xine_decoder.c | 164 +++++++++++++++++++++++++++++++++++----- 3 files changed, 328 insertions(+), 22 deletions(-) create mode 100644 src/libdivx4/decore-if.h (limited to 'src') diff --git a/src/libdivx4/Makefile.am b/src/libdivx4/Makefile.am index cebb2ab86..a4a2595dc 100644 --- a/src/libdivx4/Makefile.am +++ b/src/libdivx4/Makefile.am @@ -8,14 +8,17 @@ LIBTOOL = $(SHELL) $(top_builddir)/libtool-nofpic libdir = $(XINE_PLUGINDIR) -if HAVE_DIVX4 +# +# use HAVE_DIVX4 to make compilation optional; +# not really needed because the divx4 plugin sources are self-contained. +# +#if HAVE_DIVX4 divx4_module = xineplug_decode_divx4.la -endif +#endif lib_LTLIBRARIES = $(divx4_module) xineplug_decode_divx4_la_SOURCES = xine_decoder.c -xineplug_decode_divx4_la_LIBADD = @DIVX4_LIBS@ xineplug_decode_divx4_la_LDFLAGS = -avoid-version -module debug: diff --git a/src/libdivx4/decore-if.h b/src/libdivx4/decore-if.h new file mode 100644 index 000000000..72e34521a --- /dev/null +++ b/src/libdivx4/decore-if.h @@ -0,0 +1,177 @@ +/* + * Copyright (C) 2001 the xine project + * + * This file is part of xine, a unix video player. + * + * xine is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * xine is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + * $Id: decore-if.h,v 1.1 2001/10/14 00:43:06 guenter Exp $ + * + * This file documents the interface for the decore() function + * in libdivxdecore. In case of problems, it is recommended you compare + * the definitions in this file with the header file that came with your + * divx4 library (see below). + * + * The divxdecore library can be found as part of the divx4linux package at + * http://www.divx.com or http://avifile.sourceforge.net The package also + * contains a text file documenting the decore/encore API. + * + * Alternatively, the open source OpenDivx project (http://www.projectmayo.com) + * also provides a divxdecore library with the same interface. There is + * a project called XviD at http://www.videocoding.de that extends the + * opendivx project. + * + * THIS FILE AND THE XINE DECORE PLUGIN ARE INTENDED FOR THE BINARY DIVX4LINUX + * PACKAGE. OPENDIVX DECORE LIBRARIES ARE CURRENTLY NOT SUPPORTED AND MAY OR + * MAY NOT WORK. + * + * Harm van der Heijden + */ + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _DECORE_IF_H_ +#define _DECORE_IF_H_ + +/* decore commands (2nd parameter in decore()) */ +#define DEC_OPT_MEMORY_REQS 0 +#define DEC_OPT_INIT 1 +#define DEC_OPT_RELEASE 2 +#define DEC_OPT_SETPP 3 +#define DEC_OPT_SETOUT 4 +#define DEC_OPT_FRAME 5 +#define DEC_OPT_FRAME_311 6 +#define DEC_OPT_SETPP2 7 + +/* decore() return values. */ +#define DEC_OK 0 +#define DEC_MEMORY 1 +#define DEC_BAD_FORMAT 2 +#define DEC_EXIT 3 + +/* colour formats -- yuv */ +#define DEC_YUY2 1 +#define DEC_YUV2 DEC_YUY2 +#define DEC_UYVY 2 +#define DEC_420 3 +#define DEC_YV12 13 /* looks like an afterthought, eh? */ + +/* colour formats -- rgb + not yet used by xine, but perhaps in the future. + (decore yuv->rgb conversion may be better than libsdl/Xshm) */ +#define DEC_RGB32 4 +#define DEC_RGB24 5 +#define DEC_RGB555 6 +#define DEC_RGB565 7 + +#define DEC_RGB32_INV 8 +#define DEC_RGB24_INV 9 +#define DEC_RGB555_INV 10 +#define DEC_RGB565_INV 11 + +/* pseudo colour format; makes decore() return pointers to internal + yuv buffers for manual conversion, see DEC_PICTURE */ +#define DEC_USER 12 + +/* memory requirement structure; the officical codec spec calls for + a DEC_OPT_MEMORY_REQ call prior to DEC_OPT_INIT, but it does not + actually seem to be used */ +typedef struct +{ + unsigned long mp4_edged_ref_buffers_size; + unsigned long mp4_edged_for_buffers_size; + unsigned long mp4_edged_back_buffers_size; + unsigned long mp4_display_buffers_size; + unsigned long mp4_state_size; + unsigned long mp4_tables_size; + unsigned long mp4_stream_size; + unsigned long mp4_reference_size; +} DEC_MEM_REQS; + +/* included in DEC_PARAM for init, not really used otherwise. */ +typedef struct +{ + void * mp4_edged_ref_buffers; + void * mp4_edged_for_buffers; + void * mp4_edged_back_buffers; + void * mp4_display_buffers; + void * mp4_state; + void * mp4_tables; + void * mp4_stream; + void * mp4_reference; +} DEC_BUFFERS; + +/* struct for DEC_OPT_INIT */ +typedef struct +{ + int x_dim; /* frame width */ + int y_dim; /* frame height */ + int output_format; /* refers to colour formats defined above */ + int time_incr; /* mystery parameter, use 15 */ + DEC_BUFFERS buffers; /* memcpy 0's in this struct before init */ +} DEC_PARAM; + +/* struct for DEC_OPT_DECODE */ +typedef struct +{ + void *bmp; /* pointer to rgb, yuv or DEC_PICTURE buffer */ + void *bitstream; /* input bit stream */ + long length; /* length of input */ + int render_flag; /* 1 to actually render the frame */ + unsigned int stride; /* bmp stride; should be width */ +} DEC_FRAME; + +/* decode frame information. not yet used by xine */ +typedef struct +{ + int intra; + int *quant_store; + int quant_stride; +} DEC_FRAME_INFO; + +/* structure for DEC_OPT_SETPP, for setting the postprocessing level */ +typedef struct +{ + int postproc_level; /* between 0-100, actually used 0-60 */ +} DEC_SET; + +/* structure for DEC_USER output format, should be used instead of bmp ptr */ +typedef struct +{ + void *y; + void *u; + void *v; + int stride_y; + int stride_uv; +} DEC_PICTURE; + +/* Finally, decore() itself. Refer to the official codec interface text for + a complete description. */ +int decore( unsigned long handle, unsigned long dec_opt, void* param1, void* param2); +/* handle: unique caller handle. xine uses the video_decoder_t ptr. + dec_opt: decore command id + param1: depends on command. Usually ptr to struct with input values. + param2: depends on command. Usually ptr to struct with output values. */ + +/* typedef for pointer to decore function */ +typedef int (*decoreFunc)(unsigned long, unsigned long, void*, void*); + +#endif // _DECORE_IF_H_ +#ifdef __cplusplus +} +#endif + diff --git a/src/libdivx4/xine_decoder.c b/src/libdivx4/xine_decoder.c index 9052a30a5..752c9beef 100644 --- a/src/libdivx4/xine_decoder.c +++ b/src/libdivx4/xine_decoder.c @@ -17,7 +17,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * - * $Id: xine_decoder.c,v 1.1 2001/10/07 18:06:00 guenter Exp $ + * $Id: xine_decoder.c,v 1.2 2001/10/14 00:43:06 guenter Exp $ * * xine decoder plugin using divx4 * @@ -41,6 +41,7 @@ #include #include #include +#include #include "xine_internal.h" #include "cpu_accel.h" @@ -48,7 +49,7 @@ #include "buffer.h" #include "metronom.h" -#include +#include "decore-if.h" /* now this is ripped of wine's vfw.h */ typedef struct { @@ -77,6 +78,7 @@ typedef struct divx4_decoder_s { long biHeight; unsigned char buf[128*1024]; int size; + decoreFunc decore; /* ptr to decore function in libdivxdecore */ /* whether to decode MSMPEG4_V3 format (aka divx ;-) and divx 3.11-- thank god they dropped the smileys with divx4) @@ -85,6 +87,18 @@ typedef struct divx4_decoder_s { /* postprocessing level; currently valid values 0-6 (internally 0-100) set by divx4_postproc in .xinerc */ int postproc; + /* what output format we ask of decore() + supported at the moment: + DEC_YV12, copied straight into image buffer by decore(), + fast but perhaps risky. + DEC_USER, decore() returns pointers to internal y,u,v buffers, + and we copy the data ourselves. Not optimised, so probably slower. + It seems that OpenDivx likes this better. */ + int decore_format; + /* can we handle 311 format? No easy way to find out (divx4linux can, + OpenDivx cannot, so the user can set it in .xinerc. If 0, can_handle + only returns MPEG4, yielding 311 to ffmpeg */ + int can_handle_311; } divx4_decoder_t; static unsigned long str2ulong(void *data) { @@ -93,11 +107,23 @@ static unsigned long str2ulong(void *data) { return ( str[0] | (str[1]<<8) | (str[2]<<16) | (str[3]<<24) ); } +static char* decore_retval(int ret) +{ + switch (ret) { + case DEC_OK: return "DEC_OK"; + case DEC_MEMORY: return "DEC_MEMORY"; + case DEC_BAD_FORMAT: return "DEC_BAD_FORMAT"; + case DEC_EXIT: return "DEC_EXIT"; + } + return "[Unknown code]"; +} + static int divx4_can_handle (video_decoder_t *this_gen, int buf_type) { + divx4_decoder_t *this = (divx4_decoder_t *) this_gen; buf_type &= 0xFFFF0000; /* divx4 currently does not support MSMPEG4 v1/v2 */ - return ( buf_type == BUF_VIDEO_MSMPEG4_V3 || + return ( (buf_type == BUF_VIDEO_MSMPEG4_V3 && this->can_handle_311) || /* buf_type == BUF_VIDEO_MSMPEG4_V12 || */ buf_type == BUF_VIDEO_MPEG4); } @@ -116,6 +142,8 @@ static void divx4_decode_data (video_decoder_t *this_gen, buf_element_t *buf) { DEC_PARAM param; /* for init */ DEC_SET setpp; /* for setting postproc level */ DEC_FRAME frame; /* for getting a frame */ + DEC_PICTURE pict;/* contains ptrs to the decoders internal yuv buffers */ + int ret; divx4_decoder_t *this = (divx4_decoder_t *) this_gen; @@ -151,17 +179,27 @@ static void divx4_decode_data (video_decoder_t *this_gen, buf_element_t *buf) { /* FIXME: the decoder can also supply RGB data, and my avifile experience is that it's far preferable over generic yuv conversion. Would this be interesting for the XShm crowd, lacking a YUV overlay? */ - param.output_format=DEC_YV12; + param.output_format=this->decore_format; memset(¶m.buffers, 0, sizeof(param.buffers)); - /* FIXME: check return value: */ - decore((unsigned long)this, DEC_OPT_INIT, ¶m, &this->bih); + + ret = this->decore((unsigned long)this, DEC_OPT_INIT, ¶m, &this->bih); + if (ret != DEC_OK) { + printf("divx4: decore DEC_OPT_INIT command returned %s.\n", decore_retval(ret)); + return; + } /* multiply postproc level by 10 for internal consumption */ - printf("Divx4: Setting post processing level to %d (see ~/.xinerc)\n" - "Divx4: Valid range 0-6, reduce if you get frame drop\n", + printf("divx4: Setting post processing level to %d (see ~/.xinerc)\n" + "divx4: Valid range 0-6, reduce if you get frame drop\n", this->postproc); setpp.postproc_level=this->postproc*10; - decore((unsigned long)this, DEC_OPT_SETPP, &setpp, 0); + + ret = this->decore((unsigned long)this, DEC_OPT_SETPP, &setpp, 0); + if (ret != DEC_OK) + { + printf("divx4: decore DEC_OPT_SETPP command returned %s.\n", decore_retval(ret)); + /* perhaps not fatal, so we'll continue */ + } this->decoder_ok = 1; this->video_out->open (this->video_out); @@ -172,8 +210,8 @@ static void divx4_decode_data (video_decoder_t *this_gen, buf_element_t *buf) { this->size += buf->size; - if (buf->decoder_info[0] == 2) { // what does this mean? - // allocate image (taken from ffmpeg plugin) + if (buf->decoder_info[0] == 2) { /* what does this mean? */ + /* allocate image (taken from ffmpeg plugin) */ vo_frame_t *img; img = this->video_out->get_frame (this->video_out, /* this->av_picture.linesize[0], */ @@ -186,21 +224,68 @@ static void divx4_decode_data (video_decoder_t *this_gen, buf_element_t *buf) { /* setup the decode frame parameters, as demonstrated by avifile. - FIXME: I assume here that the layout of base[] is flat, - i.e. that base[0], [1] and [2] all point inside the same + If decore format is DEC_YV12, I assume here that the layout of + base[] is flat, i.e. that base[0], [1] and [2] all point inside the same contiguous bit of memory. It seems to work for the Xv driver - but I don not know if this is always acceptable. + but I don't not know if this is always acceptable. Use DEC_USER if this + causes problems (configurable via .xinerc). Also, OpenDivx seems to + prefer DEC_USER. */ frame.bitstream= (void*)this->buf; - frame.bmp=img->base[0]; // can I do this? + + if (this->decore_format == DEC_USER) + frame.bmp=&pict; /* decore will set ptrs to internal y,u&v buffers */ + else + frame.bmp=img->base[0]; /* YV12: assume y,u & v buffers are contiguous */ + frame.length=this->size; frame.render_flag=1; frame.stride=this->biWidth; if(this->use_311_compat) - decore((unsigned long)this, DEC_OPT_FRAME_311, &frame, 0); + ret = this->decore((unsigned long)this, DEC_OPT_FRAME_311, &frame, 0); else - decore((unsigned long)this, DEC_OPT_FRAME, &frame, 0); + ret = this->decore((unsigned long)this, DEC_OPT_FRAME, &frame, 0); + + if (ret != DEC_OK) { + printf("divx4: decore DEC_OPT_FRAME command returned %s.\n", decore_retval(ret)); + img->bad_frame = 1; /* better skip this one */ + } + else if (this->decore_format == DEC_USER) + { + /* We need to copy the yuv data from the decoder's internal buffers. + Y size is width*height, U and V width*height/4 */ + int i; + int src_offset,dst_offset; + /* shortcut if stride_y equals width */ + if (pict.stride_y == img->width) { + memcpy(img->base[0], pict.y, img->width*img->height); + } + else { /* copy line by line */ + src_offset=dst_offset = 0; + for (i=0; iheight; i++) { + memcpy(img->base[0]+dst_offset, pict.y+src_offset, img->width); + src_offset += pict.stride_y; + dst_offset += img->width; + } + } + /* same for u,v data, but at 1/4 resolution. + FIXME: Weird... I thought YV12 means order y-v-u, yet base[1] + seems to be u and base[2] is v. */ + if (pict.stride_uv == img->width>>1) { + memcpy(img->base[1], pict.u, (img->width*img->height)>>2); + memcpy(img->base[2], pict.v, (img->width*img->height)>>2); + } + else { + src_offset=dst_offset = 0; + for (i=0; iheight>>1; i++) { + memcpy(img->base[1]+dst_offset, pict.u+src_offset, img->width>>1); + memcpy(img->base[2]+dst_offset, pict.v+src_offset, img->width>>1); + src_offset += pict.stride_uv; + dst_offset += img->width>>1; + } + } + } /* this again from ffmpeg plugin */ img->PTS = buf->PTS; @@ -218,7 +303,9 @@ static void divx4_close (video_decoder_t *this_gen) { if (this->decoder_ok) { /* FIXME: this segfaults here - decore((unsigned long)this, DEC_OPT_RELEASE, 0, 0);*/ + (note: avifile also has the release command commented out; + probably a known 'feature') + this->decore((unsigned long)this, DEC_OPT_RELEASE, 0, 0);*/ this->video_out->close(this->video_out); this->decoder_ok = 0; @@ -234,6 +321,9 @@ static char *divx4_get_id(void) { video_decoder_t *init_video_decoder_plugin (int iface_version, config_values_t *cfg) { divx4_decoder_t *this ; + char *libdecore_name; + void *libdecore_handle; + decoreFunc libdecore_func = 0; if (iface_version != 2) { printf( "divx4: plugin doesn't support plugin API version %d.\n" @@ -244,6 +334,22 @@ video_decoder_t *init_video_decoder_plugin (int iface_version, config_values_t * return NULL; } + /* Try to dlopen libdivxdecore, then look for decore function + if it fails, print a message and return 0 so that xine ignores + us from then on. */ + libdecore_name = cfg->lookup_str(cfg, "divx4_libdivxdecore", "libdivxdecore.so"); + libdecore_handle = dlopen(libdecore_name, RTLD_LAZY); + if (libdecore_handle) + libdecore_func = dlsym(libdecore_handle, "decore"); + if (! libdecore_func) { + printf("divx4: could not find decore function in library \"%s\"\n" + "divx4: system returned \"%s\"\n" + "divx4: libdivxdecore unavailable; this plugin will be disabled.\n", + libdecore_name, dlerror()); + return NULL; + } + printf("divx4: successfully opened \"%s\"\n", libdecore_name); + this = (divx4_decoder_t *) malloc (sizeof (divx4_decoder_t)); this->video_decoder.interface_version = 2; @@ -253,9 +359,29 @@ video_decoder_t *init_video_decoder_plugin (int iface_version, config_values_t * this->video_decoder.close = divx4_close; this->video_decoder.get_identifier = divx4_get_id; this->video_decoder.priority = cfg->lookup_int(cfg, "divx4_priority", 6); - this->postproc = cfg->lookup_int(cfg, "divx4_postproc", 3); + this->decore = libdecore_func; + this->postproc = cfg->lookup_int(cfg, "divx4_postproc", 3); + this->decore_format = cfg->lookup_int(cfg, "divx4_decoreformat", 1); + this->can_handle_311 = cfg->lookup_int(cfg, "divx4_msmpeg4v3", 1); this->size = 0; + /* at the moment availabe values are 0-6, but future versions may support + higher levels. Internally, postproc is multiplied by 10 and values + between 0 and 100 are valid */ + if (this->postproc > 10) this->postproc=10; + if (this->postproc < 0) this->postproc=0; + + /* translate the decore_format value to the internal constant, correct if + an illegal value was given. + This might someday be extended to allow for RGB output from the decoder */ + if (this->decore_format == 0) this->decore_format = DEC_YV12; + else if (this->decore_format == 1) this->decore_format = DEC_USER; + else { + printf("divx4: Illegal value %d for divx4_decoreformat, using 1.\n" + "divx4: Valid are 0 (YV12, faster) and 1 (USER, safer). No quality difference.\n", + this->decore_format); + this->decore_format = DEC_USER; + } return (video_decoder_t *) this; } -- cgit v1.2.3