From fe2a390351727cb5ae264588293f8bd7d6d5198e Mon Sep 17 00:00:00 2001 From: Miguel Freitas Date: Tue, 28 Sep 2004 18:49:38 +0000 Subject: xxmc patch by Thomas Hellstrom (with some changes) there is still some work to do, please report any breakages. note: new xxmc driver tested with both nvidia and via libraries. CVS patchset: 7007 CVS date: 2004/09/28 18:49:38 --- AUTHORS | 6 +- ChangeLog | 8 +- configure.ac | 187 ++- include/xine.h.in | 3 +- src/libmpeg2/Makefile.am | 3 +- src/libmpeg2/decode.c | 146 ++- src/libmpeg2/header.c | 5 +- src/libmpeg2/mpeg2.h | 9 +- src/libmpeg2/mpeg2_internal.h | 3 + src/libmpeg2/slice_xvmc.c | 9 +- src/libmpeg2/slice_xvmc_vld.c | 248 ++++ src/libmpeg2/xxmc.h | 12 + src/video_out/Makefile.am | 11 +- src/video_out/alphablend.c | 188 +++ src/video_out/alphablend.h | 40 + src/video_out/video_out_xvmc.c | 17 +- src/video_out/video_out_xxmc.c | 2652 ++++++++++++++++++++++++++++++++++++++++ src/video_out/xvmc_mocomp.c | 274 +++++ src/video_out/xvmc_vld.c | 171 +++ src/video_out/xxmc.h | 293 +++++ src/xine-engine/Makefile.am | 3 +- src/xine-engine/accel_xvmc.h | 152 +++ src/xine-engine/post.c | 36 +- src/xine-engine/video_out.c | 60 +- src/xine-engine/video_out.h | 61 +- 25 files changed, 4396 insertions(+), 201 deletions(-) create mode 100644 src/libmpeg2/slice_xvmc_vld.c create mode 100644 src/libmpeg2/xxmc.h create mode 100644 src/video_out/video_out_xxmc.c create mode 100644 src/video_out/xvmc_mocomp.c create mode 100644 src/video_out/xvmc_vld.c create mode 100644 src/video_out/xxmc.h create mode 100644 src/xine-engine/accel_xvmc.h diff --git a/AUTHORS b/AUTHORS index 85f2f36e2..e024c6460 100644 --- a/AUTHORS +++ b/AUTHORS @@ -503,5 +503,9 @@ Ryan Tadlock Casper Boemann reuse stubs for unresolved exports of win32 dlls - + +Thomas Hellström + XxMC driver with reworked XvMC support, including VIA CLE266 vld + extensions. + (let us know if we've forgotten anyone) diff --git a/ChangeLog b/ChangeLog index 19a4196c5..3dc83ee53 100644 --- a/ChangeLog +++ b/ChangeLog @@ -7,7 +7,13 @@ (these files required cropping after decoding) * Fix crashes with some input plugins when no audio output was available * Windows ports updates and cleanups - + * new xxmc driver supporting XvMC with extended vld (for VIA CLE266), + idct and mocomp accelerations. includes automatic Xv fallback for + non-mpeg streams. supports overlays and OSD. + * suggested using the libXvMCW so xine won't depend on any vendor + specific library. you can get the old behaviour (not recommended) + using ./configure --with-xvmc-lib=XvMCNVIDIA + xine-lib (1-rc6) * Moved win32 frontend into separate module. * Fixed Xv initialization to enable multiple instances of the Xv plugin diff --git a/configure.ac b/configure.ac index 8071d2a7c..35f1f683b 100644 --- a/configure.ac +++ b/configure.ac @@ -472,8 +472,6 @@ dnl static linking is preferred! dnl but only dynamic linking is possible when using libtool < 1.4.0 AC_PREREQ_LIBTOOL(1.4.0, xv_lib="libXv.a", xv_lib="libXv.so") -AC_PREREQ_LIBTOOL(1.4.0, xvmc_lib="libXvMC.a", xvmc_lib="libXvMC.so") -AC_PREREQ_LIBTOOL(1.4.0, xvmc_lib_nv="libXvMCNVIDIA.a", xv_lib_nv="libXvMCNVIDIA_dynamic.so.1") host_or_hostalias="$host" if test "$host_or_hostalias" = ""; then @@ -492,14 +490,6 @@ case "$host_or_hostalias" in echo "warning: hppa linker - disabling static libXv" xv_lib="libXv.so" fi - if test "$xvmc_lib" = "libXvMC.a"; then - echo "warning: hppa linker - disabling static libXvMC" - xvmc_lib="libXvMC.so" - fi - if test "$xvmc_lib_nv" = "libXvMCNVIDIA.a"; then - echo "warning: hppa linker - disabling static libXvMCNVIDIA" - xvmc_lib_nv="libXvMCNVIDIA_dynamic.so.1" - fi ;; i386-*-freebsd*) @@ -566,45 +556,138 @@ AC_SUBST(XV_LIB) AC_SUBST(EXTRA_X_LIBS) AC_SUBST(EXTRA_X_CFLAGS) -AC_ARG_WITH(xvmc-path, AC_HELP_STRING([--with-xvmc-path=path], [where libXvMC is installed]), - xvmc_path="$withval", xvmc_path="/usr/X11R6/lib") - -AC_CHECK_LIB(XvMC, XvMCQueryExtension, - [ AC_MSG_CHECKING(for $xvmc_lib location) - if test -f "$xvmc_path/$xvmc_lib_nv"; then - if test -f "$xvmc_path/$xvmc_lib"; then - AC_MSG_RESULT(found in $xvmc_path) - XVMC_LIB="-L$xvmc_path -lXvMC -lXvMCNVIDIA" - AC_DEFINE(HAVE_XVMC,1,[Define this if you have libXvMC installed]) - ac_have_xvmc="yes" - if test x$xvmc_lib = "xlibXvMC.a" ; then - AC_DEFINE(HAVE_XVMC_STATIC,1,[Define this if you have libXvMC.a]) - fi - else - AC_MSG_RESULT(not found in $xvmc_path) - echo - echo "****************************************************************" - echo "* if you don't have a libXvMC.so on your system, use: *" - echo "* ld --whole-archive -shared -o libXvMC.so.1 libXvMC.a *" - echo "* then: ln -s libXvMC.so.1 libXvMC.so *" - echo "* to create it or try to use --with-xvmc-path to set the *" - echo "* location of libXvMC.so *" - echo "****************************************************************" - echo - fi - fi ],, [$X_LIBS $X_PRE_LIBS -lXext $X_EXTRA_LIBS]) +dnl +dnl Check if we can enable the xxmc plugin. +dnl +if test x$no_x = "x"; then + +AC_ARG_WITH(xxmc-path, AC_HELP_STRING([--with-xxmc-path=path], [where libXvMC libraries for the + xxmc plugin are installed. Defalts to the default X library path.]), + xxmc_path="$withval", xxmc_path="$x_libraries") +AC_ARG_WITH(xxmc-lib, AC_HELP_STRING([--with-xxmc-lib=XXXX], [The name of the XvMC library + libXXXX.so for the xxmc plugin.]),xxmc_stub="$withval", + xxmc_stub="XvMCW") +saved_libs="$LIBS" +XXMC_LIB="-L$xxmc_path -l$xxmc_stub" +AC_MSG_CHECKING(whether to enable the xxmc plugin with vld extensions) +AC_MSG_RESULT() +dnl Check if vld "extended" XvMC is available +if test x$xxmc_stub == "xXvMCW"; then + AC_CHECK_LIB($xxmc_stub, XvMCPutSlice, + ac_have_xxmc="yes", + [ac_have_xxmc="no" + AC_MSG_RESULT([*** Could not link with -l$xxmc_stub for vld extensions.])], + [-L$xxmc_path $X_LIBS $X_PRE_LIBS $XV_LIB -lXext $X_EXTRA_LIBS]) +else + if test x$ac_have_xv = "xyes"; then + AC_CHECK_LIB($xxmc_stub, XvMCPutSlice, + [ac_have_xxmc="yes" + XXMC_LIB="$XXMC_LIB -lXvMC"], + [ac_have_xxmc="no" + AC_MSG_RESULT([*** Could not link with -l$xxmc_stub -lXvMC for vld extensions.])], + [-L$xxmc_path -lXvMC $X_LIBS $X_PRE_LIBS $XV_LIB -lXext $X_EXTRA_LIBS]) + else + ac_have_xxmc="no", + fi +fi +if test x$ac_have_xxmc = "xyes"; then + AC_CHECK_HEADERS($x_includes/X11/extensions/vldXvMC.h, + [ac_have_vldxvmc_h="yes"], + ac_have_xxmc="no",) + if test "x$ac_have_vldxvmc_h" = "xyes"; then + AC_DEFINE([HAVE_VLDXVMC], [1], + [Define 1 if you have vldXvMC.h]) + fi +fi +AM_CONDITIONAL(HAVE_VLDXVMC, test x$ac_have_vldxvmc_h = "xyes") +dnl Try fallback to standard XvMC if vld failed +if test x$ac_have_xxmc = "xno"; then + if test x$xxmc_stub == "xXvMCW"; then + AC_CHECK_LIB($xxmc_stub, XvMCCreateContext, + ac_have_xxmc="yes", + [ac_have_xxmc="no" + AC_MSG_RESULT([*** Could not link with -l$xxmc_stub for standard XvMC.])], + [-L$xxmc_path $X_LIBS $X_PRE_LIBS $XV_LIB -lXext $X_EXTRA_LIBS]) + else + if test x$ac_have_xv = "xyes"; then + AC_CHECK_LIB($xxmc_stub, XvMCCreateContext, + [ac_have_xxmc="yes" + XXMC_LIB="$XXMC_LIB -lXvMC"], + [ac_have_xxmc="no" + AC_MSG_RESULT([*** Could not link with -lXvMC for standard XvMC.])], + [-L$xxmc_path -lXvMC $X_LIBS $X_PRE_LIBS $XV_LIB -lXext $X_EXTRA_LIBS]) + else + ac_have_xxmc="no", + fi + fi +fi +if test x$ac_have_xxmc = "xyes"; then + AC_CHECK_HEADERS($x_includes/X11/extensions/XvMC.h,, + ac_have_xxmc="no",) +fi +if test x$ac_have_xxmc = "xyes"; then + AC_DEFINE(HAVE_XXMC,1,[Define this to compile the xxmc plugin.]) + if test "x$ac_have_vldxvmc_h" = "xyes"; then + AC_MSG_RESULT([*** Enabling xxmc plugin with vld extensions.]) + else + AC_MSG_RESULT([*** Enabling xxmc plugin for standard XvMC *only*.]) + fi +else + AC_MSG_RESULT([*** Disabling xxmc plugin due to above errors.]) +fi +LIBS="$saved_libs" +fi +AM_CONDITIONAL(HAVE_XXMC, test x$ac_have_xxmc = "xyes") +AC_SUBST(XXMC_LIB) -AM_CONDITIONAL(HAVE_XVMC, test x$ac_have_xvmc = "xyes") -dnl AM_CONDITIONAL(HAVE_XVMC_STATIC, test x$ac_have_xvmc = "xyes" -a x$xvmc_lib = "xlibXvMC.a") dnl -dnl xine_check use XvMC functions API. +dnl Check if we can enable the xvmc plugin. dnl +if test x$no_x = "x"; then + +AC_ARG_WITH(xvmc-path, AC_HELP_STRING([--with-xvmc-path=path], [where libXvMC libraries for the + xvmc plugin are installed. Defalts to the default X library path.]), + xvmc_path="$withval", xvmc_path="$x_libraries") +AC_ARG_WITH(xvmc-lib, AC_HELP_STRING([--with-xvmc-lib=XXXX], [The name of the XvMC library + libXXXX.so for the xvmc plugin.]),xvmc_stub="$withval", + xvmc_stub="XvMCW") +saved_libs="$LIBS" +XVMC_LIB="-L$xvmc_path -l$xvmc_stub" +AC_MSG_CHECKING(whether to enable the xvmc plugin) +AC_MSG_RESULT() +if test x$xvmc_stub == "xXvMCW"; then + AC_CHECK_LIB($xvmc_stub, XvMCCreateContext, + ac_have_xvmc="yes", + [ac_have_xvmc="no" + AC_MSG_RESULT([*** Could not link with -l$xvmc_stub.])], + [-L$xvmc_path $X_LIBS $X_PRE_LIBS $XV_LIB -lXext $X_EXTRA_LIBS]) +else + if test x$ac_have_xv = "xyes"; then + AC_CHECK_LIB($xvmc_stub, XvMCCreateContext, + [ac_have_xvmc="yes" + XVMC_LIB="$XVMC_LIB -lXvMC"], + [ac_have_xvmc="no" + AC_MSG_RESULT([*** Could not link with -lXvMC.])], + [-L$xvmc_path -lXvMC $X_LIBS $X_PRE_LIBS $XV_LIB -lXext $X_EXTRA_LIBS]) + else + ac_have_xvmc="no", + fi +fi if test x$ac_have_xvmc = "xyes"; then - EXTRA_X_LIBS="-L$xvmc_path $XVMC_LIBS -lXext" - EXTRA_X_CFLAGS="" + AC_CHECK_HEADERS($x_includes/X11/extensions/XvMC.h,, + ac_have_xvmc="no",) +fi +if test x$ac_have_xvmc = "xyes"; then + AC_DEFINE(HAVE_XVMC,1,[Define this if you have an XvMC library and XvMC.h installed.]) + AC_MSG_RESULT([*** Enabling old xvmc plugin.]) +else + AC_MSG_RESULT([*** Disabling old xvmc plugin due to above errors.]) fi -AC_SUBST(XVMC_LIB) +LIBS="$saved_libs" +fi +AM_CONDITIONAL(HAVE_XVMC, test x$ac_have_xvmc = "xyes") +AC_SUBST(XVMC_LIB) dnl --------------------------------------------- dnl Checks for Xinerama extension @@ -2330,21 +2413,17 @@ if test x"$no_x" != "xyes"; then echo " - Xv (XVideo *shared*)" fi fi - dnl XvMC - if test x$ac_have_xvmc = "xyes"; then - if test x$xvmc_lib="xlibXvMC.a"; then - echo " - XvMC (XVideo *static*)" + dnl XxMC + if test x$ac_have_xxmc = "xyes"; then + if test "x$ac_have_vldxvmc_h" = "xyes"; then + echo " - XxMC (XVideo extended motion compensation)" else - echo " - XvMC (XVideo *shared*)" + echo " - XxMC (XVideo motion compensation - vld extensions DISABLED)" fi fi - dnl XvMCNVIDIA + dnl XvMC if test x$ac_have_xvmc = "xyes"; then - if test x$xvmc_lib="xlibXvMCNVIDIA.a"; then - echo " - XvMCNVIDIA (XVideo *static*)" - else - echo " - XvMCNVIDIA (XVideo *shared*)" - fi + echo " - XvMC (XVideo motion compensation)" fi if test x$ac_have_opengl = "xyes" -a x$ac_have_glut="xyes" -o \ x$ac_have_opengl = "xyes" -a x$ac_have_glu="xyes"; then diff --git a/include/xine.h.in b/include/xine.h.in index f03e9fa1d..a4633c78e 100644 --- a/include/xine.h.in +++ b/include/xine.h.in @@ -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.h.in,v 1.130 2004/09/22 20:18:50 miguelfreitas Exp $ + * $Id: xine.h.in,v 1.131 2004/09/28 18:49:39 miguelfreitas Exp $ * * public xine-lib (libxine) interface and documentation * @@ -417,6 +417,7 @@ int xine_get_current_frame (xine_stream_t *stream, #define XINE_IMGFMT_YV12 (('2'<<24)|('1'<<16)|('V'<<8)|'Y') #define XINE_IMGFMT_YUY2 (('2'<<24)|('Y'<<16)|('U'<<8)|'Y') #define XINE_IMGFMT_XVMC (('C'<<24)|('M'<<16)|('v'<<8)|'X') +#define XINE_IMGFMT_XXMC (('C'<<24)|('M'<<16)|('x'<<8)|'X') /* get current xine's virtual presentation timestamp (1/90000 sec) * note: this is mostly internal data. diff --git a/src/libmpeg2/Makefile.am b/src/libmpeg2/Makefile.am index c0d06d978..78351525d 100644 --- a/src/libmpeg2/Makefile.am +++ b/src/libmpeg2/Makefile.am @@ -21,10 +21,11 @@ xineplug_decode_mpeg2_la_SOURCES = \ motion_comp_vis.c \ slice.c \ slice_xvmc.c \ + slice_xvmc_vld.c \ stats.c \ xine_decoder.c xineplug_decode_mpeg2_la_LIBADD = $(MLIB_LIBS) $(XINE_LIB) xineplug_decode_mpeg2_la_LDFLAGS = -avoid-version -module @XINE_PLUGIN_MIN_SYMS@ -noinst_HEADERS = vlc.h mpeg2.h mpeg2_internal.h idct_mlib.h vis.h +noinst_HEADERS = vlc.h mpeg2.h xxmc.h mpeg2_internal.h idct_mlib.h vis.h diff --git a/src/libmpeg2/decode.c b/src/libmpeg2/decode.c index bb5076489..114e8bc11 100644 --- a/src/libmpeg2/decode.c +++ b/src/libmpeg2/decode.c @@ -1,4 +1,4 @@ -/* + /* * decode.c * Copyright (C) 2000-2002 Michel Lespinasse * Copyright (C) 1999-2000 Aaron Holtzman @@ -25,7 +25,6 @@ */ #include "config.h" - #include #include /* memcpy/memset, try to remove */ #include @@ -42,6 +41,7 @@ #include "mpeg2.h" #include "mpeg2_internal.h" #include "xineutils.h" +#include "xxmc.h" /* #define LOG_PAN_SCAN @@ -90,7 +90,10 @@ void mpeg2_init (mpeg2dec_t * mpeg2dec, /* initialize substructures */ mpeg2_header_state_init (mpeg2dec->picture); - if( output->get_capabilities(output) & VO_CAP_XVMC_MOCOMP ) { + if ( output->get_capabilities(output) & VO_CAP_XXMC) { + printf("libmpeg2: output port has XxMC capability\n"); + mpeg2dec->frame_format = XINE_IMGFMT_XXMC; + } else if( output->get_capabilities(output) & VO_CAP_XVMC_MOCOMP) { printf("libmpeg2: output port has XvMC capability\n"); mpeg2dec->frame_format = XINE_IMGFMT_XVMC; } else { @@ -274,6 +277,38 @@ static inline int parse_chunk (mpeg2dec_t * mpeg2dec, int code, if (is_frame_done && picture->current_frame != NULL) { + /* + * This frame completion code will move to a separate libmpeg2_accel.c file? + * int libmpeg2_accel_frame_completion(mpeg2dec_t *, picture_t *, int); + */ + + if (mpeg2dec->frame_format == XINE_IMGFMT_XXMC) { + xine_xxmc_t *xxmc = (xine_xxmc_t *) + picture->current_frame->accel_data; + switch(xxmc->format) { + case XINE_IMGFMT_XXMC: + switch(xxmc->acceleration) { + case XINE_XVMC_ACCEL_VLD: + mpeg2_xxmc_vld_frame_complete(mpeg2dec, picture, code); + break; + case XINE_XVMC_ACCEL_IDCT: + case XINE_XVMC_ACCEL_MOCOMP: + xxmc->decoded = !picture->current_frame->bad_frame; + xxmc->proc_xxmc_flush( picture->current_frame ); + break; + default: + break; + } + default: + break; + } + } + + /* + * End of frame completion code. + */ + + if (((picture->picture_structure == FRAME_PICTURE) || (picture->second_field)) ) { @@ -486,7 +521,7 @@ static inline int parse_chunk (mpeg2dec_t * mpeg2dec, int code, picture->current_frame != picture->forward_reference_frame ) { picture->current_frame->free (picture->current_frame); } - if (picture->picture_coding_type == B_TYPE) + if (picture->picture_coding_type == B_TYPE) { picture->current_frame = mpeg2dec->stream->video_out->get_frame (mpeg2dec->stream->video_out, picture->coded_picture_width, @@ -494,7 +529,15 @@ static inline int parse_chunk (mpeg2dec_t * mpeg2dec, int code, get_aspect_ratio(mpeg2dec), mpeg2dec->frame_format, flags); - else { + /* + * Move to libmpeg2_accel.c + * int libmpeg2_accel_new_frame(mpeg2dec_t *, picture_t *) + */ + mpeg2_xxmc_choose_coding(mpeg2dec->frame_format, picture); + /* + * End of new frame accel code. + */ + } else { picture->current_frame = mpeg2dec->stream->video_out->get_frame (mpeg2dec->stream->video_out, picture->coded_picture_width, @@ -502,6 +545,14 @@ static inline int parse_chunk (mpeg2dec_t * mpeg2dec, int code, get_aspect_ratio(mpeg2dec), mpeg2dec->frame_format, flags); + /* + * Move to libmpeg2_accel.c + * int libmpeg2_accel_new_frame(mpeg2dec_t *, picture_t *) + */ + mpeg2_xxmc_choose_coding(mpeg2dec->frame_format, picture); + /* + * End of new frame accel code. + */ if (picture->forward_reference_frame && picture->forward_reference_frame != picture->backward_reference_frame) picture->forward_reference_frame->free (picture->forward_reference_frame); @@ -510,11 +561,30 @@ static inline int parse_chunk (mpeg2dec_t * mpeg2dec, int code, picture->backward_reference_frame; picture->backward_reference_frame = picture->current_frame; } - if(mpeg2dec->new_sequence) - { - picture->mc = picture->current_frame->macroblocks; - mpeg2dec->new_sequence = 0; + + /* + * Move to libmpeg2_accel.c + * int libmpeg2_accel_new_sequence(mpeg2dec_t *, picture_t *) + */ + + if(mpeg2dec->new_sequence) { + switch(mpeg2dec->frame_format) { + case XINE_IMGFMT_XXMC: + case XINE_IMGFMT_XVMC: { + xine_xvmc_t *xvmc = (xine_xvmc_t *) + picture->current_frame->accel_data; + picture->mc = xvmc->macroblocks; + mpeg2dec->new_sequence = 0; + break; + } + default: + break; + } } + /* + * End of new sequence accel code. + */ + picture->current_frame->bad_frame = 1; picture->current_frame->drawn = 0; picture->current_frame->pts = mpeg2dec->pts; @@ -543,6 +613,7 @@ static inline int parse_chunk (mpeg2dec_t * mpeg2dec, int code, picture->current_frame->id, picture->picture_coding_type == I_TYPE ? "I" : picture->picture_coding_type == P_TYPE ? "P" : "B"); mpeg2dec->pts = 0; + /*printf("Starting to decode frame %d\n",picture->current_frame->id);*/ } } @@ -551,17 +622,50 @@ static inline int parse_chunk (mpeg2dec_t * mpeg2dec, int code, printf("slice target %08x past %08x future %08x\n",picture->current_frame,picture->forward_reference_frame,picture->backward_reference_frame); fflush(stdout); #endif - - if(picture->mc && picture->mc->xvmc_accel) { - mpeg2_xvmc_slice (picture, code, buffer); - - } else { - mpeg2_slice (picture, code, buffer); + /* + * The below accelerated slice function choice will move to libmpeg2_accel.c ? + * int libmpeg2_accel_slice(mpeg2dec_t *, picture_t *, int , char *) + */ + + switch( mpeg2dec->frame_format ) { + case XINE_IMGFMT_XXMC: + { + xine_xxmc_t *xxmc = (xine_xxmc_t *) + picture->current_frame->accel_data; + switch(xxmc->format) { + case XINE_IMGFMT_XXMC: + switch(xxmc->acceleration) { + case XINE_XVMC_ACCEL_VLD: + mpeg2_xxmc_slice(mpeg2dec, picture, code, buffer); + break; + case XINE_XVMC_ACCEL_IDCT: + case XINE_XVMC_ACCEL_MOCOMP: + mpeg2_xvmc_slice (picture, code, buffer); + break; + default: + mpeg2_slice (picture, code, buffer); + break; + } + break; + default: + mpeg2_slice (picture, code, buffer); + break; + } + break; + } + case XINE_IMGFMT_XVMC: + mpeg2_xvmc_slice (picture, code, buffer); + break; + default: + mpeg2_slice (picture, code, buffer); + break; } + /* + * End of acceleration code. + */ if( picture->v_offset > picture->limit_y ) { picture->current_frame->bad_frame = 0; - lprintf("frame %d successfuly decoded\n",picture->current_frame->id); } } } @@ -604,6 +708,7 @@ static inline uint8_t * copy_chunk (mpeg2dec_t * mpeg2dec, } } mpeg2dec->code = byte; + mpeg2dec->chunk_size = chunk_ptr - mpeg2dec->chunk_buffer - 3; mpeg2dec->chunk_ptr = mpeg2dec->chunk_buffer; mpeg2dec->shift = 0xffffff00; return current; @@ -652,6 +757,15 @@ void mpeg2_discontinuity (mpeg2dec_t * mpeg2dec) { picture->forward_reference_frame->pts = 0; if ( picture->backward_reference_frame ) picture->backward_reference_frame->pts = 0; + + /* + * Move to libmpeg2_accel.c + * int libmpeg2_accel_discontinuity(mpeg2dec_t *); + */ + mpeg2dec->xxmc_last_slice_code=-1; + /* + * End of discontinuity accel code. + */ } void mpeg2_reset (mpeg2dec_t * mpeg2dec) { diff --git a/src/libmpeg2/header.c b/src/libmpeg2/header.c index 0f10588b0..e435fb405 100644 --- a/src/libmpeg2/header.c +++ b/src/libmpeg2/header.c @@ -104,6 +104,8 @@ static uint32_t get_bits(uint8_t *buffer, uint32_t count, uint32_t *bit_position void mpeg2_header_state_init (picture_t * picture) { picture->scan = mpeg2_scan_norm; + picture->load_intra_quantizer_matrix = 1; + picture->load_non_intra_quantizer_matrix = 1; } int mpeg2_header_sequence (picture_t * picture, uint8_t * buffer) @@ -150,7 +152,8 @@ int mpeg2_header_sequence (picture_t * picture, uint8_t * buffer) else for (i = 0; i < 64; i++) picture->non_intra_quantizer_matrix[i] = 16; - + picture->load_intra_quantizer_matrix = 1; + picture->load_non_intra_quantizer_matrix = 1; /* MPEG1 - for testing only */ picture->mpeg1 = 1; picture->intra_dc_precision = 0; diff --git a/src/libmpeg2/mpeg2.h b/src/libmpeg2/mpeg2.h index b6500d1ef..b2ecf669e 100644 --- a/src/libmpeg2/mpeg2.h +++ b/src/libmpeg2/mpeg2.h @@ -21,6 +21,9 @@ /* Structure for the mpeg2dec decoder */ +#ifndef MPEG2_H +#define MPEG2_H + typedef struct mpeg2dec_s { xine_video_port_t * output; uint32_t frame_format; @@ -45,6 +48,7 @@ typedef struct mpeg2dec_s { uint8_t * chunk_ptr; /* last start code ? */ uint8_t code; + uint32_t chunk_size; int64_t pts; uint32_t rff_pattern; @@ -55,7 +59,8 @@ typedef struct mpeg2dec_s { /* a spu decoder for possible closed captions */ spu_decoder_t *cc_dec; - + int xxmc_last_slice_code; + unsigned xxmc_mb_pic_height; } mpeg2dec_t ; @@ -81,3 +86,5 @@ void mpeg2_discontinuity (mpeg2dec_t * mpeg2dec); * currently */ /* void process_userdata(mpeg2dec_t *mpeg2dec, uint8_t *buffer); */ + +#endif diff --git a/src/libmpeg2/mpeg2_internal.h b/src/libmpeg2/mpeg2_internal.h index 6ec414789..27611e132 100644 --- a/src/libmpeg2/mpeg2_internal.h +++ b/src/libmpeg2/mpeg2_internal.h @@ -22,6 +22,7 @@ */ #include "video_out.h" +#include "accel_xvmc.h" /* macroblock modes */ #define MACROBLOCK_INTRA XINE_MACROBLOCK_INTRA @@ -108,6 +109,8 @@ typedef struct picture_s { /* sequence header stuff */ uint8_t intra_quantizer_matrix [64]; uint8_t non_intra_quantizer_matrix [64]; + int load_intra_quantizer_matrix; + int load_non_intra_quantizer_matrix; /* The width and height of the picture snapped to macroblock units */ int coded_picture_width; diff --git a/src/libmpeg2/slice_xvmc.c b/src/libmpeg2/slice_xvmc.c index ec23e25ad..1f6176e78 100644 --- a/src/libmpeg2/slice_xvmc.c +++ b/src/libmpeg2/slice_xvmc.c @@ -34,7 +34,7 @@ #include "xineutils.h" #include "attributes.h" - +#include "accel_xvmc.h" #define MOTION_ACCEL XINE_VO_MOTION_ACCEL #define IDCT_ACCEL XINE_VO_IDCT_ACCEL @@ -1700,6 +1700,7 @@ void mpeg2_xvmc_slice (picture_t * picture, int code, uint8_t * buffer) #define bits (picture->bitstream_bits) #define bit_ptr (picture->bitstream_ptr) cpu_state_t cpu_state; + xine_xvmc_t *xvmc = (xine_xvmc_t *) picture->current_frame->accel_data; bitstream_init (picture, buffer); @@ -1889,7 +1890,7 @@ void mpeg2_xvmc_slice (picture_t * picture, int code, uint8_t * buffer) } } - picture->current_frame->proc_macro_block(picture->XvMC_x, picture->XvMC_y, + xvmc->proc_macro_block(picture->XvMC_x, picture->XvMC_y, picture->XvMC_mb_type, picture->XvMC_motion_type, picture->XvMC_mv_field_sel, @@ -1965,7 +1966,7 @@ void mpeg2_xvmc_slice (picture_t * picture, int code, uint8_t * buffer) picture->XvMC_x = picture->offset/16; picture->XvMC_y = picture->v_offset/16; - picture->current_frame->proc_macro_block(picture->XvMC_x,picture->XvMC_y, + xvmc->proc_macro_block(picture->XvMC_x,picture->XvMC_y, picture->XvMC_mb_type, picture->XvMC_motion_type, picture->XvMC_mv_field_sel, @@ -2004,7 +2005,7 @@ void mpeg2_xvmc_slice (picture_t * picture, int code, uint8_t * buffer) picture->XvMC_x = picture->offset/16; picture->XvMC_y = picture->v_offset/16; - picture->current_frame->proc_macro_block(picture->XvMC_x,picture->XvMC_y, + xvmc->proc_macro_block(picture->XvMC_x,picture->XvMC_y, picture->XvMC_mb_type, picture->XvMC_motion_type, picture->XvMC_mv_field_sel, diff --git a/src/libmpeg2/slice_xvmc_vld.c b/src/libmpeg2/slice_xvmc_vld.c new file mode 100644 index 000000000..950ec1f63 --- /dev/null +++ b/src/libmpeg2/slice_xvmc_vld.c @@ -0,0 +1,248 @@ +/* + * Copyright (c) 2004 The Unichrome project. All rights reserved. + * + * This program 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, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTIES OR REPRESENTATIONS; 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. + * + * + */ + +#include "xine_internal.h" +#include "video_out.h" +#include "mpeg2.h" +#include "mpeg2_internal.h" +#include "xxmc.h" + +static uint8_t zig_zag_scan[64] ATTR_ALIGN(16) = +{ + /* Zig-Zag scan pattern */ + 0, 1, 8,16, 9, 2, 3,10, + 17,24,32,25,18,11, 4, 5, + 12,19,26,33,40,48,41,34, + 27,20,13, 6, 7,14,21,28, + 35,42,49,56,57,50,43,36, + 29,22,15,23,30,37,44,51, + 58,59,52,45,38,31,39,46, + 53,60,61,54,47,55,62,63 +}; + +static uint8_t alternate_scan [64] ATTR_ALIGN(16) = +{ + /* Alternate scan pattern */ + 0,8,16,24,1,9,2,10,17,25,32,40,48,56,57,49, + 41,33,26,18,3,11,4,12,19,27,34,42,50,58,35,43, + 51,59,20,28,5,13,6,14,21,29,36,44,52,60,37,45, + 53,61,22,30,7,15,23,31,38,46,54,62,39,47,55,63 +}; + + + + +void mpeg2_xxmc_choose_coding(int decoder_format, picture_t *picture) +{ + if (picture->current_frame) { + if (XINE_IMGFMT_XXMC == decoder_format) { + xine_xxmc_t *xxmc = (xine_xxmc_t *) + picture->current_frame->accel_data; + + /* + * Make a request for acceleration type and mpeg coding from + * the output plugin. + */ + + xxmc->format = XINE_IMGFMT_XXMC; + xxmc->acceleration = XINE_XVMC_ACCEL_VLD| XINE_XVMC_ACCEL_IDCT + | XINE_XVMC_ACCEL_MOCOMP ; + xxmc->mpeg = (picture->mpeg1) ? XINE_XVMC_MPEG_1:XINE_XVMC_MPEG_2; + xxmc->proc_xxmc_frame(picture->current_frame); + } + } +} + + +void mpeg2_xxmc_slice( mpeg2dec_t *mpeg2dec, picture_t *picture, int code, + uint8_t *buffer) +{ + vo_frame_t + *frame = picture->current_frame; + xine_xxmc_t + *xxmc = (xine_xxmc_t *) frame->accel_data; + xine_vld_frame_t + *vft = &xxmc->vld_frame; + unsigned + mb_frame_height; + int + i; + const uint8_t * + scan_pattern; + float + ms_per_slice; + + if (1 == code) { + frame->bad_frame = 1; + + /* + * Check that first field went through OK. Otherwise, + * indicate bad frame. + */ + + if (picture->second_field) { + mpeg2dec->xxmc_last_slice_code = (xxmc->decoded) ? 0 : -1; + xxmc->decoded = 0; + } else { + mpeg2dec->xxmc_last_slice_code = 0; + } + + mb_frame_height = + (!(picture->mpeg1) && (picture->progressive_sequence)) ? + 2*((picture->coded_picture_height+31) >> 5) : + (picture->coded_picture_height+15) >> 4; + mpeg2dec->xxmc_mb_pic_height = (picture->picture_structure == FRAME_PICTURE ) ? + mb_frame_height : mb_frame_height >> 1; + + ms_per_slice = 1000. / (90000. * mb_frame_height) * frame->duration; + xxmc->sleep = 1. / (ms_per_slice * 0.45); + if (xxmc->sleep < 1.) xxmc->sleep = 1.; + + if (picture->mpeg1) { + vft->mv_ranges[0][0] = picture->b_motion.f_code[0]; + vft->mv_ranges[0][1] = picture->b_motion.f_code[0]; + vft->mv_ranges[1][0] = picture->f_motion.f_code[0]; + vft->mv_ranges[1][1] = picture->f_motion.f_code[0]; + } else { + vft->mv_ranges[0][0] = picture->b_motion.f_code[0]; + vft->mv_ranges[0][1] = picture->b_motion.f_code[1]; + vft->mv_ranges[1][0] = picture->f_motion.f_code[0]; + vft->mv_ranges[1][1] = picture->f_motion.f_code[1]; + } + + vft->picture_structure = picture->picture_structure; + vft->picture_coding_type = picture->picture_coding_type; + vft->mpeg_coding = (picture->mpeg1) ? 0 : 1; + vft->progressive_sequence = picture->progressive_sequence; + vft->scan = (picture->scan == mpeg2_scan_alt); + vft->pred_dct_frame = picture->frame_pred_frame_dct; + vft->concealment_motion_vectors = + picture->concealment_motion_vectors; + vft->q_scale_type = picture->q_scale_type; + vft->intra_vlc_format = picture->intra_vlc_format; + vft->intra_dc_precision = picture->intra_dc_precision; + vft->second_field = picture->second_field; + + /* + * Translation of libmpeg2's Q-matrix layout to VLD XvMC's. + * Errors here will give + * blocky artifacts and sometimes wrong colors. + */ + + scan_pattern = (vft->scan) ? alternate_scan : zig_zag_scan; + + if ((vft->load_intra_quantizer_matrix = picture->load_intra_quantizer_matrix)) { + for (i=0; i<64; ++i) { + vft->intra_quantizer_matrix[scan_pattern[i]] = + picture->intra_quantizer_matrix[picture->scan[i]]; + } + } + + if ((vft->load_non_intra_quantizer_matrix = picture->load_non_intra_quantizer_matrix)) { + for (i=0; i<64; ++i) { + vft->non_intra_quantizer_matrix[scan_pattern[i]] = + picture->non_intra_quantizer_matrix[picture->scan[i]]; + } + } + + picture->load_intra_quantizer_matrix = 0; + picture->load_non_intra_quantizer_matrix = 0; + vft->forward_reference_frame = picture->forward_reference_frame; + vft->backward_reference_frame = picture->backward_reference_frame; + xxmc->proc_xxmc_begin( frame ); + if (xxmc->result != 0) { + xxmc->proc_xxmc_flush( frame ); + mpeg2dec->xxmc_last_slice_code=-1; + } + } + + if ((code == mpeg2dec->xxmc_last_slice_code + 1) && + code <= mpeg2dec->xxmc_mb_pic_height) { + + /* + * Send this slice to the output plugin. May stall for a long + * time in proc_slice; + */ + + frame->bad_frame = 1; + xxmc->slice_data_size = mpeg2dec->chunk_size; + xxmc->slice_data = mpeg2dec->chunk_buffer; + xxmc->slice_code = code; + + xxmc->proc_xxmc_slice( frame ); + if (xxmc->result != 0) { + xxmc->proc_xxmc_flush( frame ); + mpeg2dec->xxmc_last_slice_code=-1; + return; + } + + if (code == mpeg2dec->xxmc_mb_pic_height) { + + /* + * We've encountered the last slice of this frame. + * Release the decoder for a new frame and, if all + * went well, tell libmpeg2 that we are ready. + */ + + mpeg2_xxmc_vld_frame_complete(mpeg2dec,picture,code); + return; + } else { + + /* + * Keep track of slices. + */ + + mpeg2dec->xxmc_last_slice_code++; + } + + } else { + + /* + * An error has occured. + */ + + lprintf("libmpeg2: VLD XvMC: Slice error.\n"); + mpeg2dec->xxmc_last_slice_code = -1; + xxmc->proc_xxmc_flush( frame ); + return; + } +} + +void mpeg2_xxmc_vld_frame_complete(mpeg2dec_t *mpeg2dec, picture_t *picture, int code) +{ + vo_frame_t + *frame = picture->current_frame; + xine_xxmc_t + *xxmc = (xine_xxmc_t *) frame->accel_data; + + if (xxmc->decoded) return; + if (mpeg2dec->xxmc_last_slice_code >= 1) { + xxmc->proc_xxmc_flush( frame ); + if (xxmc->result) { + mpeg2dec->xxmc_last_slice_code=-1; + return; + } + xxmc->decoded = 1; + mpeg2dec->xxmc_last_slice_code++; + if (picture->picture_structure == 3 || picture->second_field) { + if (xxmc->result == 0) + frame->bad_frame = 0; + } + } +} diff --git a/src/libmpeg2/xxmc.h b/src/libmpeg2/xxmc.h new file mode 100644 index 000000000..c4221200b --- /dev/null +++ b/src/libmpeg2/xxmc.h @@ -0,0 +1,12 @@ +#ifndef _XXMC_H +#define _XXMC_H + +#include "accel_xvmc.h" + +extern void mpeg2_xxmc_slice( mpeg2dec_t *mpeg2dec, picture_t *picture, + int code, uint8_t *buffer); +extern void mpeg2_xxmc_choose_coding(int decoder_format, picture_t *picture); + +extern void mpeg2_xxmc_vld_frame_complete(mpeg2dec_t *mpeg2dec, picture_t *picture, int code); + +#endif diff --git a/src/video_out/Makefile.am b/src/video_out/Makefile.am index 9bd16cff7..5c4cb5187 100644 --- a/src/video_out/Makefile.am +++ b/src/video_out/Makefile.am @@ -24,6 +24,9 @@ endif if HAVE_XVMC xvmc_module = xineplug_vo_out_xvmc.la endif +if HAVE_XXMC +xxmc_module = xineplug_vo_out_xxmc.la +endif if HAVE_OPENGL #opengl_module = opengl_module = xineplug_vo_out_opengl.la @@ -87,6 +90,7 @@ lib_LTLIBRARIES = $(xshm_module) $(xv_module) $(xvmc_module) \ $(directx_module) \ $(caca_module) \ $(macosx_module) \ + $(xxmc_module) \ xineplug_vo_out_none.la xineplug_vo_out_xshm_la_SOURCES = yuv2rgb.c yuv2rgb_mmx.c yuv2rgb_mlib.c \ @@ -99,9 +103,14 @@ xineplug_vo_out_xv_la_LIBADD = $(XV_LIB) $(X_LIBS) -lXext $(XINE_LIB) xineplug_vo_out_xv_la_LDFLAGS = -avoid-version -module @XINE_PLUGIN_MIN_SYMS@ xineplug_vo_out_xvmc_la_SOURCES = deinterlace.c alphablend.c video_out_xvmc.c -xineplug_vo_out_xvmc_la_LIBADD = $(XV_LIB) $(XVMC_LIB) $(X_LIBS) -lXext $(XINE_LIB) +xineplug_vo_out_xvmc_la_LIBADD = $(XVMC_LIB) $(XV_LIB) $(X_LIBS) -lXext $(XINE_LIB) xineplug_vo_out_xvmc_la_LDFLAGS = -avoid-version -module @XINE_PLUGIN_MIN_SYMS@ +xineplug_vo_out_xxmc_la_SOURCES = $(X11OSD) deinterlace.c alphablend.c video_out_xxmc.c\ + xvmc_mocomp.c xvmc_vld.c xxmc.h +xineplug_vo_out_xxmc_la_LIBADD = $(XXMC_LIB) $(XV_LIB) $(X_LIBS) -lXext $(XINE_LIB) +xineplug_vo_out_xxmc_la_LDFLAGS = -avoid-version -module @XINE_PLUGIN_MIN_SYMS@ + xineplug_vo_out_opengl_la_SOURCES = yuv2rgb.c yuv2rgb_mmx.c yuv2rgb_mlib.c \ alphablend.c video_out_opengl.c xineplug_vo_out_opengl_la_LIBADD = $(MLIB_LIBS) $(OPENGL_LIBS) $(GLUT_LIBS) \ diff --git a/src/video_out/alphablend.c b/src/video_out/alphablend.c index be5f01617..a9f216a9e 100644 --- a/src/video_out/alphablend.c +++ b/src/video_out/alphablend.c @@ -1277,3 +1277,191 @@ void blend_yuy2 (uint8_t * dst_img, vo_overlay_t * img_overl, dst_y += dst_pitch; } } + +void clear_xx44_palette(xx44_palette_t *p) +{ + register int i; + register uint32_t *cluts = p->cluts; + register int *ids = p->lookup_cache; + + i= p->size; + while(i--) + *cluts++ = 0; + i = 2*OVL_PALETTE_SIZE; + while(i--) + *ids++ = -1; + p->max_used=1; +} + +void init_xx44_palette(xx44_palette_t *p, unsigned num_entries) +{ + p->size = (num_entries > XX44_PALETTE_SIZE) ? XX44_PALETTE_SIZE : num_entries; +} + +void dispose_xx44_palette(xx44_palette_t *p) +{ +} + +static void colorToPalette(const uint32_t *icolor, unsigned char *palette_p, + unsigned num_xvmc_components, char *xvmc_components) +{ + const clut_t *color = (const clut_t *) icolor; + int i; + for (i=0; icr; break; + case 'U': *palette_p = color->cb; break; + case 'Y': + default: *palette_p = color->y; break; + } + *palette_p++; + } +} + + +void xx44_to_xvmc_palette(const xx44_palette_t *p,unsigned char *xvmc_palette, + unsigned first_xx44_entry, unsigned num_xx44_entries, + unsigned num_xvmc_components, char *xvmc_components) +{ + register int i; + register const uint32_t *cluts = p->cluts + first_xx44_entry; + + for (i=0; icluts) < p->size) { + colorToPalette(cluts++, xvmc_palette, num_xvmc_components, xvmc_components); + xvmc_palette += num_xvmc_components; + } + } +} + +static int xx44_paletteIndex(xx44_palette_t *p, int color, uint32_t clut) +{ + + register int i; + register uint32_t *cluts = p->cluts; + register int tmp; + + if ((tmp = p->lookup_cache[color]) >= 0) + if (cluts[tmp] == clut) return tmp; + + for (i=0; imax_used; ++i) { + if (*cluts++ == clut) return p->lookup_cache[color] = i; + } + + if (p->max_used == p->size -1) { + printf("video_out: Warning! Out of xx44 palette colors!\n"); + return 1; + } + p->cluts[p->max_used] = clut; + return p->lookup_cache[color] = p->max_used++; +} + +static void memblend_xx44(uint8_t *mem,uint8_t val, register size_t size, uint8_t mask) +{ + register uint8_t masked_val = val & mask; + + while(size--) { + if ((*mem & mask) <= masked_val ) *mem = val; + mem++; + } +} + +void blend_xx44 (uint8_t *dst_img, vo_overlay_t *img_overl, + int dst_width, int dst_height, int dst_pitch, + xx44_palette_t *palette,int ia44) +{ + int src_width = img_overl->width; + int src_height = img_overl->height; + rle_elem_t *rle = img_overl->rle; + rle_elem_t *rle_limit = rle + img_overl->num_rle; + int mask; + int x_off = img_overl->x; + int y_off = img_overl->y; + int x, y; + uint8_t norm_pixel,clip_pixel; + uint8_t *dst_y; + uint8_t *dst; + uint8_t alphamask = (ia44) ? 0x0F : 0xF0; + int clip_right; + + if (!img_overl) + return; + + dst_y = dst_img + dst_pitch*y_off + x_off; + + if( (x_off + img_overl->width) < dst_width ) + clip_right = img_overl->width; + else + clip_right = dst_width - x_off; + + if ((src_height + y_off) > dst_height) + src_height = dst_height - y_off; + + for (y = 0; y < src_height; y++) { + + mask = !(img_overl->clip_top > y || img_overl->clip_bottom < y); + dst = dst_y; + + for (x = 0; x < src_width;) { + int len = (x + rle->len > clip_right) ? clip_right -x + 1 : rle->len; + + if (len > 0) { + norm_pixel = (uint8_t)((xx44_paletteIndex(palette,rle->color, + img_overl->color[rle->color]) << 4) | + (img_overl->trans[rle->color] & 0x0F)); + clip_pixel = (uint8_t)((xx44_paletteIndex(palette,rle->color+OVL_PALETTE_SIZE, + img_overl->clip_color[rle->color]) << 4) | + (img_overl->clip_trans[rle->color] & 0x0F)); + if (!ia44) { + norm_pixel = ((norm_pixel & 0x0F) << 4) | ((norm_pixel & 0xF0) >> 4); + clip_pixel = ((clip_pixel & 0x0F) << 4) | ((clip_pixel & 0xF0) >> 4); + } + if (mask) { + if (x < img_overl->clip_left) { + if (x + len - 1 < img_overl->clip_left) { + memblend_xx44(dst,norm_pixel,len, alphamask); + dst += len; + } else { + memblend_xx44(dst,norm_pixel,img_overl->clip_left -x, alphamask); + dst += img_overl->clip_left - x; + len -= img_overl->clip_left - x; + if (len < img_overl->clip_right - img_overl->clip_left + 1) { + memblend_xx44(dst,clip_pixel,len, alphamask); + dst += len; + } else { + memblend_xx44(dst,clip_pixel,img_overl->clip_right - img_overl->clip_left +1, + alphamask); + dst += img_overl->clip_right - img_overl->clip_left +1; + len -= img_overl->clip_right - img_overl->clip_left +1; + memblend_xx44(dst,norm_pixel,len, alphamask); + dst += len; + } + } + } else if (x <= img_overl->clip_right) { + if (len < img_overl->clip_right - x + 1) { + memblend_xx44(dst,clip_pixel,len, alphamask); + dst += len; + } else { + memblend_xx44(dst,clip_pixel,img_overl->clip_right - x +1,alphamask); + dst += img_overl->clip_right - x +1; + len -= img_overl->clip_right - x +1; + memblend_xx44(dst,norm_pixel,len, alphamask); + dst += len; + } + } else { + memblend_xx44(dst,norm_pixel,len, alphamask); + dst += len; + } + } else { + memblend_xx44(dst,norm_pixel,len, alphamask); + dst += len; + } + } + x += rle->len; + rle++; + if (rle >= rle_limit) break; + } + if (rle >= rle_limit) break; + dst_y += dst_pitch; + } +} diff --git a/src/video_out/alphablend.h b/src/video_out/alphablend.h index 974f363d8..dd7f799ea 100644 --- a/src/video_out/alphablend.h +++ b/src/video_out/alphablend.h @@ -53,10 +53,22 @@ typedef struct { /* CLUT == Color LookUp Table */ uint8_t foo : 8; } ATTRIBUTE_PACKED clut_t; + #if PRAGMA_PACK #pragma pack() #endif +#define XX44_PALETTE_SIZE 32 + +typedef struct { + unsigned size; + unsigned max_used; + uint32_t cluts[XX44_PALETTE_SIZE]; + /* cache palette entries for both colors and clip_colors */ + int lookup_cache[OVL_PALETTE_SIZE*2]; +} xx44_palette_t; + + void blend_rgb16 (uint8_t * img, vo_overlay_t * img_overl, int img_width, int img_height, int dst_width, int dst_height); @@ -75,4 +87,32 @@ void blend_yuv (uint8_t *dst_base[3], vo_overlay_t * img_overl, void blend_yuy2 (uint8_t * dst_img, vo_overlay_t * img_overl, int dst_width, int dst_height, int dst_pitch); +/* + * This function isn't too smart about blending. We want to avoid creating new + * colors in the palette as a result from two non-zero colors needed to be + * blended. Instead we choose the color with the highest alpha value to be + * visible. Some parts of the code taken from the "VeXP" project. + */ + +void blend_xx44 (uint8_t *dst_img, vo_overlay_t *img_overl, + int dst_width, int dst_height, int dst_pitch, + xx44_palette_t *palette,int ia44); + +/* + * Functions to handle the xine-specific palette. + */ + +void clear_xx44_palette(xx44_palette_t *p); +void init_xx44_palette(xx44_palette_t *p, unsigned num_entries); +void dispose_xx44_palette(xx44_palette_t *p); + +/* + * Convert the xine-specific palette to something useful. + */ + +void xx44_to_xvmc_palette(const xx44_palette_t *p,unsigned char *xvmc_palette, + unsigned first_xx44_entry, unsigned num_xx44_entries, + unsigned num_xvmc_components, char *xvmc_components); + + #endif diff --git a/src/video_out/video_out_xvmc.c b/src/video_out/video_out_xvmc.c index 6046910b4..8c2dee108 100644 --- a/src/video_out/video_out_xvmc.c +++ b/src/video_out/video_out_xvmc.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: video_out_xvmc.c,v 1.17 2004/09/22 20:29:17 miguelfreitas Exp $ + * $Id: video_out_xvmc.c,v 1.18 2004/09/28 18:49:40 miguelfreitas Exp $ * * video_out_xvmc.c, X11 video motion compensation extension interface for xine * @@ -70,6 +70,7 @@ #include "xine.h" #include "video_out.h" #include "xine_internal.h" +#include "accel_xvmc.h" /* TODO - delete these? */ #include "alphablend.h" @@ -125,7 +126,7 @@ typedef struct { /* temporary Xv only storage */ XvImage *image; XShmSegmentInfo shminfo; - + xine_xvmc_t xvmc_data; } xvmc_frame_t; @@ -494,7 +495,6 @@ static void xvmc_frame_dispose (vo_frame_t *vo_img) { XFree (frame->image); XUnlockDisplay (this->display); } - free (frame); } @@ -577,6 +577,8 @@ static vo_frame_t *xvmc_alloc_frame (vo_driver_t *this_gen) { if (!frame) return NULL; + frame->vo_frame.accel_data = &frame->xvmc_data; + /* keep track of frames and how many frames alocated. */ this->frames[this->num_frame_buffers++] = frame; @@ -590,8 +592,8 @@ static vo_frame_t *xvmc_alloc_frame (vo_driver_t *this_gen) { frame->vo_frame.proc_frame = NULL; frame->vo_frame.field = xvmc_frame_field; frame->vo_frame.dispose = xvmc_frame_dispose; - frame->vo_frame.proc_macro_block = xvmc_proc_macro_block; frame->vo_frame.driver = this_gen; + frame->xvmc_data.proc_macro_block = xvmc_proc_macro_block; return (vo_frame_t *) frame; } @@ -777,6 +779,7 @@ static void xvmc_update_frame_format (vo_driver_t *this_gen, double ratio, int format, int flags) { xvmc_driver_t *this = (xvmc_driver_t *) this_gen; xvmc_frame_t *frame = (xvmc_frame_t *) frame_gen; + xine_xvmc_t *xvmc = (xine_xvmc_t *) frame_gen->accel_data; lprintf ("xvmc_update_frame_format\n"); @@ -816,14 +819,16 @@ static void xvmc_update_frame_format (vo_driver_t *this_gen, frame->ratio = ratio; - frame->vo_frame.macroblocks = (xine_macroblocks_t *)&this->macroblocks; + xvmc->macroblocks = (xine_macroblocks_t *)&this->macroblocks; if( flags & VO_NEW_SEQUENCE_FLAG ) { xvmc_set_context (this, width, height, ratio, format, flags, - frame->vo_frame.macroblocks); + xvmc->macroblocks); } + this->macroblocks.num_blocks = 0; this->macroblocks.macroblockptr = this->macroblocks.macroblockbaseptr; this->macroblocks.xine_mc.blockptr = this->macroblocks.xine_mc.blockbaseptr; + } static void xvmc_clean_output_area (xvmc_driver_t *this) { diff --git a/src/video_out/video_out_xxmc.c b/src/video_out/video_out_xxmc.c new file mode 100644 index 000000000..98dc0db86 --- /dev/null +++ b/src/video_out/video_out_xxmc.c @@ -0,0 +1,2652 @@ +/* + * Copyright (C) 2000-2004 the xine project + * Copyright (C) 2004 the Unichrome project + * + * This file is part of xine, a free 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: video_out_xxmc.c,v 1.1 2004/09/28 18:49:40 miguelfreitas Exp $ + * + * video_out_xxmc.c, X11 decoding accelerated video extension interface for xine + * + * based on mpeg2dec code from + * Aaron Holtzman + * + * Xv image support by Gerd Knorr + * + * xine-specific code by Guenter Bartsch + * + * overlay support by James Courtier-Dutton - July 2001 + * X11 unscaled overlay support by Miguel Freitas - Nov 2003 + * XvMC VLD implementation by Thomas Hellström - August-Sep 2004 + * XvMC merge by Thomas Hellström - Sep 2004 + * + * Test IDCT + * Test VLD + */ + + + +#include "xxmc.h" + +static int gX11Fail; +static int xxmc_xvmc_update_context(xxmc_driver_t *driver,xxmc_frame_t *frame); +static void dispose_ximage (xxmc_driver_t *this, XShmSegmentInfo *shminfo, + XvImage *myimage); + + +/* + * Acceleration level priority. Static for now. It may well turn out that IDCT + * is more efficient than VLD. + */ + +static unsigned accel_priority[] = { +#ifdef HAVE_VLDXVMC + XINE_XVMC_ACCEL_VLD, +#endif + XINE_XVMC_ACCEL_IDCT, + XINE_XVMC_ACCEL_MOCOMP}; +#define NUM_ACCEL_PRIORITY (sizeof(accel_priority)/sizeof(accel_priority[0])) + +#ifndef XVMC_VLD + #define XVMC_VLD 0 +#endif + +/* + * Additional thread safety, since the plugin may decide to destroy a context + * while it's surfaces are still active in the video-out loop. + * When / If XvMC libs are reasonably thread-safe, the locks can be made + * more efficient by allowing multiple threads in that do not destroy + * the context or surfaces that may be active in other threads. + */ + +static void init_context_lock(context_lock_t *c) +{ + pthread_cond_init(&c->cond,NULL); + pthread_mutex_init(&c->mutex,NULL); + c->num_readers = 0; +} + +static void free_context_lock(context_lock_t *c) +{ + pthread_mutex_destroy(&c->mutex); + pthread_cond_destroy(&c->cond); +} + +void xvmc_context_reader_lock(context_lock_t *c) +{ + pthread_mutex_lock(&c->mutex); +#ifdef XVMC_THREAD_SAFE + c->num_readers++; + pthread_mutex_unlock(&c->mutex); +#endif +} + +void xvmc_context_reader_unlock(context_lock_t *c) +{ +#ifdef XVMC_THREAD_SAFE + pthread_mutex_lock(&c->mutex); + if (c->num_readers > 0) { + if (--(c->num_readers) == 0) { + pthread_cond_broadcast(&c->cond); + } + } +#endif + pthread_mutex_unlock(&c->mutex); +} + +static void xvmc_context_writer_lock(context_lock_t *c) +{ + pthread_mutex_lock(&c->mutex); +#ifdef XVMC_THREAD_SAFE + while(c->num_readers) { + pthread_cond_wait(&c->cond, &c->mutex); + } +#endif +} + +static void xvmc_context_writer_unlock(context_lock_t *c) +{ + pthread_mutex_unlock(&c->mutex); +} + +/* + * A number of simple surface allocator functions that implements the + * notion that a surface may be invalid if it is asynchronously + * destroyed. Both surfaces and subpictures are handled this way. + */ + + + +static void xxmc_xvmc_dump_surfaces(xxmc_driver_t *this ) +{ + int + i; + xvmc_surface_handler_t *handler = &this->xvmc_surf_handler; + + for (i=0; ixine, XINE_VERBOSITY_DEBUG, "%d %d;",handler->surfInUse[i], + handler->surfValid[i]); + } + xprintf(this->xine, XINE_VERBOSITY_DEBUG, "\n"); +} + +static void xxmc_xvmc_dump_subpictures(xxmc_driver_t *this) +{ + int + i; + xvmc_surface_handler_t *handler = &this->xvmc_surf_handler; + + for (i=0; ixine, XINE_VERBOSITY_DEBUG, "%d %d;",handler->subInUse[i], + handler->subValid[i]); + } + xprintf(this->xine, XINE_VERBOSITY_DEBUG, "\n"); +} + + +static void xxmc_xvmc_surface_handler_construct(xxmc_driver_t *this) +{ + int i; + xvmc_surface_handler_t *handler = &this->xvmc_surf_handler; + + pthread_mutex_init(&handler->mutex,NULL); + for (i=0; isurfInUse[i] = 0; + handler->surfValid[i] = 0; + } + for (i=0; isubInUse[i] = 0; + handler->subValid[i] = 0; + } +} + +static void xxmc_xvmc_destroy_surfaces(xxmc_driver_t *this) +{ + int i; + xvmc_surface_handler_t *handler = &this->xvmc_surf_handler; + + pthread_mutex_lock(&handler->mutex); + for (i=0; i < XVMC_MAX_SURFACES; ++i) { + XVMCLOCKDISPLAY( this->display ); + if (handler->surfValid[i]) { + XvMCFlushSurface( this->display , handler->surfaces+i); + XvMCSyncSurface( this->display, handler->surfaces+i ); + XvMCHideSurface( this->display, handler->surfaces+i ); + XvMCDestroySurface( this->display, handler->surfaces+i ); + } + XVMCUNLOCKDISPLAY( this->display ); + handler->surfValid[i] = 0; + } + pthread_mutex_unlock(&handler->mutex); + +} + +static void xxmc_xvmc_destroy_subpictures(xxmc_driver_t *this) +{ + int i; + xvmc_surface_handler_t *handler = &this->xvmc_surf_handler; + + pthread_mutex_lock(&handler->mutex); + for (i=0; i < XVMC_MAX_SUBPICTURES; ++i) { + XVMCLOCKDISPLAY( this->display ); + if (handler->subValid[i]) { + XvMCFlushSubpicture( this->display , handler->subpictures+i); + XvMCSyncSubpicture( this->display, handler->subpictures+i ); + XvMCDestroySubpicture( this->display, handler->subpictures+i ); + } + XVMCUNLOCKDISPLAY( this->display ); + handler->subValid[i] = 0; + } + pthread_mutex_unlock(&handler->mutex); +} + +static XvMCSurface *xxmc_xvmc_alloc_surface(xxmc_driver_t *this, + XvMCContext *context) +{ + xvmc_surface_handler_t *handler = &this->xvmc_surf_handler; + int i; + + pthread_mutex_lock(&handler->mutex); + xxmc_xvmc_dump_surfaces(this); + for (i=0; isurfValid[i] && !handler->surfInUse[i]) { + handler->surfInUse[i] = 1; + xxmc_xvmc_dump_surfaces(this); + pthread_mutex_unlock(&handler->mutex); + return handler->surfaces + i; + } + } + for (i=0; isurfInUse[i]) { + XVMCLOCKDISPLAY( this->display ); + if (Success != XvMCCreateSurface( this->display, context, + handler->surfaces + i)) { + XVMCUNLOCKDISPLAY( this->display ); + pthread_mutex_unlock(&handler->mutex); + return NULL; + } + XVMCUNLOCKDISPLAY( this->display ); + xprintf (this->xine, XINE_VERBOSITY_DEBUG, + "video_out_xxmc: Created surface %d\n",i); + handler->surfInUse[i] = 1; + handler->surfValid[i] = 1; + pthread_mutex_unlock(&handler->mutex); + return handler->surfaces + i; + } + } + pthread_mutex_unlock(&handler->mutex); + return NULL; +} + +static void xxmc_xvmc_free_surface(xxmc_driver_t *this, XvMCSurface *surf) +{ + xvmc_surface_handler_t *handler = &this->xvmc_surf_handler; + unsigned + index = surf - handler->surfaces; + + if (index >= XVMC_MAX_SURFACES) return; + pthread_mutex_lock(&handler->mutex); + xprintf (this->xine, XINE_VERBOSITY_DEBUG, + "video_out_xxmc: Disposing of surface %d\n",index); + handler->surfInUse[index]--; + xxmc_xvmc_dump_surfaces(this); + pthread_mutex_unlock(&handler->mutex); +} + +int xxmc_xvmc_surface_valid(xxmc_driver_t *this, XvMCSurface *surf) +{ + xvmc_surface_handler_t *handler = &this->xvmc_surf_handler; + unsigned + index = surf - handler->surfaces; + int ret; + + if (index >= XVMC_MAX_SURFACES) return 0; + pthread_mutex_lock(&handler->mutex); + ret = handler->surfValid[index]; + pthread_mutex_unlock(&handler->mutex); + return ret; +} + +static XvMCSubpicture *xxmc_xvmc_alloc_subpicture + (xxmc_driver_t *this, + XvMCContext *context, unsigned short width, + unsigned short height, int xvimage_id) +{ + int i; + xvmc_surface_handler_t *handler = &this->xvmc_surf_handler; + int status; + + pthread_mutex_lock(&handler->mutex); + xxmc_xvmc_dump_subpictures(this); + for (i=0; isubValid[i] && !handler->subInUse[i]) { + XVMCLOCKDISPLAY( this->display ); + if (XvMCGetSubpictureStatus( this->display, handler->subpictures + i, + &status)) { + XVMCUNLOCKDISPLAY( this->display ); + continue; + } + XVMCUNLOCKDISPLAY( this->display ); + if (status & XVMC_DISPLAYING) + continue; + handler->subInUse[i] = 1; + xxmc_xvmc_dump_subpictures(this); + pthread_mutex_unlock(&handler->mutex); + return handler->subpictures + i; + } + } + for (i=0; isubInUse[i]) { + XVMCLOCKDISPLAY( this->display ); + if (Success != XvMCCreateSubpicture( this->display, context, + handler->subpictures + i, + width, height, xvimage_id)) { + XVMCUNLOCKDISPLAY( this->display ); + pthread_mutex_unlock(&handler->mutex); + return NULL; + } + XVMCUNLOCKDISPLAY( this->display ); + xprintf (this->xine, XINE_VERBOSITY_DEBUG, + "video_out_xxmc: Created subpicture %d\n",i); + handler->subInUse[i] = 1; + handler->subValid[i] = 1; + pthread_mutex_unlock(&handler->mutex); + return handler->subpictures + i; + } + } + pthread_mutex_unlock(&handler->mutex); + return NULL; +} + +static void xxmc_xvmc_free_subpicture(xxmc_driver_t *this, XvMCSubpicture *sub) +{ + + xvmc_surface_handler_t *handler = &this->xvmc_surf_handler; + unsigned + index = sub - handler->subpictures; + + if (index >= XVMC_MAX_SUBPICTURES) return; + pthread_mutex_lock(&handler->mutex); + xprintf (this->xine, XINE_VERBOSITY_DEBUG, + "video_out_xxmc: Disposing of subpicture %d\n",index); + handler->subInUse[index] = 0; + xxmc_xvmc_dump_subpictures(this); + pthread_mutex_unlock(&handler->mutex); + +} + +/* + * Here follows a number of callback function. + */ + + +/* + * Callback function for the VO-loop to duplicate frame data. + */ + + +static void xxmc_duplicate_frame_data(vo_frame_t *this_gen, + vo_frame_t *original) +{ + xxmc_frame_t *this = (xxmc_frame_t *) this_gen, + *orig = (xxmc_frame_t *) original; + xxmc_driver_t *driver = (xxmc_driver_t *) this_gen->driver; + xine_t *xine = driver->xine; + xine_xxmc_t *xxmc; + XvMCSubpicture *tmp; + int need_dummy; + + if (original->format == XINE_IMGFMT_XXMC) { + xxmc = &orig->xxmc_data; + switch(xxmc->format) { + case XINE_IMGFMT_YV12: + yv12_to_yv12( original->base[0], original->pitches[0], + this_gen->base[0], this_gen->pitches[0], + original->base[1], original->pitches[1], + this_gen->base[1], this_gen->pitches[1], + original->base[2], original->pitches[2], + this_gen->base[2], this_gen->pitches[2], + this_gen->width, this_gen->height); + xprintf(xine, XINE_VERBOSITY_DEBUG, "Duplicate Frame YV12.\n"); + break; + case XINE_IMGFMT_XXMC: + xvmc_context_writer_lock( &driver->xvmc_lock); + if (!xxmc_xvmc_surface_valid(driver,orig->xvmc_surf)) { + xvmc_context_writer_unlock( &driver->xvmc_lock ); + return; + } + this->xxmc_data = *xxmc; + this->width = original->width; + this->height = original->height; + if (! xxmc_xvmc_update_context(driver,this) ) { + xvmc_context_writer_unlock( &driver->xvmc_lock ); + return; + } + xvmc_context_writer_unlock( &driver->xvmc_lock ); + xvmc_context_reader_lock( &driver->xvmc_lock ); + if (!xxmc_xvmc_surface_valid(driver,orig->xvmc_surf) || + !xxmc_xvmc_surface_valid(driver,this->xvmc_surf)) { + xvmc_context_reader_unlock( &driver->xvmc_lock ); + return; + } + + /* + * Allocate a dummy subpicture and copy using + * XvMCBlendsubpicture2. VLD implementations can do blending with a + * NULL subpicture. Use that if possible. + */ + + need_dummy = (xxmc->acceleration != XINE_XVMC_ACCEL_VLD); + tmp = NULL; + if (need_dummy) { + tmp = xxmc_xvmc_alloc_subpicture( driver, &driver->context, + this->width, this->height, + driver->xvmc_cap + [driver->xvmc_cur_cap].subPicType.id); + } + if (tmp || !need_dummy) { + XVMCLOCKDISPLAY( driver->display ); + if (tmp) XvMCClearSubpicture(driver->display, tmp , 0,0, this->width, + this->height, 0); + if (Success == XvMCBlendSubpicture2( driver->display, orig->xvmc_surf, + this->xvmc_surf, tmp, + 0,0,this->width, this->height, + 0,0,this->width, this->height)) { + this->xxmc_data.decoded = 1; + } + XVMCUNLOCKDISPLAY( driver->display ); + if (tmp) xxmc_xvmc_free_subpicture( driver, tmp); + } + + xvmc_context_reader_unlock( &driver->xvmc_lock ); + xprintf(xine, XINE_VERBOSITY_DEBUG, "Duplicated XvMC frame %d %d.\n", + this->width,this->height); + break; + default: + break; + } + } +} + + + +static uint32_t xxmc_get_capabilities (vo_driver_t *this_gen) { + xxmc_driver_t *this = (xxmc_driver_t *) this_gen; + + return this->capabilities; +} + + +static void xxmc_frame_field (vo_frame_t *vo_img, int which_field) +{ + xxmc_driver_t *this = (xxmc_driver_t *) vo_img->driver; + + + lprintf ("xvmc_frame_field\n"); + if (this->xvmc_cap) { + if (this->xvmc_accel & (XINE_XVMC_ACCEL_IDCT | XINE_XVMC_ACCEL_MOCOMP)) { + this->macroblocks.num_blocks = 0; + this->macroblocks.macroblockptr = this->macroblocks.macroblockbaseptr; + this->macroblocks.xine_mc.blockptr = this->macroblocks.xine_mc.blockbaseptr; + } + } +} + +static void xxmc_frame_dispose (vo_frame_t *vo_img) { + xxmc_frame_t *frame = (xxmc_frame_t *) vo_img ; + xxmc_driver_t *this = (xxmc_driver_t *) vo_img->driver; + + xprintf (this->xine, XINE_VERBOSITY_DEBUG, "Disposing of frame\n"); + + if (this->xvmc_cap && frame->xvmc_surf) { + xxmc_xvmc_free_surface( this, frame->xvmc_surf ); + frame->xvmc_surf = 0; + } + + if (frame->image) { + + if (this->use_shm) { + XLockDisplay (this->display); + XShmDetach (this->display, &frame->shminfo); + XFree (frame->image); + XUnlockDisplay (this->display); + + shmdt (frame->shminfo.shmaddr); + shmctl (frame->shminfo.shmid, IPC_RMID, NULL); + } + else { + if (frame->image->data) free(frame->image->data); + XLockDisplay (this->display); + XFree (frame->image); + XUnlockDisplay (this->display); + } + } + free (frame); +} + +/* + * Note that this one does NOT allocate the XvMC surface. That is + * done by an additional decoder callback. + */ + +static vo_frame_t *xxmc_alloc_frame (vo_driver_t *this_gen) { + xxmc_driver_t *this = (xxmc_driver_t *) this_gen; + xxmc_frame_t *frame ; + + frame = (xxmc_frame_t *) xine_xmalloc (sizeof (xxmc_frame_t)); + if (!frame) + return NULL; + + pthread_mutex_init (&frame->vo_frame.mutex, NULL); + frame->xvmc_surf = NULL; + + /* + * supply required functions + */ + + frame->vo_frame.proc_slice = NULL; + frame->vo_frame.proc_frame = NULL; + frame->vo_frame.proc_duplicate_frame_data = NULL; + frame->vo_frame.field = xxmc_frame_field; + frame->vo_frame.dispose = xxmc_frame_dispose; + frame->vo_frame.driver = this_gen; + + xprintf (this->xine, XINE_VERBOSITY_DEBUG, "Allocating frame\n"); + + return (vo_frame_t *) frame; +} + +static int HandleXError (Display *display, XErrorEvent *xevent) { + char str [1024]; + + XGetErrorText (display, xevent->error_code, str, 1024); + printf ("received X error event: %s\n", str); + gX11Fail = 1; + + return 0; +} + +/* called xlocked */ +static void x11_InstallXErrorHandler (xxmc_driver_t *this) { + this->x11_old_error_handler = XSetErrorHandler (HandleXError); + XSync(this->display, False); +} + +/* called xlocked */ +static void x11_DeInstallXErrorHandler (xxmc_driver_t *this) { + XSetErrorHandler (this->x11_old_error_handler); + XSync(this->display, False); + this->x11_old_error_handler = NULL; +} + +/* called xlocked */ +static XvImage *create_ximage (xxmc_driver_t *this, XShmSegmentInfo *shminfo, + int width, int height, int format) { + unsigned int xv_format; + XvImage *image = NULL; + + if (this->use_pitch_alignment) { + width = (width + 7) & ~0x7; + } + + switch (format) { + case XINE_IMGFMT_YV12: + case XINE_IMGFMT_XXMC: + xv_format = this->xv_format_yv12; + break; + case XINE_IMGFMT_YUY2: + xv_format = this->xv_format_yuy2; + break; + case FOURCC_IA44: + case FOURCC_AI44: + xv_format = format; + break; + default: + xprintf (this->xine, XINE_VERBOSITY_DEBUG, "create_ximage: unknown format %08x\n",format); + _x_abort(); + } + + if (this->use_shm) { + + /* + * try shm + */ + + gX11Fail = 0; + x11_InstallXErrorHandler (this); + + image = XvShmCreateImage(this->display, this->xv_port, xv_format, 0, + width, height, shminfo); + + if (image == NULL ) { + xprintf(this->xine, XINE_VERBOSITY_LOG, + _("video_out_xxmc: XvShmCreateImage failed\n" + "video_out_xxmc: => not using MIT Shared Memory extension.\n")); + this->use_shm = 0; + goto finishShmTesting; + } + + shminfo->shmid = shmget(IPC_PRIVATE, image->data_size, IPC_CREAT | 0777); + + if (image->data_size==0) { + xprintf(this->xine, XINE_VERBOSITY_LOG, + _("video_out_xxmc: XvShmCreateImage returned a zero size\n" + "video_out_xxmc: => not using MIT Shared Memory extension.\n")); + this->use_shm = 0; + goto finishShmTesting; + } + + if (shminfo->shmid < 0 ) { + xprintf(this->xine, XINE_VERBOSITY_LOG, + _("video_out_xxmc: shared memory error in shmget: %s\n" + "video_out_xxmc: => not using MIT Shared Memory extension.\n"), strerror(errno)); + this->use_shm = 0; + goto finishShmTesting; + } + + shminfo->shmaddr = (char *) shmat(shminfo->shmid, 0, 0); + + if (shminfo->shmaddr == NULL) { + xprintf(this->xine, XINE_VERBOSITY_DEBUG, + "video_out_xxmc: shared memory error (address error NULL)\n"); + this->use_shm = 0; + goto finishShmTesting; + } + + if (shminfo->shmaddr == ((char *) -1)) { + xprintf(this->xine, XINE_VERBOSITY_DEBUG, + "video_out_xxmc: shared memory error (address error)\n"); + this->use_shm = 0; + goto finishShmTesting; + } + + shminfo->readOnly = False; + image->data = shminfo->shmaddr; + + XShmAttach(this->display, shminfo); + + XSync(this->display, False); + shmctl(shminfo->shmid, IPC_RMID, 0); + + if (gX11Fail) { + xprintf(this->xine, XINE_VERBOSITY_LOG, + _("video_out_xxmc: x11 error during shared memory XImage creation\n" + "video_out_xxmc: => not using MIT Shared Memory extension.\n")); + shmdt (shminfo->shmaddr); + shmctl (shminfo->shmid, IPC_RMID, 0); + shminfo->shmid = -1; + this->use_shm = 0; + goto finishShmTesting; + } + + /* + * Now that the Xserver has learned about and attached to the + * shared memory segment, delete it. It's actually deleted by + * the kernel when all users of that segment have detached from + * it. Gives an automatic shared memory cleanup in case we crash. + */ + shmctl (shminfo->shmid, IPC_RMID, 0); + shminfo->shmid = -1; + + finishShmTesting: + x11_DeInstallXErrorHandler(this); + } + + + /* + * fall back to plain Xv if necessary + */ + + if (!this->use_shm) { + char *data; + + switch (format) { + case XINE_IMGFMT_YV12: + case XINE_IMGFMT_XXMC: + data = malloc (width * height * 3/2); + break; + case XINE_IMGFMT_YUY2: + data = malloc (width * height * 2); + break; + case FOURCC_IA44: + case FOURCC_AI44: + data = malloc (width * height); + break; + default: + xprintf (this->xine, XINE_VERBOSITY_DEBUG, "create_ximage: unknown format %08x\n",format); + _x_abort(); + } + + image = XvCreateImage (this->display, this->xv_port, + xv_format, data, width, height); + } + return image; +} + + +/* + * Utility functions for the main update surface callback. + */ + + +static void xxmc_dispose_context(xxmc_driver_t *driver) +{ + if (driver->contextActive) { + + if (driver->xvmc_accel & (XINE_XVMC_ACCEL_MOCOMP | XINE_XVMC_ACCEL_IDCT)) { + xvmc_macroblocks_t *macroblocks = &driver->macroblocks; + + XvMCDestroyMacroBlocks( driver->display, ¯oblocks->macro_blocks ); + XvMCDestroyBlocks( driver->display , ¯oblocks->blocks ); + } + + xprintf(driver->xine, XINE_VERBOSITY_LOG, + "video_out_xxmc: Freeing up XvMC Surfaces and subpictures.\n"); + if (driver->xvmc_palette) free(driver->xvmc_palette); + dispose_xx44_palette( &driver->palette ); + xxmc_xvmc_destroy_subpictures( driver ); + xxmc_xvmc_destroy_surfaces( driver ); + xprintf(driver->xine, XINE_VERBOSITY_LOG, + "video_out_xxmc: Freeing up XvMC Context.\n"); + XLockDisplay (driver->display); + if (driver->subImage) + dispose_ximage(driver, &driver->subShmInfo, driver->subImage); + driver->subImage = NULL; + XUnlockDisplay (driver->display); + XVMCLOCKDISPLAY( driver->display ); + XvMCDestroyContext( driver->display, &driver->context); + XVMCUNLOCKDISPLAY( driver->display ); + driver->contextActive = 0; + driver->hwSubpictures = 0; + } +} + +static int xxmc_find_context(xxmc_driver_t *driver, xine_xxmc_t *xxmc, + unsigned width, unsigned height) +{ + int i,k,found; + xvmc_capabilities_t *curCap; + unsigned request_mpeg_flags, request_accel_flags; + + request_mpeg_flags = xxmc->mpeg; + found = 0; + + for (k = 0; k < NUM_ACCEL_PRIORITY; ++k) { + request_accel_flags = xxmc->acceleration & accel_priority[k]; + if (!request_accel_flags) continue; + + curCap = driver->xvmc_cap; + for (i =0; i < driver->xvmc_num_cap; ++i) { + xprintf(driver->xine, XINE_VERBOSITY_LOG, + "video_out_xxmc: Surface type %d. Capabilities 0x%8x 0x%8x\n",i, + curCap->mpeg_flags,curCap->accel_flags); + xprintf(driver->xine, XINE_VERBOSITY_LOG, + "video_out_xxmc: Requests: 0x%8x 0x%8x\n", + request_mpeg_flags,request_accel_flags); + if (((curCap->mpeg_flags & request_mpeg_flags) == request_mpeg_flags) && + ((curCap->accel_flags & request_accel_flags)) && + (width <= curCap->max_width) && + (height <= curCap->max_height)) { + found = 1; + break; + } + curCap++; + } + if ( found ) { + driver->xvmc_cur_cap = i; + break; + } + } + if ( found ) { + driver->xvmc_accel = request_accel_flags; + return 1; + } + driver->xvmc_accel = 0; + return 0; +} + +static int xxmc_create_context(xxmc_driver_t *driver, unsigned width, unsigned height) +{ + xvmc_capabilities_t *curCap; + + curCap = driver->xvmc_cap + driver->xvmc_cur_cap; + xprintf(driver->xine, XINE_VERBOSITY_LOG, + "video_out_xxmc: Creating new XvMC Context\n"); + XVMCLOCKDISPLAY( driver->display ); + if (Success == XvMCCreateContext( driver->display, driver->xv_port, + curCap->type_id, width, + height, driver->context_flags, + &driver->context)) { + driver->xvmc_mpeg = curCap->mpeg_flags; + driver->xvmc_width = width; + driver->xvmc_height = height; + driver->contextActive = 1; + } + XVMCUNLOCKDISPLAY( driver->display ); + return driver->contextActive; +} + +static void xxmc_setup_subpictures(xxmc_driver_t *driver, unsigned width, unsigned height) +{ + xvmc_capabilities_t *curCap; + XvMCSubpicture *sp; + + if (driver->contextActive) { + + /* + * Determine if we can use hardware subpictures, and in that case, set up an + * XvImage that we can use for blending. + */ + curCap = driver->xvmc_cap + driver->xvmc_cur_cap; + + if ((width > curCap->sub_max_width) || + (height > curCap->sub_max_height)) return; + + if ((driver->xvmc_backend_subpic = (curCap->flags & XVMC_BACKEND_SUBPICTURE))) + xprintf(driver->xine, XINE_VERBOSITY_LOG, + "video_out_xxmc: Using Backend subpictures.\n"); + + if (!driver->subImage) { + /* + * Note: If other image formats than xx44 are to be used here, they must be + * translated to XINE_IMGFMT_XXX, since that is what create_ximage + * expects. + */ + + XLockDisplay (driver->display); + + driver->subImage = + create_ximage(driver, &driver->subShmInfo, width, height, curCap->subPicType.id); + XUnlockDisplay (driver->display); + if (NULL == driver->subImage) { + xprintf(driver->xine, XINE_VERBOSITY_LOG, + "video_out_xxmc: Failed allocating XvImage for supbictures.\n"); + return; + } + } + + sp = xxmc_xvmc_alloc_subpicture( driver, &driver->context, width, + height, curCap->subPicType.id); + if (sp == NULL) return; + + init_xx44_palette( &driver->palette, sp->num_palette_entries); + driver->xvmc_palette = (char *) xine_xmalloc(sp->num_palette_entries + * sp->entry_bytes); + xxmc_xvmc_free_subpicture( driver, sp); + if (driver->xvmc_palette == NULL) return; + driver->hwSubpictures = 1; + } +} + +static int xxmc_mocomp_create_macroblocks(xxmc_driver_t *driver, + xxmc_frame_t *frame, + int slices) +{ + Status ret; + xvmc_macroblocks_t *macroblocks = &driver->macroblocks; + xine_xxmc_t *xxmc = (xine_xxmc_t *) frame->vo_frame.accel_data; + + slices = (slices * driver->xvmc_width) / 16; + ret = XvMCCreateMacroBlocks(driver->display, &driver->context, slices, + ¯oblocks->macro_blocks); + if (ret) return 0; + ret = XvMCCreateBlocks(driver->display, &driver->context, slices*6, + ¯oblocks->blocks); + if (ret) return 0; + + macroblocks->xine_mc.blockbaseptr = macroblocks->blocks.blocks; + macroblocks->xine_mc.blockptr = macroblocks->xine_mc.blockbaseptr; + macroblocks->num_blocks = 0; + macroblocks->macroblockbaseptr = macroblocks->macro_blocks.macro_blocks; + macroblocks->macroblockptr = macroblocks->macroblockbaseptr; + macroblocks->slices = slices; + xxmc->xvmc.macroblocks = (xine_macroblocks_t *)macroblocks; + + return 1; +} + +static void xvmc_check_colorkey_properties(xxmc_driver_t *driver) +{ + int num,i; + XvAttribute *xvmc_attributes; + Atom ap; + + /* + * Determine if the context is of "Overlay" type. If so, + * check whether we can autopaint. + */ + + driver->have_xvmc_autopaint = 0; + if (driver->context_flags & XVMC_OVERLAID_SURFACE) { + XVMCLOCKDISPLAY( driver->display ); + xvmc_attributes = XvMCQueryAttributes( driver->display, + &driver->context, + &num); + if (xvmc_attributes) { + for (i=0; idisplay, "XV_AUTOPAINT_COLORKEY", False); + XvMCSetAttribute(driver->display, &driver->context,ap, + driver->props[VO_PROP_AUTOPAINT_COLORKEY].value); + driver->have_xvmc_autopaint = 1; + } + } + } + XFree(xvmc_attributes); + XVMCUNLOCKDISPLAY( driver->display ); + + /* + * If we have a shape overlay, switch to colorkey since we have a + * colorkey overlay. + */ + + if ( driver->xoverlay ) { + if ( !driver->xoverlay_ck) { + XLockDisplay( driver->display ); + x11osd_destroy( driver->xoverlay ); + driver->xoverlay = x11osd_create( driver->xine, driver->display, + driver->screen, driver->drawable, + X11OSD_COLORKEY); + if ( driver->xoverlay ) { + x11osd_colorkey( driver->xoverlay, driver->colorkey, &driver->sc); + driver->xoverlay_ck = 1; + } + } + } + } else { + + /* + * Not a colorkey overlay. Swith to shape. + */ + + if ( driver->xoverlay ) { + if ( driver->xoverlay_ck ) { + XLockDisplay( driver->display ); + x11osd_destroy( driver->xoverlay ); + driver->xoverlay = x11osd_create( driver->xine, driver->display, + driver->screen, driver->drawable, + X11OSD_SHAPED); + driver->xoverlay_ck = 0; + } + } + } +} + + +static int xxmc_xvmc_update_context(xxmc_driver_t *driver, xxmc_frame_t *frame) +{ + xine_xxmc_t *xxmc = &frame->xxmc_data; + + /* + * Are we at all capable of doing XvMC ? + */ + + if (driver->xvmc_cap == 0 || frame->format != XINE_IMGFMT_XXMC) + return 0; + + /* + * Determine if we have to change context. + */ + + if (((frame->width != driver->xvmc_width) || + (frame->height != driver->xvmc_height) || + (xxmc->mpeg != driver->xvmc_mpeg))) { + + + xprintf(driver->xine, XINE_VERBOSITY_LOG, + "video_out_xxmc: New format. Need to change XvMC Context.\n" + "width: %d height: %d mpeg: %d acceleration: %d\n", frame->width, frame->height, + xxmc->mpeg, xxmc->acceleration); + + if (frame->xvmc_surf) + xxmc_xvmc_free_surface( driver , frame->xvmc_surf); + frame->xvmc_surf = NULL; + + + xxmc_dispose_context( driver ); + + if (xxmc_find_context( driver, xxmc, frame->width, frame->height )) { + xxmc_create_context( driver, frame->width, frame->height); + xvmc_check_colorkey_properties( driver ); + xxmc_setup_subpictures(driver, frame->width, frame->height); + if ((driver->xvmc_accel & (XINE_XVMC_ACCEL_MOCOMP | XINE_XVMC_ACCEL_IDCT))) { + if (!xxmc_mocomp_create_macroblocks(driver, frame, 1)) { + lprintf("video_out_xxmc: ERROR: Macroblock allocation failed\n"); + xxmc_dispose_context( driver ); + } + } + } + + if (!driver->contextActive) { + printf("video_out_xxmc: Using software decoding for this stream.\n"); + driver->xvmc_accel = 0; + } else { + printf("video_out_xxmc: Using hardware decoding for this stream.\n"); + } + } + + /* + * If we have changed context since the surface was updated, xvmc_surf + * is either NULL or invalid. If it is invalid. Set it to NULL. + * Also if there are other users of this surface, deregister our use of + * it and later try to allocate a new, fresh one. + */ + + if (frame->xvmc_surf) { + if (! xxmc_xvmc_surface_valid( driver, frame->xvmc_surf )) { + xxmc_xvmc_free_surface(driver , frame->xvmc_surf); + frame->xvmc_surf = NULL; + } + } + + /* + * If it is NULL, check that we have a valid XvMC context, and in that case, + * create a new surface. + */ + + if ((frame->xvmc_surf == NULL) && (driver->contextActive) ) { + if (NULL == (frame->xvmc_surf = + xxmc_xvmc_alloc_surface( driver, &driver->context))) { + printf("video_out_xxmc: ERROR: Accelerated surface allocation failed.\n" + "video_out_xxmc: You are probably out of framebuffer memory.\n" + "video_out_xxmc: Falling back to software decoding.\n"); + + driver->xvmc_accel = 0; + xxmc_dispose_context( driver ); + } + } + + + driver->xvmc_mpeg = xxmc->mpeg; + driver->xvmc_width = frame->width; + driver->xvmc_height = frame->height; + return driver->contextActive; +} + + +/* + * This one is called by the decoder to tell us what type of + * XxMC image format it really want to use. It could be either an + * XvMC format or an Xv format. This allows us to handle different + * stream format accelerations such as mpeg2, mpeg4, mpeg1 etc. at + * the same time as we can handle IDCT, MOCOMP, VLD. etc. For un- + * supported XvMC formats, we just fall back to YV12. + */ + +static void xxmc_update_xxmc(vo_frame_t *vo_img) { + + xxmc_frame_t *frame = (xxmc_frame_t *) vo_img; + xxmc_driver_t *driver = (xxmc_driver_t *) frame->vo_frame.driver; + xine_xxmc_t *xxmc = &frame->xxmc_data; + + xvmc_context_writer_lock( &driver->xvmc_lock); + if (xxmc->format == XINE_IMGFMT_XXMC) { + + /* + * Check if we can find a suitable context for what the + * decoder plugin wants! Otherwise, fall back to YV12. + */ + + if (! xxmc_xvmc_update_context(driver, frame)) { + + /* + * Either no suitable context was found or an XvMC error occured. + */ + + xxmc->format = XINE_IMGFMT_YV12; + xxmc->acceleration = 0; + xxmc->xvmc.macroblocks = 0; + } else { + + /* + * We're running accelerated. + */ + + xxmc->format = XINE_IMGFMT_XXMC; + xxmc->acceleration = driver->xvmc_accel; + xxmc->xvmc.macroblocks = (xine_macroblocks_t *) &driver->macroblocks; + switch(driver->xvmc_accel) { + case XINE_XVMC_ACCEL_IDCT: + xxmc->xvmc.macroblocks->xvmc_accel = XINE_VO_IDCT_ACCEL; + break; + case XINE_XVMC_ACCEL_MOCOMP: + xxmc->xvmc.macroblocks->xvmc_accel = XINE_VO_MOTION_ACCEL; + break; + default: + xxmc->xvmc.macroblocks->xvmc_accel = 0; + } + } + xxmc->decoded = 0; + } + xvmc_context_writer_unlock( &driver->xvmc_lock); +} + +/* called xlocked */ +static void dispose_ximage (xxmc_driver_t *this, + XShmSegmentInfo *shminfo, + XvImage *myimage) { + + if (this->use_shm) { + + XShmDetach (this->display, shminfo); + XFree (myimage); + shmdt (shminfo->shmaddr); + if (shminfo->shmid >= 0) { + shmctl (shminfo->shmid, IPC_RMID, 0); + shminfo->shmid = -1; + } + + } + else { + if (myimage->data) free(myimage->data); + XFree (myimage); + } + +} + +/* + * Just fills in functions. Surface and context updates are not done here. + */ + + +static void xxmc_update_frame_format (vo_driver_t *this_gen, + vo_frame_t *frame_gen, + uint32_t width, uint32_t height, + double ratio, int format, int flags) { + + xxmc_driver_t *this = (xxmc_driver_t *) this_gen; + xxmc_frame_t *frame = (xxmc_frame_t *) frame_gen; + + if ( XINE_IMGFMT_XXMC == format ) { + frame->xxmc_data.proc_xxmc_frame = xxmc_update_xxmc; + frame->xxmc_data.proc_xxmc_flush = xvmc_vld_flush; +#ifdef HAVE_VLDXVMC + frame->xxmc_data.proc_xxmc_begin = xvmc_vld_frame; + frame->xxmc_data.proc_xxmc_slice = xvmc_vld_slice; +#endif + frame->xxmc_data.xvmc.proc_macro_block = xxmc_xvmc_proc_macro_block; + frame->vo_frame.accel_data = &frame->xxmc_data; + frame->vo_frame.proc_duplicate_frame_data = xxmc_duplicate_frame_data; + } else { + frame->vo_frame.accel_data = &frame->xxmc_data; + frame->xxmc_data.format = format; + } + + if (this->use_pitch_alignment) { + width = (width + 7) & ~0x7; + } + + if ((frame->width != width) + || (frame->height != height) + || (frame->format != format)) { + + XLockDisplay (this->display); + + /* + * (re-) allocate xvimage + */ + + if (frame->image) { + dispose_ximage (this, &frame->shminfo, frame->image); + frame->image = NULL; + } + + frame->image = create_ximage (this, &frame->shminfo, width, height, format); + + if(format == XINE_IMGFMT_YUY2) { + frame->vo_frame.pitches[0] = frame->image->pitches[0]; + frame->vo_frame.base[0] = frame->image->data + frame->image->offsets[0]; + } + else { + frame->vo_frame.pitches[0] = frame->image->pitches[0]; + frame->vo_frame.pitches[1] = frame->image->pitches[2]; + frame->vo_frame.pitches[2] = frame->image->pitches[1]; + frame->vo_frame.base[0] = frame->image->data + frame->image->offsets[0]; + frame->vo_frame.base[1] = frame->image->data + frame->image->offsets[2]; + frame->vo_frame.base[2] = frame->image->data + frame->image->offsets[1]; + } + + frame->width = width; + frame->height = height; + frame->format = format; + + XUnlockDisplay (this->display); + } + frame->ratio = ratio; +} + +/* + * From Xv. + */ + + +#define DEINTERLACE_CROMA +static void xxmc_deinterlace_frame (xxmc_driver_t *this) { + uint8_t *recent_bitmaps[VO_NUM_RECENT_FRAMES]; + xxmc_frame_t *frame = this->recent_frames[0]; + int i; + int xvscaling; + + xvscaling = (this->deinterlace_method == DEINTERLACE_ONEFIELDXV) ? 2 : 1; + + if (!this->deinterlace_frame.image + || (frame->width != this->deinterlace_frame.width) + || (frame->height != this->deinterlace_frame.height ) + || (frame->format != this->deinterlace_frame.format) + || (frame->ratio != this->deinterlace_frame.ratio)) { + XLockDisplay (this->display); + + if(this->deinterlace_frame.image) + dispose_ximage (this, &this->deinterlace_frame.shminfo, + this->deinterlace_frame.image); + + this->deinterlace_frame.image = create_ximage (this, &this->deinterlace_frame.shminfo, + frame->width,frame->height / xvscaling, + frame->format); + this->deinterlace_frame.width = frame->width; + this->deinterlace_frame.height = frame->height; + this->deinterlace_frame.format = frame->format; + this->deinterlace_frame.ratio = frame->ratio; + + XUnlockDisplay (this->display); + } + + + if ( this->deinterlace_method != DEINTERLACE_ONEFIELDXV ) { +#ifdef DEINTERLACE_CROMA + + /* I don't think this is the right way to do it (deinterlacing croma by croma info). + DScaler deinterlaces croma together with luma, but it's easier for them because + they have that components 1:1 at the same table. + */ + for( i = 0; i < VO_NUM_RECENT_FRAMES; i++ ) + if( this->recent_frames[i] && this->recent_frames[i]->width == frame->width && + this->recent_frames[i]->height == frame->height ) + recent_bitmaps[i] = this->recent_frames[i]->image->data + frame->width*frame->height; + else + recent_bitmaps[i] = NULL; + + deinterlace_yuv( this->deinterlace_frame.image->data+frame->width*frame->height, + recent_bitmaps, frame->width/2, frame->height/2, this->deinterlace_method ); + for( i = 0; i < VO_NUM_RECENT_FRAMES; i++ ) + if( this->recent_frames[i] && this->recent_frames[i]->width == frame->width && + this->recent_frames[i]->height == frame->height ) + recent_bitmaps[i] = this->recent_frames[i]->image->data + frame->width*frame->height*5/4; + else + recent_bitmaps[i] = NULL; + + deinterlace_yuv( this->deinterlace_frame.image->data+frame->width*frame->height*5/4, + recent_bitmaps, frame->width/2, frame->height/2, this->deinterlace_method ); + +#else + + /* know bug: we are not deinterlacing Cb and Cr */ + xine_fast_memcpy(this->deinterlace_frame.image->data + frame->width*frame->height, + frame->image->data + frame->width*frame->height, + frame->width*frame->height*1/2); + +#endif + + for( i = 0; i < VO_NUM_RECENT_FRAMES; i++ ) + if( this->recent_frames[i] && this->recent_frames[i]->width == frame->width && + this->recent_frames[i]->height == frame->height ) + recent_bitmaps[i] = this->recent_frames[i]->image->data; + else + recent_bitmaps[i] = NULL; + + deinterlace_yuv( this->deinterlace_frame.image->data, recent_bitmaps, + frame->width, frame->height, this->deinterlace_method ); + } + else { + /* + dirty and cheap deinterlace method: we give half of the lines to xv + driver and let it scale for us. + note that memcpy's below don't seem to impact much on performance, + specially when fast memcpys are available. + */ + uint8_t *dst, *src; + + dst = this->deinterlace_frame.image->data; + src = this->recent_frames[0]->image->data; + for( i = 0; i < frame->height; i+=2 ) { + xine_fast_memcpy(dst,src,frame->width); + dst += frame->width; + src += 2 * frame->width; + } + + dst = this->deinterlace_frame.image->data + frame->width * frame->height / 2; + src = this->recent_frames[0]->image->data + frame->width * frame->height; + for( i = 0; i < frame->height; i+=4 ) { + xine_fast_memcpy(dst,src,frame->width / 2); + dst += frame->width / 2; + src += frame->width; + } + + dst = this->deinterlace_frame.image->data + frame->width * frame->height * 5 / 8; + src = this->recent_frames[0]->image->data + frame->width * frame->height * 5 / 4; + for( i = 0; i < frame->height; i+=4 ) { + xine_fast_memcpy(dst,src,frame->width / 2); + dst += frame->width / 2; + src += frame->width; + } + } + + this->cur_frame = &this->deinterlace_frame; +} + +static void xxmc_clean_output_area (xxmc_driver_t *this) { + int i, autopainting; + + XLockDisplay (this->display); + + XSetForeground (this->display, this->gc, this->black.pixel); + + for( i = 0; i < 4; i++ ) { + if( this->sc.border[i].w && this->sc.border[i].h ) { + XFillRectangle(this->display, this->drawable, this->gc, + this->sc.border[i].x, this->sc.border[i].y, + this->sc.border[i].w, this->sc.border[i].h); + } + } + + /* + * XvMC does not support autopainting regardless of whether there's an + * Xv attribute for this. If there is an XvMC attribute for autopainting, + * we ca assume it is supported. This is checked whenever a context is + * changed. + */ + + autopainting = (this->props[VO_PROP_AUTOPAINT_COLORKEY].value == 1); + if ((this->contextActive && + (this->context_flags & XVMC_OVERLAID_SURFACE) && + (! this->have_xvmc_autopaint || + ! autopainting)) || + (! this->contextActive && !autopainting)) { + XSetForeground (this->display, this->gc, this->colorkey); + XFillRectangle (this->display, this->drawable, this->gc, + this->sc.output_xoffset, this->sc.output_yoffset, + this->sc.output_width, this->sc.output_height); + } + + if (this->xoverlay) { + x11osd_resize (this->xoverlay, this->sc.gui_width, this->sc.gui_height); + this->ovl_changed = 1; + } + + XUnlockDisplay (this->display); +} + +/* + * convert delivered height/width to ideal width/height + * taking into account aspect ratio and zoom factor + */ + +static void xxmc_compute_ideal_size (xxmc_driver_t *this) { + _x_vo_scale_compute_ideal_size( &this->sc ); +} + + +/* + * make ideal width/height "fit" into the gui + */ + +static void xxmc_compute_output_size (xxmc_driver_t *this) { + + _x_vo_scale_compute_output_size( &this->sc ); + + /* onefield_xv divide by 2 the number of lines */ + if (this->deinterlace_enabled + && (this->deinterlace_method == DEINTERLACE_ONEFIELDXV) + && ((this->cur_frame->format == XINE_IMGFMT_YV12) + || this->cur_frame->format == XINE_IMGFMT_XXMC)) { + this->sc.displayed_height = this->sc.displayed_height / 2 - 1; + this->sc.displayed_yoffset = this->sc.displayed_yoffset / 2; + } +} + +static void xxmc_overlay_begin (vo_driver_t *this_gen, + vo_frame_t *frame_gen, int changed) { + xxmc_driver_t *this = (xxmc_driver_t *) this_gen; + + this->ovl_changed += changed; + + if( this->ovl_changed && this->xoverlay ) { + XLockDisplay (this->display); + x11osd_clear(this->xoverlay); + XUnlockDisplay (this->display); + } + if (this->ovl_changed && this->hwSubpictures ) { + xxmc_frame_t *frame = (xxmc_frame_t *) frame_gen; + + LOCK_AND_SURFACE_VALID( this, frame->xvmc_surf ); + this->new_subpic = xxmc_xvmc_alloc_subpicture + ( this, &this->context, this->xvmc_width, + this->xvmc_height, + this->xvmc_cap[this->xvmc_cur_cap].subPicType.id); + + if (this->new_subpic) { + this->first_overlay = 1; + XVMCLOCKDISPLAY( this->display ); + XvMCClearSubpicture(this->display, this->new_subpic, 0,0, + this->xvmc_width, + this->xvmc_height, 0x00); + XVMCUNLOCKDISPLAY( this->display ); + clear_xx44_palette(&this->palette); + } + xvmc_context_reader_unlock( &this->xvmc_lock ); + } +} + +static void xxmc_overlay_end (vo_driver_t *this_gen, vo_frame_t *vo_img) +{ + xxmc_driver_t *this = (xxmc_driver_t *) this_gen; + xxmc_frame_t *frame = (xxmc_frame_t *) vo_img; + + + if( this->ovl_changed && this->xoverlay ) { + XLockDisplay (this->display); + x11osd_expose(this->xoverlay); + XUnlockDisplay (this->display); + } + if (this->hwSubpictures) { + LOCK_AND_SURFACE_VALID( this, frame->xvmc_surf ); + if (this->ovl_changed) { + if (this->old_subpic) { + xxmc_xvmc_free_subpicture(this, this->old_subpic); + this->old_subpic = NULL; + } + if (this->new_subpic) { + this->old_subpic = this->new_subpic; + this->new_subpic = NULL; + xx44_to_xvmc_palette( &this->palette, this->xvmc_palette, + 0, this->old_subpic->num_palette_entries, + this->old_subpic->entry_bytes, + this->reverse_nvidia_palette ? "YVU" : + this->old_subpic->component_order); + XVMCLOCKDISPLAY( this->display ); + XvMCSetSubpicturePalette( this->display, this->old_subpic, + this->xvmc_palette); + XvMCFlushSubpicture( this->display , this->old_subpic); + XvMCSyncSubpicture( this->display, this->old_subpic ); + XVMCUNLOCKDISPLAY( this->display ); + } + } + if (this->old_subpic && (! this->first_overlay)) { + XVMCLOCKDISPLAY( this->display ); + if (this->xvmc_backend_subpic ) { + XvMCBlendSubpicture( this->display, frame->xvmc_surf, + this->old_subpic,0,0,this->xvmc_width, + this->xvmc_height, 0, 0, + this->xvmc_width, this->xvmc_height ); + } else { + XvMCBlendSubpicture2( this->display, frame->xvmc_surf, + frame->xvmc_surf, + this->old_subpic, 0,0,this->xvmc_width, + this->xvmc_height,0,0,this->xvmc_width, + this->xvmc_height); + } + XVMCUNLOCKDISPLAY( this->display ); + } + xvmc_context_reader_unlock(&this->xvmc_lock ); + } + this->ovl_changed = 0; +} + + +static void xxmc_overlay_blend (vo_driver_t *this_gen, vo_frame_t *frame_gen, + vo_overlay_t *overlay) +{ + xxmc_driver_t *this = (xxmc_driver_t *) this_gen; + xxmc_frame_t *frame = (xxmc_frame_t *) frame_gen; + + if (overlay->rle) { + if( overlay->unscaled ) { + if( this->ovl_changed && this->xoverlay ) { + XLockDisplay (this->display); + x11osd_blend(this->xoverlay, overlay); + XUnlockDisplay (this->display); + } + } else if (this->hwSubpictures) { + if (this->ovl_changed) { + if (this->new_subpic) { + LOCK_AND_SURFACE_VALID( this, frame->xvmc_surf ); + if (this->first_overlay) { + memset(this->subImage->data,0,this->subImage->width* + this->subImage->height); + this->first_overlay = 0; + } + blend_xx44(this->subImage->data, overlay, this->subImage->width, + this->subImage->height, this->subImage->width, + &this->palette, (this->subImage->id == FOURCC_IA44)); + XVMCLOCKDISPLAY( this->display ); + XvMCCompositeSubpicture( this->display, this->new_subpic, + this->subImage, + overlay->x, overlay->y,overlay->width, + overlay->height, + overlay->x, overlay->y); + XVMCUNLOCKDISPLAY( this->display ); + xvmc_context_reader_unlock( &this->xvmc_lock ); + } + } + } else { + if ((frame->format == XINE_IMGFMT_YV12) || + (frame->format == XINE_IMGFMT_XXMC)) { + blend_yuv(frame->vo_frame.base, overlay, + frame->width, frame->height, frame->vo_frame.pitches); + } else { + blend_yuy2(frame->vo_frame.base[0], overlay, + frame->width, frame->height, frame->vo_frame.pitches[0]); + } + } + } +} + +static void xxmc_add_recent_frame (xxmc_driver_t *this, xxmc_frame_t *frame) +{ + int i; + i = VO_NUM_RECENT_FRAMES-1; + if( this->recent_frames[i] ) { + this->recent_frames[i]->vo_frame.free + (&this->recent_frames[i]->vo_frame); + } + for( ; i ; i-- ) + this->recent_frames[i] = this->recent_frames[i-1]; + + this->recent_frames[0] = frame; +} + +static int xxmc_redraw_needed (vo_driver_t *this_gen) +{ + xxmc_driver_t *this = (xxmc_driver_t *) this_gen; + int ret = 0; + + if( this->cur_frame ) { + + this->sc.delivered_height = this->cur_frame->height; + this->sc.delivered_width = this->cur_frame->width; + this->sc.delivered_ratio = this->cur_frame->ratio; + + this->sc.crop_left = this->cur_frame->vo_frame.crop_left; + this->sc.crop_right = this->cur_frame->vo_frame.crop_right; + this->sc.crop_top = this->cur_frame->vo_frame.crop_top; + this->sc.crop_bottom = this->cur_frame->vo_frame.crop_bottom; + + xxmc_compute_ideal_size(this); + + if( _x_vo_scale_redraw_needed( &this->sc ) ) { + + xxmc_compute_output_size (this); + xxmc_clean_output_area (this); + + ret = 1; + } + } + else + ret = 1; + + return ret; +} + +static void xxmc_display_frame (vo_driver_t *this_gen, vo_frame_t *frame_gen) +{ + xxmc_driver_t *this = (xxmc_driver_t *) this_gen; + xxmc_frame_t *frame = (xxmc_frame_t *) frame_gen; + xine_xxmc_t *xxmc = &frame->xxmc_data; + + /* + * queue frames (deinterlacing) + * free old frames + */ + + xvmc_context_reader_lock( &this->xvmc_lock ); + xxmc_add_recent_frame (this, frame); /* deinterlacing */ + + this->cur_frame = frame; + + + /* + * let's see if this frame is different in size / aspect + * ratio from the previous one + */ + if ( (frame->width != this->sc.delivered_width) + || (frame->height != this->sc.delivered_height) + || (frame->ratio != this->sc.delivered_ratio) ) { + lprintf("frame format changed\n"); + this->sc.force_redraw = 1; /* trigger re-calc of output size */ + } + + + /* + * deinterlace frame if necessary + * (currently only working for YUV images) + */ + + if (this->deinterlace_enabled && this->deinterlace_method + && ((frame->format == XINE_IMGFMT_YV12) || + (frame->format == XINE_IMGFMT_XXMC)) + && deinterlace_yuv_supported( this->deinterlace_method ) == 1) { + if (frame->format != XINE_IMGFMT_XXMC) + xxmc_deinterlace_frame (this); + else if (xxmc->format != XINE_IMGFMT_XXMC) + xxmc_deinterlace_frame (this); + } + + /* + * tell gui that we are about to display a frame, + * ask for offset and output size + */ + + xxmc_redraw_needed (this_gen); + if (frame->xvmc_surf && (xxmc->format == XINE_IMGFMT_XXMC)) { + if (xxmc->decoded && xxmc_xvmc_surface_valid(this, frame->xvmc_surf)) { + XVMCLOCKDISPLAY( this->display ); + XvMCPutSurface( this->display, frame->xvmc_surf , this->drawable, + this->sc.displayed_xoffset, this->sc.displayed_yoffset, + this->sc.displayed_width, this->sc.displayed_height, + this->sc.output_xoffset, this->sc.output_yoffset, + this->sc.output_width, this->sc.output_height, + ((this->deinterlace_enabled) ? + XVMC_TOP_FIELD : XVMC_FRAME_PICTURE)); + XVMCUNLOCKDISPLAY( this->display ); + } + } else { + XLockDisplay (this->display); + if (this->use_shm) { + XvShmPutImage(this->display, this->xv_port, + this->drawable, this->gc, frame->image, + this->sc.displayed_xoffset, this->sc.displayed_yoffset, + this->sc.displayed_width, this->sc.displayed_height, + this->sc.output_xoffset, this->sc.output_yoffset, + this->sc.output_width, this->sc.output_height, True); + + } else { + XvPutImage(this->display, this->xv_port, + this->drawable, this->gc, frame->image, + this->sc.displayed_xoffset, this->sc.displayed_yoffset, + this->sc.displayed_width, this->sc.displayed_height, + this->sc.output_xoffset, this->sc.output_yoffset, + this->sc.output_width, this->sc.output_height); + } + XSync(this->display, False); + XUnlockDisplay (this->display); + } + + this->cur_frame = frame; + xvmc_context_reader_unlock( &this->xvmc_lock ); + +} + +static int xxmc_get_property (vo_driver_t *this_gen, int property) { + xxmc_driver_t *this = (xxmc_driver_t *) this_gen; + + switch (property) { + case VO_PROP_WINDOW_WIDTH: + this->props[property].value = this->sc.gui_width; + break; + case VO_PROP_WINDOW_HEIGHT: + this->props[property].value = this->sc.gui_height; + break; + } + + lprintf("video_out_xxmc: property #%d = %d\n", property, this->props[property].value); + + return this->props[property].value; +} + +static void xxmc_property_callback (void *property_gen, xine_cfg_entry_t *entry) { + xxmc_property_t *property = (xxmc_property_t *) property_gen; + xxmc_driver_t *this = property->this; + + xvmc_context_reader_lock( &this->xvmc_lock ); + XLockDisplay (this->display); + XvSetPortAttribute (this->display, this->xv_port, + property->atom, + entry->num_value); + XUnlockDisplay (this->display); + if (this->contextActive) { + XVMCLOCKDISPLAY( this->display ); + XvMCSetAttribute(this->display, &this->context, + property->atom, + entry->num_value); + XVMCUNLOCKDISPLAY( this->display ); + } + xvmc_context_reader_unlock( &this->xvmc_lock ); +} + +static int xxmc_set_property (vo_driver_t *this_gen, + int property, int value) { + xxmc_driver_t *this = (xxmc_driver_t *) this_gen; + + if (this->props[property].atom != None) { + + /* value is out of bound */ + if((value < this->props[property].min) || (value > this->props[property].max)) + value = (this->props[property].min + this->props[property].max) >> 1; + xvmc_context_reader_lock( &this->xvmc_lock ); + if (this->contextActive) { + XVMCLOCKDISPLAY( this->display ); + XvMCSetAttribute(this->display, &this->context, + this->props[property].atom, + value); + XVMCUNLOCKDISPLAY( this->display ); + } + xvmc_context_reader_unlock( &this->xvmc_lock ); + + XLockDisplay (this->display); + XvSetPortAttribute (this->display, this->xv_port, + this->props[property].atom, value); + XvGetPortAttribute (this->display, this->xv_port, + this->props[property].atom, + &this->props[property].value); + XUnlockDisplay (this->display); + + if (this->props[property].entry) + this->props[property].entry->num_value = this->props[property].value; + + return this->props[property].value; + } + else { + switch (property) { + + case VO_PROP_INTERLACED: + this->props[property].value = value; + xprintf(this->xine, XINE_VERBOSITY_LOG, + "video_out_xxmc: VO_PROP_INTERLACED(%d)\n", this->props[property].value); + this->deinterlace_enabled = value; + if (this->deinterlace_method == DEINTERLACE_ONEFIELDXV) { + xxmc_compute_ideal_size (this); + xxmc_compute_output_size (this); + } + break; + + case VO_PROP_ASPECT_RATIO: + if (value>=XINE_VO_ASPECT_NUM_RATIOS) + value = XINE_VO_ASPECT_AUTO; + + this->props[property].value = value; + xprintf(this->xine, XINE_VERBOSITY_LOG, + "video_out_xxmc: VO_PROP_ASPECT_RATIO(%d)\n", this->props[property].value); + this->sc.user_ratio = value; + + xxmc_compute_ideal_size (this); + + this->sc.force_redraw = 1; /* trigger re-calc of output size */ + break; + + case VO_PROP_ZOOM_X: + if ((value >= XINE_VO_ZOOM_MIN) && (value <= XINE_VO_ZOOM_MAX)) { + this->props[property].value = value; + xprintf(this->xine, XINE_VERBOSITY_LOG, + "video_out_xxmc: VO_PROP_ZOOM_X = %d\n", this->props[property].value); + + this->sc.zoom_factor_x = (double)value / (double)XINE_VO_ZOOM_STEP; + + xxmc_compute_ideal_size (this); + + this->sc.force_redraw = 1; /* trigger re-calc of output size */ + } + break; + + case VO_PROP_ZOOM_Y: + if ((value >= XINE_VO_ZOOM_MIN) && (value <= XINE_VO_ZOOM_MAX)) { + this->props[property].value = value; + xprintf(this->xine, XINE_VERBOSITY_LOG, + "video_out_xxmc: VO_PROP_ZOOM_Y = %d\n", this->props[property].value); + + this->sc.zoom_factor_y = (double)value / (double)XINE_VO_ZOOM_STEP; + + xxmc_compute_ideal_size (this); + + this->sc.force_redraw = 1; /* trigger re-calc of output size */ + } + break; + } + } + return value; +} + +static void xxmc_get_property_min_max (vo_driver_t *this_gen, + int property, int *min, int *max) { + xxmc_driver_t *this = (xxmc_driver_t *) this_gen; + + *min = this->props[property].min; + *max = this->props[property].max; +} + +static int xxmc_gui_data_exchange (vo_driver_t *this_gen, + int data_type, void *data) { + + xxmc_driver_t *this = (xxmc_driver_t *) this_gen; + + switch (data_type) { +#ifndef XINE_DISABLE_DEPRECATED_FEATURES + case XINE_GUI_SEND_COMPLETION_EVENT: + break; +#endif + + case XINE_GUI_SEND_EXPOSE_EVENT: { + /* XExposeEvent * xev = (XExposeEvent *) data; */ + + if (this->cur_frame) { + xxmc_frame_t *frame = this->cur_frame; + xine_xxmc_t *xxmc = &frame->xxmc_data; + + xxmc_redraw_needed (this_gen); + + /* + * Paint colorkey if needed. + */ + + xxmc_clean_output_area (this); + xvmc_context_reader_lock( &this->xvmc_lock ); + + if (frame->xvmc_surf && (xxmc->format == XINE_IMGFMT_XXMC)) { + if (xxmc->decoded && xxmc_xvmc_surface_valid(this, frame->xvmc_surf)) { + XVMCLOCKDISPLAY( this->display ); + XvMCPutSurface( this->display, frame->xvmc_surf, this->drawable, + this->sc.displayed_xoffset, this->sc.displayed_yoffset, + this->sc.displayed_width, this->sc.displayed_height, + this->sc.output_xoffset, this->sc.output_yoffset, + this->sc.output_width, this->sc.output_height, + ((this->deinterlace_enabled) ? XVMC_TOP_FIELD : XVMC_FRAME_PICTURE)); + XVMCUNLOCKDISPLAY( this->display ); + } + } else { + XLockDisplay (this->display); + if (this->use_shm) { + XvShmPutImage(this->display, this->xv_port, + this->drawable, this->gc, frame->image, + this->sc.displayed_xoffset, this->sc.displayed_yoffset, + this->sc.displayed_width, this->sc.displayed_height, + this->sc.output_xoffset, this->sc.output_yoffset, + this->sc.output_width, this->sc.output_height, True); + } else { + XvPutImage(this->display, this->xv_port, + this->drawable, this->gc, frame->image, + this->sc.displayed_xoffset, this->sc.displayed_yoffset, + this->sc.displayed_width, this->sc.displayed_height, + this->sc.output_xoffset, this->sc.output_yoffset, + this->sc.output_width, this->sc.output_height); + } + XSync(this->display, False); + XUnlockDisplay (this->display); + } + + if(this->xoverlay) + x11osd_expose(this->xoverlay); + xvmc_context_reader_unlock( &this->xvmc_lock ); + } + } + break; + + case XINE_GUI_SEND_DRAWABLE_CHANGED: + XLockDisplay (this->display); + this->drawable = (Drawable) data; + XFreeGC(this->display, this->gc); + this->gc = XCreateGC (this->display, this->drawable, 0, NULL); + if(this->xoverlay) + x11osd_drawable_changed(this->xoverlay, this->drawable); + this->ovl_changed = 1; + XUnlockDisplay (this->display); + this->sc.force_redraw = 1; + break; + + case XINE_GUI_SEND_TRANSLATE_GUI_TO_VIDEO: + { + int x1, y1, x2, y2; + x11_rectangle_t *rect = data; + + _x_vo_scale_translate_gui2video(&this->sc, rect->x, rect->y, + &x1, &y1); + _x_vo_scale_translate_gui2video(&this->sc, rect->x + rect->w, rect->y + rect->h, + &x2, &y2); + rect->x = x1; + rect->y = y1; + rect->w = x2-x1; + rect->h = y2-y1; + + /* onefield_xv divide by 2 the number of lines */ + if (this->deinterlace_enabled + && (this->deinterlace_method == DEINTERLACE_ONEFIELDXV) + && ((this->cur_frame->format == XINE_IMGFMT_YV12) || + (this->cur_frame->format == XINE_IMGFMT_XXMC))) { + rect->y = rect->y * 2; + rect->h = rect->h * 2; + } + + } + break; + + default: + return -1; + } + + return 0; +} + +static void xxmc_dispose (vo_driver_t *this_gen) { + xxmc_driver_t *this = (xxmc_driver_t *) this_gen; + int i; + + + if (this->xvmc_cap) { + xvmc_context_writer_lock( &this->xvmc_lock ); + xxmc_dispose_context( this ); + if (this->old_subpic) { + xxmc_xvmc_free_subpicture(this, this->old_subpic); + this->old_subpic = NULL; + } + if (this->new_subpic) { + xxmc_xvmc_free_subpicture(this, this->old_subpic); + this->new_subpic = NULL; + } + xvmc_context_writer_unlock( &this->xvmc_lock ); + } + + + if (this->deinterlace_frame.image) { + XLockDisplay (this->display); + dispose_ximage (this, &this->deinterlace_frame.shminfo, + this->deinterlace_frame.image); + XUnlockDisplay (this->display); + this->deinterlace_frame.image = NULL; + } + + XLockDisplay (this->display); + if(XvUngrabPort (this->display, this->xv_port, CurrentTime) != Success) { + xprintf (this->xine, XINE_VERBOSITY_DEBUG, "video_out_xxmc: xxmc_exit: XvUngrabPort() failed.\n"); + } + XFreeGC(this->display, this->gc); + XUnlockDisplay (this->display); + + for( i=0; i < VO_NUM_RECENT_FRAMES; i++ ) { + if( this->recent_frames[i] ) + this->recent_frames[i]->vo_frame.dispose + (&this->recent_frames[i]->vo_frame); + this->recent_frames[i] = NULL; + } + + if( this->xoverlay ) { + XLockDisplay (this->display); + x11osd_destroy (this->xoverlay); + XUnlockDisplay (this->display); + } + free_context_lock(&this->xvmc_lock); + + free (this); +} + +/* called xlocked */ +static int xxmc_check_yv12 (Display *display, XvPortID port) { + XvImageFormatValues *formatValues; + int formats; + int i; + + formatValues = XvListImageFormats (display, port, &formats); + + for (i = 0; i < formats; i++) + if ((formatValues[i].id == XINE_IMGFMT_YV12) && + (! (strcmp (formatValues[i].guid, "YV12")))) { + XFree (formatValues); + return 0; + } + + XFree (formatValues); + return 1; +} + +/* called xlocked */ +static void xxmc_check_capability (xxmc_driver_t *this, + int property, XvAttribute attr, + int base_id, char *str_prop, + char *config_name, + char *config_desc, + char *config_help) { + int int_default; + cfg_entry_t *entry; + + if (VO_PROP_COLORKEY && (attr.max_value == ~0)) + attr.max_value = 2147483615; + + this->props[property].min = attr.min_value; + this->props[property].max = attr.max_value; + this->props[property].atom = XInternAtom (this->display, str_prop, False); + + XvGetPortAttribute (this->display, this->xv_port, + this->props[property].atom, &int_default); + + xprintf(this->xine, XINE_VERBOSITY_DEBUG, + "video_out_xxmc: port attribute %s (%d) value is %d\n", str_prop, property, int_default); + + /* + * We enable autopaint by default. + */ + if(strcmp(str_prop, "XV_AUTOPAINT_COLORKEY") == 0) + int_default = 1; + + if (config_name) { + /* is this a boolean property ? */ + if ((attr.min_value == 0) && (attr.max_value == 1)) { + this->config->register_bool (this->config, config_name, int_default, + config_desc, + config_help, 20, xxmc_property_callback, &this->props[property]); + + } else { + this->config->register_range (this->config, config_name, int_default, + this->props[property].min, this->props[property].max, + config_desc, + config_help, 20, xxmc_property_callback, &this->props[property]); + } + + entry = this->config->lookup_entry (this->config, config_name); + + if((entry->num_value < this->props[property].min) || + (entry->num_value > this->props[property].max)) { + + this->config->update_num(this->config, config_name, + ((this->props[property].min + this->props[property].max) >> 1)); + + entry = this->config->lookup_entry (this->config, config_name); + } + + this->props[property].entry = entry; + + xxmc_set_property (&this->vo_driver, property, entry->num_value); + + + if (strcmp(str_prop, "XV_COLORKEY") == 0) { + this->use_colorkey |= 1; + this->colorkey = entry->num_value; + } else if(strcmp(str_prop, "XV_AUTOPAINT_COLORKEY") == 0) { + if(entry->num_value==1) + this->use_colorkey |= 2; + } + } else + this->props[property].value = int_default; +} + +static void xxmc_update_XV_FILTER(void *this_gen, xine_cfg_entry_t *entry) { + xxmc_driver_t *this = (xxmc_driver_t *) this_gen; + Atom atom; + int xv_filter; + + xv_filter = entry->num_value; + + XLockDisplay(this->display); + atom = XInternAtom (this->display, "XV_FILTER", False); + XvSetPortAttribute (this->display, this->xv_port, atom, xv_filter); + XUnlockDisplay(this->display); + + xprintf(this->xine, XINE_VERBOSITY_DEBUG, + "video_out_xxmc: bilinear scaling mode (XV_FILTER) = %d\n",xv_filter); +} + +static void xxmc_update_XV_DOUBLE_BUFFER(void *this_gen, xine_cfg_entry_t *entry) { + xxmc_driver_t *this = (xxmc_driver_t *) this_gen; + Atom atom; + int xv_double_buffer; + + xv_double_buffer = entry->num_value; + + XLockDisplay(this->display); + atom = XInternAtom (this->display, "XV_DOUBLE_BUFFER", False); + XvSetPortAttribute (this->display, this->xv_port, atom, xv_double_buffer); + XUnlockDisplay(this->display); + + xprintf(this->xine, XINE_VERBOSITY_DEBUG, + "video_out_xxmc: double buffering mode = %d\n", xv_double_buffer); +} + +static void xxmc_update_xv_pitch_alignment(void *this_gen, xine_cfg_entry_t *entry) { + xxmc_driver_t *this = (xxmc_driver_t *) this_gen; + + this->use_pitch_alignment = entry->num_value; +} + +static void xxmc_update_cpu_save(void *this_gen, xine_cfg_entry_t *entry) { + xxmc_driver_t *this = (xxmc_driver_t *) this_gen; + + this->cpu_save_enabled = entry->num_value; +} + +static void xxmc_update_nvidia_fix(void *this_gen, xine_cfg_entry_t *entry) { + xxmc_driver_t *this = (xxmc_driver_t *) this_gen; + + this->reverse_nvidia_palette = entry->num_value; +} + +static void xxmc_update_deinterlace(void *this_gen, xine_cfg_entry_t *entry) { + xxmc_driver_t *this = (xxmc_driver_t *) this_gen; + + this->deinterlace_method = entry->num_value; +} + + +static void checkXvMCCap( xxmc_driver_t *this, XvPortID xv_port) +{ + int + numSurf,numSub,i,j; + XvMCSurfaceInfo + *surfaceInfo,*curInfo; + XvMCContext + c; + xvmc_capabilities_t + *curCap; + XvImageFormatValues + *formatValues; + + this->xvmc_cap = 0; + init_context_lock( &this->xvmc_lock ); + xvmc_context_writer_lock( &this->xvmc_lock ); + this->old_subpic = NULL; + this->new_subpic = NULL; + this->contextActive = 0; + this->subImage = NULL; + this->hwSubpictures = 0; + this->xvmc_palette = NULL; + + XVMCLOCKDISPLAY( this->display ); + + if ( !XvMCQueryExtension(this->display, &this->xvmc_eventbase, + &this->xvmc_errbase)) { + XVMCUNLOCKDISPLAY( this->display ); + xvmc_context_writer_unlock( &this->xvmc_lock ); + return; + } + xprintf (this->xine, XINE_VERBOSITY_DEBUG, + "video_out_xxmc: XvMC extension present.\n"); + + surfaceInfo = XvMCListSurfaceTypes(this->display, xv_port, &numSurf); + if (0 == surfaceInfo) { + XVMCUNLOCKDISPLAY( this->display ); + xvmc_context_writer_unlock( &this->xvmc_lock ); + return; + } + this->xvmc_cap = (xvmc_capabilities_t *) + xine_xmalloc(numSurf * sizeof(xvmc_capabilities_t)); + if (NULL == this->xvmc_cap) return; + this->xvmc_num_cap = numSurf; + curInfo = surfaceInfo; + curCap = this->xvmc_cap; + + xprintf (this->xine, XINE_VERBOSITY_DEBUG, + "video_out_xxmc: Found %d XvMC surface types\n",numSurf); + + for (i=0; i< numSurf; ++i) { + curCap->mpeg_flags = 0; + curCap->accel_flags = 0; + if (curInfo->chroma_format == XVMC_CHROMA_FORMAT_420) { + curCap->mpeg_flags |= ((curInfo->mc_type & XINE_XVMC_MPEG_1) ? + XINE_XVMC_MPEG_1 : 0); + curCap->mpeg_flags |= ((curInfo->mc_type & XINE_XVMC_MPEG_2) ? + XINE_XVMC_MPEG_2 : 0); + curCap->mpeg_flags |= ((curInfo->mc_type & XINE_XVMC_MPEG_4) ? + XINE_XVMC_MPEG_4 : 0); + curCap->accel_flags |= ((curInfo->mc_type & XVMC_VLD) ? + XINE_XVMC_ACCEL_VLD : 0); + curCap->accel_flags |= ((curInfo->mc_type & XVMC_IDCT) ? + XINE_XVMC_ACCEL_IDCT : 0); + curCap->accel_flags |= ((curInfo->mc_type & (XVMC_VLD | XVMC_IDCT)) ? + 0 : XINE_XVMC_ACCEL_MOCOMP); + curCap->max_width = curInfo->max_width; + curCap->max_height = curInfo->max_height; + curCap->sub_max_width = curInfo->subpicture_max_width; + curCap->sub_max_height = curInfo->subpicture_max_height; + curCap->flags = curInfo->flags; + xprintf (this->xine, XINE_VERBOSITY_DEBUG, + "video_out_xxmc: Surface type %d: Max size: %d %d.\n", + i,curCap->max_width,curCap->max_height); + xprintf (this->xine, XINE_VERBOSITY_DEBUG, + "video_out_xxmc: Surface type %d: Max subpic size: %d %d.\n", + i,curCap->sub_max_width,curCap->sub_max_height); + + curCap->type_id = curInfo->surface_type_id; + formatValues = XvMCListSubpictureTypes( this->display, xv_port, + curCap->type_id, &numSub); + curCap->subPicType.id = 0; + if (formatValues) { + xprintf (this->xine, XINE_VERBOSITY_DEBUG, + "video_out_xxmc: Surface type %d: Found %d XvMC subpicture " + "types\n",i,numSub); + for (j = 0; jsubPicType = formatValues[j]; + xprintf (this->xine, XINE_VERBOSITY_DEBUG, + "video_out_xxmc: Surface type %d: Detected and using " + "IA44 subpicture type.\n",i); + /* Prefer IA44 */ + break; + } else if (formatValues[j].id == FOURCC_AI44) { + curCap->subPicType = formatValues[j]; + xprintf (this->xine, XINE_VERBOSITY_DEBUG, + "video_out_xxmc: Surface type %d: Detected AI44 " + "subpicture type.\n",i); + } + } + } + + XFree(formatValues); + + curInfo++; + curCap++; + } + } + XFree(surfaceInfo); + + /* + * Try to create a direct rendering context. This will fail if we are not + * on the displaying computer or an indirect context is not available. + */ + + curCap = this->xvmc_cap; + if (Success == XvMCCreateContext( this->display, xv_port, curCap->type_id, + curCap->max_width,curCap->max_height, + XVMC_DIRECT, &c)) { + this->context_flags = XVMC_DIRECT; + } else if (Success == XvMCCreateContext( this->display, xv_port, curCap->type_id, + curCap->max_width,curCap->max_height, + 0, &c)) { + this->context_flags = 0; + } else { + free(this->xvmc_cap); + this->xvmc_cap = 0; + xprintf (this->xine, XINE_VERBOSITY_DEBUG, + "video_out_xxmc: Apparent attempt to use a direct XvMC " + "context\nvideo_out_xxmc: on a remote display. " + "Falling back to XV.\n"); + XVMCUNLOCKDISPLAY( this->display ); + xvmc_context_writer_unlock( &this->xvmc_lock ); + return; + } + XvMCDestroyContext( this->display, &c); + xxmc_xvmc_surface_handler_construct(this); + this->capabilities |= VO_CAP_XXMC; + XVMCUNLOCKDISPLAY( this->display ); + init_xx44_palette( &this->palette , 0); + xvmc_context_writer_unlock( &this->xvmc_lock ); + return; + +} + + + + +static vo_driver_t *open_plugin (video_driver_class_t *class_gen, const void *visual_gen) { + xxmc_class_t *class = (xxmc_class_t *) class_gen; + config_values_t *config = class->config; + xxmc_driver_t *this; + int i, formats; + XvAttribute *attr; + XvImageFormatValues *fo; + int nattr; + x11_visual_t *visual = (x11_visual_t *) visual_gen; + XColor dummy; + XvImage *myimage; + unsigned int adaptors, j; + unsigned int ver,rel,req,ev,err; + XShmSegmentInfo myshminfo; + XvPortID xv_port; + XvAdaptorInfo *adaptor_info; + unsigned int adaptor_num; + cfg_entry_t *entry; + int use_more_frames; + + this = (xxmc_driver_t *) xine_xmalloc (sizeof (xxmc_driver_t)); + if (!this) + return NULL; + + this->display = visual->display; + this->screen = visual->screen; + this->config = config; + + /* + * check for Xvideo support + */ + + XLockDisplay(this->display); + if (Success != XvQueryExtension(this->display, &ver,&rel, &req, &ev,&err)) { + xprintf (class->xine, XINE_VERBOSITY_LOG, _("video_out_xxmc: Xv extension not present.\n")); + XUnlockDisplay(this->display); + return NULL; + } + + /* + * check adaptors, search for one that supports (at least) yuv12 + */ + + if (Success != XvQueryAdaptors(this->display,DefaultRootWindow(this->display), &adaptors, &adaptor_info)) { + xprintf(class->xine, XINE_VERBOSITY_DEBUG, "video_out_xxmc: XvQueryAdaptors failed.\n"); + XUnlockDisplay(this->display); + return NULL; + } + + xv_port = 0; + + for ( adaptor_num = 0; (adaptor_num < adaptors) && !xv_port; adaptor_num++ ) { + + if (adaptor_info[adaptor_num].type & XvImageMask) { + + for (j = 0; j < adaptor_info[adaptor_num].num_ports && !xv_port; j++) + if (( !(xxmc_check_yv12 (this->display, + adaptor_info[adaptor_num].base_id + j))) + && (XvGrabPort (this->display, + adaptor_info[adaptor_num].base_id + j, + 0) == Success)) { + xv_port = adaptor_info[adaptor_num].base_id + j; + } + + if( xv_port ) + break; + } + } + + if (!xv_port) { + xprintf(class->xine, XINE_VERBOSITY_LOG, + _("video_out_xxmc: Xv extension is present but I couldn't find a usable yuv12 port.\n" + " Looks like your graphics hardware driver doesn't support Xv?!\n")); + + /* XvFreeAdaptorInfo (adaptor_info); this crashed on me (gb)*/ + XUnlockDisplay(this->display); + return NULL; + } + else + xprintf(class->xine, XINE_VERBOSITY_LOG, + _("video_out_xxmc: using Xv port %ld from adaptor %s for hardware " + "colorspace conversion and scaling.\n"), xv_port, + adaptor_info[adaptor_num].name); + + XUnlockDisplay(this->display); + + this->xv_port = xv_port; + + _x_vo_scale_init (&this->sc, 1, 0, config ); + this->sc.frame_output_cb = visual->frame_output_cb; + this->sc.user_data = visual->user_data; + + this->drawable = visual->d; + XLockDisplay (this->display); + this->gc = XCreateGC (this->display, this->drawable, 0, NULL); + XUnlockDisplay (this->display); + this->capabilities = VO_CAP_CROP; + this->use_shm = 1; + this->deinterlace_method = 0; + this->deinterlace_frame.image = NULL; + this->use_colorkey = 0; + this->colorkey = 0; + this->xoverlay = NULL; + this->ovl_changed = 0; + this->x11_old_error_handler = NULL; + this->xine = class->xine; + + XLockDisplay (this->display); + XAllocNamedColor (this->display, + DefaultColormap(this->display, this->screen), + "black", &this->black, &dummy); + XUnlockDisplay (this->display); + + this->vo_driver.get_capabilities = xxmc_get_capabilities; + this->vo_driver.alloc_frame = xxmc_alloc_frame; + this->vo_driver.update_frame_format = xxmc_update_frame_format; + this->vo_driver.overlay_begin = xxmc_overlay_begin; + this->vo_driver.overlay_blend = xxmc_overlay_blend; + this->vo_driver.overlay_end = xxmc_overlay_end; + this->vo_driver.display_frame = xxmc_display_frame; + this->vo_driver.get_property = xxmc_get_property; + this->vo_driver.set_property = xxmc_set_property; + this->vo_driver.get_property_min_max = xxmc_get_property_min_max; + this->vo_driver.gui_data_exchange = xxmc_gui_data_exchange; + this->vo_driver.dispose = xxmc_dispose; + this->vo_driver.redraw_needed = xxmc_redraw_needed; + + /* + * init properties + */ + + for (i = 0; i < VO_NUM_PROPERTIES; i++) { + this->props[i].value = 0; + this->props[i].min = 0; + this->props[i].max = 0; + this->props[i].atom = None; + this->props[i].entry = NULL; + this->props[i].this = this; + } + + this->props[VO_PROP_INTERLACED].value = 0; + this->sc.user_ratio = + this->props[VO_PROP_ASPECT_RATIO].value = XINE_VO_ASPECT_AUTO; + this->props[VO_PROP_ZOOM_X].value = 100; + this->props[VO_PROP_ZOOM_Y].value = 100; + + /* + * check this adaptor's capabilities + */ + + XLockDisplay (this->display); + attr = XvQueryPortAttributes(this->display, xv_port, &nattr); + if(attr && nattr) { + int k; + + for(k = 0; k < nattr; k++) { + if((attr[k].flags & XvSettable) && (attr[k].flags & XvGettable)) { + if(!strcmp(attr[k].name, "XV_HUE")) { + if (!strncmp(adaptor_info[adaptor_num].name, "NV", 2)) { + xprintf (this->xine, XINE_VERBOSITY_NONE, "video_out_xxmc: ignoring broken XV_HUE settings on NVidia cards\n"); + } else { + xxmc_check_capability (this, VO_PROP_HUE, attr[k], + adaptor_info[adaptor_num].base_id, "XV_HUE", + NULL, NULL, NULL); + } + } else if(!strcmp(attr[k].name, "XV_SATURATION")) { + xxmc_check_capability (this, VO_PROP_SATURATION, attr[k], + adaptor_info[adaptor_num].base_id, "XV_SATURATION", + NULL, NULL, NULL); + + } else if(!strcmp(attr[k].name, "XV_BRIGHTNESS")) { + xxmc_check_capability (this, VO_PROP_BRIGHTNESS, attr[k], + adaptor_info[adaptor_num].base_id, "XV_BRIGHTNESS", + NULL, NULL, NULL); + + } else if(!strcmp(attr[k].name, "XV_CONTRAST")) { + xxmc_check_capability (this, VO_PROP_CONTRAST, attr[k], + adaptor_info[adaptor_num].base_id, "XV_CONTRAST", + NULL, NULL, NULL); + + } else if(!strcmp(attr[k].name, "XV_COLORKEY")) { + xxmc_check_capability (this, VO_PROP_COLORKEY, attr[k], + adaptor_info[adaptor_num].base_id, "XV_COLORKEY", + "video.xv_colorkey", + _("video overlay colour key"), + _("The colour key is used to tell the graphics card where to " + "overlay the video image. Try different values, if you experience " + "windows becoming transparent.")); + + } else if(!strcmp(attr[k].name, "XV_AUTOPAINT_COLORKEY")) { + xxmc_check_capability (this, VO_PROP_AUTOPAINT_COLORKEY, attr[k], + adaptor_info[adaptor_num].base_id, "XV_AUTOPAINT_COLORKEY", + "video.xv_autopaint_colorkey", + _("autopaint colour key"), + _("Make Xv autopaint its colorkey.")); + + } else if(!strcmp(attr[k].name, "XV_FILTER")) { + int xv_filter; + /* This setting is specific to Permedia 2/3 cards. */ + xv_filter = config->register_range (config, "video.XV_FILTER", 0, + attr[k].min_value, attr[k].max_value, + _("bilinear scaling mode"), + _("Selects the bilinear scaling mode for Permedia cards. " + "The individual values are:\n\n" + "Permedia 2\n" + "0 - disable bilinear filtering\n" + "1 - enable bilinear filtering\n\n" + "Permedia 3\n" + "0 - disable bilinear filtering\n" + "1 - horizontal linear filtering\n" + "2 - enable full bilinear filtering"), + 20, xxmc_update_XV_FILTER, this); + config->update_num(config,"video.XV_FILTER",xv_filter); + } else if(!strcmp(attr[k].name, "XV_DOUBLE_BUFFER")) { + int xv_double_buffer; + xv_double_buffer = + config->register_bool (config, "video.XV_DOUBLE_BUFFER", 1, + _("enable double buffering"), + _("Double buffering will synchronize the update of the video image to the " + "repainting of the entire screen (\"vertical retrace\"). This eliminates " + "flickering and tearing artifacts, but will use more graphics memory."), + 20, xxmc_update_XV_DOUBLE_BUFFER, this); + config->update_num(config,"video.XV_DOUBLE_BUFFER",xv_double_buffer); + } + } + } + XFree(attr); + } + else + xprintf(this->xine, XINE_VERBOSITY_DEBUG, "video_out_xxmc: no port attributes defined.\n"); + XvFreeAdaptorInfo(adaptor_info); + + /* + * check XvMC capabilities + */ + + checkXvMCCap( this, xv_port ); + + /* + * check supported image formats + */ + + + fo = XvListImageFormats(this->display, this->xv_port, (int*)&formats); + XUnlockDisplay (this->display); + + this->xv_format_yv12 = 0; + this->xv_format_yuy2 = 0; + + for(i = 0; i < formats; i++) { + lprintf ("Xv image format: 0x%x (%4.4s) %s\n", + fo[i].id, (char*)&fo[i].id, + (fo[i].format == XvPacked) ? "packed" : "planar"); + + if (fo[i].id == XINE_IMGFMT_YV12) { + this->xv_format_yv12 = fo[i].id; + this->capabilities |= VO_CAP_YV12; + xprintf(this->xine, XINE_VERBOSITY_LOG, + _("video_out_xxmc: this adaptor supports the yv12 format.\n")); + } else if (fo[i].id == XINE_IMGFMT_YUY2) { + this->xv_format_yuy2 = fo[i].id; + this->capabilities |= VO_CAP_YUY2; + xprintf(this->xine, XINE_VERBOSITY_LOG, + _("video_out_xxmc: this adaptor supports the yuy2 format.\n")); + } + } + + if(fo) { + XLockDisplay(this->display); + XFree(fo); + XUnlockDisplay(this->display); + } + + /* + * try to create a shared image + * to find out if MIT shm really works, using supported format + */ + + XLockDisplay (this->display); + myimage = create_ximage (this, &myshminfo, 100, 100, + (this->xv_format_yv12 != 0) ? XINE_IMGFMT_YV12 : XINE_IMGFMT_YUY2); + dispose_ximage (this, &myshminfo, myimage); + XUnlockDisplay (this->display); + + this->use_pitch_alignment = + config->register_bool (config, "video.xv_pitch_alignment", 0, + _("pitch alignment workaround"), + _("Some buggy video drivers need a workaround to function properly."), + 10, xxmc_update_xv_pitch_alignment, this); + + use_more_frames= + config->register_bool (config, "video.xvmc_more_frames", 0, + _("Make XvMC allocate more frames for better buffering."), + _("Some XvMC implementations allow more than 8 frames.\n" + "This option, when turned on, makes the driver try to\n" + "allocate 15 frames. A must for unichrome and live VDR.\n"), + 10, NULL, this); + this->cpu_save_enabled = + config->register_bool (config, "video.unichrome_cpu_save", 0, + _("Unichrome cpu save"), + _("Saves CPU time by sleeping while decoder works.\n" + "Only for Linux kernel 2.6 series or 2.4 with multimedia patch.\n" + "Experimental.\n"), + 10, xxmc_update_cpu_save, this); + this->deinterlace_method = + config->register_enum (config, "video.deinterlace_method", 0, + deinterlace_methods, + _("deinterlace_methods"), + _("This config setting is deprecated. You should use the new " + "deinterlacing post processing settings instead.\n"), + 10, xxmc_update_deinterlace, this); + this->reverse_nvidia_palette = + config->register_bool (config, "video.xvmc_nvidia_color_fix", 0, + _("Fix buggy NVIDIA XvMC subpicture colors"), + _("There's a bug in NVIDIA's XvMC lib that makes red OSD colors\n" + "look blue and vice versa. This option provides a workaround.\n"), + 10, xxmc_update_nvidia_fix, this); + + this->deinterlace_enabled = 0; +#ifdef HAVE_VLDXVMC + printf("video_out_xxmc: Unichrome CPU saving is %s.\n", + (this->cpu_save_enabled) ? "on":"off"); +#else + printf("video_out_xxmc: warning - compiled with no vld extensions.\n"); +#endif + this->props[VO_PROP_MAX_NUM_FRAMES].value = (use_more_frames) ? 15:8; + this->cpu_saver = 0.; + + this->xoverlay = NULL; + + /* + * FIXME: YV12 deinterlace method. + */ + + + entry = this->config->lookup_entry (this->config, "gui.osd_use_unscaled"); + if (entry->num_value == 1) { + XLockDisplay (this->display); + if( this->use_colorkey ) { + this->xoverlay = x11osd_create (this->xine, this->display, this->screen, + this->drawable, X11OSD_COLORKEY); + if(this->xoverlay) + x11osd_colorkey(this->xoverlay, this->colorkey, &this->sc); + this->xoverlay_ck = 1; + } else { + this->xoverlay = x11osd_create (this->xine, this->display, this->screen, + this->drawable, X11OSD_SHAPED); + this->xoverlay_ck = 0; + } + XUnlockDisplay (this->display); + } + + if( this->xoverlay ) { + this->capabilities |= VO_CAP_UNSCALED_OVERLAY; + } + return &this->vo_driver; +} + +/* + * class functions + */ + +static char* get_identifier (video_driver_class_t *this_gen) { + return "XxMC"; +} + +static char* get_description (video_driver_class_t *this_gen) { + return _("xine video output plugin using the MIT X video extension"); +} + +static void dispose_class (video_driver_class_t *this_gen) { + xxmc_class_t *this = (xxmc_class_t *) this_gen; + + free (this); +} + +static void *init_class (xine_t *xine, void *visual_gen) { + xxmc_class_t *this = (xxmc_class_t *) xine_xmalloc (sizeof (xxmc_class_t)); + + this->driver_class.open_plugin = open_plugin; + this->driver_class.get_identifier = get_identifier; + this->driver_class.get_description = get_description; + this->driver_class.dispose = dispose_class; + + this->config = xine->config; + this->xine = xine; + + return this; +} + +static vo_info_t vo_info_xxmc = { + 9, /* priority */ + XINE_VISUAL_TYPE_X11 /* visual type */ +}; + +/* + * exported plugin catalog entry + */ + +plugin_info_t xine_plugin_info[] = { + /* type, API, "name", version, special_info, init_function */ + { PLUGIN_VIDEO_OUT, 20, "xxmc", XINE_VERSION_CODE, &vo_info_xxmc, init_class }, + { PLUGIN_NONE, 0, "", 0, NULL, NULL } +}; + diff --git a/src/video_out/xvmc_mocomp.c b/src/video_out/xvmc_mocomp.c new file mode 100644 index 000000000..94c6e9906 --- /dev/null +++ b/src/video_out/xvmc_mocomp.c @@ -0,0 +1,274 @@ +/* + * Copyright (C) 2000-2004 the xine project + * + * This file is part of xine, a free 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: xvmc_mocomp.c,v 1.1 2004/09/28 18:49:40 miguelfreitas Exp $ + * + * XvMC image support by Jack Kelliher + */ + +#include "xxmc.h" + + +static void calc_DMV(int DMV[][2], int *dmvector, + int mvx, int mvy, int picture_structure, int top_field_first) { + + if (picture_structure==VO_BOTH_FIELDS) { + if (top_field_first) { + /* vector for prediction of top field from bottom field */ + DMV[0][0] = ((mvx +(mvx>0))>>1) + dmvector[0]; + DMV[0][1] = ((mvy +(mvy>0))>>1) + dmvector[1] - 1; + + /* vector for prediction of bottom field from top field */ + DMV[1][0] = ((3*mvx+(mvx>0))>>1) + dmvector[0]; + DMV[1][1] = ((3*mvy+(mvy>0))>>1) + dmvector[1] + 1; + } + else { + /* vector for prediction of top field from bottom field */ + DMV[0][0] = ((3*mvx+(mvx>0))>>1) + dmvector[0]; + DMV[0][1] = ((3*mvy+(mvy>0))>>1) + dmvector[1] - 1; + + /* vector for prediction of bottom field from top field */ + DMV[1][0] = ((mvx +(mvx>0))>>1) + dmvector[0]; + DMV[1][1] = ((mvy +(mvy>0))>>1) + dmvector[1] + 1; + } + } + else { + /* vector for prediction from field of opposite 'parity' */ + DMV[0][0] = ((mvx+(mvx>0))>>1) + dmvector[0]; + DMV[0][1] = ((mvy+(mvy>0))>>1) + dmvector[1]; + + /* correct for vertical field shift */ + if (picture_structure==VO_TOP_FIELD) + DMV[0][1]--; + else + DMV[0][1]++; + + } +} + + + + +static void xvmc_render_macro_blocks(vo_frame_t *current_image, + vo_frame_t *backward_ref_image, + vo_frame_t *forward_ref_image, + int picture_structure, + int second_field, + xvmc_macroblocks_t *macroblocks) { + xxmc_driver_t *this = (xxmc_driver_t *) current_image->driver; + xxmc_frame_t *current_frame = (xxmc_frame_t *) current_image; + xxmc_frame_t *forward_frame = (xxmc_frame_t *) forward_ref_image; + xxmc_frame_t *backward_frame = (xxmc_frame_t *) backward_ref_image; + + lprintf ("xvmc_render_macro_blocks\n"); + lprintf ("slices %d 0x%08lx 0x%08lx 0x%08lx\n", + macroblocks->slices, + (long) current_frame, (long) backward_frame, + (long) forward_frame); + + XVMCLOCKDISPLAY( this->display); + XvMCRenderSurface(this->display, &this->context, picture_structure, + current_frame->xvmc_surf, + forward_frame ? forward_frame->xvmc_surf : NULL, + backward_frame ? backward_frame->xvmc_surf : NULL, + second_field, + macroblocks->slices, 0, ¯oblocks->macro_blocks, + ¯oblocks->blocks); + XVMCUNLOCKDISPLAY( this->display); +} + + + +void xxmc_xvmc_proc_macro_block(int x, int y, int mb_type, int motion_type, + int (*mv_field_sel)[2], int *dmvector, int cbp, + int dct_type, vo_frame_t *current_frame, + vo_frame_t *forward_ref_frame, + vo_frame_t *backward_ref_frame, int picture_structure, + int second_field, int (*f_mot_pmv)[2], int (*b_mot_pmv)[2]) +{ + xxmc_driver_t *this = (xxmc_driver_t *) current_frame->driver; + xvmc_macroblocks_t *mbs = &this->macroblocks; + int top_field_first = current_frame->top_field_first; + int picture_coding_type = current_frame->picture_coding_type; + + xvmc_context_reader_lock( &this->xvmc_lock ); + mbs->macroblockptr->x = x; + mbs->macroblockptr->y = y; + + if(mb_type & XINE_MACROBLOCK_INTRA) { + mbs->macroblockptr->macroblock_type = XVMC_MB_TYPE_INTRA; + } + else { + mbs->macroblockptr->macroblock_type = 0; + /* XvMC doesn't support skips */ + if(!(mb_type & (XINE_MACROBLOCK_MOTION_BACKWARD | XINE_MACROBLOCK_MOTION_FORWARD))) { + mb_type |= XINE_MACROBLOCK_MOTION_FORWARD; + motion_type = (picture_structure == VO_BOTH_FIELDS) ? XINE_MC_FRAME : XINE_MC_FIELD; + mbs->macroblockptr->PMV[0][0][0] = 0; + mbs->macroblockptr->PMV[0][0][1] = 0; + } + else { + if(mb_type & XINE_MACROBLOCK_MOTION_BACKWARD) { + mbs->macroblockptr->macroblock_type |= XVMC_MB_TYPE_MOTION_BACKWARD; + mbs->macroblockptr->PMV[0][1][0] = b_mot_pmv[0][0]; + mbs->macroblockptr->PMV[0][1][1] = b_mot_pmv[0][1]; + mbs->macroblockptr->PMV[1][1][0] = b_mot_pmv[1][0]; + mbs->macroblockptr->PMV[1][1][1] = b_mot_pmv[1][1]; + + } + + if(mb_type & XINE_MACROBLOCK_MOTION_FORWARD) { + mbs->macroblockptr->macroblock_type |= XVMC_MB_TYPE_MOTION_FORWARD; + mbs->macroblockptr->PMV[0][0][0] = f_mot_pmv[0][0]; + mbs->macroblockptr->PMV[0][0][1] = f_mot_pmv[0][1]; + mbs->macroblockptr->PMV[1][0][0] = f_mot_pmv[1][0]; + mbs->macroblockptr->PMV[1][0][1] = f_mot_pmv[1][1]; + } + } + + if((mb_type & XINE_MACROBLOCK_PATTERN) && cbp) + mbs->macroblockptr->macroblock_type |= XVMC_MB_TYPE_PATTERN; + + mbs->macroblockptr->motion_type = motion_type; + + if(motion_type == XINE_MC_DMV) { + int DMV[2][2]; + + if(picture_structure == VO_BOTH_FIELDS) { + calc_DMV(DMV,dmvector, f_mot_pmv[0][0], + f_mot_pmv[0][1]>>1, picture_structure, + top_field_first); + + mbs->macroblockptr->PMV[1][0][0] = DMV[0][0]; + mbs->macroblockptr->PMV[1][0][1] = DMV[0][1]; + mbs->macroblockptr->PMV[1][1][0] = DMV[1][0]; + mbs->macroblockptr->PMV[1][1][1] = DMV[1][1]; + } + else { + calc_DMV(DMV,dmvector, f_mot_pmv[0][0], + f_mot_pmv[0][1]>>1, picture_structure, + top_field_first); + + mbs->macroblockptr->PMV[0][1][0] = DMV[0][0]; + mbs->macroblockptr->PMV[0][1][1] = DMV[0][1]; + } + } + + if((motion_type == XINE_MC_FIELD) || (motion_type == XINE_MC_16X8)) { + mbs->macroblockptr->motion_vertical_field_select = 0; + if(mv_field_sel[0][0]) + mbs->macroblockptr->motion_vertical_field_select |= 1; + if(mv_field_sel[0][1]) + mbs->macroblockptr->motion_vertical_field_select |= 2; + if(mv_field_sel[1][0]) + mbs->macroblockptr->motion_vertical_field_select |= 4; + if(mv_field_sel[1][1]) + mbs->macroblockptr->motion_vertical_field_select |= 8; + } + } /* else of if(mb_type & XINE_MACROBLOCK_INTRA) */ + + mbs->macroblockptr->index = ((unsigned long)mbs->xine_mc.blockptr - + (unsigned long)mbs->xine_mc.blockbaseptr) >> 7; + + mbs->macroblockptr->dct_type = dct_type; + mbs->macroblockptr->coded_block_pattern = cbp; + + cbp &= 0x3F; + mbs->macroblockptr->coded_block_pattern = cbp; + + while(cbp) { + if(cbp & 1) mbs->macroblockptr->index--; + cbp >>= 1; + } + +#ifdef PRINTDATA + printf("\n"); + printf("-- %04d %04d %02x %02x %02x %02x",mbs->macroblockptr->x,mbs->macroblockptr->y,mbs->macroblockptr->macroblock_type, + mbs->macroblockptr->motion_type,mbs->macroblockptr->motion_vertical_field_select,mbs->macroblockptr->dct_type); + printf(" [%04d %04d %04d %04d %04d %04d %04d %04d] ", + mbs->macroblockptr->PMV[0][0][0],mbs->macroblockptr->PMV[0][0][1],mbs->macroblockptr->PMV[0][1][0],mbs->macroblockptr->PMV[0][1][1], + mbs->macroblockptr->PMV[1][0][0],mbs->macroblockptr->PMV[1][0][1],mbs->macroblockptr->PMV[1][1][0],mbs->macroblockptr->PMV[1][1][1]); + + printf(" %04d %04x\n",mbs->macroblockptr->index,mbs->macroblockptr->coded_block_pattern); +#endif + + mbs->num_blocks++; + mbs->macroblockptr++; + + if(mbs->num_blocks == mbs->slices) { +#ifdef PRINTDATA + printf("macroblockptr %lx", mbs->macroblockptr); + printf("** RenderSurface %04d %04x\n",picture_structure, + second_field ? XVMC_SECOND_FIELD : 0); + fflush(stdout); +#endif +#ifdef PRINTFRAME + printf(" target %08x past %08x future %08x\n", + current_frame, + forward_ref_frame, + backward_ref_frame); +#endif +#ifdef PRINTFRAME + if (picture_coding_type == XINE_PICT_P_TYPE) + printf(" coding type P_TYPE\n"); + if (picture_coding_type == XINE_PICT_I_TYPE) + printf(" coding type I_TYPE\n"); + if (picture_coding_type == XINE_PICT_B_TYPE) + printf(" coding type B_TYPE\n"); + if (picture_coding_type == XINE_PICT_D_TYPE) + printf(" coding type D_TYPE\n"); + fflush(stdout); +#endif + + if (picture_coding_type == XINE_PICT_B_TYPE) + xvmc_render_macro_blocks( + current_frame, + backward_ref_frame, + forward_ref_frame, + picture_structure, + second_field ? XVMC_SECOND_FIELD : 0, + mbs); + if (picture_coding_type == XINE_PICT_P_TYPE) + xvmc_render_macro_blocks( + current_frame, + NULL, + forward_ref_frame, + picture_structure, + second_field ? XVMC_SECOND_FIELD : 0, + mbs); + if (picture_coding_type == XINE_PICT_I_TYPE) + xvmc_render_macro_blocks( + current_frame, + NULL, + NULL, + picture_structure, + second_field ? XVMC_SECOND_FIELD : 0, + mbs); + + mbs->num_blocks = 0; + mbs->macroblockptr = mbs->macroblockbaseptr; + mbs->xine_mc.blockptr = mbs->xine_mc.blockbaseptr; + } + + xvmc_context_reader_unlock( &this->xvmc_lock ); + +} + + + diff --git a/src/video_out/xvmc_vld.c b/src/video_out/xvmc_vld.c new file mode 100644 index 000000000..d542ca515 --- /dev/null +++ b/src/video_out/xvmc_vld.c @@ -0,0 +1,171 @@ +/* + * Copyright (C) 2000-2004 the xine project + * Copyright (C) 2004 the Unichrome project + * + * This file is part of xine, a free 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: xvmc_vld.c,v 1.1 2004/09/28 18:49:40 miguelfreitas Exp $ + * + * xvmc_vld.c, X11 decoding accelerated video extension interface for xine + * + * Author: Thomas Hellström, (2004) + */ + +#include "xxmc.h" +#include + +#ifdef HAVE_VLDXVMC +void xvmc_vld_frame(struct vo_frame_s *this_gen) + +{ + vo_frame_t *this = (vo_frame_t *) this_gen; + xxmc_frame_t + *cf = (xxmc_frame_t *) this; + xine_vld_frame_t + *vft = &(cf->xxmc_data.vld_frame); + xxmc_frame_t + *ff = (xxmc_frame_t *) vft->forward_reference_frame, + *bf = (xxmc_frame_t *) vft->backward_reference_frame; + XvMCMpegControl ctl; + xxmc_driver_t + *driver = (xxmc_driver_t *) cf->vo_frame.driver; + XvMCSurface *fs=0, *bs=0; + XvMCQMatrix qmx; + + ctl.BHMV_range = vft->mv_ranges[0][0]; + ctl.BVMV_range = vft->mv_ranges[0][1]; + ctl.FHMV_range = vft->mv_ranges[1][0]; + ctl.FVMV_range = vft->mv_ranges[1][1]; + ctl.picture_structure = vft->picture_structure; + ctl.intra_dc_precision = vft->intra_dc_precision; + ctl.picture_coding_type = vft->picture_coding_type; + ctl.mpeg_coding = (vft->mpeg_coding == 0) ? XVMC_MPEG_1 : XVMC_MPEG_2; + ctl.flags = 0; + ctl.flags |= (vft->progressive_sequence) ? + XVMC_PROGRESSIVE_SEQUENCE : 0 ; + ctl.flags |= (vft->scan) ? + XVMC_ALTERNATE_SCAN : XVMC_ZIG_ZAG_SCAN; + ctl.flags |= (vft->pred_dct_frame) ? + XVMC_PRED_DCT_FRAME : XVMC_PRED_DCT_FIELD; + ctl.flags |= (this->top_field_first) ? + XVMC_TOP_FIELD_FIRST : XVMC_BOTTOM_FIELD_FIRST; + ctl.flags |= (vft->concealment_motion_vectors) ? + XVMC_CONCEALMENT_MOTION_VECTORS : 0 ; + ctl.flags |= (vft->q_scale_type) ? + XVMC_Q_SCALE_TYPE : 0; + ctl.flags |= (vft->intra_vlc_format) ? + XVMC_INTRA_VLC_FORMAT : 0; + ctl.flags |= (vft->second_field) ? + XVMC_SECOND_FIELD : 0 ; + + if (ff) fs=ff->xvmc_surf; + if (bf) bs=bf->xvmc_surf; + + /* + * Below is for interlaced streams and second_field. + */ + + if (ctl.picture_coding_type == XVMC_P_PICTURE) + bs = cf->xvmc_surf; + + if ((qmx.load_intra_quantiser_matrix = vft->load_intra_quantizer_matrix)) { + memcpy(qmx.intra_quantiser_matrix,vft->intra_quantizer_matrix, + sizeof(qmx.intra_quantiser_matrix)); + } + if ((qmx.load_non_intra_quantiser_matrix = vft->load_non_intra_quantizer_matrix)) { + memcpy(qmx.non_intra_quantiser_matrix,vft->non_intra_quantizer_matrix, + sizeof(qmx.non_intra_quantiser_matrix)); + } + qmx.load_chroma_intra_quantiser_matrix = 0; + qmx.load_chroma_non_intra_quantiser_matrix = 0; + xvmc_context_reader_lock( &driver->xvmc_lock ); + if ( ! xxmc_xvmc_surface_valid( driver, cf->xvmc_surf)) { + cf->xxmc_data.result = 128; + xvmc_context_reader_unlock( &driver->xvmc_lock ); + return; + } + XVMCLOCKDISPLAY( driver->display ); + XvMCLoadQMatrix(driver->display, &driver->context, &qmx); + while((cf->xxmc_data.result = + XvMCBeginSurface(driver->display, &driver->context, cf->xvmc_surf, + fs, bs, &ctl))); + XVMCUNLOCKDISPLAY( driver->display ); + xvmc_context_reader_unlock( &driver->xvmc_lock ); + driver->cpu_saver = 0.; +} + +void xvmc_vld_slice(vo_frame_t *this_gen) +{ + xxmc_frame_t + *cf = (xxmc_frame_t *) this_gen; + xxmc_driver_t + *driver = (xxmc_driver_t *) cf->vo_frame.driver; + + xvmc_context_reader_lock( &driver->xvmc_lock ); + if ( ! xxmc_xvmc_surface_valid( driver, cf->xvmc_surf)) { + cf->xxmc_data.result = 128; + xvmc_context_reader_unlock( &driver->xvmc_lock ); + return; + } + XVMCLOCKDISPLAY( driver->display ); + cf->xxmc_data.result = + XvMCPutSlice2(driver->display,&driver->context,cf->xxmc_data.slice_data, + cf->xxmc_data.slice_data_size,cf->xxmc_data.slice_code); + /* + * If CPU-saving mode is enabled, sleep after every xxmc->sleep slice. This will free + * up the cpu while the decoder is working on the slice. The value of xxmc->sleep is calculated + * so that the decoder thread sleeps at most 50% of the frame delay, + * assuming a 2.6 kernel clock of 1000 Hz. + */ + + XVMCUNLOCKDISPLAY( driver->display ); + xvmc_context_reader_unlock( &driver->xvmc_lock ); + if (driver->cpu_save_enabled) { + driver->cpu_saver += 1.; + if (driver->cpu_saver >= cf->xxmc_data.sleep) { + usleep(1); + driver->cpu_saver -= cf->xxmc_data.sleep; + } + } +} +#endif + +extern void xvmc_vld_flush(vo_frame_t *this_gen) +{ + + xxmc_frame_t + *frame = (xxmc_frame_t *) this_gen; + xxmc_driver_t + *driver = (xxmc_driver_t *) this_gen->driver; + + xvmc_context_reader_lock( &driver->xvmc_lock ); + + if ( ! xxmc_xvmc_surface_valid( driver, frame->xvmc_surf)) { + frame->xxmc_data.result = 128; + xvmc_context_reader_unlock( &driver->xvmc_lock ); + return; + } + + XVMCLOCKDISPLAY( driver->display ); + frame->xxmc_data.result = XvMCFlushSurface( driver->display, frame->xvmc_surf ); + frame->xxmc_data.result = XvMCSyncSurface( driver->display, frame->xvmc_surf ); + XVMCUNLOCKDISPLAY( driver->display ); + + xvmc_context_reader_unlock( &driver->xvmc_lock ); + +} + diff --git a/src/video_out/xxmc.h b/src/video_out/xxmc.h new file mode 100644 index 000000000..b11d9207e --- /dev/null +++ b/src/video_out/xxmc.h @@ -0,0 +1,293 @@ +/* + * Copyright (C) 2000-2004 the xine project + * Copyright (C) 2004 the unichrome project + * + * This file is part of xine, a free 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: xxmc.h,v 1.1 2004/09/28 18:49:40 miguelfreitas Exp $ + * + * video_out_xxmc.c, X11 decoding accelerated video extension interface for xine + * + * based on mpeg2dec code from + * Aaron Holtzman + * + * Xv image support by Gerd Knorr + * + * xine-specific code by Guenter Bartsch + * + * overlay support by James Courtier-Dutton - July 2001 + * X11 unscaled overlay support by Miguel Freitas - Nov 2003 + * XxMC implementation by Thomas Hellström - August 2004 + */ + +#ifndef _XXMC_H +#define _XXMC_H + +#undef XVMC_THREAD_SAFE + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifdef HAVE_XV + +#include +#include +#include +#include +#include + +#if defined (__SVR4) && defined (__sun) +# include +#else +# include +#endif + +#include +#if defined(__FreeBSD__) +#include +#endif +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#ifdef HAVE_VLDXVMC + #include +#else + #include + #include +#endif + +#define LOG_MODULE "video_out_xxmc" +#define LOG_VERBOSE +/* +#define LOG +*/ + +#include "xine.h" +#include "video_out.h" +#include "xine_internal.h" +#include "alphablend.h" +#include "deinterlace.h" +#include "xineutils.h" +#include "vo_scale.h" +#include "x11osd.h" +#include "accel_xvmc.h" + +#define FOURCC_IA44 0x34344149 +#define FOURCC_AI44 0x34344941 +#define XVMC_MAX_SURFACES 16 +#define XVMC_MAX_SUBPICTURES 4 + +typedef struct xxmc_driver_s xxmc_driver_t; + +typedef struct { + xine_macroblocks_t xine_mc; + XvMCBlockArray blocks; /* pointer to memory for dct block array */ + int num_blocks; + XvMCMacroBlock *macroblockptr; /* pointer to current macro block */ + XvMCMacroBlock *macroblockbaseptr; /* pointer to base MacroBlock in MB array */ + XvMCMacroBlockArray macro_blocks; /* pointer to memory for macroblock array */ + int slices; +} xvmc_macroblocks_t; + + +typedef struct { + int value; + int min; + int max; + Atom atom; + + cfg_entry_t *entry; + + xxmc_driver_t *this; +} xxmc_property_t; + +typedef struct { + vo_frame_t vo_frame; + + int width, height, format; + double ratio; + + XvImage *image; + XShmSegmentInfo shminfo; + + /* XvMC specific stuff */ + + XvMCSurface *xvmc_surf; + xine_xxmc_t xxmc_data; +} xxmc_frame_t; + +typedef struct{ + unsigned int mpeg_flags; + unsigned int accel_flags; + unsigned int max_width; + unsigned int max_height; + unsigned int sub_max_width; + unsigned int sub_max_height; + int type_id; + XvImageFormatValues subPicType; + int flags; +} xvmc_capabilities_t; + +typedef struct xvmc_surface_handler_s { + XvMCSurface surfaces[XVMC_MAX_SURFACES]; + int surfInUse[XVMC_MAX_SURFACES]; + int surfValid[XVMC_MAX_SURFACES]; + XvMCSubpicture subpictures[XVMC_MAX_SUBPICTURES]; + int subInUse[XVMC_MAX_SUBPICTURES]; + int subValid[XVMC_MAX_SUBPICTURES]; + pthread_mutex_t mutex; +} xvmc_surface_handler_t; + +typedef struct context_lock_s { + pthread_mutex_t mutex; + pthread_cond_t cond; + int num_readers; +} context_lock_t; + +#define LOCK_AND_SURFACE_VALID(driver, surface) \ + xvmc_context_reader_lock( &(driver)->xvmc_lock ); \ + if (!xxmc_xvmc_surface_valid((driver),(surface))) { \ + xvmc_context_reader_unlock( &(driver)->xvmc_lock ); \ + return; \ + } + +#ifdef XVMC_THREAD_SAFE +#define XVMCLOCKDISPLAY(display) +#define XVMCUNLOCKDISPLAY(display) +#else +#define XVMCLOCKDISPLAY(display) XLockDisplay(display); +#define XVMCUNLOCKDISPLAY(display) XUnlockDisplay(display); +#endif + +struct xxmc_driver_s { + vo_driver_t vo_driver; + + config_values_t *config; + + /* X11 / Xv related stuff */ + Display *display; + int screen; + Drawable drawable; + unsigned int xv_format_yv12; + unsigned int xv_format_yuy2; + XVisualInfo vinfo; + GC gc; + XvPortID xv_port; + XColor black; + + int use_shm; + int use_pitch_alignment; + xxmc_property_t props[VO_NUM_PROPERTIES]; + uint32_t capabilities; + xxmc_frame_t *recent_frames[VO_NUM_RECENT_FRAMES]; + xxmc_frame_t *cur_frame; + x11osd *xoverlay; + int ovl_changed; + + /* all scaling information goes here */ + vo_scale_t sc; + xxmc_frame_t deinterlace_frame; + int deinterlace_method; + int deinterlace_enabled; + int use_colorkey; + uint32_t colorkey; + int (*x11_old_error_handler) (Display *, XErrorEvent *); + xine_t *xine; + + /* XvMC related stuff here */ + xvmc_macroblocks_t macroblocks; + xvmc_capabilities_t *xvmc_cap; + unsigned xvmc_num_cap; + unsigned int xvmc_max_subpic_x; + unsigned int xvmc_max_subpic_y; + int xvmc_eventbase; + int xvmc_errbase; + int hwSubpictures; + XvMCSubpicture *old_subpic,*new_subpic; + xx44_palette_t palette; + int first_overlay; + float cpu_saver; + int cpu_save_enabled; + int reverse_nvidia_palette; + int context_flags; + + /* + * These variables are protected by the context lock: + */ + + unsigned xvmc_cur_cap; + int xvmc_backend_subpic; + XvMCContext context; + int contextActive; + xvmc_surface_handler_t xvmc_surf_handler; + unsigned xvmc_mpeg; + unsigned xvmc_accel; + unsigned xvmc_width; + unsigned xvmc_height; + int have_xvmc_autopaint; + int xoverlay_ck; + + /* + * Only creation and destruction of the below. + */ + + char *xvmc_palette; + XvImage *subImage; + XShmSegmentInfo subShmInfo; + + /* + * The mutex below is needed since XlockDisplay wasn't really enough + * to protect the XvMC Calls. + */ + context_lock_t xvmc_lock; +}; + +typedef struct { + video_driver_class_t driver_class; + + config_values_t *config; + xine_t *xine; +} xxmc_class_t; + +extern void xvmc_context_reader_unlock(context_lock_t *c); +extern void xvmc_context_reader_lock(context_lock_t *c); +extern int xxmc_xvmc_surface_valid(xxmc_driver_t *this, XvMCSurface *surf); + +extern void xvmc_vld_slice(vo_frame_t *this_gen); +extern void xvmc_vld_frame(struct vo_frame_s *this_gen); +extern void xvmc_vld_flush(vo_frame_t *this_gen); + +extern void xxmc_xvmc_proc_macro_block(int x, int y, int mb_type, int motion_type, + int (*mv_field_sel)[2], int *dmvector, + int cbp, + int dct_type, vo_frame_t *current_frame, + vo_frame_t *forward_ref_frame, + vo_frame_t *backward_ref_frame, + int picture_structure, + int second_field, int (*f_mot_pmv)[2], + int (*b_mot_pmv)[2]); + +#endif +#endif diff --git a/src/xine-engine/Makefile.am b/src/xine-engine/Makefile.am index 61f4163c4..696a501b6 100644 --- a/src/xine-engine/Makefile.am +++ b/src/xine-engine/Makefile.am @@ -28,7 +28,8 @@ libxine_la_SOURCES = xine.c metronom.c configfile.c buffer.c \ input_rip.c info_helper.c # FIXME: these are currently unused: -EXTRA_DIST = lrb.c lrb.h +EXTRA_DIST = lrb.c lrb.h accel_xvmc.h + libxine_la_DEPENDENCIES = @INTLLIBS@ $(XINEUTILS_LIB) $(zlib_dep) \ $(dirent_lib) $(pthread_dep) $(LIBXINEPOSIX) diff --git a/src/xine-engine/accel_xvmc.h b/src/xine-engine/accel_xvmc.h new file mode 100644 index 000000000..ea10a40ff --- /dev/null +++ b/src/xine-engine/accel_xvmc.h @@ -0,0 +1,152 @@ +/* + * Copyright (C) 2000-2003 the xine project + * Copyright (C) 2004 the Unichrome project + * + * This file is part of xine, a free 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: accel_xvmc.h,v 1.1 2004/09/28 18:49:40 miguelfreitas Exp $ + * + * + * Common acceleration definitions for XvMC. + * + * + */ + +#ifndef HAVE_XINE_ACCEL_H +#define HAVE_XINE_ACCEL_H + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +typedef struct xine_macroblock_s { + short *blockptr; /* pointer to current dct block */ + short *blockbaseptr; /* pointer to base of dct block array in blocks */ + short xvmc_accel; /* type of acceleration supported */ +} xine_macroblocks_t; + +typedef struct xine_vld_frame_s { + int version; /* Backward compatibility */ + int mv_ranges[2][2]; + int picture_structure; + int picture_coding_type; + int intra_dc_precision; + int mpeg_coding; + int progressive_sequence; + int scan; + int pred_dct_frame; + int concealment_motion_vectors; + int q_scale_type; + int intra_vlc_format; + int second_field; + int load_intra_quantizer_matrix; + int load_non_intra_quantizer_matrix; + uint8_t intra_quantizer_matrix[64]; + uint8_t non_intra_quantizer_matrix[64]; + vo_frame_t *backward_reference_frame; + vo_frame_t *forward_reference_frame; +} xine_vld_frame_t; + + +typedef struct xine_xvmc_s { + xine_macroblocks_t *macroblocks; + void (*proc_macro_block)(int x,int y,int mb_type, + int motion_type,int (*mv_field_sel)[2], + int *dmvector,int cbp,int dct_type, + vo_frame_t *current_frame,vo_frame_t *forward_ref_frame, + vo_frame_t *backward_ref_frame,int picture_structure, + int second_field,int (*f_mot_pmv)[2],int (*b_mot_pmv)[2]); +} xine_xvmc_t ; + +typedef struct xine_xxmc_s { + + /* + * We inherit the xine_xvmc_t properties. + */ + + xine_xvmc_t xvmc; + + unsigned format; + unsigned mpeg; + unsigned acceleration; + xine_vld_frame_t vld_frame; + uint8_t *slice_data; + unsigned slice_data_size; + unsigned slice_code; + int result; + int decoded; + float sleep; + void (*proc_xxmc_frame) (vo_frame_t *vo_img); + void (*proc_xxmc_begin) (vo_frame_t *vo_img); + void (*proc_xxmc_slice) (vo_frame_t *vo_img); + void (*proc_xxmc_flush) (vo_frame_t *vo_img); +} xine_xxmc_t; + + /* + * Register XvMC stream types here. + */ + +#define XINE_XVMC_MPEG_1 0x00000001 +#define XINE_XVMC_MPEG_2 0x00000002 +#define XINE_XVMC_MPEG_4 0x00000004 + + /* + * Register XvMC acceleration levels here. + */ + +#define XINE_XVMC_ACCEL_MOCOMP 0x00000001 +#define XINE_XVMC_ACCEL_IDCT 0x00000002 +#define XINE_XVMC_ACCEL_VLD 0x00000004 + + +/* xvmc acceleration types */ +#define XINE_VO_MOTION_ACCEL 1 +#define XINE_VO_IDCT_ACCEL 2 +#define XINE_VO_SIGNED_INTRA 4 + +/* motion types */ +#define XINE_MC_FIELD 1 +#define XINE_MC_FRAME 2 +#define XINE_MC_16X8 2 +#define XINE_MC_DMV 3 + +/* picture coding type */ +#define XINE_PICT_I_TYPE 1 +#define XINE_PICT_P_TYPE 2 +#define XINE_PICT_B_TYPE 3 +#define XINE_PICT_D_TYPE 4 + +/* macroblock modes */ +#define XINE_MACROBLOCK_INTRA 1 +#define XINE_MACROBLOCK_PATTERN 2 +#define XINE_MACROBLOCK_MOTION_BACKWARD 4 +#define XINE_MACROBLOCK_MOTION_FORWARD 8 +#define XINE_MACROBLOCK_QUANT 16 +#define XINE_MACROBLOCK_DCT_TYPE_INTERLACED 32 + + + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/src/xine-engine/post.c b/src/xine-engine/post.c index 9f49b2115..5f8eca309 100644 --- a/src/xine-engine/post.c +++ b/src/xine-engine/post.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: post.c,v 1.26 2004/05/29 14:45:25 mroi Exp $ + * $Id: post.c,v 1.27 2004/09/28 18:49:40 miguelfreitas Exp $ */ /* @@ -345,34 +345,6 @@ static void post_frame_dispose(vo_frame_t *vo_img) { _x_post_dec_usage(port); } -static void post_frame_proc_macro_block(int x, - int y, - int mb_type, - int motion_type, - int (*mv_field_sel)[2], - int *dmvector, - int cbp, - int dct_type, - vo_frame_t *current_frame, - vo_frame_t *forward_ref_frame, - vo_frame_t *backward_ref_frame, - int picture_structure, - int second_field, - int (*f_mot_pmv)[2], - int (*b_mot_pmv)[2]) { - post_video_port_t *port = _x_post_video_frame_to_port(current_frame); - - if (port->frame_lock) pthread_mutex_lock(port->frame_lock); - _x_post_frame_copy_down(current_frame, current_frame->next); - current_frame->next->proc_macro_block(x, y, mb_type, motion_type, mv_field_sel, - dmvector, cbp, dct_type, current_frame->next, - forward_ref_frame, backward_ref_frame, - picture_structure, second_field, - f_mot_pmv, b_mot_pmv); - _x_post_frame_copy_up(current_frame, current_frame->next); - if (port->frame_lock) pthread_mutex_unlock(port->frame_lock); -} - vo_frame_t *_x_post_intercept_video_frame(vo_frame_t *frame, post_video_port_t *port) { vo_frame_t *new_frame; @@ -397,8 +369,6 @@ vo_frame_t *_x_post_intercept_video_frame(vo_frame_t *frame, post_video_port_t * port->new_frame->proc_frame ? port->new_frame->proc_frame : NULL; new_frame->proc_slice = port->new_frame->proc_slice ? port->new_frame->proc_slice : NULL; - new_frame->proc_macro_block = - port->new_frame->proc_macro_block ? port->new_frame->proc_macro_block : NULL; new_frame->field = port->new_frame->field ? port->new_frame->field : post_frame_field; new_frame->draw = @@ -417,8 +387,6 @@ vo_frame_t *_x_post_intercept_video_frame(vo_frame_t *frame, post_video_port_t * new_frame->proc_frame = post_frame_proc_frame; if (frame->proc_slice && !new_frame->proc_slice) new_frame->proc_slice = post_frame_proc_slice; - if (frame->proc_macro_block && !new_frame->proc_macro_block) - new_frame->proc_macro_block = post_frame_proc_macro_block; } return new_frame; @@ -450,7 +418,7 @@ void _x_post_frame_copy_down(vo_frame_t *from, vo_frame_t *to) { to->progressive_frame = from->progressive_frame; to->picture_coding_type = from->picture_coding_type; to->drawn = from->drawn; - to->macroblocks = from->macroblocks; + to->accel_data = from->accel_data; to->stream = from->stream; if (to->extra_info != from->extra_info) diff --git a/src/xine-engine/video_out.c b/src/xine-engine/video_out.c index dfc6aa5b7..b482c2784 100644 --- a/src/xine-engine/video_out.c +++ b/src/xine-engine/video_out.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: video_out.c,v 1.206 2004/09/22 20:29:17 miguelfreitas Exp $ + * $Id: video_out.c,v 1.207 2004/09/28 18:49:40 miguelfreitas Exp $ * * frame allocation / queuing / scheduling / output functions */ @@ -335,7 +335,7 @@ static vo_frame_t *vo_get_frame (xine_video_port_t *this_gen, img->crop_right = 0; img->crop_top = 0; img->crop_bottom = 0; - img->macroblocks = NULL; + _x_extra_info_reset ( img->extra_info ); /* let driver ensure this image has the right format */ @@ -615,31 +615,36 @@ static vo_frame_t * duplicate_frame( vos_t *this, vo_frame_t *img ) { pthread_mutex_unlock (&dupl->mutex); - switch (img->format) { - case XINE_IMGFMT_YV12: - yv12_to_yv12( - /* Y */ - img->base[0], img->pitches[0], - dupl->base[0], dupl->pitches[0], - /* U */ - img->base[1], img->pitches[1], - dupl->base[1], dupl->pitches[1], - /* V */ - img->base[2], img->pitches[2], - dupl->base[2], dupl->pitches[2], - /* width x height */ - img->width, img->height); - break; - case XINE_IMGFMT_YUY2: - yuy2_to_yuy2( - /* src */ - img->base[0], img->pitches[0], - /* dst */ - dupl->base[0], dupl->pitches[0], - /* width x height */ - img->width, img->height); - break; - } + if (dupl->proc_duplicate_frame_data) { + dupl->proc_duplicate_frame_data(dupl,img); + } else { + + switch (img->format) { + case XINE_IMGFMT_YV12: + yv12_to_yv12( + /* Y */ + img->base[0], img->pitches[0], + dupl->base[0], dupl->pitches[0], + /* U */ + img->base[1], img->pitches[1], + dupl->base[1], dupl->pitches[1], + /* V */ + img->base[2], img->pitches[2], + dupl->base[2], dupl->pitches[2], + /* width x height */ + img->width, img->height); + break; + case XINE_IMGFMT_YUY2: + yuy2_to_yuy2( + /* src */ + img->base[0], img->pitches[0], + /* dst */ + dupl->base[0], dupl->pitches[0], + /* width x height */ + img->width, img->height); + break; + } + } dupl->bad_frame = 0; dupl->pts = 0; @@ -1661,6 +1666,7 @@ xine_video_port_t *_x_vo_new_port (xine_t *xine, vo_driver_t *driver, int grabon img = driver->alloc_frame (driver) ; if (!img) break; + img->proc_duplicate_frame_data = NULL; img->id = i; diff --git a/src/xine-engine/video_out.h b/src/xine-engine/video_out.h index c96307471..ba35e2e2a 100644 --- a/src/xine-engine/video_out.h +++ b/src/xine-engine/video_out.h @@ -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: video_out.h,v 1.110 2004/09/26 22:54:52 valtri Exp $ + * $Id: video_out.h,v 1.111 2004/09/28 18:49:40 miguelfreitas Exp $ * * * xine version of video_out.h @@ -60,13 +60,6 @@ typedef struct video_driver_class_s video_driver_class_t; typedef struct vo_overlay_s vo_overlay_t; typedef struct video_overlay_manager_s video_overlay_manager_t; -typedef struct xine_macroblock_s { - short *blockptr; /* pointer to current dct block */ - short *blockbaseptr; /* pointer to base of dct block array in blocks */ - short xvmc_accel; /* type of acceleration supported */ -} xine_macroblocks_t; - - /* public part, video drivers may add private fields * * Remember that adding new functions to this structure requires @@ -78,6 +71,11 @@ struct vo_frame_s { * member functions */ + /* Duplicate picture data and acceleration specific data of a frame. */ + /* if the image format isn't already known by Xine. Currently this is needed */ + /* For all image formats except XINE_IMGFMT_YV12 and XINE_IMGFMT_YUY2 */ + void (*proc_duplicate_frame_data) (vo_frame_t *vo_img, vo_frame_t *src); + /* tell video driver to copy/convert the whole of this frame, may be NULL */ /* at least one of proc_frame() and proc_slice() MUST set the variable proc_called to 1 */ void (*proc_frame) (vo_frame_t *vo_img); @@ -86,23 +84,6 @@ struct vo_frame_s { /* at least one of proc_frame() and proc_slice() MUST set the variable proc_called to 1 */ void (*proc_slice) (vo_frame_t *vo_img, uint8_t **src); - /* XvMC routine for rendering macroblocks, may be NULL */ - void (*proc_macro_block)(int x, - int y, - int mb_type, - int motion_type, - int (*mv_field_sel)[2], - int *dmvector, - int cbp, - int dct_type, - vo_frame_t *current_frame, - vo_frame_t *forward_ref_frame, - vo_frame_t *backward_ref_frame, - int picture_structure, - int second_field, - int (*f_mot_pmv)[2], - int (*b_mot_pmv)[2]); - /* tell video driver that the decoder starts a new field */ void (*field) (vo_frame_t *vo_img, int which_field); @@ -161,8 +142,8 @@ struct vo_frame_s { int flags; /* remember the frame flags */ int proc_called; /* track use of proc_*() methods */ - /* used to carry macroblocks information for XvMC acceleration */ - xine_macroblocks_t *macroblocks; + /* Used to carry private data for accelerated plugins.*/ + void *accel_data; /* "backward" references to where this frame originates from */ xine_video_port_t *port; @@ -292,31 +273,7 @@ struct xine_video_port_s { #define VO_CAP_XVMC_IDCT 0x00000008 /* driver can use XvMC idct acceleration */ #define VO_CAP_UNSCALED_OVERLAY 0x00000010 /* driver can blend overlay at output resolution */ #define VO_CAP_CROP 0x00000020 /* driver can crop */ - -/* macroblock modes */ -#define XINE_MACROBLOCK_INTRA 1 -#define XINE_MACROBLOCK_PATTERN 2 -#define XINE_MACROBLOCK_MOTION_BACKWARD 4 -#define XINE_MACROBLOCK_MOTION_FORWARD 8 -#define XINE_MACROBLOCK_QUANT 16 -#define XINE_MACROBLOCK_DCT_TYPE_INTERLACED 32 - -/* motion types */ -#define XINE_MC_FIELD 1 -#define XINE_MC_FRAME 2 -#define XINE_MC_16X8 2 -#define XINE_MC_DMV 3 - -/* picture coding type */ -#define XINE_PICT_I_TYPE 1 -#define XINE_PICT_P_TYPE 2 -#define XINE_PICT_B_TYPE 3 -#define XINE_PICT_D_TYPE 4 - -/* xvmc acceleration types */ -#define XINE_VO_MOTION_ACCEL 1 -#define XINE_VO_IDCT_ACCEL 2 -#define XINE_VO_SIGNED_INTRA 4 +#define VO_CAP_XXMC 0x00000040 /* driver can use extended XvMC */ /* -- cgit v1.2.3