diff --git a/packages/mediacenter/xbmc/patches/xbmc-11.0.1-902.01-xvba_support-fc969e525002544a65cbf9660c4562cd4e2d45f1.patch b/packages/mediacenter/xbmc/patches/xbmc-11.0.1-902.01-xvba_support-fc969e525002544a65cbf9660c4562cd4e2d45f1.patch deleted file mode 100644 index 7738d91487..0000000000 --- a/packages/mediacenter/xbmc/patches/xbmc-11.0.1-902.01-xvba_support-fc969e525002544a65cbf9660c4562cd4e2d45f1.patch +++ /dev/null @@ -1,7176 +0,0 @@ -diff --git a/configure.in b/configure.in -index e1cc9d2..d0d3beb 100755 ---- a/configure.in -+++ b/configure.in -@@ -98,6 +98,8 @@ vaapi_not_found="== Could not find libva. VAAPI support disabled. ==" - vaapi_disabled="== VAAPI support manually disabled. ==" - crystalhd_not_found="== Could not find libcrystalhd. CrystalHD support disabled. ==" - crystalhd_disabled="== CrystalHD support manually disabled. ==" -+xvba_not_found="== Could not find amdxvba.h. XVBA support disabled. ==" -+xvba_disabled="== XVBA support manually disabled. ==" - vdadecoder_enabled="== VDADecoder support enabled. ==" - vdadecoder_disabled="== VDADecoder support manually disabled. ==" - vtbdecoder_enabled="== VTBDecoder support enabled. ==" -@@ -204,6 +206,12 @@ AC_ARG_ENABLE([crystalhd], - [enable CrystalHD decoding (default is auto)])], - [use_crystalhd=$enableval], - [use_crystalhd=auto]) -+ -+AC_ARG_ENABLE([xvba], -+ [AS_HELP_STRING([--enable-xvba], -+ [enable XVBA decoding (default is auto)])], -+ [use_xvba=$enableval], -+ [use_xvba=auto]) - - AC_ARG_ENABLE([vdadecoder], - [AS_HELP_STRING([--enable-vdadecoder], -@@ -1382,6 +1390,38 @@ else - USE_CRYSTALHD=0 - fi - -+# XVBA -+if test "x$use_xvba" != "xno"; then -+ if test "$host_vendor" = "apple" ; then -+ if test "x$use_xvba" = "xyes"; then -+ AC_MSG_ERROR([XVBA not supported on this platform]) -+ else -+ use_xvba="no" -+ AC_MSG_NOTICE($xvba_disabled) -+ fi -+ USE_XVBA=0 -+ else -+ initial_val=$use_xvba -+ AC_CHECK_HEADER([amd/amdxvba.h],, use_xvba=no, [#include ]) -+ -+ if test "x$use_xvba" = "xno"; then -+ if test "x$initial_val" = "xyes"; then -+ AC_MSG_ERROR($xvba_not_found) -+ else -+ AC_MSG_RESULT($xvba_not_found) -+ fi -+ USE_XVBA=0 -+ else -+ AC_DEFINE([HAVE_LIBXVBA], [1], [Define to 1 if you have the 'xvba' header (amdxvba.h)]) -+ USE_XVBA=1 -+ fi -+ fi -+else -+ AC_MSG_NOTICE($xvba_disabled) -+ USE_XVBA=0 -+fi -+ -+ - # VDADecoder - if test "x$use_vdadecoder" != "xno"; then - if test "$host_vendor" = "apple" ; then -@@ -1578,6 +1618,12 @@ else - final_message="$final_message\n CrystalHD:\tNo" - fi - -+if test "x$use_xvba" != "xno"; then -+ final_message="$final_message\n XVBA:\t\tYes" -+else -+ final_message="$final_message\n XVBA:\t\tNo" -+fi -+ - if test "x$use_vdadecoder" != "xno"; then - final_message="$final_message\n VDADecoder:\tYes" - else -@@ -1952,6 +1998,7 @@ AC_SUBST(USE_OPENGLES) - AC_SUBST(USE_VDPAU) - AC_SUBST(USE_VAAPI) - AC_SUBST(USE_CRYSTALHD) -+AC_SUBST(USE_XVBA) - AC_SUBST(USE_LIBSMBCLIENT) - AC_SUBST(USE_LIBNFS) - AC_SUBST(USE_LIBAFPCLIENT) -@@ -2094,6 +2141,7 @@ XB_CONFIG_MODULE([lib/ffmpeg], [ - --enable-gpl \ - `if test "x$use_vdpau" != "xno"; then echo --enable-vdpau; else echo --disable-vdpau; fi` \ - `if test "x$use_vaapi" != "xno"; then echo --enable-vaapi; else echo --disable-vaapi; fi` \ -+ `if test "x$use_xvba" != "xno"; then echo --enable-xvba; else echo --disable-xvba; fi` \ - --enable-protocol=http \ - --enable-pthreads \ - --enable-runtime-cpudetect \ -diff --git a/language/English/strings.xml b/language/English/strings.xml -index 0cf25b6..c48c056 100644 ---- a/language/English/strings.xml -+++ b/language/English/strings.xml -@@ -1234,6 +1234,8 @@ - Allow hardware acceleration (OpenMax) - Pixel Shaders - Allow hardware acceleration (VideoToolbox) -+ Allow hardware acceleration (XVBA) -+ Use XvBA shared surfaces - - A/V sync method - Audio clock -diff --git a/lib/UnrarXLib/extract.cpp b/lib/UnrarXLib/extract.cpp -index b4a8091..da60857 100644 ---- a/lib/UnrarXLib/extract.cpp -+++ b/lib/UnrarXLib/extract.cpp -@@ -1,9 +1,5 @@ - #include "rar.hpp" - #include "Util.h" --#ifdef _LINUX --#include "XSyncUtils.h" --#include "XEventUtils.h" --#endif - - // a cautious wrapper around strncpy - char *strncpy_null_terminated(char *dest, const char *src, size_t n) -diff --git a/lib/UnrarXLib/unpack.cpp b/lib/UnrarXLib/unpack.cpp -index 265b54f..bc2f220 100644 ---- a/lib/UnrarXLib/unpack.cpp -+++ b/lib/UnrarXLib/unpack.cpp -@@ -8,11 +8,6 @@ - #include "unpack20.cpp" - #endif - --#ifdef _LINUX --#include "XSyncUtils.h" --#include "XEventUtils.h" --#endif -- - Unpack::Unpack(ComprDataIO *DataIO) - { - UnpIO=DataIO; -diff --git a/lib/UnrarXLib/unpack15.cpp b/lib/UnrarXLib/unpack15.cpp -index e1b5f10..725e2be 100644 ---- a/lib/UnrarXLib/unpack15.cpp -+++ b/lib/UnrarXLib/unpack15.cpp -@@ -1,7 +1,3 @@ --#ifdef _LINUX --#include "XSyncUtils.h" --#endif -- - #define STARTL1 2 - static unsigned int DecL1[]={0x8000,0xa000,0xc000,0xd000,0xe000,0xea00, - 0xee00,0xf000,0xf200,0xf200,0xffff}; -diff --git a/lib/ffmpeg/configure b/lib/ffmpeg/configure -index fec801c..fc73296 100755 ---- a/lib/ffmpeg/configure -+++ b/lib/ffmpeg/configure -@@ -111,6 +111,7 @@ Configuration options: - --disable-vaapi disable VAAPI code - --disable-vdpau disable VDPAU code - --disable-dxva2 disable DXVA2 code -+ --disable-xvba disable XVBA code - --enable-runtime-cpudetect detect cpu capabilities at runtime (bigger binary) - --enable-hardcoded-tables use hardcoded tables instead of runtime generation - --enable-memalign-hack emulate memalign, interferes with memory debuggers -@@ -932,6 +933,7 @@ CONFIG_LIST=" - swscale_alpha - vaapi - vdpau -+ xvba - version3 - x11grab - zlib -@@ -1240,6 +1242,7 @@ h264_decoder_select="golomb h264dsp h264pred" - h264_dxva2_hwaccel_deps="dxva2api_h" - h264_dxva2_hwaccel_select="dxva2 h264_decoder" - h264_vaapi_hwaccel_select="vaapi" -+h264_xvba_hwaccel_select="xvba" - h264_vdpau_decoder_select="vdpau h264_decoder" - imc_decoder_select="fft mdct" - jpegls_decoder_select="golomb" -@@ -1263,6 +1266,7 @@ mpeg2_dxva2_hwaccel_deps="dxva2api_h" - mpeg2_dxva2_hwaccel_select="dxva2 mpeg2video_decoder" - mpeg2_vaapi_hwaccel_select="vaapi mpeg2video_decoder" - mpeg4_vaapi_hwaccel_select="vaapi mpeg4_decoder" -+mpeg2_xvba_hwaccel_select="xvba mpeg2video_decoder" - mpeg4_vdpau_decoder_deps="vdpau_vdpau_h vdpau_vdpau_x11_h vdpau_mpeg4_support" - mpeg4_vdpau_decoder_select="vdpau mpeg4_decoder" - mpeg_xvmc_decoder_deps="X11_extensions_XvMClib_h" -@@ -1306,6 +1310,7 @@ vc1_decoder_select="h263_decoder" - vc1_dxva2_hwaccel_deps="dxva2api_h DXVA_PictureParameters_wDecodedPictureIndex" - vc1_dxva2_hwaccel_select="dxva2 vc1_decoder" - vc1_vaapi_hwaccel_select="vaapi vc1_decoder" -+vc1_xvba_hwaccel_select="xvba vc1_decoder" - vc1_vdpau_decoder_select="vdpau vc1_decoder" - vorbis_decoder_select="mdct" - vorbis_encoder_select="mdct" -@@ -1327,12 +1332,14 @@ wmv3_decoder_select="vc1_decoder" - wmv3_dxva2_hwaccel_select="vc1_dxva2_hwaccel" - wmv3_vaapi_hwaccel_select="vc1_vaapi_hwaccel" - wmv3_vdpau_decoder_select="vc1_vdpau_decoder" -+wmv3_xvba_hwaccel_select="vc1_xvba_hwaccel" - zlib_decoder_select="zlib" - zlib_encoder_select="zlib" - zmbv_decoder_select="zlib" - zmbv_encoder_select="zlib" - - vaapi_deps="va_va_h" -+xvba_deps="amd_amdxvba_h" - vdpau_deps="vdpau_vdpau_h vdpau_vdpau_x11_h" - - # parsers -@@ -2762,6 +2769,7 @@ check_header sys/select.h - check_header termios.h - check_header vdpau/vdpau.h - check_header vdpau/vdpau_x11.h -+check_header amd/amdxvba.h - check_cpp_condition vdpau/vdpau.h "defined(VDP_DECODER_PROFILE_MPEG4_PART2_SP)" && enable vdpau_mpeg4_support - - check_header X11/extensions/XvMClib.h -diff --git a/lib/ffmpeg/libavcodec/Makefile b/lib/ffmpeg/libavcodec/Makefile -index 6a0a05b..65cca69 100644 ---- a/lib/ffmpeg/libavcodec/Makefile -+++ b/lib/ffmpeg/libavcodec/Makefile -@@ -3,7 +3,7 @@ include $(SUBDIR)../config.mak - NAME = avcodec - FFLIBS = avcore avutil - --HEADERS = avcodec.h avfft.h dxva2.h opt.h vaapi.h vdpau.h xvmc.h -+HEADERS = avcodec.h avfft.h dxva2.h opt.h vaapi.h vdpau.h xvmc.h xvba.h - - OBJS = allcodecs.o \ - audioconvert.o \ -@@ -43,6 +43,7 @@ RDFT-OBJS-$(CONFIG_HARDCODED_TABLES) += sin_tables.o - OBJS-$(CONFIG_RDFT) += rdft.o $(RDFT-OBJS-yes) - OBJS-$(CONFIG_VAAPI) += vaapi.o - OBJS-$(CONFIG_VDPAU) += vdpau.o -+OBJS-$(CONFIG_XVBA) += xvba.o - - # decoders/encoders/hardware accelerators - OBJS-$(CONFIG_A64MULTI_ENCODER) += a64multienc.o elbg.o -@@ -169,6 +170,7 @@ OBJS-$(CONFIG_H264_DECODER) += h264.o \ - mpegvideo.o error_resilience.o - OBJS-$(CONFIG_H264_DXVA2_HWACCEL) += dxva2_h264.o - OBJS-$(CONFIG_H264_VAAPI_HWACCEL) += vaapi_h264.o -+OBJS-$(CONFIG_H264_XVBA_HWACCEL) += xvba_h264.o - OBJS-$(CONFIG_HUFFYUV_DECODER) += huffyuv.o - OBJS-$(CONFIG_HUFFYUV_ENCODER) += huffyuv.o - OBJS-$(CONFIG_IDCIN_DECODER) += idcinvideo.o -@@ -246,6 +248,7 @@ OBJS-$(CONFIG_MPEG1VIDEO_ENCODER) += mpeg12enc.o mpegvideo_enc.o \ - mpegvideo.o error_resilience.o - OBJS-$(CONFIG_MPEG2_DXVA2_HWACCEL) += dxva2_mpeg2.o - OBJS-$(CONFIG_MPEG2_VAAPI_HWACCEL) += vaapi_mpeg2.o -+OBJS-$(CONFIG_MPEG2_XVBA_HWACCEL) += xvba_mpeg2.o - OBJS-$(CONFIG_MPEG2VIDEO_DECODER) += mpeg12.o mpeg12data.o \ - mpegvideo.o error_resilience.o - OBJS-$(CONFIG_MPEG2VIDEO_ENCODER) += mpeg12enc.o mpegvideo_enc.o \ -@@ -379,6 +382,7 @@ OBJS-$(CONFIG_VC1_DECODER) += vc1dec.o vc1.o vc1data.o vc1dsp.o \ - intrax8.o intrax8dsp.o - OBJS-$(CONFIG_VC1_DXVA2_HWACCEL) += dxva2_vc1.o - OBJS-$(CONFIG_VC1_VAAPI_HWACCEL) += vaapi_vc1.o -+OBJS-$(CONFIG_VC1_XVBA_HWACCEL) += xvba_vc1.o - OBJS-$(CONFIG_VCR1_DECODER) += vcr1.o - OBJS-$(CONFIG_VCR1_ENCODER) += vcr1.o - OBJS-$(CONFIG_VMDAUDIO_DECODER) += vmdav.o -@@ -647,6 +651,7 @@ SKIPHEADERS-$(CONFIG_DXVA2) += dxva2.h dxva2_internal.h - SKIPHEADERS-$(CONFIG_LIBDIRAC) += libdirac.h - SKIPHEADERS-$(CONFIG_LIBSCHROEDINGER) += libschroedinger.h - SKIPHEADERS-$(CONFIG_VAAPI) += vaapi_internal.h -+SKIPHEADERS-$(CONFIG_XVBA) += xvba_internal.h - SKIPHEADERS-$(CONFIG_VDPAU) += vdpau.h - SKIPHEADERS-$(CONFIG_XVMC) += xvmc.h - SKIPHEADERS += mpegaudio3.h -diff --git a/lib/ffmpeg/libavcodec/allcodecs.c b/lib/ffmpeg/libavcodec/allcodecs.c -index 04c5c6a..38b8791 100644 ---- a/lib/ffmpeg/libavcodec/allcodecs.c -+++ b/lib/ffmpeg/libavcodec/allcodecs.c -@@ -57,13 +57,17 @@ void avcodec_register_all(void) - REGISTER_HWACCEL (H263_VAAPI, h263_vaapi); - REGISTER_HWACCEL (H264_DXVA2, h264_dxva2); - REGISTER_HWACCEL (H264_VAAPI, h264_vaapi); -+ REGISTER_HWACCEL (H264_XVBA, h264_xvba); - REGISTER_HWACCEL (MPEG2_DXVA2, mpeg2_dxva2); - REGISTER_HWACCEL (MPEG2_VAAPI, mpeg2_vaapi); - REGISTER_HWACCEL (MPEG4_VAAPI, mpeg4_vaapi); -+ REGISTER_HWACCEL (MPEG2_XVBA, mpeg2_xvba); - REGISTER_HWACCEL (VC1_DXVA2, vc1_dxva2); - REGISTER_HWACCEL (VC1_VAAPI, vc1_vaapi); -+ REGISTER_HWACCEL (VC1_XVBA, vc1_xvba); - REGISTER_HWACCEL (WMV3_DXVA2, wmv3_dxva2); - REGISTER_HWACCEL (WMV3_VAAPI, wmv3_vaapi); -+ REGISTER_HWACCEL (WMV3_XVBA, wmv3_xvba); - - /* video codecs */ - REGISTER_ENCODER (A64MULTI, a64multi); -diff --git a/lib/ffmpeg/libavcodec/h264.c b/lib/ffmpeg/libavcodec/h264.c -index 0e002ce..d054b20 100644 ---- a/lib/ffmpeg/libavcodec/h264.c -+++ b/lib/ffmpeg/libavcodec/h264.c -@@ -55,6 +55,7 @@ static const uint8_t div6[52]={ - static const enum PixelFormat hwaccel_pixfmt_list_h264_jpeg_420[] = { - PIX_FMT_DXVA2_VLD, - PIX_FMT_VAAPI_VLD, -+ PIX_FMT_XVBA_VLD, - PIX_FMT_YUVJ420P, - PIX_FMT_NONE - }; -diff --git a/lib/ffmpeg/libavcodec/mpegvideo.c b/lib/ffmpeg/libavcodec/mpegvideo.c -index 31642e6..56113c7 100644 ---- a/lib/ffmpeg/libavcodec/mpegvideo.c -+++ b/lib/ffmpeg/libavcodec/mpegvideo.c -@@ -117,6 +117,7 @@ const enum PixelFormat ff_pixfmt_list_420[] = { - const enum PixelFormat ff_hwaccel_pixfmt_list_420[] = { - PIX_FMT_DXVA2_VLD, - PIX_FMT_VAAPI_VLD, -+ PIX_FMT_XVBA_VLD, - PIX_FMT_YUV420P, - PIX_FMT_NONE - }; -diff --git a/lib/ffmpeg/libavcodec/xvba.c b/lib/ffmpeg/libavcodec/xvba.c -new file mode 100644 -index 0000000..48fd905 ---- /dev/null -+++ b/lib/ffmpeg/libavcodec/xvba.c -@@ -0,0 +1,65 @@ -+/* -+ * HW decode acceleration for MPEG-2, H.264 and VC-1 -+ * -+ * Copyright (C) 2005-2011 Team XBMC -+ * -+ * This file is part of FFmpeg. -+ * -+ * FFmpeg is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU Lesser General Public -+ * License as published by the Free Software Foundation; either -+ * version 2.1 of the License, or (at your option) any later version. -+ * -+ * FFmpeg 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 -+ * Lesser General Public License for more details. -+ * -+ * You should have received a copy of the GNU Lesser General Public -+ * License along with FFmpeg; if not, write to the Free Software -+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -+ */ -+ -+ -+/** -+ * \addtogroup XVBA_Decoding -+ * -+ * @{ -+ */ -+ -+#include -+#include "xvba.h" -+#include "avcodec.h" -+ -+int ff_xvba_translate_profile(int profile) { -+ -+ if (profile == 66) -+ return 1; -+ else if (profile == 77) -+ return 2; -+ else if (profile == 100) -+ return 3; -+ else if (profile == 0) -+ return 4; -+ else if (profile == 1) -+ return 5; -+ else if (profile == 3) -+ return 6; -+ else -+ return -1; -+} -+ -+void ff_xvba_add_slice_data(struct xvba_render_state *render, const void *buffer, uint32_t size) { -+ -+ render->buffers = av_fast_realloc( -+ render->buffers, -+ &render->buffers_alllocated, -+ sizeof(struct xvba_bitstream_buffers)*(render->num_slices + 1) -+ ); -+ -+ render->buffers[render->num_slices].buffer = buffer; -+ render->buffers[render->num_slices].size = size; -+ -+ render->num_slices++; -+} -+ -diff --git a/lib/ffmpeg/libavcodec/xvba.h b/lib/ffmpeg/libavcodec/xvba.h -new file mode 100644 -index 0000000..a62d649 ---- /dev/null -+++ b/lib/ffmpeg/libavcodec/xvba.h -@@ -0,0 +1,65 @@ -+/* -+ * HW decode acceleration for MPEG-2, H.264 and VC-1 -+ * -+ * Copyright (C) 2005-2011 Team XBMC -+ * -+ * This file is part of FFmpeg. -+ * -+ * FFmpeg is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU Lesser General Public -+ * License as published by the Free Software Foundation; either -+ * version 2.1 of the License, or (at your option) any later version. -+ * -+ * FFmpeg 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 -+ * Lesser General Public License for more details. -+ * -+ * You should have received a copy of the GNU Lesser General Public -+ * License along with FFmpeg; if not, write to the Free Software -+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -+ */ -+ -+#ifndef AVCODEC_XVBA_H -+#define AVCODEC_XVBA_H -+ -+#include -+#include -+#include -+ -+ -+/** -+ * \defgroup XVBA_Decoding VA API Decoding -+ * \ingroup Decoder -+ * @{ -+ */ -+ -+/** \brief The videoSurface is used for rendering. */ -+#define FF_XVBA_STATE_USED_FOR_RENDER 1 -+ -+/** -+ * \brief The videoSurface is needed for reference/prediction. -+ * The codec manipulates this. -+ */ -+#define FF_XVBA_STATE_USED_FOR_REFERENCE 2 -+ -+/* @} */ -+ -+struct xvba_bitstream_buffers -+{ -+ const void *buffer; -+ unsigned int size; -+}; -+ -+struct xvba_render_state { -+ -+ int state; ///< Holds FF_XVBA_STATE_* values. -+ void *surface; -+ XVBAPictureDescriptor *picture_descriptor; -+ XVBAQuantMatrixAvc *iq_matrix; -+ unsigned int num_slices; -+ struct xvba_bitstream_buffers *buffers; -+ uint32_t buffers_alllocated; -+}; -+ -+#endif /* AVCODEC_XVBA_H */ -diff --git a/lib/ffmpeg/libavcodec/xvba_h264.c b/lib/ffmpeg/libavcodec/xvba_h264.c -new file mode 100644 -index 0000000..0d98dea ---- /dev/null -+++ b/lib/ffmpeg/libavcodec/xvba_h264.c -@@ -0,0 +1,180 @@ -+/* -+ * H.264 HW decode acceleration through XVBA -+ * -+ * Copyright (C) 2005-2011 Team XBMC -+ * -+ * This file is part of FFmpeg. -+ * -+ * FFmpeg is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU Lesser General Public -+ * License as published by the Free Software Foundation; either -+ * version 2.1 of the License, or (at your option) any later version. -+ * -+ * FFmpeg 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 -+ * Lesser General Public License for more details. -+ * -+ * You should have received a copy of the GNU Lesser General Public -+ * License along with FFmpeg; if not, write to the Free Software -+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -+ */ -+ -+#include "xvba.h" -+#include "xvba_internal.h" -+#include "h264.h" -+#include -+ -+/** @file -+ * This file implements the glue code between FFmpeg's and XvBA API's -+ * structures for H.264 decoding. -+ */ -+ -+ -+/** Initialize and start decoding a frame with XVBA. */ -+static int start_frame(AVCodecContext *avctx, -+ av_unused const uint8_t *buffer, -+ av_unused uint32_t size) -+{ -+ H264Context * const h = avctx->priv_data; -+ MpegEncContext * const s = &h->s; -+ struct xvba_render_state *render; -+ XVBAPictureDescriptor *pic_descriptor; -+ int i; -+ -+ render = (struct xvba_render_state *)s->current_picture_ptr->data[0]; -+ assert(render); -+ -+ if (render->picture_descriptor == 0) -+ return -1; -+ -+ pic_descriptor = render->picture_descriptor; -+ -+ for (i = 0; i < 2; ++i) { -+ int foc = s->current_picture_ptr->field_poc[i]; -+ if (foc == INT_MAX) -+ foc = 0; -+ pic_descriptor->avc_curr_field_order_cnt_list[i] = foc; -+ } -+ -+ pic_descriptor->avc_frame_num = h->frame_num; -+ -+ render->num_slices = 0; -+ -+ return 0; -+} -+ -+/** End a hardware decoding based frame. */ -+static int end_frame(AVCodecContext *avctx) -+{ -+ H264Context * const h = avctx->priv_data; -+ MpegEncContext * const s = &h->s; -+ struct xvba_render_state *render; -+ XVBAPictureDescriptor *pic_descriptor; -+ XVBAQuantMatrixAvc *iq_matrix; -+ -+ render = (struct xvba_render_state *)s->current_picture_ptr->data[0]; -+ assert(render); -+ -+ if (render->picture_descriptor == 0 || render->iq_matrix == 0) -+ return -1; -+ -+ pic_descriptor = render->picture_descriptor; -+ iq_matrix = render->iq_matrix; -+ -+ av_dlog(avctx, "end_frame()\n"); -+ -+ /* Fill in Picture Parameters*/ -+ pic_descriptor->profile = ff_xvba_translate_profile(avctx->profile); -+ pic_descriptor->level = avctx->level; -+ pic_descriptor->width_in_mb = s->mb_width; -+ pic_descriptor->height_in_mb = s->mb_height; -+ pic_descriptor->picture_structure = s->picture_structure; -+ pic_descriptor->chroma_format = s->chroma_format ? s->chroma_format : 1; -+ pic_descriptor->avc_intra_flag = (h->slice_type == FF_I_TYPE) ? 1 : 0; -+ pic_descriptor->avc_reference = (s->current_picture_ptr->reference & 3) ? 1 : 0; -+ -+ pic_descriptor->avc_bit_depth_luma_minus8 = h->sps.bit_depth_luma - 8; -+ pic_descriptor->avc_bit_depth_chroma_minus8 = h->sps.bit_depth_chroma - 8; -+ pic_descriptor->avc_log2_max_frame_num_minus4 = h->sps.log2_max_frame_num -4; -+ pic_descriptor->avc_pic_order_cnt_type = h->sps.poc_type; -+ pic_descriptor->avc_log2_max_pic_order_cnt_lsb_minus4 = h->sps.log2_max_poc_lsb - 4; -+ pic_descriptor->avc_num_ref_frames = h->sps.ref_frame_count; -+ pic_descriptor->avc_reserved_8bit = 0; -+ -+ pic_descriptor->avc_num_slice_groups_minus1 = h->pps.slice_group_count - 1; -+ pic_descriptor->avc_num_ref_idx_l0_active_minus1 = h->pps.ref_count[0] - 1; -+ pic_descriptor->avc_num_ref_idx_l1_active_minus1 = h->pps.ref_count[1] - 1; -+ -+ pic_descriptor->avc_pic_init_qp_minus26 = h->pps.init_qp - 26; -+ pic_descriptor->avc_pic_init_qs_minus26 = h->pps.init_qs - 26; -+ pic_descriptor->avc_chroma_qp_index_offset = h->pps.chroma_qp_index_offset[0]; -+ pic_descriptor->avc_second_chroma_qp_index_offset = h->pps.chroma_qp_index_offset[1]; -+ pic_descriptor->avc_slice_group_change_rate_minus1 = 0; // not implemented in ffmpeg -+ pic_descriptor->avc_reserved_16bit = 0; // must be 0 -+ memset(pic_descriptor->avc_field_order_cnt_list,0,sizeof(pic_descriptor->avc_field_order_cnt_list)); // must be 0 -+ memset(pic_descriptor->avc_slice_group_map,0,sizeof(pic_descriptor->avc_slice_group_map)); // must be 0 -+ -+ // sps -+ pic_descriptor->sps_info.avc.delta_pic_always_zero_flag = h->sps.delta_pic_order_always_zero_flag; -+ pic_descriptor->sps_info.avc.direct_8x8_inference_flag = h->sps.direct_8x8_inference_flag; -+ pic_descriptor->sps_info.avc.frame_mbs_only_flag = h->sps.frame_mbs_only_flag; -+ pic_descriptor->sps_info.avc.gaps_in_frame_num_value_allowed_flag = h->sps.gaps_in_frame_num_allowed_flag; -+ pic_descriptor->sps_info.avc.mb_adaptive_frame_field_flag = h->sps.mb_aff; -+ pic_descriptor->sps_info.avc.residual_colour_transform_flag = h->sps.residual_color_transform_flag; -+ pic_descriptor->sps_info.avc.xvba_avc_sps_reserved = 0; -+ -+ // pps -+ pic_descriptor->pps_info.avc.entropy_coding_mode_flag = h->pps.cabac; -+ pic_descriptor->pps_info.avc.pic_order_present_flag = h->pps.pic_order_present; -+ pic_descriptor->pps_info.avc.weighted_pred_flag = h->pps.weighted_pred; -+ pic_descriptor->pps_info.avc.weighted_bipred_idc = h->pps.weighted_bipred_idc; -+ pic_descriptor->pps_info.avc.deblocking_filter_control_present_flag = h->pps.deblocking_filter_parameters_present; -+ pic_descriptor->pps_info.avc.constrained_intra_pred_flag = h->pps.constrained_intra_pred; -+ pic_descriptor->pps_info.avc.redundant_pic_cnt_present_flag = h->pps.redundant_pic_cnt_present; -+ pic_descriptor->pps_info.avc.transform_8x8_mode_flag = h->pps.transform_8x8_mode; -+ pic_descriptor->pps_info.avc.xvba_avc_pps_reserved = 0; // must be 0 -+ -+ memcpy(iq_matrix->bScalingLists4x4, h->pps.scaling_matrix4, sizeof(iq_matrix->bScalingLists4x4)); -+ memcpy(iq_matrix->bScalingLists8x8, h->pps.scaling_matrix8, sizeof(iq_matrix->bScalingLists8x8)); -+ -+ // Wait for an I-frame before start decoding. Workaround for ATI UVD and UVD+ GPUs -+ if (!h->got_first_iframe) { -+ if (h->slice_type != FF_I_TYPE && h->slice_type != FF_SI_TYPE) -+ return -1; -+ h->got_first_iframe = 1; -+ } -+ -+ ff_draw_horiz_band(s, 0, s->avctx->height); -+ -+ return 0; -+} -+ -+/** Decode the given H.264 slice with VA API. */ -+static int decode_slice(AVCodecContext *avctx, -+ const uint8_t *buffer, -+ uint32_t size) -+{ -+ H264Context * const h = avctx->priv_data; -+ MpegEncContext * const s = &h->s; -+ struct xvba_render_state *render; -+ -+ render = (struct xvba_render_state *)s->current_picture_ptr->data[0]; -+ assert(render); -+ -+ ff_xvba_add_slice_data(render, buffer, size); -+ -+ return 0; -+} -+ -+AVHWAccel ff_h264_xvba_hwaccel = { -+ .name = "h264_xvba", -+ .type = AVMEDIA_TYPE_VIDEO, -+ .id = CODEC_ID_H264, -+ .pix_fmt = PIX_FMT_XVBA_VLD, -+ .capabilities = 0, -+ .start_frame = start_frame, -+ .end_frame = end_frame, -+ .decode_slice = decode_slice, -+ .priv_data_size = 0, -+}; -diff --git a/lib/ffmpeg/libavcodec/xvba_internal.h b/lib/ffmpeg/libavcodec/xvba_internal.h -new file mode 100644 -index 0000000..9653f85 ---- /dev/null -+++ b/lib/ffmpeg/libavcodec/xvba_internal.h -@@ -0,0 +1,24 @@ -+/* -+ * HW decode acceleration for MPEG-2, H.264 and VC-1 -+ * -+ * Copyright (C) 2005-2011 Team XBMC -+ * -+ * This file is part of FFmpeg. -+ * -+ * FFmpeg is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU Lesser General Public -+ * License as published by the Free Software Foundation; either -+ * version 2.1 of the License, or (at your option) any later version. -+ * -+ * FFmpeg 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 -+ * Lesser General Public License for more details. -+ * -+ * You should have received a copy of the GNU Lesser General Public -+ * License along with FFmpeg; if not, write to the Free Software -+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -+ */ -+ -+int ff_xvba_translate_profile(int profile); -+void ff_xvba_add_slice_data(struct xvba_render_state *render, const uint8_t *buffer, uint32_t size); -diff --git a/lib/ffmpeg/libavcodec/xvba_mpeg2.c b/lib/ffmpeg/libavcodec/xvba_mpeg2.c -new file mode 100644 -index 0000000..552ef95 ---- /dev/null -+++ b/lib/ffmpeg/libavcodec/xvba_mpeg2.c -@@ -0,0 +1,52 @@ -+/* -+ * MPEG-2 HW decode acceleration through XVBA -+ * -+ * Copyright (C) 2005-2011 Team XBMC -+ * -+ * This file is part of FFmpeg. -+ * -+ * FFmpeg is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU Lesser General Public -+ * License as published by the Free Software Foundation; either -+ * version 2.1 of the License, or (at your option) any later version. -+ * -+ * FFmpeg 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 -+ * Lesser General Public License for more details. -+ * -+ * You should have received a copy of the GNU Lesser General Public -+ * License along with FFmpeg; if not, write to the Free Software -+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -+ */ -+ -+#include "dsputil.h" -+ -+static int start_frame(AVCodecContext *avctx, av_unused const uint8_t *buffer, av_unused uint32_t size) -+{ -+ struct MpegEncContext * const s = avctx->priv_data; -+ return 0; -+} -+ -+static int end_frame(AVCodecContext *avctx) -+{ -+ return 0; -+} -+ -+static int decode_slice(AVCodecContext *avctx, const uint8_t *buffer, uint32_t size) -+{ -+ struct MpegEncContext * const s = avctx->priv_data; -+ return 0; -+} -+ -+AVHWAccel ff_mpeg2_xvba_hwaccel = { -+ .name = "mpeg2_xvba", -+ .type = AVMEDIA_TYPE_VIDEO, -+ .id = CODEC_ID_MPEG2VIDEO, -+ .pix_fmt = PIX_FMT_XVBA_VLD, -+ .capabilities = 0, -+ .start_frame = start_frame, -+ .end_frame = end_frame, -+ .decode_slice = decode_slice, -+ .priv_data_size = 0, -+}; -diff --git a/lib/ffmpeg/libavcodec/xvba_vc1.c b/lib/ffmpeg/libavcodec/xvba_vc1.c -new file mode 100644 -index 0000000..e7b9211 ---- /dev/null -+++ b/lib/ffmpeg/libavcodec/xvba_vc1.c -@@ -0,0 +1,194 @@ -+/* -+ * VC-1 HW decode acceleration through XVBA -+ * -+ * Copyright (C) 2005-2011 Team XBMC -+ * -+ * This file is part of FFmpeg. -+ * -+ * FFmpeg is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU Lesser General Public -+ * License as published by the Free Software Foundation; either -+ * version 2.1 of the License, or (at your option) any later version. -+ * -+ * FFmpeg 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 -+ * Lesser General Public License for more details. -+ * -+ * You should have received a copy of the GNU Lesser General Public -+ * License along with FFmpeg; if not, write to the Free Software -+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -+ */ -+ -+#include "xvba.h" -+#include "xvba_internal.h" -+#include "vc1.h" -+#include "vc1data.h" -+#include -+ -+ -+/** @file -+ * Implement structures of ffmpeg <-> XvBA -+ */ -+ -+/* Initialize and start decoding a frame with XvBA */ -+static int start_frame(AVCodecContext *avctx, -+ av_unused const uint8_t *buffer, -+ av_unused uint32_t size) -+{ -+ VC1Context * const v = avctx->priv_data; -+ MpegEncContext * const s = &v->s; -+ struct xvba_render_state *render; -+ -+ render = (struct xvba_render_state *)s->current_picture_ptr->data[0]; -+ assert(render); -+ -+ render->num_slices = 0; -+ return 0; -+} -+ -+/* End a hardware decoding based frame */ -+static int end_frame(AVCodecContext *avctx) -+{ -+ VC1Context* const v = avctx->priv_data; -+ MpegEncContext* const s = &v->s; -+ struct xvba_render_state *render, *last, *next; -+ XVBAPictureDescriptor *pic_descriptor; -+ -+ render = (struct xvba_render_state *)s->current_picture_ptr->data[0]; -+ assert(render); -+ -+ if (render->picture_descriptor == 0) -+ return -1; -+ -+ pic_descriptor = render->picture_descriptor; -+ -+ av_dlog(avctx, "xvba_vc1_end_frame()\n"); -+ -+ memset(pic_descriptor, 0, sizeof(*pic_descriptor)); -+ -+ /* Fill in Parameters - for reference see AMD sdk documentation */ -+ pic_descriptor->profile = ff_xvba_translate_profile(v->profile); -+ pic_descriptor->level = v->level; -+ //done like in va-driver and vaapi -+ if (v->profile == PROFILE_ADVANCED) { -+ pic_descriptor->width_in_mb = s->avctx->coded_width; -+ pic_descriptor->height_in_mb = s->avctx->coded_height; -+ } else { -+ pic_descriptor->width_in_mb = s->mb_width; -+ pic_descriptor->height_in_mb = s->mb_height; -+ } -+ pic_descriptor->picture_structure = s->picture_structure; -+ // xvba-video set this to 1 only 4:2:0 supported -+ // doc says: if not set, choose 1 - we try this -+ pic_descriptor->chroma_format = 1; -+ pic_descriptor->avc_intra_flag = s->pict_type == FF_I_TYPE || v->bi_type == 1; -+ pic_descriptor->avc_reference = (s->current_picture_ptr->reference & 3) ? 1 : 0; -+ -+ // VC-1 explicit parameters see page 30 of sdk -+ // sps_info -+ pic_descriptor->sps_info.vc1.postprocflag = v->postprocflag; -+ -+ // done as in vaapi -+ pic_descriptor->sps_info.vc1.pulldown = v->broadcast; -+ pic_descriptor->sps_info.vc1.interlace = v->interlace; -+ pic_descriptor->sps_info.vc1.tfcntrflag = v->tfcntrflag; -+ pic_descriptor->sps_info.vc1.finterpflag = v->finterpflag; -+ pic_descriptor->sps_info.vc1.reserved = 1; -+ // eventually check if this makes sense together with interlace -+ pic_descriptor->sps_info.vc1.psf = v->psf; -+ // what about if it is a frame (page 31) -+ // looked at xvba-driver -+ pic_descriptor->sps_info.vc1.second_field = !s->first_field; -+ pic_descriptor->sps_info.vc1.xvba_vc1_sps_reserved = 0; -+ -+ // VC-1 explicit parameters see page 30 of sdk -+ // pps_info -+ pic_descriptor->pps_info.vc1.panscan_flag = v->panscanflag; -+ pic_descriptor->pps_info.vc1.refdist_flag = v->refdist_flag; -+ pic_descriptor->pps_info.vc1.loopfilter = s->loop_filter; -+ pic_descriptor->pps_info.vc1.fastuvmc = v->fastuvmc; -+ pic_descriptor->pps_info.vc1.extended_mv = v->extended_mv; -+ pic_descriptor->pps_info.vc1.dquant = v->dquant; -+ pic_descriptor->pps_info.vc1.vstransform = v->vstransform; -+ pic_descriptor->pps_info.vc1.overlap = v->overlap; -+ pic_descriptor->pps_info.vc1.quantizer = v->quantizer_mode; -+ pic_descriptor->pps_info.vc1.extended_dmv = v->extended_dmv; -+ pic_descriptor->pps_info.vc1.maxbframes = s->avctx->max_b_frames; -+ pic_descriptor->pps_info.vc1.rangered = (pic_descriptor->profile == PROFILE_SIMPLE) ? 0 : v->rangered; -+ pic_descriptor->pps_info.vc1.syncmarker = (pic_descriptor->profile == PROFILE_SIMPLE) ? 0 : s->resync_marker; -+ pic_descriptor->pps_info.vc1.multires = v->multires; -+ pic_descriptor->pps_info.vc1.reserved = 1; -+ pic_descriptor->pps_info.vc1.range_mapy_flag = v->range_mapy_flag; -+ pic_descriptor->pps_info.vc1.range_mapy = v->range_mapy; -+ pic_descriptor->pps_info.vc1.range_mapuv_flag = v->range_mapuv_flag; -+ pic_descriptor->pps_info.vc1.range_mapuv = v->range_mapuv; -+ pic_descriptor->pps_info.vc1.xvba_vc1_pps_reserved = 0; -+ -+ pic_descriptor->past_surface = 0; -+ pic_descriptor->future_surface = 0; -+ switch (s->pict_type) { -+ case FF_B_TYPE: -+ next = (struct xvba_render_state *)s->next_picture.data[0]; -+ assert(next); -+ if (next) -+ pic_descriptor->past_surface = next->surface; -+ // fall-through -+ case FF_P_TYPE: -+ last = (struct xvba_render_state *)s->last_picture.data[0]; -+ assert(last); -+ if (last) -+ pic_descriptor->future_surface = last->surface; -+ break; -+ } -+ -+ ff_draw_horiz_band(s, 0, s->avctx->height); -+ -+ return 0; -+} -+ -+static int decode_slice(AVCodecContext *avctx, const uint8_t *buffer, uint32_t size) -+{ -+ VC1Context* const v = avctx->priv_data; -+ MpegEncContext* const s = &v->s; -+ struct xvba_render_state *render; -+ -+ render = (struct xvba_render_state *)s->current_picture_ptr->data[0]; -+ assert(render); -+ -+ if (avctx->codec_id == CODEC_ID_VC1 && -+ size >= 4 && IS_MARKER(AV_RB32(buffer))) { -+ buffer += 4; -+ size -= 4; -+ } -+ -+ ff_xvba_add_slice_data(render, buffer, size); -+ -+ return 0; -+} -+ -+#if CONFIG_WMV3_XVBA_HWACCEL -+AVHWAccel ff_wmv3_xvba_hwaccel = { -+ .name = "wmv3_xvba", -+ .type = AVMEDIA_TYPE_VIDEO, -+ .id = CODEC_ID_WMV3, -+ .pix_fmt = PIX_FMT_XVBA_VLD, -+ .capabilities = 0, -+ .start_frame = start_frame, -+ .end_frame = end_frame, -+ .decode_slice = decode_slice, -+ .priv_data_size = 0, -+}; -+#endif -+ -+AVHWAccel ff_vc1_xvba_hwaccel = { -+ .name = "vc1_xvba", -+ .type = AVMEDIA_TYPE_VIDEO, -+ .id = CODEC_ID_VC1, -+ .pix_fmt = PIX_FMT_XVBA_VLD, -+ .capabilities = 0, -+ .start_frame = start_frame, -+ .end_frame = end_frame, -+ .decode_slice = decode_slice, -+ .priv_data_size = 0, -+}; -diff --git a/lib/ffmpeg/libavcodec/xvmc_internal.h b/lib/ffmpeg/libavcodec/xvmc_internal.h -index 9bb8909..a64d6ee 100644 ---- a/lib/ffmpeg/libavcodec/xvmc_internal.h -+++ b/lib/ffmpeg/libavcodec/xvmc_internal.h -@@ -1,5 +1,7 @@ - /* -- * XVideo Motion Compensation internal functions -+ * HW decode acceleration for MPEG-2, H.264 and VC-1 -+ * -+ * Copyright (C) 2005-2011 Team XBMC - * - * This file is part of FFmpeg. - * -diff --git a/lib/ffmpeg/libavutil/pixdesc.c b/lib/ffmpeg/libavutil/pixdesc.c -index 83aa8b0..fcc20d0 100644 ---- a/lib/ffmpeg/libavutil/pixdesc.c -+++ b/lib/ffmpeg/libavutil/pixdesc.c -@@ -717,6 +717,12 @@ const AVPixFmtDescriptor av_pix_fmt_descriptors[PIX_FMT_NB] = { - .log2_chroma_h = 1, - .flags = PIX_FMT_HWACCEL, - }, -+ [PIX_FMT_XVBA_VLD] = { -+ .name = "xvba_vld", -+ .log2_chroma_w = 1, -+ .log2_chroma_h = 1, -+ .flags = PIX_FMT_HWACCEL, -+ }, - [PIX_FMT_YUV420P16LE] = { - .name = "yuv420p16le", - .nb_components= 3, -diff --git a/lib/ffmpeg/libavutil/pixfmt.h b/lib/ffmpeg/libavutil/pixfmt.h -index 8ec91c8..4803dd7 100644 ---- a/lib/ffmpeg/libavutil/pixfmt.h -+++ b/lib/ffmpeg/libavutil/pixfmt.h -@@ -127,6 +127,7 @@ enum PixelFormat { - PIX_FMT_YUV444P16BE, ///< planar YUV 4:4:4, 48bpp, (1 Cr & Cb sample per 1x1 Y samples), big-endian - PIX_FMT_VDPAU_MPEG4, ///< MPEG4 HW decoding with VDPAU, data[0] contains a vdpau_render_state struct which contains the bitstream of the slices as well as various fields extracted from headers - PIX_FMT_DXVA2_VLD, ///< HW decoding through DXVA2, Picture.data[3] contains a LPDIRECT3DSURFACE9 pointer -+ PIX_FMT_XVBA_VLD, ///< HW decoding through DXVA2, Picture.data[3] contains a vaapi_render_state struct which contains the bitstream of the slices as well as various fields extracted from headers - - PIX_FMT_RGB444BE, ///< packed RGB 4:4:4, 16bpp, (msb)4A 4R 4G 4B(lsb), big-endian, most significant bits to 0 - PIX_FMT_RGB444LE, ///< packed RGB 4:4:4, 16bpp, (msb)4A 4R 4G 4B(lsb), little-endian, most significant bits to 0 -diff --git a/xbmc/Application.cpp b/xbmc/Application.cpp -index 3dc3d47..7ff943e 100644 -diff --git a/xbmc/ApplicationMessenger.cpp b/xbmc/ApplicationMessenger.cpp -index 14c1802..8173e99 100644 ---- a/xbmc/ApplicationMessenger.cpp -+++ b/xbmc/ApplicationMessenger.cpp -@@ -75,7 +75,7 @@ - - using namespace std; - --CDelayedMessage::CDelayedMessage(ThreadMessage& msg, unsigned int delay) -+CDelayedMessage::CDelayedMessage(ThreadMessage& msg, unsigned int delay) : CThread("CDelayedMessage") - { - m_msg.dwMessage = msg.dwMessage; - m_msg.dwParam1 = msg.dwParam1; -diff --git a/xbmc/cdrip/CDDAReader.cpp b/xbmc/cdrip/CDDAReader.cpp -index 16fa7b6..6c242d8 100644 ---- a/xbmc/cdrip/CDDAReader.cpp -+++ b/xbmc/cdrip/CDDAReader.cpp -@@ -29,7 +29,7 @@ - - #define SECTOR_COUNT 52 - --CCDDAReader::CCDDAReader() -+CCDDAReader::CCDDAReader() : CThread("CCDDAReader") - { - m_sRipBuffer[0].pbtStream = NULL; - m_sRipBuffer[1].pbtStream = NULL; -diff --git a/xbmc/cores/DllLoader/exports/emu_kernel32.cpp b/xbmc/cores/DllLoader/exports/emu_kernel32.cpp -index 13a23e2..493d64d 100644 ---- a/xbmc/cores/DllLoader/exports/emu_kernel32.cpp -+++ b/xbmc/cores/DllLoader/exports/emu_kernel32.cpp -@@ -240,15 +240,6 @@ extern "C" DWORD WINAPI dllGetCurrentProcessId(void) - #endif - } - --extern "C" BOOL WINAPI dllGetProcessTimes(HANDLE hProcess, LPFILETIME lpCreationTime, LPFILETIME lpExitTime, LPFILETIME lpKernelTime, LPFILETIME lpUserTime) --{ -- // since the xbox has only one process, we just take the current thread -- HANDLE h = GetCurrentThread(); -- BOOL res = GetThreadTimes(h, lpCreationTime, lpExitTime, lpKernelTime, lpUserTime); -- -- return res; --} -- - extern "C" int WINAPI dllDuplicateHandle(HANDLE hSourceProcessHandle, // handle to source process - HANDLE hSourceHandle, // handle to duplicate - HANDLE hTargetProcessHandle, // handle to target process -diff --git a/xbmc/cores/DllLoader/exports/emu_kernel32.h b/xbmc/cores/DllLoader/exports/emu_kernel32.h -index 2e637a7..9cc2f0b 100644 ---- a/xbmc/cores/DllLoader/exports/emu_kernel32.h -+++ b/xbmc/cores/DllLoader/exports/emu_kernel32.h -@@ -686,7 +686,6 @@ extern "C" BOOL WINAPI dllGetProcessAffinityMask(HANDLE hProcess, LPDWORD lpProc - - extern "C" HGLOBAL WINAPI dllLoadResource(HMODULE module, HRSRC res); - extern "C" HRSRC WINAPI dllFindResourceA(HMODULE module, LPCTSTR name, LPCTSTR type); --extern "C" BOOL WINAPI dllGetProcessTimes(HANDLE hProcess, LPFILETIME lpCreationTime, LPFILETIME lpExitTime, LPFILETIME lpKernelTime, LPFILETIME lpUserTime); - extern "C" int WINAPI dllGetLocaleInfoA(LCID Locale, LCTYPE LCType, LPTSTR lpLCData, int cchData); - extern "C" UINT WINAPI dllGetConsoleCP(); - extern "C" UINT WINAPI dllGetConsoleOutputCP(); -diff --git a/xbmc/cores/DummyVideoPlayer.cpp b/xbmc/cores/DummyVideoPlayer.cpp -index f0b4aeb..47d25e4 100644 ---- a/xbmc/cores/DummyVideoPlayer.cpp -+++ b/xbmc/cores/DummyVideoPlayer.cpp -@@ -33,7 +33,7 @@ - - CDummyVideoPlayer::CDummyVideoPlayer(IPlayerCallback& callback) - : IPlayer(callback), -- CThread() -+ CThread("CDummyVideoPlayer") - { - m_paused = false; - m_clock = 0; -diff --git a/xbmc/cores/VideoRenderers/LinuxRendererGL.cpp b/xbmc/cores/VideoRenderers/LinuxRendererGL.cpp -index 8172750..77e4855 100644 ---- a/xbmc/cores/VideoRenderers/LinuxRendererGL.cpp -+++ b/xbmc/cores/VideoRenderers/LinuxRendererGL.cpp -@@ -61,6 +61,9 @@ - VA_MICRO_VERSION == 0 && VA_SDS_VERSION < 5))) - - #endif -+#ifdef HAVE_LIBXVBA -+#include "cores/dvdplayer/DVDCodecs/Video/XVBA.h" -+#endif - - #ifdef HAS_GLX - #include -@@ -121,6 +124,10 @@ CLinuxRendererGL::YUVBUFFER::YUVBUFFER() - #ifdef HAVE_LIBVDPAU - vdpau = NULL; - #endif -+#ifdef HAVE_LIBXVBA -+ xvba = NULL; -+ xvba_tmp = NULL; -+#endif - } - - CLinuxRendererGL::YUVBUFFER::~YUVBUFFER() -@@ -160,6 +167,7 @@ CLinuxRendererGL::CLinuxRendererGL() - m_rgbPbo = 0; - - m_dllSwScale = new DllSwScale; -+ m_bValidated = false; - } - - CLinuxRendererGL::~CLinuxRendererGL() -@@ -224,7 +232,7 @@ bool CLinuxRendererGL::ValidateRenderer() - - void CLinuxRendererGL::ManageTextures() - { -- m_NumYV12Buffers = 2; -+ m_NumYV12Buffers = 3; - //m_iYV12RenderBuffer = 0; - return; - } -@@ -241,6 +249,11 @@ bool CLinuxRendererGL::ValidateRenderTarget() - else - CLog::Log(LOGNOTICE,"Using GL_TEXTURE_2D"); - -+ // function pointer for texture might change in -+ // call to LoadShaders -+ for (int i = 0 ; i < m_NumYV12Buffers ; i++) -+ (this->*m_textureDelete)(i); -+ - // create the yuv textures - LoadShaders(); - -@@ -569,6 +582,11 @@ void CLinuxRendererGL::Flush() - m_bValidated = false; - } - -+unsigned int CLinuxRendererGL::GetProcessorSize() -+{ -+ return m_NumYV12Buffers; -+} -+ - void CLinuxRendererGL::Update(bool bPauseDrawing) - { - if (!m_bConfigured) return; -@@ -730,14 +748,15 @@ unsigned int CLinuxRendererGL::PreInit() - { - CSingleLock lock(g_graphicsContext); - m_bConfigured = false; -- m_bValidated = false; -- UnInit(); -+ if (m_bValidated) -+ UnInit(); -+ - m_resolution = g_guiSettings.m_LookAndFeelResolution; - if ( m_resolution == RES_WINDOW ) - m_resolution = RES_DESKTOP; - - m_iYV12RenderBuffer = 0; -- m_NumYV12Buffers = 2; -+ m_NumYV12Buffers = 3; - - // setup the background colour - m_clearColour = (float)(g_advancedSettings.m_videoBlackBarColour & 0xff) / 0xff; -@@ -817,7 +836,7 @@ void CLinuxRendererGL::UpdateVideoFilter() - case VS_SCALINGMETHOD_LINEAR: - SetTextureFilter(m_scalingMethod == VS_SCALINGMETHOD_NEAREST ? GL_NEAREST : GL_LINEAR); - m_renderQuality = RQ_SINGLEPASS; -- if (((m_renderMethod & RENDER_VDPAU) || (m_renderMethod & RENDER_VAAPI)) && m_nonLinStretch) -+ if (((m_renderMethod & RENDER_VDPAU) || (m_renderMethod & RENDER_VAAPI) || (m_renderMethod & RENDER_XVBA)) && m_nonLinStretch) - { - m_pVideoFilterShader = new StretchFilterShader(); - if (!m_pVideoFilterShader->CompileAndLink()) -@@ -898,6 +917,11 @@ void CLinuxRendererGL::LoadShaders(int field) - CLog::Log(LOGNOTICE, "GL: Using VAAPI render method"); - m_renderMethod = RENDER_VAAPI; - } -+ else if (CONF_FLAGS_FORMAT_MASK(m_iFlags) == CONF_FLAGS_FORMAT_XVBA) -+ { -+ CLog::Log(LOGNOTICE, "GL: Using XVBA render method"); -+ m_renderMethod = RENDER_XVBA; -+ } - else - { - int requestedMethod = g_guiSettings.GetInt("videoplayer.rendermethod"); -@@ -1032,6 +1056,18 @@ void CLinuxRendererGL::LoadShaders(int field) - m_textureCreate = &CLinuxRendererGL::CreateVAAPITexture; - m_textureDelete = &CLinuxRendererGL::DeleteVAAPITexture; - } -+ else if (CONF_FLAGS_FORMAT_MASK(m_iFlags) == CONF_FLAGS_FORMAT_XVBA) -+ { -+ m_textureUpload = &CLinuxRendererGL::UploadXVBATexture; -+ m_textureCreate = &CLinuxRendererGL::CreateXVBATexture; -+ m_textureDelete = &CLinuxRendererGL::DeleteXVBATexture; -+ } -+ else if (CONF_FLAGS_FORMAT_MASK(m_iFlags) == CONF_FLAGS_FORMAT_XVBA_YV12) -+ { -+ m_textureUpload = &CLinuxRendererGL::UploadXVBAyv12Texture; -+ m_textureCreate = &CLinuxRendererGL::CreateXVBAyv12Texture; -+ m_textureDelete = &CLinuxRendererGL::DeleteXVBAyv12Texture; -+ } - else - { - // setup default YV12 texture handlers -@@ -1125,6 +1161,13 @@ void CLinuxRendererGL::Render(DWORD flags, int renderBuffer) - RenderVDPAU(renderBuffer, m_currentField); - } - #endif -+#ifdef HAVE_LIBXVBA -+ else if (m_renderMethod & RENDER_XVBA) -+ { -+ UpdateVideoFilter(); -+ RenderXVBA(renderBuffer, m_currentField); -+ } -+#endif - #ifdef HAVE_LIBVA - else if (m_renderMethod & RENDER_VAAPI) - { -@@ -1598,6 +1641,77 @@ void CLinuxRendererGL::RenderVAAPI(int index, int field) - #endif - } - -+void CLinuxRendererGL::RenderXVBA(int index, int field) -+{ -+#ifdef HAVE_LIBXVBA -+ YUVPLANE &plane = m_buffers[index].fields[field][0]; -+ -+ glEnable(m_textureTarget); -+ glActiveTextureARB(GL_TEXTURE0); -+ glBindTexture(m_textureTarget, plane.id); -+ -+ // Try some clamping or wrapping -+ glTexParameteri(m_textureTarget, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); -+ glTexParameteri(m_textureTarget, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); -+ -+ if (m_pVideoFilterShader) -+ { -+ GLint filter; -+ if (!m_pVideoFilterShader->GetTextureFilter(filter)) -+ filter = m_scalingMethod == VS_SCALINGMETHOD_NEAREST ? GL_NEAREST : GL_LINEAR; -+ -+ glTexParameteri(m_textureTarget, GL_TEXTURE_MAG_FILTER, filter); -+ glTexParameteri(m_textureTarget, GL_TEXTURE_MIN_FILTER, filter); -+ m_pVideoFilterShader->SetSourceTexture(0); -+ m_pVideoFilterShader->SetWidth(m_sourceWidth); -+ m_pVideoFilterShader->SetHeight(m_sourceHeight); -+ -+ //disable non-linear stretch when a dvd menu is shown, parts of the menu are rendered through the overlay renderer -+ //having non-linear stretch on breaks the alignment -+ if (g_application.m_pPlayer && g_application.m_pPlayer->IsInMenu()) -+ m_pVideoFilterShader->SetNonLinStretch(1.0); -+ else -+ m_pVideoFilterShader->SetNonLinStretch(pow(g_settings.m_fPixelRatio, g_advancedSettings.m_videoNonLinStretchRatio)); -+ -+ m_pVideoFilterShader->Enable(); -+ } -+ else -+ { -+ GLint filter = m_scalingMethod == VS_SCALINGMETHOD_NEAREST ? GL_NEAREST : GL_LINEAR; -+ glTexParameteri(m_textureTarget, GL_TEXTURE_MAG_FILTER, filter); -+ glTexParameteri(m_textureTarget, GL_TEXTURE_MIN_FILTER, filter); -+ } -+ -+ glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); -+ VerifyGLState(); -+ -+ glBegin(GL_QUADS); -+ if (m_textureTarget==GL_TEXTURE_2D) -+ { -+ glTexCoord2f(plane.rect.x1, plane.rect.y1); glVertex2f(m_destRect.x1, m_destRect.y1); -+ glTexCoord2f(plane.rect.x2, plane.rect.y1); glVertex2f(m_destRect.x2, m_destRect.y1); -+ glTexCoord2f(plane.rect.x2, plane.rect.y2); glVertex2f(m_destRect.x2, m_destRect.y2); -+ glTexCoord2f(plane.rect.x1, plane.rect.y2); glVertex2f(m_destRect.x1, m_destRect.y2); -+ } -+ else -+ { -+ glTexCoord2f(m_destRect.x1, m_destRect.y1); glVertex4f(m_destRect.x1, m_destRect.y1, 0.0f, 0.0f); -+ glTexCoord2f(m_destRect.x2, m_destRect.y1); glVertex4f(m_destRect.x2, m_destRect.y1, 1.0f, 0.0f); -+ glTexCoord2f(m_destRect.x2, m_destRect.y2); glVertex4f(m_destRect.x2, m_destRect.y2, 1.0f, 1.0f); -+ glTexCoord2f(m_destRect.x1, m_destRect.y2); glVertex4f(m_destRect.x1, m_destRect.y2, 0.0f, 1.0f); -+ } -+ glEnd(); -+ VerifyGLState(); -+ -+ if (m_pVideoFilterShader) -+ m_pVideoFilterShader->Disable(); -+ -+ glBindTexture (m_textureTarget, 0); -+ glDisable(m_textureTarget); -+#endif -+} -+ -+ - void CLinuxRendererGL::RenderSoftware(int index, int field) - { - YUVPLANES &planes = m_buffers[index].fields[field]; -@@ -2352,6 +2466,426 @@ void CLinuxRendererGL::UploadVAAPITexture(int index) - #endif - } - -+void CLinuxRendererGL::DeleteXVBATexture(int index) -+{ -+#ifdef HAVE_LIBXVBA -+ YUVPLANE &planeFallback = m_buffers[index].fields[0][1]; -+ YUVFIELDS &fields = m_buffers[index].fields; -+ -+ if (m_buffers[index].xvba) -+ m_buffers[index].xvba->FinishGL(); -+ -+ SAFE_RELEASE(m_buffers[index].xvba); -+ SAFE_RELEASE(m_buffers[index].xvba_tmp); -+ -+ if(planeFallback.id && glIsTexture(planeFallback.id)) -+ glDeleteTextures(1, &planeFallback.id); -+ planeFallback.id = 0; -+ fields[0][0].id = 0; -+ fields[1][0].id = 0; -+ fields[2][0].id = 0; -+#endif -+} -+ -+ -+bool CLinuxRendererGL::CreateXVBATexture(int index) -+{ -+#ifdef HAVE_LIBXVBA -+ YV12Image &im = m_buffers[index].image; -+ YUVFIELDS &fields = m_buffers[index].fields; -+ YUVPLANE &plane = fields[0][0]; -+ YUVPLANE &planeFallback = fields[0][1]; -+ -+ DeleteXVBATexture(index); -+ -+ memset(&im , 0, sizeof(im)); -+ memset(&fields, 0, sizeof(fields)); -+ im.height = m_sourceHeight; -+ im.width = m_sourceWidth; -+ -+ for(int f = 0;fSet(); -+#endif -+ return true; -+} -+ -+void CLinuxRendererGL::UploadXVBATexture(int index) -+{ -+#ifdef HAVE_LIBXVBA -+ XVBA::CDecoder *xvba = m_buffers[index].xvba; -+ -+ if (m_buffers[index].xvba_tmp) -+ { -+ SAFE_RELEASE(m_buffers[index].xvba); -+ xvba = m_buffers[index].xvba = m_buffers[index].xvba_tmp; -+ m_buffers[index].xvba_tmp = NULL; -+ } -+ -+ YUVFIELDS &fields = m_buffers[index].fields; -+ YUVPLANE &planeFallback = fields[0][1]; -+ YUVPLANE &plane = fields[m_currentField][0]; -+ -+ if (!xvba) -+ { -+ fields[0][0].id = planeFallback.id; -+ fields[1][0].id = planeFallback.id; -+ fields[2][0].id = planeFallback.id; -+ m_eventTexturesDone[index]->Set(); -+ return; -+ } -+ -+ XVBA_SURFACE_FLAG field; -+ if (m_currentField == FIELD_TOP) -+ field = XVBA_TOP_FIELD; -+ else if (m_currentField == FIELD_BOT) -+ field = XVBA_BOTTOM_FIELD; -+ else -+ field = XVBA_FRAME; -+ -+ glEnable(m_textureTarget); -+ if (xvba->UploadTexture(index, field, m_textureTarget) == 1) -+ plane.id = xvba->GetTexture(index, field); -+ -+ // crop texture -+ CRect crop = xvba->GetCropRect(); -+ plane.rect = m_sourceRect; -+ plane.rect.x1 += crop.x1; -+ plane.rect.x2 -= m_sourceWidth - crop.x2; -+ plane.rect.y1 += crop.y1; -+ plane.rect.y2 -= m_sourceHeight - crop.y2; -+ plane.rect.y1 /= plane.pixpertex_y; -+ plane.rect.y2 /= plane.pixpertex_y; -+ plane.rect.x1 /= plane.pixpertex_x; -+ plane.rect.x2 /= plane.pixpertex_x; -+ if (m_textureTarget == GL_TEXTURE_2D) -+ { -+ plane.rect.y1 /= plane.texheight; -+ plane.rect.y2 /= plane.texheight; -+ plane.rect.x1 /= plane.texwidth; -+ plane.rect.x2 /= plane.texwidth; -+ } -+ -+ glDisable(m_textureTarget); -+ -+ m_eventTexturesDone[index]->Set(); -+#endif -+} -+ -+//******************************************************************************************************** -+// XVBA YV12 Texture creation, deletion, copying + clearing -+//******************************************************************************************************** -+void CLinuxRendererGL::DeleteXVBAyv12Texture(int index) -+{ -+#ifdef HAVE_LIBXVBA -+ YV12Image &im = m_buffers[index].image; -+ YUVFIELDS &fields = m_buffers[index].fields; -+ GLuint *pbo = m_buffers[index].pbo; -+ -+ if (m_buffers[index].xvba) -+ m_buffers[index].xvba->FinishGL(); -+ -+ SAFE_RELEASE(m_buffers[index].xvba); -+ SAFE_RELEASE(m_buffers[index].xvba_tmp); -+ -+ if( fields[FIELD_FULL][0].id == 0 ) return; -+ -+ /* finish up all textures, and delete them */ -+ g_graphicsContext.BeginPaint(); //FIXME -+ for(int f = 0;f> im.cshift_x; -+ im.stride[2] = im.width >> im.cshift_x; -+ -+ im.planesize[0] = im.stride[0] * im.height; -+ im.planesize[1] = im.stride[1] * ( im.height >> im.cshift_y ); -+ im.planesize[2] = im.stride[2] * ( im.height >> im.cshift_y ); -+ -+ im.plane[1] = im.plane[2] = 0; -+ pbo[1] = pbo[2] = 0; -+ -+ bool pboSetup = false; -+ if (m_pboUsed) -+ { -+ pboSetup = true; -+ -+ glGenBuffersARB(1, pbo); -+ glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, pbo[0]); -+ glBufferDataARB(GL_PIXEL_UNPACK_BUFFER_ARB, im.planesize[0] + im.planesize[0]/2 + PBO_OFFSET, 0, GL_STREAM_DRAW_ARB); -+ void* pboPtr = glMapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, GL_WRITE_ONLY_ARB); -+ if (pboPtr) -+ { -+ im.plane[0] = (BYTE*) pboPtr + PBO_OFFSET; -+ memset(im.plane[0], 0, im.planesize[0]); -+ } -+ else -+ { -+ CLog::Log(LOGWARNING,"GL: failed to set up pixel buffer object"); -+ pboSetup = false; -+ } -+ -+ if (!pboSetup) -+ { -+ glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, pbo[0]); -+ glUnmapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB); -+ glDeleteBuffersARB(1, pbo); -+ memset(m_buffers[index].pbo, 0, sizeof(m_buffers[index].pbo)); -+ } -+ -+ glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0); -+ } -+ -+ if (!pboSetup) -+ { -+ im.plane[0] = new BYTE[im.planesize[0]+im.planesize[0]/2]; -+ } -+ -+ glEnable(m_textureTarget); -+ for(int f = 0;f> fieldshift; -+ -+ if (m_renderMethod & RENDER_SW) -+ { -+ planes[1].texwidth = 0; -+ planes[1].texheight = 0; -+ planes[2].texwidth = 0; -+ planes[2].texheight = 0; -+ } -+ else -+ { -+ planes[1].texwidth = planes[0].texwidth >> im.cshift_x; -+ planes[1].texheight = planes[0].texheight >> im.cshift_y; -+ planes[2].texwidth = planes[0].texwidth >> im.cshift_x; -+ planes[2].texheight = planes[0].texheight >> im.cshift_y; -+ } -+ -+ for (int p = 0; p < 3; p++) -+ { -+ planes[p].pixpertex_x = 1; -+ planes[p].pixpertex_y = 1; -+ } -+ -+ if(m_renderMethod & RENDER_POT) -+ { -+ for(int p = 0; p < 3; p++) -+ { -+ planes[p].texwidth = NP2(planes[p].texwidth); -+ planes[p].texheight = NP2(planes[p].texheight); -+ } -+ } -+ -+ for(int p = 0; p < 3; p++) -+ { -+ YUVPLANE &plane = planes[p]; -+ if (plane.texwidth * plane.texheight == 0) -+ continue; -+ -+ glBindTexture(m_textureTarget, plane.id); -+ if (m_renderMethod & RENDER_SW) -+ { -+ glTexImage2D(m_textureTarget, 0, GL_RGBA, plane.texwidth, plane.texheight, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, NULL); -+ } -+ else -+ { -+ GLint format; -+ if (p == 2) //V plane needs an alpha texture -+ format = GL_ALPHA; -+ else -+ format = GL_LUMINANCE; -+ -+ glTexImage2D(m_textureTarget, 0, format, plane.texwidth, plane.texheight, 0, format, GL_UNSIGNED_BYTE, NULL); -+ } -+ -+ glTexParameteri(m_textureTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR); -+ glTexParameteri(m_textureTarget, GL_TEXTURE_MAG_FILTER, GL_LINEAR); -+ glTexParameteri(m_textureTarget, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); -+ glTexParameteri(m_textureTarget, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); -+ VerifyGLState(); -+ } -+ } -+ glDisable(m_textureTarget); -+ m_eventTexturesDone[index]->Set(); -+#endif -+ return true; -+} -+ -+void CLinuxRendererGL::UploadXVBAyv12Texture(int source) -+{ -+#ifdef HAVE_LIBXVBA -+ YUVBUFFER& buf = m_buffers[source]; -+ YV12Image* im = &buf.image; -+ YUVFIELDS& fields = buf.fields; -+ XVBA::CDecoder *xvba = m_buffers[source].xvba; -+ -+ if (m_buffers[source].xvba_tmp) -+ { -+ SAFE_RELEASE(m_buffers[source].xvba); -+ xvba = m_buffers[source].xvba = m_buffers[source].xvba_tmp; -+ m_buffers[source].xvba_tmp = NULL; -+ } -+ -+ if (!(im->flags&IMAGE_FLAG_READY) || !xvba) -+ { -+ m_eventTexturesDone[source]->Set(); -+ return; -+ } -+ -+ bool deinterlacing; -+ if (m_currentField == FIELD_FULL) -+ deinterlacing = false; -+ else -+ deinterlacing = true; -+ -+ glEnable(m_textureTarget); -+ VerifyGLState(); -+ -+ glPixelStorei(GL_UNPACK_ALIGNMENT,1); -+ -+ if (deinterlacing) -+ { -+ // Load Even Y Field -+ LoadPlane( fields[FIELD_TOP][0] , GL_LUMINANCE, buf.flipindex -+ , im->width, im->height >> 1 -+ , im->stride[0]*2, im->plane[0] ); -+ -+ //load Odd Y Field -+ LoadPlane( fields[FIELD_BOT][0], GL_LUMINANCE, buf.flipindex -+ , im->width, im->height >> 1 -+ , im->stride[0]*2, im->plane[0] + im->stride[0], &buf.pbo[0] ) ; -+ -+ // Load Even U & V Fields -+ LoadPlane( fields[FIELD_TOP][1], GL_LUMINANCE, buf.flipindex -+ , im->width >> im->cshift_x, im->height >> (im->cshift_y + 1) -+ , im->stride[1]*2, im->plane[0] + im->planesize[0] + im->planesize[1], &buf.pbo[0] ); -+ -+ LoadPlane( fields[FIELD_TOP][2], GL_ALPHA, buf.flipindex -+ , im->width >> im->cshift_x, im->height >> (im->cshift_y + 1) -+ , im->stride[2]*2, im->plane[0] + im->planesize[0], &buf.pbo[0] ); -+ -+ // Load Odd U & V Fields -+ LoadPlane( fields[FIELD_BOT][1], GL_LUMINANCE, buf.flipindex -+ , im->width >> im->cshift_x, im->height >> (im->cshift_y + 1) -+ , im->stride[1]*2, im->plane[0] + im->stride[1] + im->planesize[0] + im->planesize[1], &buf.pbo[0] ); -+ -+ LoadPlane( fields[FIELD_BOT][2], GL_ALPHA, buf.flipindex -+ , im->width >> im->cshift_x, im->height >> (im->cshift_y + 1) -+ , im->stride[2]*2, im->plane[0] + im->stride[2] + im->planesize[0], &buf.pbo[0] ); -+ } -+ else -+ { -+ //Load Y plane -+ LoadPlane( fields[FIELD_FULL][0], GL_LUMINANCE, buf.flipindex -+ , im->width, im->height -+ , im->stride[0], im->plane[0], &buf.pbo[0] ); -+ -+ //load U plane -+ LoadPlane( fields[FIELD_FULL][1], GL_LUMINANCE, buf.flipindex -+ , im->width >> im->cshift_x, im->height >> im->cshift_y -+ , im->stride[1], im->plane[0] + im->planesize[0] + im->planesize[1] , &buf.pbo[0] ); -+ -+ //load V plane -+ LoadPlane( fields[FIELD_FULL][2], GL_ALPHA, buf.flipindex -+ , im->width >> im->cshift_x, im->height >> im->cshift_y -+ , im->stride[2], im->plane[0] + im->planesize[0], &buf.pbo[0] ); -+ } -+ -+ m_eventTexturesDone[source]->Set(); -+ -+ VerifyGLState(); -+ -+ // crop texture -+ CRect crop = xvba->GetCropRect(); -+ m_sourceRect.x1 += crop.x1; -+ m_sourceRect.x2 -= m_sourceWidth - crop.x2; -+ m_sourceRect.y1 += crop.y1; -+ m_sourceRect.y2 -= m_sourceHeight - crop.y2; -+ CalculateTextureSourceRects(source, 3); -+ -+ glDisable(m_textureTarget); -+#endif -+} -+ - void CLinuxRendererGL::UploadYUV422PackedTexture(int source) - { - YUVBUFFER& buf = m_buffers[source]; -@@ -2935,6 +3469,9 @@ bool CLinuxRendererGL::Supports(ERENDERFEATURE feature) - if (m_renderMethod & RENDER_VAAPI) - return false; - -+ if (m_renderMethod & RENDER_XVBA) -+ return false; -+ - return (m_renderMethod & RENDER_GLSL) - || (m_renderMethod & RENDER_ARB) - || ((m_renderMethod & RENDER_SW) && glewIsSupported("GL_ARB_imaging") == GL_TRUE); -@@ -2948,6 +3485,9 @@ bool CLinuxRendererGL::Supports(ERENDERFEATURE feature) - if (m_renderMethod & RENDER_VAAPI) - return false; - -+ if (m_renderMethod & RENDER_XVBA) -+ return false; -+ - return (m_renderMethod & RENDER_GLSL) - || (m_renderMethod & RENDER_ARB) - || ((m_renderMethod & RENDER_SW) && glewIsSupported("GL_ARB_imaging") == GL_TRUE); -@@ -2971,7 +3511,8 @@ bool CLinuxRendererGL::Supports(ERENDERFEATURE feature) - if (feature == RENDERFEATURE_NONLINSTRETCH) - { - if (((m_renderMethod & RENDER_GLSL) && !(m_renderMethod & RENDER_POT)) || -- (m_renderMethod & RENDER_VDPAU) || (m_renderMethod & RENDER_VAAPI)) -+ (m_renderMethod & RENDER_VDPAU) || (m_renderMethod & RENDER_VAAPI) || -+ (m_renderMethod & RENDER_XVBA)) - return true; - } - -@@ -3034,10 +3575,22 @@ bool CLinuxRendererGL::Supports(EINTERLACEMETHOD method) - return false; - #endif - -- if(method == VS_INTERLACEMETHOD_DEINTERLACE -- || method == VS_INTERLACEMETHOD_DEINTERLACE_HALF -- || method == VS_INTERLACEMETHOD_SW_BLEND) -- return true; -+ if (CONF_FLAGS_FORMAT_MASK(m_iFlags) != CONF_FLAGS_FORMAT_XVBA) -+ { -+ if(method == VS_INTERLACEMETHOD_DEINTERLACE -+ || method == VS_INTERLACEMETHOD_DEINTERLACE_HALF -+ || method == VS_INTERLACEMETHOD_SW_BLEND) -+ return true; -+ } -+ -+ if(m_renderMethod & RENDER_XVBA) -+ { -+ if (method == VS_INTERLACEMETHOD_RENDER_BOB_INVERTED -+ || method == VS_INTERLACEMETHOD_RENDER_BOB) -+ return true; -+ else -+ return false; -+ } - - if((method == VS_INTERLACEMETHOD_RENDER_BLEND - || method == VS_INTERLACEMETHOD_RENDER_WEAVE_INVERTED -@@ -3069,7 +3622,7 @@ bool CLinuxRendererGL::Supports(ESCALINGMETHOD method) - || method == VS_SCALINGMETHOD_LANCZOS3) - { - if ((glewIsSupported("GL_EXT_framebuffer_object") && (m_renderMethod & RENDER_GLSL)) || -- (m_renderMethod & RENDER_VDPAU) || (m_renderMethod & RENDER_VAAPI)) -+ (m_renderMethod & RENDER_VDPAU) || (m_renderMethod & RENDER_VAAPI) || (m_renderMethod & RENDER_XVBA)) - { - // spline36 and lanczos3 are only allowed through advancedsettings.xml - if(method != VS_SCALINGMETHOD_SPLINE36 -@@ -3128,7 +3681,7 @@ void CLinuxRendererGL::UnBindPbo(YUVBUFFER& buff) - pbo = true; - - glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, buff.pbo[plane]); -- glBufferDataARB(GL_PIXEL_UNPACK_BUFFER_ARB, buff.image.planesize[plane] + PBO_OFFSET, NULL, GL_STREAM_DRAW_ARB); -+ glBufferDataARB(GL_PIXEL_UNPACK_BUFFER_ARB, buff.image.planesize[plane] + buff.image.planesize[plane]/2 + PBO_OFFSET, NULL, GL_STREAM_DRAW_ARB); - buff.image.plane[plane] = (BYTE*)glMapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, GL_WRITE_ONLY_ARB) + PBO_OFFSET; - } - if(pbo) -@@ -3152,4 +3705,13 @@ void CLinuxRendererGL::AddProcessor(VAAPI::CHolder& holder) - } - #endif - -+#ifdef HAVE_LIBXVBA -+void CLinuxRendererGL::AddProcessor(XVBA::CDecoder* xvba) -+{ -+ YUVBUFFER &buf = m_buffers[NextYV12Texture()]; -+ SAFE_RELEASE(buf.xvba_tmp); -+ buf.xvba_tmp = (XVBA::CDecoder*)xvba->Acquire(); -+} -+#endif -+ - #endif -diff --git a/xbmc/cores/VideoRenderers/LinuxRendererGL.h b/xbmc/cores/VideoRenderers/LinuxRendererGL.h -index 38c84aa..ae0b81b 100644 ---- a/xbmc/cores/VideoRenderers/LinuxRendererGL.h -+++ b/xbmc/cores/VideoRenderers/LinuxRendererGL.h -@@ -40,6 +40,7 @@ class CBaseTexture; - namespace Shaders { class BaseYUV2RGBShader; } - namespace Shaders { class BaseVideoFilterShader; } - namespace VAAPI { struct CHolder; } -+namespace XVBA { class CDecoder; } - - #define NUM_BUFFERS 3 - -@@ -94,6 +95,7 @@ enum RenderMethod - RENDER_VDPAU=0x08, - RENDER_POT=0x10, - RENDER_VAAPI=0x20, -+ RENDER_XVBA=0x40, - }; - - enum RenderQuality -@@ -141,6 +143,7 @@ public: - virtual void UnInit(); - virtual void Reset(); /* resets renderer after seek for example */ - virtual void Flush(); -+ virtual unsigned int GetProcessorSize(); - - #ifdef HAVE_LIBVDPAU - virtual void AddProcessor(CVDPAU* vdpau); -@@ -148,6 +151,9 @@ public: - #ifdef HAVE_LIBVA - virtual void AddProcessor(VAAPI::CHolder& holder); - #endif -+#ifdef HAVE_LIBXVBA -+ virtual void AddProcessor(XVBA::CDecoder* xvba); -+#endif - - virtual void RenderUpdate(bool clear, DWORD flags = 0, DWORD alpha = 255); - -@@ -194,6 +200,14 @@ protected: - void DeleteVAAPITexture(int index); - bool CreateVAAPITexture(int index); - -+ void UploadXVBATexture(int index); -+ void DeleteXVBATexture(int index); -+ bool CreateXVBATexture(int index); -+ -+ void UploadXVBAyv12Texture(int index); -+ void DeleteXVBAyv12Texture(int index); -+ bool CreateXVBAyv12Texture(int index); -+ - void UploadYUV422PackedTexture(int index); - void DeleteYUV422PackedTexture(int index); - bool CreateYUV422PackedTexture(int index); -@@ -211,6 +225,7 @@ protected: - void RenderSoftware(int renderBuffer, int field); // single pass s/w yuv2rgb renderer - void RenderVDPAU(int renderBuffer, int field); // render using vdpau hardware - void RenderVAAPI(int renderBuffer, int field); // render using vdpau hardware -+ void RenderXVBA(int renderBuffer, int field); // render using xvba hardware - - CFrameBufferObject m_fbo; - -@@ -270,6 +285,10 @@ protected: - #ifdef HAVE_LIBVA - VAAPI::CHolder& vaapi; - #endif -+#ifdef HAVE_LIBXVBA -+ XVBA::CDecoder* xvba; -+ XVBA::CDecoder* xvba_tmp; -+#endif - }; - - typedef YUVBUFFER YUVBUFFERS[NUM_BUFFERS]; -diff --git a/xbmc/cores/VideoRenderers/RenderFlags.h b/xbmc/cores/VideoRenderers/RenderFlags.h -index f663380..cbe82c5 100644 ---- a/xbmc/cores/VideoRenderers/RenderFlags.h -+++ b/xbmc/cores/VideoRenderers/RenderFlags.h -@@ -79,5 +79,7 @@ - #define CONF_FLAGS_FORMAT_VAAPI 0x030000 - #define CONF_FLAGS_FORMAT_OMXEGL 0x040000 - #define CONF_FLAGS_FORMAT_CVBREF 0x080000 -+#define CONF_FLAGS_FORMAT_XVBA 0x011000 -+#define CONF_FLAGS_FORMAT_XVBA_YV12 0x012000 - #define CONF_FLAGS_FORMAT_BYPASS 0x100000 - #endif -diff --git a/xbmc/cores/VideoRenderers/RenderManager.cpp b/xbmc/cores/VideoRenderers/RenderManager.cpp -index b917860..10d116d 100644 ---- a/xbmc/cores/VideoRenderers/RenderManager.cpp -+++ b/xbmc/cores/VideoRenderers/RenderManager.cpp -@@ -53,6 +53,10 @@ - #include "../dvdplayer/DVDCodecs/Video/DVDVideoCodec.h" - #include "../dvdplayer/DVDCodecs/DVDCodecUtils.h" - -+#ifdef HAVE_LIBXVBA -+ #include "../dvdplayer/DVDCodecs/Video/XVBA.h" -+#endif -+ - #define MAXPRESENTDELAY 0.500 - - /* at any point we want an exclusive lock on rendermanager */ -@@ -791,6 +795,25 @@ int CXBMCRenderManager::AddVideoPicture(DVDVideoPicture& pic) - else if(pic.format == DVDVideoPicture::FMT_VAAPI) - m_pRenderer->AddProcessor(*pic.vaapi); - #endif -+#ifdef HAVE_LIBXVBA -+ else if(pic.format == DVDVideoPicture::FMT_XVBA) -+ { -+ if (pic.xvba) -+ { -+ m_pRenderer->AddProcessor(pic.xvba); -+ pic.xvba->Present(index); -+ } -+ } -+ else if(pic.format == DVDVideoPicture::FMT_XVBA_YV12) -+ { -+ if (pic.xvba) -+ { -+ m_pRenderer->AddProcessor(pic.xvba); -+ pic.xvba->Present(index); -+ pic.xvba->CopyYV12(index, image.plane[0]); -+ } -+ } -+#endif - m_pRenderer->ReleaseImage(index, false); - - return index; -diff --git a/xbmc/cores/VideoRenderers/VideoShaders/YUV2RGBShader.cpp b/xbmc/cores/VideoRenderers/VideoShaders/YUV2RGBShader.cpp -index fa9f68a..68f4008 100644 ---- a/xbmc/cores/VideoRenderers/VideoShaders/YUV2RGBShader.cpp -+++ b/xbmc/cores/VideoRenderers/VideoShaders/YUV2RGBShader.cpp -@@ -186,6 +186,8 @@ BaseYUV2RGBGLSLShader::BaseYUV2RGBGLSLShader(bool rect, unsigned flags, bool str - m_defines += "#define XBMC_YUY2\n"; - else if (CONF_FLAGS_FORMAT_MASK(flags) == CONF_FLAGS_FORMAT_UYVY) - m_defines += "#define XBMC_UYVY\n"; -+ if (CONF_FLAGS_FORMAT_MASK(flags) == CONF_FLAGS_FORMAT_XVBA_YV12) -+ m_defines += "#define XBMC_YV12\n"; - - VertexShader()->LoadSource("yuv2rgb_vertex.glsl", m_defines); - #elif HAS_GLES == 2 -diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/CrystalHD.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/CrystalHD.cpp -index ae107a6..1b8cd96 100644 ---- a/xbmc/cores/dvdplayer/DVDCodecs/Video/CrystalHD.cpp -+++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/CrystalHD.cpp -@@ -323,7 +323,7 @@ CPictureBuffer::~CPictureBuffer() - #pragma mark - - #endif - CMPCOutputThread::CMPCOutputThread(void *device, DllLibCrystalHD *dll, bool has_bcm70015) : -- CThread(), -+ CThread("CMPCOutputThread"), - m_dll(dll), - m_device(device), - m_has_bcm70015(has_bcm70015), -diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodec.h b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodec.h -index e4bd9c9..edc2fe1 100644 ---- a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodec.h -+++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodec.h -@@ -34,6 +34,7 @@ - - namespace DXVA { class CSurfaceContext; } - namespace VAAPI { struct CHolder; } -+namespace XVBA { class CDecoder; } - class CVDPAU; - class COpenMax; - class COpenMaxVideo; -@@ -64,6 +65,9 @@ struct DVDVideoPicture - struct { - VAAPI::CHolder* vaapi; - }; -+ struct { -+ XVBA::CDecoder* xvba; -+ }; - - struct { - COpenMax *openMax; -@@ -109,6 +113,8 @@ struct DVDVideoPicture - FMT_VAAPI, - FMT_OMXEGL, - FMT_CVBREF, -+ FMT_XVBA, -+ FMT_XVBA_YV12, - } format; - }; - -diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp -index b4e1451..374907f 100644 ---- a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp -+++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp -@@ -56,6 +56,9 @@ - #ifdef HAVE_LIBVA - #include "VAAPI.h" - #endif -+#ifdef HAVE_LIBXVBA -+#include "XVBA.h" -+#endif - - using namespace boost; - -@@ -100,6 +103,22 @@ enum PixelFormat CDVDVideoCodecFFmpeg::GetFormat( struct AVCodecContext * avctx - dec->Release(); - } - #endif -+#ifdef HAVE_LIBXVBA -+ if(*cur == PIX_FMT_XVBA_VLD && g_guiSettings.GetBool("videoplayer.usexvba")) -+ { -+ if(ctx->GetHardware()) -+ return *cur; -+ -+ XVBA::CDecoder* dec = new XVBA::CDecoder(); -+ if(dec->Open(avctx, *cur, ctx->m_uSurfacesCount)) -+ { -+ ctx->SetHardware(dec); -+ return *cur; -+ } -+ else -+ dec->Release(); -+ } -+#endif - #ifdef HAVE_LIBVA - // mpeg4 vaapi decoding is disabled - if(*cur == PIX_FMT_VAAPI_VLD && g_guiSettings.GetBool("videoplayer.usevaapi") -diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/Makefile.in b/xbmc/cores/dvdplayer/DVDCodecs/Video/Makefile.in -index 1dce256..8b7d5fb 100644 ---- a/xbmc/cores/dvdplayer/DVDCodecs/Video/Makefile.in -+++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/Makefile.in -@@ -17,6 +17,10 @@ SRCS+= CrystalHD.cpp \ - DVDVideoCodecCrystalHD.cpp \ - - endif -+ifeq (@USE_XVBA@,1) -+SRCS+= XVBA.cpp \ -+ -+endif - ifeq (@USE_VDA@,1) - SRCS+= DVDVideoCodecVDA.cpp \ - -diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/XVBA.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/XVBA.cpp -new file mode 100644 -index 0000000..1f4c4c8 ---- /dev/null -+++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/XVBA.cpp -@@ -0,0 +1,1419 @@ -+/* -+ * Copyright (C) 2005-2011 Team XBMC -+ * http://www.xbmc.org -+ * -+ * 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 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 XBMC; see the file COPYING. If not, write to -+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. -+ * http://www.gnu.org/copyleft/gpl.html -+ * -+ */ -+ -+#include "system.h" -+#ifdef HAVE_LIBXVBA -+#include -+#include -+#include "XVBA.h" -+#include "windowing/WindowingFactory.h" -+#include "guilib/GraphicContext.h" -+#include "settings/GUISettings.h" -+#include "utils/TimeUtils.h" -+ -+using namespace XVBA; -+ -+// XVBA interface -+ -+#define XVBA_LIBRARY "libXvBAW.so.1" -+ -+typedef Bool (*XVBAQueryExtensionProc) (Display *dpy, int *vers); -+typedef Status (*XVBACreateContextProc) (void *input, void *output); -+typedef Status (*XVBADestroyContextProc) (void *context); -+typedef Bool (*XVBAGetSessionInfoProc) (void *input, void *output); -+typedef Status (*XVBACreateSurfaceProc) (void *input, void *output); -+typedef Status (*XVBACreateGLSharedSurfaceProc)(void *input, void *output); -+typedef Status (*XVBADestroySurfaceProc) (void *surface); -+typedef Status (*XVBACreateDecodeBuffersProc) (void *input, void *output); -+typedef Status (*XVBADestroyDecodeBuffersProc) (void *input); -+typedef Status (*XVBAGetCapDecodeProc) (void *input, void *output); -+typedef Status (*XVBACreateDecodeProc) (void *input, void *output); -+typedef Status (*XVBADestroyDecodeProc) (void *session); -+typedef Status (*XVBAStartDecodePictureProc) (void *input); -+typedef Status (*XVBADecodePictureProc) (void *input); -+typedef Status (*XVBAEndDecodePictureProc) (void *input); -+typedef Status (*XVBASyncSurfaceProc) (void *input, void *output); -+typedef Status (*XVBAGetSurfaceProc) (void *input); -+typedef Status (*XVBATransferSurfaceProc) (void *input); -+ -+static struct -+{ -+ XVBAQueryExtensionProc QueryExtension; -+ XVBACreateContextProc CreateContext; -+ XVBADestroyContextProc DestroyContext; -+ XVBAGetSessionInfoProc GetSessionInfo; -+ XVBACreateSurfaceProc CreateSurface; -+ XVBACreateGLSharedSurfaceProc CreateGLSharedSurface; -+ XVBADestroySurfaceProc DestroySurface; -+ XVBACreateDecodeBuffersProc CreateDecodeBuffers; -+ XVBADestroyDecodeBuffersProc DestroyDecodeBuffers; -+ XVBAGetCapDecodeProc GetCapDecode; -+ XVBACreateDecodeProc CreateDecode; -+ XVBADestroyDecodeProc DestroyDecode; -+ XVBAStartDecodePictureProc StartDecodePicture; -+ XVBADecodePictureProc DecodePicture; -+ XVBAEndDecodePictureProc EndDecodePicture; -+ XVBASyncSurfaceProc SyncSurface; -+ XVBAGetSurfaceProc GetSurface; -+ XVBATransferSurfaceProc TransferSurface; -+}g_XVBA_vtable; -+ -+//----------------------------------------------------------------------------- -+//----------------------------------------------------------------------------- -+ -+CXVBAContext *CXVBAContext::m_context = 0; -+CCriticalSection CXVBAContext::m_section; -+Display *CXVBAContext::m_display = 0; -+void *CXVBAContext::m_dlHandle = 0; -+ -+CXVBAContext::CXVBAContext() -+{ -+ m_context = 0; -+// m_dlHandle = 0; -+ m_xvbaContext = 0; -+ m_refCount = 0; -+} -+ -+void CXVBAContext::Release() -+{ -+ CSingleLock lock(m_section); -+ -+ m_refCount--; -+ if (m_refCount <= 0) -+ { -+ Close(); -+ delete this; -+ m_context = 0; -+ } -+} -+ -+void CXVBAContext::Close() -+{ -+ CLog::Log(LOGNOTICE, "XVBA::Close - closing decoder context"); -+ -+ DestroyContext(); -+// if (m_dlHandle) -+// { -+// dlclose(m_dlHandle); -+// m_dlHandle = 0; -+// } -+} -+ -+bool CXVBAContext::EnsureContext(CXVBAContext **ctx) -+{ -+ CSingleLock lock(m_section); -+ -+ if (m_context) -+ { -+ m_context->m_refCount++; -+ *ctx = m_context; -+ return true; -+ } -+ -+ m_context = new CXVBAContext(); -+ *ctx = m_context; -+ { -+ CSingleLock gLock(g_graphicsContext); -+ if (!m_context->LoadSymbols() || !m_context->CreateContext()) -+ { -+ delete m_context; -+ m_context = 0; -+ return false; -+ } -+ } -+ -+ m_context->m_refCount++; -+ -+ *ctx = m_context; -+ return true; -+} -+ -+bool CXVBAContext::LoadSymbols() -+{ -+ if (!m_dlHandle) -+ { -+ m_dlHandle = dlopen(XVBA_LIBRARY, RTLD_LAZY); -+ if (!m_dlHandle) -+ { -+ const char* error = dlerror(); -+ if (!error) -+ error = "dlerror() returned NULL"; -+ -+ CLog::Log(LOGERROR,"XVBA::LoadSymbols: Unable to get handle to lib: %s", error); -+ return false; -+ } -+ } -+ else -+ return true; -+ -+#define INIT_PROC(PREFIX, PROC) do { \ -+ g_##PREFIX##_vtable.PROC = (PREFIX##PROC##Proc) \ -+ dlsym(m_dlHandle, #PREFIX #PROC); \ -+ } while (0) -+ -+#define INIT_PROC_CHECK(PREFIX, PROC) do { \ -+ dlerror(); \ -+ INIT_PROC(PREFIX, PROC); \ -+ if (dlerror()) { \ -+ dlclose(m_dlHandle); \ -+ m_dlHandle = NULL; \ -+ return false; \ -+ } \ -+ } while (0) -+ -+#define XVBA_INIT_PROC(PROC) INIT_PROC_CHECK(XVBA, PROC) -+ -+ XVBA_INIT_PROC(QueryExtension); -+ XVBA_INIT_PROC(CreateContext); -+ XVBA_INIT_PROC(DestroyContext); -+ XVBA_INIT_PROC(GetSessionInfo); -+ XVBA_INIT_PROC(CreateSurface); -+ XVBA_INIT_PROC(CreateGLSharedSurface); -+ XVBA_INIT_PROC(DestroySurface); -+ XVBA_INIT_PROC(CreateDecodeBuffers); -+ XVBA_INIT_PROC(DestroyDecodeBuffers); -+ XVBA_INIT_PROC(GetCapDecode); -+ XVBA_INIT_PROC(CreateDecode); -+ XVBA_INIT_PROC(DestroyDecode); -+ XVBA_INIT_PROC(StartDecodePicture); -+ XVBA_INIT_PROC(DecodePicture); -+ XVBA_INIT_PROC(EndDecodePicture); -+ XVBA_INIT_PROC(SyncSurface); -+ XVBA_INIT_PROC(GetSurface); -+ XVBA_INIT_PROC(TransferSurface); -+ -+#undef XVBA_INIT_PROC -+#undef INIT_PROC -+ -+ return true; -+} -+ -+bool CXVBAContext::CreateContext() -+{ -+ if (m_xvbaContext) -+ return true; -+ -+ CLog::Log(LOGNOTICE,"XVBA::CreateContext - creating decoder context"); -+ -+ Drawable window; -+ { CSingleLock lock(g_graphicsContext); -+ if (!m_display) -+ m_display = XOpenDisplay(NULL); -+ window = 0; -+ } -+ -+ int version; -+ if (!g_XVBA_vtable.QueryExtension(m_display, &version)) -+ return false; -+ CLog::Log(LOGNOTICE,"XVBA::CreateContext - opening xvba version: %i", version); -+ -+ // create XVBA Context -+ XVBA_Create_Context_Input contextInput; -+ XVBA_Create_Context_Output contextOutput; -+ contextInput.size = sizeof(contextInput); -+ contextInput.display = m_display; -+ contextInput.draw = window; -+ contextOutput.size = sizeof(contextOutput); -+ if(Success != g_XVBA_vtable.CreateContext(&contextInput, &contextOutput)) -+ { -+ CLog::Log(LOGERROR,"XVBA::CreateContext - failed to create context"); -+ return false; -+ } -+ m_xvbaContext = contextOutput.context; -+ -+ return true; -+} -+ -+void CXVBAContext::DestroyContext() -+{ -+ if (!m_xvbaContext) -+ return; -+ -+ g_XVBA_vtable.DestroyContext(m_xvbaContext); -+ m_xvbaContext = 0; -+// XCloseDisplay(m_display); -+} -+ -+void *CXVBAContext::GetContext() -+{ -+ return m_xvbaContext; -+} -+ -+//----------------------------------------------------------------------------- -+//----------------------------------------------------------------------------- -+ -+static unsigned int decoderId = 0; -+ -+CDecoder::CDecoder() -+{ -+ m_context = 0; -+ m_xvbaSession = 0; -+ m_flipBuffer = 0; -+} -+ -+CDecoder::~CDecoder() -+{ -+ Close(); -+} -+ -+typedef struct { -+ unsigned int size; -+ unsigned int num_of_decodecaps; -+ XVBADecodeCap decode_caps_list[]; -+} XVBA_GetCapDecode_Output_Base; -+ -+void CDecoder::OnLostDevice() -+{ -+ CLog::Log(LOGNOTICE,"XVBA::OnLostDevice event"); -+ -+ CExclusiveLock lock(m_decoderSection); -+ DestroySession(); -+ if (m_context) -+ m_context->Release(); -+ m_context = 0; -+ -+ m_displayState = XVBA_LOST; -+ m_displayEvent.Reset(); -+} -+ -+void CDecoder::OnResetDevice() -+{ -+ CLog::Log(LOGNOTICE,"XVBA::OnResetDevice event"); -+ -+ CExclusiveLock lock(m_displaySection); -+ if (m_displayState == XVBA_LOST) -+ { -+ m_displayState = XVBA_RESET; -+ m_displayEvent.Set(); -+ } -+} -+ -+bool CDecoder::Open(AVCodecContext* avctx, const enum PixelFormat fmt, unsigned int surfaces) -+{ -+ std::string Vendor = g_Windowing.GetRenderVendor(); -+ std::transform(Vendor.begin(), Vendor.end(), Vendor.begin(), ::tolower); -+ if (Vendor.compare(0, 3, "ati") != 0) -+ { -+ return false; -+ } -+ -+ m_decoderId = decoderId++; -+ -+ CLog::Log(LOGNOTICE,"(XVBA::Open) opening xvba decoder, id: %d", m_decoderId); -+ -+ if(avctx->coded_width == 0 -+ || avctx->coded_height == 0) -+ { -+ CLog::Log(LOGWARNING,"(XVBA) no width/height available, can't init"); -+ return false; -+ } -+ -+ if (!m_dllAvUtil.Load()) -+ return false; -+ -+ if (!CXVBAContext::EnsureContext(&m_context)) -+ return false; -+ -+ // xvba get session info -+ XVBA_GetSessionInfo_Input sessionInput; -+ XVBA_GetSessionInfo_Output sessionOutput; -+ sessionInput.size = sizeof(sessionInput); -+ sessionInput.context = m_context->GetContext(); -+ sessionOutput.size = sizeof(sessionOutput); -+ if (Success != g_XVBA_vtable.GetSessionInfo(&sessionInput, &sessionOutput)) -+ { -+ CLog::Log(LOGERROR,"(XVBA) can't get session info"); -+ return false; -+ } -+ if (sessionOutput.getcapdecode_output_size == 0) -+ { -+ CLog::Log(LOGERROR,"(XVBA) session decode not supported"); -+ return false; -+ } -+ -+ // get decoder capabilities -+ XVBA_GetCapDecode_Input capInput; -+ XVBA_GetCapDecode_Output *capOutput; -+ capInput.size = sizeof(capInput); -+ capInput.context = m_context->GetContext(); -+ capOutput = (XVBA_GetCapDecode_Output *)calloc(sessionOutput.getcapdecode_output_size, 1); -+ capOutput->size = sessionOutput.getcapdecode_output_size; -+ if (Success != g_XVBA_vtable.GetCapDecode(&capInput, capOutput)) -+ { -+ CLog::Log(LOGERROR,"(XVBA) can't get decode capabilities"); -+ return false; -+ } -+ -+ int match = -1; -+ if (avctx->codec_id == CODEC_ID_H264) -+ { -+ // search for profile high -+ for (unsigned int i = 0; i < capOutput->num_of_decodecaps; ++i) -+ { -+ if (capOutput->decode_caps_list[i].capability_id == XVBA_H264 && -+ capOutput->decode_caps_list[i].flags == XVBA_H264_HIGH) -+ { -+ match = (int) i; -+ break; -+ } -+ } -+ if (match < 0) -+ { -+ CLog::Log(LOGNOTICE, "(XVBA::Open) - profile XVBA_H264_HIGH not found"); -+ } -+ } -+ else if (avctx->codec_id == CODEC_ID_VC1) -+ { -+ // search for profile advanced -+ for (unsigned int i = 0; i < capOutput->num_of_decodecaps; ++i) -+ { -+ if (capOutput->decode_caps_list[i].capability_id == XVBA_VC1 && -+ capOutput->decode_caps_list[i].flags == XVBA_VC1_ADVANCED) -+ { -+ match = (int) i; -+ break; -+ } -+ } -+ if (match < 0) -+ { -+ CLog::Log(LOGNOTICE, "(XVBA::Open) - profile XVBA_VC1_ADVANCED not found"); -+ } -+ } -+ else if (avctx->codec_id == CODEC_ID_MPEG2VIDEO) -+ { -+ // search for profile high -+ for (unsigned int i = 0; i < capOutput->num_of_decodecaps; ++i) -+ { -+ if (capOutput->decode_caps_list[i].capability_id == XVBA_MPEG2_VLD) -+ { -+ // XXX: uncomment when implemented -+ // match = (int) i; -+ // break; -+ } -+ } -+ if (match < 0) -+ { -+ CLog::Log(LOGNOTICE, "(XVBA::Open) - profile XVBA_MPEG2_VLD not found"); -+ } -+ } -+ else if (avctx->codec_id == CODEC_ID_WMV3) -+ { -+ // search for profile high -+ for (unsigned int i = 0; i < capOutput->num_of_decodecaps; ++i) -+ { -+ if (capOutput->decode_caps_list[i].capability_id == XVBA_VC1 && -+ capOutput->decode_caps_list[i].flags == XVBA_VC1_MAIN) -+ { -+ match = (int) i; -+ break; -+ } -+ } -+ if (match < 0) -+ { -+ CLog::Log(LOGNOTICE, "(XVBA::Open) - profile XVBA_VC1_MAIN not found"); -+ } -+ } -+ -+ if (match < 0) -+ { -+ free(capOutput); -+ return false; -+ } -+ -+ CLog::Log(LOGNOTICE,"(XVBA) using decoder capability id: %i flags: %i", -+ capOutput->decode_caps_list[match].capability_id, -+ capOutput->decode_caps_list[match].flags); -+ CLog::Log(LOGNOTICE,"(XVBA) using surface type: %x", -+ capOutput->decode_caps_list[match].surface_type); -+ -+ m_decoderCap = capOutput->decode_caps_list[match]; -+ -+ free(capOutput); -+ -+ // set some varables -+ m_xvbaSession = 0; -+ m_xvbaBufferPool.data_buffer = 0; -+ m_xvbaBufferPool.iq_matrix_buffer = 0; -+ m_xvbaBufferPool.picture_descriptor_buffer = 0; -+ picAge.b_age = picAge.ip_age[0] = picAge.ip_age[1] = 256*256*256*64; -+ m_surfaceWidth = 0; -+ m_surfaceHeight = 0; -+ m_presentPicture = 0; -+ m_numRenderBuffers = surfaces; -+ m_flipBuffer = new RenderPicture[m_numRenderBuffers]; -+ for (unsigned int i = 0; i < m_numRenderBuffers; ++i) -+ { -+ m_flipBuffer[i].outPic = 0; -+ m_flipBuffer[i].glSurface[0] = -+ m_flipBuffer[i].glSurface[1] = -+ m_flipBuffer[i].glSurface[2] = 0; -+ m_flipBuffer[i].glTexture[0] = -+ m_flipBuffer[i].glTexture[1] = -+ m_flipBuffer[i].glTexture[2] = 0; -+ } -+ for (unsigned int j = 0; j < NUM_OUTPUT_PICS; ++j) -+ m_freeOutPic.push_back(&m_allOutPic[j]); -+ m_displayState = XVBA_OPEN; -+ -+ // setup ffmpeg -+ avctx->thread_count = 1; -+ avctx->get_buffer = CDecoder::FFGetBuffer; -+ avctx->release_buffer = CDecoder::FFReleaseBuffer; -+ avctx->draw_horiz_band = CDecoder::FFDrawSlice; -+ avctx->slice_flags = SLICE_FLAG_CODED_ORDER|SLICE_FLAG_ALLOW_FIELD; -+ -+ g_Windowing.Register(this); -+ return true; -+} -+ -+void CDecoder::Close() -+{ -+ CLog::Log(LOGNOTICE, "XVBA::Close - closing decoder, id: %d", m_decoderId); -+ -+ if (!m_context) -+ return; -+ -+ FinishGL(); -+ -+ DestroySession(); -+ if (m_context) -+ m_context->Release(); -+ m_context = 0; -+ -+ while (!m_videoSurfaces.empty()) -+ { -+ xvba_render_state *render = m_videoSurfaces.back(); -+ if(render->buffers_alllocated > 0) -+ m_dllAvUtil.av_free(render->buffers); -+ m_videoSurfaces.pop_back(); -+ free(render); -+ } -+ -+ if (m_flipBuffer) -+ delete [] m_flipBuffer; -+ -+ g_Windowing.Unregister(this); -+ m_dllAvUtil.Unload(); -+} -+ -+void CDecoder::ResetState() -+{ -+ picAge.b_age = picAge.ip_age[0] = picAge.ip_age[1] = 256*256*256*64; -+ m_presentPicture = 0; -+ m_freeOutPic.clear(); -+ m_usedOutPic.clear(); -+ for (int j = 0; j < NUM_OUTPUT_PICS; ++j) -+ m_freeOutPic.push_back(&m_allOutPic[j]); -+ m_displayState = XVBA_OPEN; -+} -+ -+int CDecoder::Check(AVCodecContext* avctx) -+{ -+ EDisplayState state; -+ -+ { CSharedLock lock(m_displaySection); -+ state = m_displayState; -+ } -+ -+ if (state == XVBA_LOST) -+ { -+ CLog::Log(LOGNOTICE,"XVBA::Check waiting for display reset event"); -+ if (!m_displayEvent.WaitMSec(2000)) -+ { -+ CLog::Log(LOGERROR, "XVBA::Check - device didn't reset in reasonable time"); -+ return VC_ERROR; -+ } -+ { CSharedLock lock(m_displaySection); -+ state = m_displayState; -+ } -+ } -+ if (state == XVBA_RESET || state == XVBA_ERROR) -+ { -+ CLog::Log(LOGNOTICE,"XVBA::Check - Attempting recovery"); -+ -+ CSingleLock gLock(g_graphicsContext); -+ CExclusiveLock lock(m_decoderSection); -+ -+ DestroySession(); -+ ResetState(); -+ CXVBAContext::EnsureContext(&m_context); -+ -+ if (state == XVBA_RESET) -+ return VC_FLUSHED; -+ else -+ return VC_ERROR; -+ } -+ return 0; -+} -+ -+void CDecoder::SetError(const char* function, const char* msg, int line) -+{ -+ CLog::Log(LOGERROR, "XVBA::%s - %s, line %d", function, msg, line); -+ CExclusiveLock lock(m_displaySection); -+ m_displayState = XVBA_ERROR; -+} -+ -+bool CDecoder::CreateSession(AVCodecContext* avctx) -+{ -+ m_surfaceWidth = (avctx->coded_width+15) & ~15; -+ m_surfaceHeight = (avctx->coded_height+15) & ~15; -+ -+ m_vidWidth = avctx->width; -+ m_vidHeight = avctx->height; -+ -+ XVBA_Create_Decode_Session_Input sessionInput; -+ XVBA_Create_Decode_Session_Output sessionOutput; -+ -+ sessionInput.size = sizeof(sessionInput); -+ sessionInput.width = m_surfaceWidth; -+ sessionInput.height = m_surfaceHeight; -+ sessionInput.context = m_context->GetContext(); -+ sessionInput.decode_cap = &m_decoderCap; -+ sessionOutput.size = sizeof(sessionOutput); -+ -+ if (Success != g_XVBA_vtable.CreateDecode(&sessionInput, &sessionOutput)) -+ { -+ SetError(__FUNCTION__, "failed to create decoder session", __LINE__); -+ CLog::Log(LOGERROR, "Decoder failed with following stats: m_surfaceWidth %u, m_surfaceHeight %u," -+ " m_vidWidth %u, m_vidHeight %u, coded_width %d, coded_height %d", -+ m_surfaceWidth, -+ m_surfaceHeight, -+ m_vidWidth, -+ m_vidHeight, -+ avctx->coded_width, -+ avctx->coded_height); -+ return false; -+ } -+ m_xvbaSession = sessionOutput.session; -+ -+ -+ // create decode buffers -+ XVBA_Create_DecodeBuff_Input bufferInput; -+ XVBA_Create_DecodeBuff_Output bufferOutput; -+ -+ bufferInput.size = sizeof(bufferInput); -+ bufferInput.session = m_xvbaSession; -+ bufferInput.buffer_type = XVBA_PICTURE_DESCRIPTION_BUFFER; -+ bufferInput.num_of_buffers = 1; -+ bufferOutput.size = sizeof(bufferOutput); -+ if (Success != g_XVBA_vtable.CreateDecodeBuffers(&bufferInput, &bufferOutput) -+ || bufferOutput.num_of_buffers_in_list != 1) -+ { -+ SetError(__FUNCTION__, "failed to create picture buffer", __LINE__); -+ return false; -+ } -+ m_xvbaBufferPool.picture_descriptor_buffer = bufferOutput.buffer_list; -+ -+ // data buffer -+ bufferInput.buffer_type = XVBA_DATA_BUFFER; -+ if (Success != g_XVBA_vtable.CreateDecodeBuffers(&bufferInput, &bufferOutput) -+ || bufferOutput.num_of_buffers_in_list != 1) -+ { -+ SetError(__FUNCTION__, "failed to create data buffer", __LINE__); -+ return false; -+ } -+ m_xvbaBufferPool.data_buffer = bufferOutput.buffer_list; -+ -+ // QO Buffer -+ bufferInput.buffer_type = XVBA_QM_BUFFER; -+ if (Success != g_XVBA_vtable.CreateDecodeBuffers(&bufferInput, &bufferOutput) -+ || bufferOutput.num_of_buffers_in_list != 1) -+ { -+ SetError(__FUNCTION__, "failed to create qm buffer", __LINE__); -+ return false; -+ } -+ m_xvbaBufferPool.iq_matrix_buffer = bufferOutput.buffer_list; -+ -+ return true; -+} -+ -+void CDecoder::DestroySession() -+{ -+ XVBA_Destroy_Decode_Buffers_Input bufInput; -+ bufInput.size = sizeof(bufInput); -+ bufInput.num_of_buffers_in_list = 1; -+ -+ for (unsigned int i=0; isurface) -+ { -+ g_XVBA_vtable.DestroySurface(render->surface); -+ render->surface = 0; -+ render->picture_descriptor = 0; -+ render->iq_matrix = 0; -+ } -+ } -+ -+ if (m_xvbaSession) -+ g_XVBA_vtable.DestroyDecode(m_xvbaSession); -+ m_xvbaSession = 0; -+} -+ -+bool CDecoder::IsSurfaceValid(xvba_render_state *render) -+{ -+ // find render state in queue -+ bool found(false); -+ unsigned int i; -+ for(i = 0; i < m_videoSurfaces.size(); ++i) -+ { -+ if(m_videoSurfaces[i] == render) -+ { -+ found = true; -+ break; -+ } -+ } -+ if (!found) -+ { -+ CLog::Log(LOGERROR,"%s - video surface not found", __FUNCTION__); -+ return false; -+ } -+ if (m_videoSurfaces[i]->surface == 0) -+ { -+ m_videoSurfaces[i]->state = 0; -+ return false; -+ } -+ -+ return true; -+} -+ -+bool CDecoder::EnsureDataControlBuffers(unsigned int num) -+{ -+ if (m_xvbaBufferPool.data_control_buffers.size() >= num) -+ return true; -+ -+ unsigned int missing = num - m_xvbaBufferPool.data_control_buffers.size(); -+ -+ XVBA_Create_DecodeBuff_Input bufferInput; -+ XVBA_Create_DecodeBuff_Output bufferOutput; -+ bufferInput.size = sizeof(bufferInput); -+ bufferInput.session = m_xvbaSession; -+ bufferInput.buffer_type = XVBA_DATA_CTRL_BUFFER; -+ bufferInput.num_of_buffers = 1; -+ bufferOutput.size = sizeof(bufferOutput); -+ -+ for (unsigned int i=0; iopaque; -+ CDecoder* xvba = (CDecoder*)ctx->GetHardware(); -+ unsigned int i; -+ -+ CSharedLock lock(xvba->m_decoderSection); -+ -+ xvba_render_state * render = NULL; -+ render = (xvba_render_state*)pic->data[0]; -+ if(!render) -+ { -+ CLog::Log(LOGERROR, "XVBA::FFReleaseBuffer - invalid context handle provided"); -+ return; -+ } -+ -+ for(i=0; i<4; i++) -+ pic->data[i]= NULL; -+ -+ // find render state in queue -+ if (!xvba->IsSurfaceValid(render)) -+ { -+ CLog::Log(LOGDEBUG, "XVBA::FFReleaseBuffer - ignoring invalid buffer"); -+ return; -+ } -+ -+ render->state &= ~FF_XVBA_STATE_USED_FOR_REFERENCE; -+} -+ -+void CDecoder::FFDrawSlice(struct AVCodecContext *avctx, -+ const AVFrame *src, int offset[4], -+ int y, int type, int height) -+{ -+ CDVDVideoCodecFFmpeg* ctx = (CDVDVideoCodecFFmpeg*)avctx->opaque; -+ CDecoder* xvba = (CDecoder*)ctx->GetHardware(); -+ -+ CSharedLock lock(xvba->m_decoderSection); -+ -+ { CSharedLock dLock(xvba->m_displaySection); -+ if(xvba->m_displayState != XVBA_OPEN) -+ return; -+ } -+ -+ if(src->linesize[0] || src->linesize[1] || src->linesize[2] -+ || offset[0] || offset[1] || offset[2]) -+ { -+ CLog::Log(LOGERROR, "XVBA::FFDrawSlice - invalid linesizes or offsets provided"); -+ return; -+ } -+ -+ xvba_render_state * render; -+ -+ render = (xvba_render_state*)src->data[0]; -+ if(!render) -+ { -+ CLog::Log(LOGERROR, "XVBA::FFDrawSlice - invalid context handle provided"); -+ return; -+ } -+ -+ // ffmpeg vc-1 decoder does not flush, make sure the data buffer is still valid -+ if (!xvba->IsSurfaceValid(render)) -+ { -+ CLog::Log(LOGWARNING, "XVBA::FFDrawSlice - ignoring invalid buffer"); -+ return; -+ } -+ -+ // decoding -+ XVBA_Decode_Picture_Start_Input startInput; -+ startInput.size = sizeof(startInput); -+ startInput.session = xvba->m_xvbaSession; -+ startInput.target_surface = render->surface; -+ { CSingleLock lock(xvba->m_apiSec); -+ if (Success != g_XVBA_vtable.StartDecodePicture(&startInput)) -+ { -+ xvba->SetError(__FUNCTION__, "failed to start decoding", __LINE__); -+ return; -+ } -+ } -+ XVBA_Decode_Picture_Input picInput; -+ picInput.size = sizeof(picInput); -+ picInput.session = xvba->m_xvbaSession; -+ XVBABufferDescriptor *list[2]; -+ picInput.buffer_list = list; -+ list[0] = xvba->m_xvbaBufferPool.picture_descriptor_buffer; -+ picInput.num_of_buffers_in_list = 1; -+ if (avctx->codec_id == CODEC_ID_H264) -+ { -+ list[1] = xvba->m_xvbaBufferPool.iq_matrix_buffer; -+ picInput.num_of_buffers_in_list = 2; -+ } -+ -+ { CSingleLock lock(xvba->m_apiSec); -+ if (Success != g_XVBA_vtable.DecodePicture(&picInput)) -+ { -+ xvba->SetError(__FUNCTION__, "failed to decode picture 1", __LINE__); -+ return; -+ } -+ } -+ -+ if (!xvba->EnsureDataControlBuffers(render->num_slices)) -+ return; -+ -+ XVBADataCtrl *dataControl; -+ int location = 0; -+ xvba->m_xvbaBufferPool.data_buffer->data_size_in_buffer = 0; -+ for (unsigned int j = 0; j < render->num_slices; ++j) -+ { -+ int startCodeSize = 0; -+ uint8_t startCode[] = {0x00,0x00,0x01}; -+ if (avctx->codec_id == CODEC_ID_H264) -+ { -+ startCodeSize = 3; -+ memcpy((uint8_t*)xvba->m_xvbaBufferPool.data_buffer->bufferXVBA+location, -+ startCode, 3); -+ } -+ else if (avctx->codec_id == CODEC_ID_VC1 && -+ (memcmp(render->buffers[j].buffer, startCode, 3) != 0)) -+ { -+ startCodeSize = 4; -+ uint8_t sdf = 0x0d; -+ memcpy((uint8_t*)xvba->m_xvbaBufferPool.data_buffer->bufferXVBA+location, -+ startCode, 3); -+ memcpy((uint8_t*)xvba->m_xvbaBufferPool.data_buffer->bufferXVBA+location+3, -+ &sdf, 1); -+ } -+ // check for potential buffer overwrite -+ unsigned int bytesToCopy = render->buffers[j].size; -+ unsigned int freeBufferSize = xvba->m_xvbaBufferPool.data_buffer->buffer_size - -+ xvba->m_xvbaBufferPool.data_buffer->data_size_in_buffer; -+ if (bytesToCopy >= freeBufferSize) -+ { -+ xvba->SetError(__FUNCTION__, "bitstream buffer too large, maybe corrupted packet", __LINE__); -+ return; -+ } -+ memcpy((uint8_t*)xvba->m_xvbaBufferPool.data_buffer->bufferXVBA+location+startCodeSize, -+ render->buffers[j].buffer, -+ render->buffers[j].size); -+ dataControl = (XVBADataCtrl*)xvba->m_xvbaBufferPool.data_control_buffers[j]->bufferXVBA; -+ dataControl->SliceDataLocation = location; -+ dataControl->SliceBytesInBuffer = render->buffers[j].size+startCodeSize; -+ dataControl->SliceBitsInBuffer = dataControl->SliceBytesInBuffer * 8; -+ xvba->m_xvbaBufferPool.data_buffer->data_size_in_buffer += dataControl->SliceBytesInBuffer; -+ location += dataControl->SliceBytesInBuffer; -+ } -+ -+ int bufSize = xvba->m_xvbaBufferPool.data_buffer->data_size_in_buffer; -+ int padding = bufSize % 128; -+ if (padding) -+ { -+ padding = 128 - padding; -+ xvba->m_xvbaBufferPool.data_buffer->data_size_in_buffer += padding; -+ memset((uint8_t*)xvba->m_xvbaBufferPool.data_buffer->bufferXVBA+bufSize,0,padding); -+ } -+ -+ picInput.num_of_buffers_in_list = 2; -+ for (unsigned int i = 0; i < render->num_slices; ++i) -+ { -+ list[0] = xvba->m_xvbaBufferPool.data_buffer; -+ list[0]->data_offset = 0; -+ list[1] = xvba->m_xvbaBufferPool.data_control_buffers[i]; -+ list[1]->data_size_in_buffer = sizeof(*dataControl); -+ { CSingleLock lock(xvba->m_apiSec); -+ if (Success != g_XVBA_vtable.DecodePicture(&picInput)) -+ { -+ xvba->SetError(__FUNCTION__, "failed to decode picture 2", __LINE__); -+ return; -+ } -+ } -+ } -+ XVBA_Decode_Picture_End_Input endInput; -+ endInput.size = sizeof(endInput); -+ endInput.session = xvba->m_xvbaSession; -+ { CSingleLock lock(xvba->m_apiSec); -+ if (Success != g_XVBA_vtable.EndDecodePicture(&endInput)) -+ { -+ xvba->SetError(__FUNCTION__, "failed to decode picture 3", __LINE__); -+ return; -+ } -+ } -+ -+ // decode sync and error -+ XVBA_Surface_Sync_Input syncInput; -+ XVBA_Surface_Sync_Output syncOutput; -+ syncInput.size = sizeof(syncInput); -+ syncInput.session = xvba->m_xvbaSession; -+ syncInput.surface = render->surface; -+ syncInput.query_status = XVBA_GET_SURFACE_STATUS; -+ syncOutput.size = sizeof(syncOutput); -+ int64_t start = CurrentHostCounter(); -+ while (1) -+ { -+ { CSingleLock lock(xvba->m_apiSec); -+ if (Success != g_XVBA_vtable.SyncSurface(&syncInput, &syncOutput)) -+ { -+ xvba->SetError(__FUNCTION__, "failed sync surface 1", __LINE__); -+ return; -+ } -+ } -+ if (!(syncOutput.status_flags & XVBA_STILL_PENDING)) -+ break; -+ if (CurrentHostCounter() - start > CurrentHostFrequency()) -+ { -+ xvba->SetError(__FUNCTION__, "timed out waiting for surface", __LINE__); -+ break; -+ } -+ usleep(100); -+ } -+ render->state |= 4; -+} -+ -+int CDecoder::FFGetBuffer(AVCodecContext *avctx, AVFrame *pic) -+{ -+ CDVDVideoCodecFFmpeg* ctx = (CDVDVideoCodecFFmpeg*)avctx->opaque; -+ CDecoder* xvba = (CDecoder*)ctx->GetHardware(); -+ struct pictureAge* pA = &xvba->picAge; -+ -+ pic->data[0] = -+ pic->data[1] = -+ pic->data[2] = -+ pic->data[3] = 0; -+ -+ pic->linesize[0] = -+ pic->linesize[1] = -+ pic->linesize[2] = -+ pic->linesize[3] = 0; -+ -+ CSharedLock lock(xvba->m_decoderSection); -+ -+ { CSharedLock dLock(xvba->m_displaySection); -+ if(xvba->m_displayState != XVBA_OPEN) -+ return -1; -+ } -+ -+ if (xvba->m_xvbaSession == 0) -+ { -+ if (!xvba->CreateSession(avctx)) -+ return -1; -+ } -+ -+ xvba_render_state * render = NULL; -+ // find unused surface -+ { CSingleLock lock(xvba->m_videoSurfaceSec); -+ for(unsigned int i = 0; i < xvba->m_videoSurfaces.size(); ++i) -+ { -+ if(!(xvba->m_videoSurfaces[i]->state & (FF_XVBA_STATE_USED_FOR_REFERENCE | FF_XVBA_STATE_USED_FOR_RENDER))) -+ { -+ render = xvba->m_videoSurfaces[i]; -+ render->state = 0; -+ break; -+ } -+ } -+ } -+ -+ // create a new render state -+ if (render == NULL) -+ { -+ render = (xvba_render_state*)calloc(sizeof(xvba_render_state), 1); -+ if (render == NULL) -+ { -+ CLog::Log(LOGERROR, "XVBA::FFGetBuffer - calloc failed"); -+ return -1; -+ } -+ render->surface = 0; -+ render->buffers_alllocated = 0; -+ CSingleLock lock(xvba->m_videoSurfaceSec); -+ xvba->m_videoSurfaces.push_back(render); -+ } -+ -+ // create a new surface -+ if (render->surface == 0) -+ { -+ XVBA_Create_Surface_Input surfaceInput; -+ XVBA_Create_Surface_Output surfaceOutput; -+ surfaceInput.size = sizeof(surfaceInput); -+ surfaceInput.surface_type = xvba->m_decoderCap.surface_type; -+ surfaceInput.width = xvba->m_surfaceWidth; -+ surfaceInput.height = xvba->m_surfaceHeight; -+ surfaceInput.session = xvba->m_xvbaSession; -+ surfaceOutput.size = sizeof(surfaceOutput); -+ { CSingleLock lock(xvba->m_apiSec); -+ if (Success != g_XVBA_vtable.CreateSurface(&surfaceInput, &surfaceOutput)) -+ { -+ xvba->SetError(__FUNCTION__, "failed to create video surface", __LINE__); -+ return -1; -+ } -+ } -+ render->surface = surfaceOutput.surface; -+ render->picture_descriptor = (XVBAPictureDescriptor *)xvba->m_xvbaBufferPool.picture_descriptor_buffer->bufferXVBA; -+ render->iq_matrix = (XVBAQuantMatrixAvc *)xvba->m_xvbaBufferPool.iq_matrix_buffer->bufferXVBA; -+ CLog::Log(LOGDEBUG, "XVBA::FFGetBuffer - created video surface"); -+ } -+ -+ if (render == NULL) -+ return -1; -+ -+ pic->data[0] = (uint8_t*)render; -+ -+ if(pic->reference) -+ { -+ pic->age = pA->ip_age[0]; -+ pA->ip_age[0]= pA->ip_age[1]+1; -+ pA->ip_age[1]= 1; -+ pA->b_age++; -+ } -+ else -+ { -+ pic->age = pA->b_age; -+ pA->ip_age[0]++; -+ pA->ip_age[1]++; -+ pA->b_age = 1; -+ } -+ pic->type= FF_BUFFER_TYPE_USER; -+ -+ render->state |= FF_XVBA_STATE_USED_FOR_REFERENCE; -+ render->state &= ~4; -+ pic->reordered_opaque= avctx->reordered_opaque; -+ -+ return 0; -+} -+ -+int CDecoder::Decode(AVCodecContext* avctx, AVFrame* frame) -+{ -+ int result = Check(avctx); -+ if (result) -+ return result; -+ -+ CSharedLock lock(m_decoderSection); -+ -+ int iReturn(0); -+ if(frame) -+ { // we have a new frame from decoder -+ -+ xvba_render_state * render = (xvba_render_state*)frame->data[0]; -+ if(!render) -+ return VC_ERROR; -+ -+ // ffmpeg vc-1 decoder does not flush, make sure the data buffer is still valid -+ if (!IsSurfaceValid(render)) -+ { -+ CLog::Log(LOGWARNING, "XVBA::Decode - ignoring invalid buffer"); -+ return VC_BUFFER; -+ } -+ if (!(render->state & 4)) -+ { -+ CLog::Log(LOGDEBUG, "XVBA::Decode - ffmpeg failed"); -+ return VC_BUFFER; -+ } -+ -+ render->state |= FF_XVBA_STATE_USED_FOR_RENDER; -+ -+ CSingleLock lock(m_outPicSec); -+ if (m_freeOutPic.empty()) -+ { -+ return VC_ERROR; -+ } -+ OutputPicture *outPic = m_freeOutPic.front(); -+ m_freeOutPic.pop_front(); -+ memset(&outPic->dvdPic, 0, sizeof(DVDVideoPicture)); -+ ((CDVDVideoCodecFFmpeg*)avctx->opaque)->GetPictureCommon(&outPic->dvdPic); -+ outPic->render = render; -+ -+ if (g_guiSettings.GetBool("videoplayer.usexvbasharedsurface")) -+ outPic->dvdPic.format = DVDVideoPicture::FMT_XVBA; -+ else -+ outPic->dvdPic.format = DVDVideoPicture::FMT_XVBA_YV12; -+ outPic->dvdPic.iWidth = m_surfaceWidth; -+ outPic->dvdPic.iHeight = m_surfaceHeight; -+ outPic->dvdPic.xvba = this; -+ -+ m_usedOutPic.push_back(outPic); -+ lock.Leave(); -+ -+ iReturn |= VC_PICTURE; -+ } -+ -+ { CSingleLock lock(m_outPicSec); -+ if (!m_freeOutPic.empty()) -+ iReturn |= VC_BUFFER; -+ } -+ -+ return iReturn; -+} -+ -+bool CDecoder::GetPicture(AVCodecContext* avctx, AVFrame* frame, DVDVideoPicture* picture) -+{ -+ CSharedLock lock(m_decoderSection); -+ -+ { CSharedLock dLock(m_displaySection); -+ if(m_displayState != XVBA_OPEN) -+ return false; -+ } -+ -+ { CSingleLock lock(m_outPicSec); -+ -+ if (DiscardPresentPicture()) -+ CLog::Log(LOGWARNING,"XVBA::GetPicture: old presentPicture was still valid - now discarded"); -+ if (m_usedOutPic.size() > 0) -+ { -+ m_presentPicture = m_usedOutPic.front(); -+ m_usedOutPic.pop_front(); -+ *picture = m_presentPicture->dvdPic; -+ } -+ else -+ { -+ CLog::Log(LOGERROR,"XVBA::GetPicture: no picture"); -+ return false; -+ } -+ } -+ return true; -+} -+ -+bool CDecoder::DiscardPresentPicture() -+{ -+ CSingleLock lock(m_outPicSec); -+ if (m_presentPicture) -+ { -+ if (m_presentPicture->render) -+ m_presentPicture->render->state &= ~FF_XVBA_STATE_USED_FOR_RENDER; -+ m_presentPicture->render = NULL; -+ m_freeOutPic.push_back(m_presentPicture); -+ m_presentPicture = NULL; -+ return true; -+ } -+ return false; -+} -+ -+void CDecoder::Present(int index) -+{ -+ CSharedLock lock(m_decoderSection); -+ -+ { CSharedLock dLock(m_displaySection); -+ if(m_displayState != XVBA_OPEN) -+ return; -+ } -+ -+ if (!m_presentPicture) -+ { -+ // use last picture, we might processing a still frame here -+ int lastIndex = (index + m_numRenderBuffers -1) % m_numRenderBuffers; -+ m_presentPicture = m_flipBuffer[lastIndex].outPic; -+ m_flipBuffer[lastIndex].isDuplicate = true; -+ if (!m_presentPicture) -+ { -+ CLog::Log(LOGWARNING, "XVBA::Present: present picture is NULL"); -+ return; -+ } -+ } -+ -+ if (m_flipBuffer[index].outPic && !m_flipBuffer[index].isDuplicate) -+ { -+ if (m_flipBuffer[index].outPic->render) -+ { -+ CSingleLock lock(m_videoSurfaceSec); -+ m_flipBuffer[index].outPic->render->state &= ~FF_XVBA_STATE_USED_FOR_RENDER; -+ m_flipBuffer[index].outPic->render = NULL; -+ } -+ CSingleLock lock(m_outPicSec); -+ m_freeOutPic.push_back(m_flipBuffer[index].outPic); -+ m_flipBuffer[index].outPic = NULL; -+ } -+ -+ m_flipBuffer[index].outPic = m_presentPicture; -+ m_flipBuffer[index].isDuplicate = false; -+ m_presentPicture = NULL; -+} -+ -+void CDecoder::CopyYV12(int index, uint8_t *dest) -+{ -+ CSharedLock lock(m_decoderSection); -+ -+ { CSharedLock dLock(m_displaySection); -+ if(m_displayState != XVBA_OPEN) -+ return; -+ } -+ -+ if (!m_flipBuffer[index].outPic) -+ { -+ CLog::Log(LOGWARNING, "XVBA::CopyYV12: current picture is NULL"); -+ return; -+ } -+ if (!m_flipBuffer[index].outPic->render) -+ { -+ CLog::Log(LOGWARNING, "XVBA::CopyYV12: current render is NULL"); -+ return; -+ } -+ if (!m_flipBuffer[index].outPic->render->surface) -+ { -+ CLog::Log(LOGWARNING, "XVBA::CopyYV12: current surface is NULL"); -+ return; -+ } -+ -+ XVBA_GetSurface_Target target; -+ target.size = sizeof(target); -+ target.surfaceType = XVBA_YV12; -+ target.flag = XVBA_FRAME; -+ -+ XVBA_Get_Surface_Input input; -+ input.size = sizeof(input); -+ input.session = m_xvbaSession; -+ input.src_surface = m_flipBuffer[index].outPic->render->surface; -+ input.target_buffer = dest; -+ input.target_pitch = m_surfaceWidth; -+ input.target_width = m_surfaceWidth; -+ input.target_height = m_surfaceHeight; -+ input.target_parameter = target; -+ { CSingleLock lock(m_apiSec); -+ if (Success != g_XVBA_vtable.GetSurface(&input)) -+ { -+ CLog::Log(LOGERROR,"XVBA::CopyYV12: failed to get surface"); -+ } -+ } -+} -+ -+void CDecoder::Reset() -+{ -+ -+} -+ -+int CDecoder::UploadTexture(int index, XVBA_SURFACE_FLAG field, GLenum textureTarget) -+{ -+ CSharedLock lock(m_decoderSection); -+ -+ { CSharedLock dLock(m_displaySection); -+ if(m_displayState != XVBA_OPEN) -+ return -1; -+ } -+ -+ if (!m_flipBuffer[index].outPic || -+ !m_flipBuffer[index].outPic->render || -+ !m_flipBuffer[index].outPic->render->surface) -+ return -1; -+ -+ int i = field; -+// unsigned int first, last; -+// first = last = 0; -+// if (field != XVBA_FRAME) -+// { -+// first = 1; -+// last = 2; -+// } -+// for (unsigned int i = first; i <= last; ++i) -+ { -+ XVBA_SURFACE_FLAG field; -+ if (i==0) field = XVBA_FRAME; -+ else if (i==1) field = XVBA_TOP_FIELD; -+ else field = XVBA_BOTTOM_FIELD; -+ -+ if (!glIsTexture(m_flipBuffer[index].glTexture[i])) -+ { -+ glEnable(textureTarget); -+ glGenTextures(1, &m_flipBuffer[index].glTexture[i]); -+ glBindTexture(textureTarget, m_flipBuffer[index].glTexture[i]); -+ glTexParameteri(textureTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR); -+ glTexParameteri(textureTarget, GL_TEXTURE_MAG_FILTER, GL_LINEAR); -+ glTexParameteri(textureTarget, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); -+ glTexParameteri(textureTarget, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); -+ glPixelStorei(GL_UNPACK_ALIGNMENT, 4); -+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, m_surfaceWidth, m_surfaceHeight, 0, GL_BGRA, GL_UNSIGNED_BYTE, NULL); -+ -+ XVBA_Create_GLShared_Surface_Input surfInput; -+ XVBA_Create_GLShared_Surface_Output surfOutput; -+ surfInput.size = sizeof(surfInput); -+ surfInput.session = m_xvbaSession; -+ surfInput.gltexture = m_flipBuffer[index].glTexture[i]; -+ surfInput.glcontext = glXGetCurrentContext(); -+ surfOutput.size = sizeof(surfOutput); -+ surfOutput.surface = 0; -+ if (Success != g_XVBA_vtable.CreateGLSharedSurface(&surfInput, &surfOutput)) -+ { -+ CLog::Log(LOGERROR,"(XVBA) failed to create shared surface"); -+ return -1; -+ } -+ m_flipBuffer[index].glSurface[i] = surfOutput.surface; -+ CLog::Log(LOGDEBUG, "XVBA::GetTexture - created shared surface"); -+ } -+ -+ XVBA_Transfer_Surface_Input transInput; -+ transInput.size = sizeof(transInput); -+ transInput.session = m_xvbaSession; -+ transInput.src_surface = m_flipBuffer[index].outPic->render->surface; -+ transInput.target_surface = m_flipBuffer[index].glSurface[i]; -+ transInput.flag = field; -+ { CSingleLock lock(m_apiSec); -+ if (Success != g_XVBA_vtable.TransferSurface(&transInput)) -+ { -+ CLog::Log(LOGERROR,"(XVBA) failed to transfer surface"); -+ return -1; -+ } -+ } -+ } -+ -+// { CSingleLock lock(m_videoSurfaceSec); -+// m_flipBuffer[index].outPic->render->state &= ~FF_XVBA_STATE_USED_FOR_RENDER; -+// m_flipBuffer[index].outPic->render = NULL; -+// } -+// { -+// CSingleLock lock(m_outPicSec); -+// m_freeOutPic.push_back(m_flipBuffer[index].outPic); -+// m_flipBuffer[index].outPic = NULL; -+// } -+ -+ return 1; -+} -+ -+GLuint CDecoder::GetTexture(int index, XVBA_SURFACE_FLAG field) -+{ -+ return m_flipBuffer[index].glTexture[field]; -+} -+ -+CRect CDecoder::GetCropRect() -+{ -+ CRect crop; -+ crop.x1 = 0; -+ crop.y1 = 0; -+ crop.x2 = m_vidWidth; -+ crop.y2 = m_vidHeight; -+ return crop; -+} -+ -+void CDecoder::FinishGL() -+{ -+ CLog::Log(LOGNOTICE, "XVBA::FinishGL - clearing down gl resources"); -+ -+ CExclusiveLock lock(m_decoderSection); -+ // if decoder was created with non supported codec, we would not have a flipBuffer and segfault -+ if(!m_flipBuffer) -+ return; -+ -+ for (unsigned int i=0; irender) -+ { -+ { CSingleLock lock(m_videoSurfaceSec); -+ m_flipBuffer[i].outPic->render->state &= ~FF_XVBA_STATE_USED_FOR_RENDER; -+ m_flipBuffer[i].outPic->render = NULL; -+ } -+ { CSingleLock lock(m_outPicSec); -+ m_freeOutPic.push_back(m_flipBuffer[i].outPic); -+ m_flipBuffer[i].outPic = 0; -+ } -+ } -+ -+ for (unsigned int j=0; j<3; ++j) -+ { -+ if (m_flipBuffer[i].glSurface[j] && m_xvbaSession) -+ { -+ { CSingleLock lock(m_apiSec); -+ g_XVBA_vtable.DestroySurface(m_flipBuffer[i].glSurface[j]); -+ } -+ m_flipBuffer[i].glSurface[j] = 0; -+ CLog::Log(LOGDEBUG, "XVBA::FinishGL - destroyed shared surface"); -+ } -+ if (glIsTexture(m_flipBuffer[i].glTexture[j])) -+ { -+ glDeleteTextures(1, &m_flipBuffer[i].glTexture[j]); -+ m_flipBuffer[i].glTexture[j] = 0; -+ CLog::Log(LOGDEBUG, "XVBA::FinishGL - destroyed texture, index: %d, field %d", i, j); -+ } -+ } -+ } -+} -+ -+#endif -diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/XVBA.h b/xbmc/cores/dvdplayer/DVDCodecs/Video/XVBA.h -new file mode 100644 -index 0000000..07ef811 ---- /dev/null -+++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/XVBA.h -@@ -0,0 +1,161 @@ -+/* -+ * Copyright (C) 2005-2011 Team XBMC -+ * http://www.xbmc.org -+ * -+ * 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 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 XBMC; see the file COPYING. If not, write to -+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. -+ * http://www.gnu.org/copyleft/gpl.html -+ * -+ */ -+#pragma once -+ -+#include "X11/Xlib.h" -+#include "amd/amdxvba.h" -+#include "DllAvCodec.h" -+#include "DVDCodecs/Video/DVDVideoCodecFFmpeg.h" -+#include "threads/CriticalSection.h" -+#include "threads/SharedSection.h" -+#include "threads/Event.h" -+#include "guilib/DispResource.h" -+#include "guilib/Geometry.h" -+#include "libavcodec/xvba.h" -+#include -+#include -+ -+#define NUM_OUTPUT_PICS 7 -+ -+namespace XVBA -+{ -+ -+struct pictureAge -+{ -+ int b_age; -+ int ip_age[2]; -+}; -+ -+enum EDisplayState -+{ XVBA_OPEN -+, XVBA_RESET -+, XVBA_LOST -+, XVBA_ERROR -+}; -+ -+class CXVBAContext -+{ -+public: -+ static bool EnsureContext(CXVBAContext **ctx); -+ void *GetContext(); -+ void Release(); -+private: -+ CXVBAContext(); -+ void Close(); -+ bool LoadSymbols(); -+ bool CreateContext(); -+ void DestroyContext(); -+ static CXVBAContext *m_context; -+ static CCriticalSection m_section; -+ static Display *m_display; -+ int m_refCount; -+ static void *m_dlHandle; -+ void *m_xvbaContext; -+}; -+ -+class CDecoder : public CDVDVideoCodecFFmpeg::IHardwareDecoder, -+ public IDispResource -+{ -+public: -+ CDecoder(); -+ virtual ~CDecoder(); -+ virtual void OnLostDevice(); -+ virtual void OnResetDevice(); -+ -+ virtual bool Open(AVCodecContext* avctx, const enum PixelFormat fmt, unsigned int surfaces = 0); -+ virtual int Decode (AVCodecContext* avctx, AVFrame* frame); -+ virtual bool GetPicture(AVCodecContext* avctx, AVFrame* frame, DVDVideoPicture* picture); -+ virtual void Reset(); -+ virtual void Close(); -+ virtual int Check(AVCodecContext* avctx); -+ virtual const std::string Name() { return "xvba"; } -+ -+ void Present(int index); -+ void CopyYV12(int index, uint8_t *dest); -+ int UploadTexture(int index, XVBA_SURFACE_FLAG field, GLenum textureTarget); -+ GLuint GetTexture(int index, XVBA_SURFACE_FLAG field); -+ CRect GetCropRect(); -+ void FinishGL(); -+ -+protected: -+ bool CreateSession(AVCodecContext* avctx); -+ void DestroySession(); -+ bool EnsureDataControlBuffers(unsigned int num); -+ bool DiscardPresentPicture(); -+ void ResetState(); -+ void SetError(const char* function, const char* msg, int line); -+ bool IsSurfaceValid(xvba_render_state *render); -+ -+ // callbacks for ffmpeg -+ static void FFReleaseBuffer(AVCodecContext *avctx, AVFrame *pic); -+ static void FFDrawSlice(struct AVCodecContext *avctx, -+ const AVFrame *src, int offset[4], -+ int y, int type, int height); -+ static int FFGetBuffer(AVCodecContext *avctx, AVFrame *pic); -+ -+ DllAvUtil m_dllAvUtil; -+ CXVBAContext *m_context; -+ CSharedSection m_displaySection, m_decoderSection; -+ CEvent m_displayEvent; -+ EDisplayState m_displayState; -+ -+ unsigned int m_surfaceWidth, m_surfaceHeight; -+ unsigned int m_vidWidth, m_vidHeight; -+ unsigned int m_numRenderBuffers; -+ -+ XVBADecodeCap m_decoderCap; -+ void *m_xvbaSession; -+ unsigned int m_decoderId; -+ struct XVBABufferPool -+ { -+ XVBABufferDescriptor *picture_descriptor_buffer; -+ XVBABufferDescriptor *iq_matrix_buffer; -+ XVBABufferDescriptor *data_buffer; -+ std::vector data_control_buffers; -+ }; -+ XVBABufferPool m_xvbaBufferPool; -+ -+ std::vector m_videoSurfaces; -+ pictureAge picAge; -+ -+ struct OutputPicture -+ { -+ DVDVideoPicture dvdPic; -+ xvba_render_state *render; -+ void *glSurface; -+ }; -+ struct RenderPicture -+ { -+ OutputPicture *outPic; -+ bool isDuplicate; -+ void *glSurface[3]; -+ GLuint glTexture[3]; -+ }; -+ CCriticalSection m_outPicSec, m_videoSurfaceSec; -+ CCriticalSection m_apiSec; -+ OutputPicture m_allOutPic[NUM_OUTPUT_PICS]; -+ std::deque m_freeOutPic; -+ std::deque m_usedOutPic; -+ OutputPicture *m_presentPicture; -+ RenderPicture *m_flipBuffer; -+}; -+ -+} -diff --git a/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.cpp b/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.cpp -index 55138fa..423d9f8 100644 ---- a/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.cpp -+++ b/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.cpp -@@ -19,7 +19,6 @@ - * - */ - --#include "threads/SystemClock.h" - #include "system.h" - #ifndef __STDC_CONSTANT_MACROS - #define __STDC_CONSTANT_MACROS -@@ -44,6 +43,7 @@ - #include "filesystem/Directory.h" - #include "utils/log.h" - #include "threads/Thread.h" -+#include "threads/SystemClock.h" - #include "utils/TimeUtils.h" - - void CDemuxStreamAudioFFmpeg::GetStreamInfo(std::string& strInfo) -@@ -154,16 +154,12 @@ static void ff_flush_avutil_log_buffers(void) - ++it; - } - --#ifdef _MSC_VER --static __declspec(thread) CDVDDemuxFFmpeg* g_demuxer = 0; --#else --static TLS g_tls; --#define g_demuxer (*((CDVDDemuxFFmpeg**)g_tls.Get())) --#endif -+static XbmcThreads::ThreadLocal g_demuxer; - - static int interrupt_cb(void) - { -- if(g_demuxer && g_demuxer->Aborted()) -+ CDVDDemuxFFmpeg* demuxer = g_demuxer.get(); -+ if(demuxer && demuxer->Aborted()) - return 1; - return 0; - } -@@ -235,7 +231,7 @@ bool CDVDDemuxFFmpeg::Open(CDVDInputStream* pInput) - std::string strFile; - m_iCurrentPts = DVD_NOPTS_VALUE; - m_speed = DVD_PLAYSPEED_NORMAL; -- g_demuxer = this; -+ g_demuxer.set(this); - m_program = UINT_MAX; - - if (!pInput) return false; -@@ -507,7 +503,7 @@ bool CDVDDemuxFFmpeg::Open(CDVDInputStream* pInput) - - void CDVDDemuxFFmpeg::Dispose() - { -- g_demuxer = this; -+ g_demuxer.set(this); - - if (m_pFormatContext) - { -@@ -556,7 +552,7 @@ void CDVDDemuxFFmpeg::Reset() - - void CDVDDemuxFFmpeg::Flush() - { -- g_demuxer = this; -+ g_demuxer.set(this); - - // naughty usage of an internal ffmpeg function - if (m_pFormatContext) -@@ -572,7 +568,7 @@ void CDVDDemuxFFmpeg::Abort() - - void CDVDDemuxFFmpeg::SetSpeed(int iSpeed) - { -- g_demuxer = this; -+ g_demuxer.set(this); - - if(!m_pFormatContext) - return; -@@ -634,7 +630,7 @@ double CDVDDemuxFFmpeg::ConvertTimestamp(int64_t pts, int den, int num) - - DemuxPacket* CDVDDemuxFFmpeg::Read() - { -- g_demuxer = this; -+ g_demuxer.set(this); - - AVPacket pkt; - DemuxPacket* pPacket = NULL; -@@ -833,7 +829,7 @@ DemuxPacket* CDVDDemuxFFmpeg::Read() - - bool CDVDDemuxFFmpeg::SeekTime(int time, bool backwords, double *startpts) - { -- g_demuxer = this; -+ g_demuxer.set(this); - - if(time < 0) - time = 0; -@@ -893,7 +889,7 @@ bool CDVDDemuxFFmpeg::SeekTime(int time, bool backwords, double *startpts) - - bool CDVDDemuxFFmpeg::SeekByte(__int64 pos) - { -- g_demuxer = this; -+ g_demuxer.set(this); - - CSingleLock lock(m_critSection); - int ret = m_dllAvFormat.av_seek_frame(m_pFormatContext, -1, pos, AVSEEK_FLAG_BYTE); -diff --git a/xbmc/cores/dvdplayer/DVDPerformanceCounter.cpp b/xbmc/cores/dvdplayer/DVDPerformanceCounter.cpp -index 23c5e3e..129674a 100644 ---- a/xbmc/cores/dvdplayer/DVDPerformanceCounter.cpp -+++ b/xbmc/cores/dvdplayer/DVDPerformanceCounter.cpp -@@ -21,6 +21,7 @@ - - #include "DVDPerformanceCounter.h" - #include "DVDMessageQueue.h" -+#include "utils/TimeUtils.h" - - #include "dvd_config.h" - -@@ -68,22 +69,16 @@ HRESULT __stdcall DVDPerformanceCounterVideoQueue(PLARGE_INTEGER numerator, PLAR - - inline __int64 get_thread_cpu_usage(ProcessPerformance* p) - { -- if (p->hThread) -+ if (p->thread) - { -- FILETIME dummy; -- FILETIME current_time_thread; -- FILETIME current_time_system; - ULARGE_INTEGER old_time_thread; - ULARGE_INTEGER old_time_system; - - old_time_thread.QuadPart = p->timer_thread.QuadPart; - old_time_system.QuadPart = p->timer_system.QuadPart; - -- GetThreadTimes(p->hThread, &dummy, &dummy, ¤t_time_thread, &dummy); -- GetSystemTimeAsFileTime(¤t_time_system); -- -- FILETIME_TO_ULARGE_INTEGER(p->timer_thread, current_time_thread); -- FILETIME_TO_ULARGE_INTEGER(p->timer_system, current_time_system); -+ p->timer_thread.QuadPart = p->thread->GetAbsoluteUsage(); -+ p->timer_system.QuadPart = CurrentHostCounter(); - - __int64 threadTime = (p->timer_thread.QuadPart - old_time_thread.QuadPart); - __int64 systemTime = (p->timer_system.QuadPart - old_time_system.QuadPart); -diff --git a/xbmc/cores/dvdplayer/DVDPerformanceCounter.h b/xbmc/cores/dvdplayer/DVDPerformanceCounter.h -index 2f0b5ac..e97a14c 100644 ---- a/xbmc/cores/dvdplayer/DVDPerformanceCounter.h -+++ b/xbmc/cores/dvdplayer/DVDPerformanceCounter.h -@@ -24,7 +24,7 @@ - #define FILETIME_TO_ULARGE_INTEGER(ularge, filetime) { ularge.u.HighPart = filetime.dwHighDateTime; ularge.u.LowPart = filetime.dwLowDateTime; } - - #include "system.h" -- -+#include "threads/Thread.h" - #include "threads/SingleLock.h" - - class CDVDMessageQueue; -@@ -33,7 +33,7 @@ typedef struct stProcessPerformance - { - ULARGE_INTEGER timer_thread; - ULARGE_INTEGER timer_system; -- HANDLE hThread; -+ CThread* thread; - } ProcessPerformance; - - class CDVDPerformanceCounter -@@ -45,20 +45,20 @@ public: - bool Initialize(); - void DeInitialize(); - -- void EnableAudioQueue(CDVDMessageQueue* pQueue) { CSingleLock lock(m_critSection); m_pAudioQueue = pQueue; } -- void DisableAudioQueue() { CSingleLock lock(m_critSection); m_pAudioQueue = NULL; } -+ void EnableAudioQueue(CDVDMessageQueue* pQueue) { CSingleLock lock(m_critSection); m_pAudioQueue = pQueue; } -+ void DisableAudioQueue() { CSingleLock lock(m_critSection); m_pAudioQueue = NULL; } - -- void EnableVideoQueue(CDVDMessageQueue* pQueue) { CSingleLock lock(m_critSection); m_pVideoQueue = pQueue; } -- void DisableVideoQueue() { CSingleLock lock(m_critSection); m_pVideoQueue = NULL; } -+ void EnableVideoQueue(CDVDMessageQueue* pQueue) { CSingleLock lock(m_critSection); m_pVideoQueue = pQueue; } -+ void DisableVideoQueue() { CSingleLock lock(m_critSection); m_pVideoQueue = NULL; } - -- void EnableVideoDecodePerformance(HANDLE hThread) { CSingleLock lock(m_critSection); m_videoDecodePerformance.hThread = hThread; } -- void DisableVideoDecodePerformance() { CSingleLock lock(m_critSection); m_videoDecodePerformance.hThread = NULL; } -+ void EnableVideoDecodePerformance(CThread *thread) { CSingleLock lock(m_critSection); m_videoDecodePerformance.thread = thread; } -+ void DisableVideoDecodePerformance() { CSingleLock lock(m_critSection); m_videoDecodePerformance.thread = NULL; } - -- void EnableAudioDecodePerformance(HANDLE hThread) { CSingleLock lock(m_critSection); m_audioDecodePerformance.hThread = hThread; } -- void DisableAudioDecodePerformance() { CSingleLock lock(m_critSection); m_audioDecodePerformance.hThread = NULL; } -+ void EnableAudioDecodePerformance(CThread *thread) { CSingleLock lock(m_critSection); m_audioDecodePerformance.thread = thread; } -+ void DisableAudioDecodePerformance() { CSingleLock lock(m_critSection); m_audioDecodePerformance.thread = NULL; } - -- void EnableMainPerformance(HANDLE hThread) { CSingleLock lock(m_critSection); m_mainPerformance.hThread = hThread; } -- void DisableMainPerformance() { CSingleLock lock(m_critSection); m_mainPerformance.hThread = NULL; } -+ void EnableMainPerformance(CThread *thread) { CSingleLock lock(m_critSection); m_mainPerformance.thread = thread; } -+ void DisableMainPerformance() { CSingleLock lock(m_critSection); m_mainPerformance.thread = NULL; } - - CDVDMessageQueue* m_pAudioQueue; - CDVDMessageQueue* m_pVideoQueue; -diff --git a/xbmc/cores/dvdplayer/DVDPlayer.cpp b/xbmc/cores/dvdplayer/DVDPlayer.cpp -index 6c9a3ea..2d1338e 100644 ---- a/xbmc/cores/dvdplayer/DVDPlayer.cpp -+++ b/xbmc/cores/dvdplayer/DVDPlayer.cpp -@@ -348,7 +348,7 @@ bool CDVDPlayer::OpenFile(const CFileItem& file, const CPlayerOptions &options) - - // if playing a file close it first - // this has to be changed so we won't have to close it. -- if(ThreadHandle()) -+ if(IsRunning()) - CloseFile(); - - m_bAbortRequest = false; -@@ -440,9 +440,8 @@ void CDVDPlayer::OnStartup() - - m_messenger.Init(); - -- g_dvdPerformanceCounter.EnableMainPerformance(ThreadHandle()); -- - CUtil::ClearTempFonts(); -+ g_dvdPerformanceCounter.EnableMainPerformance(this); - } - - bool CDVDPlayer::OpenInputStream() -@@ -2897,7 +2896,7 @@ bool CDVDPlayer::OpenAudioStream(int iStream, int source) - m_dvdPlayerAudio.SendMessage(new CDVDMsg(CDVDMsg::PLAYER_STARTED), 1); - - /* audio normally won't consume full cpu, so let it have prio */ -- m_dvdPlayerAudio.SetPriority(GetThreadPriority(*this)+1); -+ m_dvdPlayerAudio.SetPriority(GetPriority()+1); - - return true; - } -@@ -2962,11 +2961,11 @@ bool CDVDPlayer::OpenVideoStream(int iStream, int source) - // the CoreAudio audio device handler thread. We do the same for - // the DVDPlayerVideo thread so it can run to sleep without getting - // swapped out by a busy OS. -- m_dvdPlayerVideo.SetPrioritySched_RR(); -+ m_dvdPlayerVideo.SetPriority(GetSchedRRPriority()); - #else - /* use same priority for video thread as demuxing thread, as */ - /* otherwise demuxer will starve if video consumes the full cpu */ -- m_dvdPlayerVideo.SetPriority(GetThreadPriority(*this)); -+ m_dvdPlayerVideo.SetPriority(GetPriority()); - #endif - return true; - -diff --git a/xbmc/cores/dvdplayer/DVDPlayerAudio.cpp b/xbmc/cores/dvdplayer/DVDPlayerAudio.cpp -index 41fbaaf..9f2128c 100644 ---- a/xbmc/cores/dvdplayer/DVDPlayerAudio.cpp -+++ b/xbmc/cores/dvdplayer/DVDPlayerAudio.cpp -@@ -518,7 +518,7 @@ void CDVDPlayerAudio::OnStartup() - m_decode.msg = NULL; - m_decode.Release(); - -- g_dvdPerformanceCounter.EnableAudioDecodePerformance(ThreadHandle()); -+ g_dvdPerformanceCounter.EnableAudioDecodePerformance(this); - - #ifdef _WIN32 - CoInitializeEx(NULL, COINIT_MULTITHREADED); -diff --git a/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp b/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp -index e28faaf..0b02b49 100644 ---- a/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp -+++ b/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp -@@ -189,7 +189,7 @@ bool CDVDPlayerVideo::OpenStream( CDVDStreamInfo &hint ) - return false; - } - -- if(g_guiSettings.GetBool("videoplayer.usedisplayasclock") && g_VideoReferenceClock.ThreadHandle() == NULL) -+ if(g_guiSettings.GetBool("videoplayer.usedisplayasclock") && !g_VideoReferenceClock.IsRunning()) - { - g_VideoReferenceClock.Create(); - //we have to wait for the clock to start otherwise alsa can cause trouble -@@ -291,7 +291,7 @@ void CDVDPlayerVideo::OnStartup() - m_iCurrentPts = DVD_NOPTS_VALUE; - m_FlipTimeStamp = m_pClock->GetAbsoluteClock(); - -- g_dvdPerformanceCounter.EnableVideoDecodePerformance(ThreadHandle()); -+ g_dvdPerformanceCounter.EnableVideoDecodePerformance(this); - } - - void CDVDPlayerVideo::Process() -@@ -1052,6 +1052,14 @@ int CDVDPlayerVideo::OutputPicture(const DVDVideoPicture* src, double pts) - flags |= CONF_FLAGS_FORMAT_CVBREF; - formatstr = "BGRA"; - break; -+ case DVDVideoPicture::FMT_XVBA: -+ flags |= CONF_FLAGS_FORMAT_XVBA; -+ formatstr = "XVBA"; -+ break; -+ case DVDVideoPicture::FMT_XVBA_YV12: -+ flags |= CONF_FLAGS_FORMAT_XVBA_YV12; -+ formatstr = "XVBA"; -+ break; - } - - if(m_bAllowFullscreen) -diff --git a/xbmc/cores/paplayer/PAPlayer.cpp b/xbmc/cores/paplayer/PAPlayer.cpp -index 43b57d3..13f5238 100644 ---- a/xbmc/cores/paplayer/PAPlayer.cpp -+++ b/xbmc/cores/paplayer/PAPlayer.cpp -@@ -52,7 +52,7 @@ - // Supporting all open audio codec standards. - // First one being nullsoft's nsv audio decoder format - --PAPlayer::PAPlayer(IPlayerCallback& callback) : IPlayer(callback) -+PAPlayer::PAPlayer(IPlayerCallback& callback) : CThread("PAPlayer"), IPlayer(callback) - { - m_bIsPlaying = false; - m_bPaused = false; -@@ -168,7 +168,7 @@ bool PAPlayer::OpenFile(const CFileItem& file, const CPlayerOptions &options) - - *m_currentFile = file; - -- if (ThreadHandle() == NULL) -+ if (!IsRunning()) - Create(); - - m_startEvent.Set(); -diff --git a/xbmc/dialogs/GUIDialogCache.cpp b/xbmc/dialogs/GUIDialogCache.cpp -index 1114cc6..85548e4 100644 ---- a/xbmc/dialogs/GUIDialogCache.cpp -+++ b/xbmc/dialogs/GUIDialogCache.cpp -@@ -29,7 +29,7 @@ - #include "threads/SingleLock.h" - #include "utils/TimeUtils.h" - --CGUIDialogCache::CGUIDialogCache(DWORD dwDelay, const CStdString& strHeader, const CStdString& strMsg) -+CGUIDialogCache::CGUIDialogCache(DWORD dwDelay, const CStdString& strHeader, const CStdString& strMsg) : CThread("CGUIDialogCache") - { - m_pDlg = (CGUIDialogProgress*)g_windowManager.GetWindow(WINDOW_DIALOG_PROGRESS); - -diff --git a/xbmc/filesystem/FileCache.cpp b/xbmc/filesystem/FileCache.cpp -index c6af9d0..63937ef 100644 ---- a/xbmc/filesystem/FileCache.cpp -+++ b/xbmc/filesystem/FileCache.cpp -@@ -79,7 +79,7 @@ private: - }; - - --CFileCache::CFileCache() -+CFileCache::CFileCache() : CThread("CFileCache") - { - m_bDeleteCache = true; - m_nSeekResult = 0; -@@ -95,7 +95,7 @@ CFileCache::CFileCache() - m_cacheFull = false; - } - --CFileCache::CFileCache(CCacheStrategy *pCache, bool bDeleteCache) -+CFileCache::CFileCache(CCacheStrategy *pCache, bool bDeleteCache) : CThread("CFileCache") - { - m_pCache = pCache; - m_bDeleteCache = bDeleteCache; -diff --git a/xbmc/filesystem/FilePipe.cpp b/xbmc/filesystem/FilePipe.cpp -index 1a55336..c61175e 100644 ---- a/xbmc/filesystem/FilePipe.cpp -+++ b/xbmc/filesystem/FilePipe.cpp -@@ -24,6 +24,8 @@ - #include "PipesManager.h" - #include "utils/StringUtils.h" - -+#define INFINITE 0xFFFFFFFF -+ - using namespace XFILE; - - CFilePipe::CFilePipe() : m_pos(0), m_length(-1), m_pipe(NULL) -diff --git a/xbmc/filesystem/FileRar.cpp b/xbmc/filesystem/FileRar.cpp -index 9c87a35..202b3ee 100644 ---- a/xbmc/filesystem/FileRar.cpp -+++ b/xbmc/filesystem/FileRar.cpp -@@ -43,7 +43,7 @@ using namespace std; - #define SEEKTIMOUT 30000 - - #ifdef HAS_FILESYSTEM_RAR --CFileRarExtractThread::CFileRarExtractThread() : hRunning(true), hQuit(true) -+CFileRarExtractThread::CFileRarExtractThread() : CThread("CFileRarExtractThread"), hRunning(true), hQuit(true) - { - m_pArc = NULL; - m_pCmd = NULL; -diff --git a/xbmc/filesystem/HTSPDirectory.cpp b/xbmc/filesystem/HTSPDirectory.cpp -index 83a1fca..152754d 100644 ---- a/xbmc/filesystem/HTSPDirectory.cpp -+++ b/xbmc/filesystem/HTSPDirectory.cpp -@@ -76,7 +76,7 @@ static SSessions g_sessions; - static CCriticalSection g_section; - - --CHTSPDirectorySession::CHTSPDirectorySession() -+CHTSPDirectorySession::CHTSPDirectorySession() : CThread("CHTSPDirectorySession") - { - } - -diff --git a/xbmc/filesystem/LastFMDirectory.cpp b/xbmc/filesystem/LastFMDirectory.cpp -index af5621c..a4b23fc 100644 ---- a/xbmc/filesystem/LastFMDirectory.cpp -+++ b/xbmc/filesystem/LastFMDirectory.cpp -@@ -69,7 +69,7 @@ bool CLastFMDirectory::RetrieveList(CStdString url) - m_dlgProgress->Progress(); - } - -- CThread thread(this); -+ CThread thread(this, "CLastFMDirectory"); - m_strSource = url; - m_strDestination = "special://temp/lastfm.xml"; - thread.Create(); -diff --git a/xbmc/filesystem/MythSession.cpp b/xbmc/filesystem/MythSession.cpp -index 45de2cc..304ecdd 100644 ---- a/xbmc/filesystem/MythSession.cpp -+++ b/xbmc/filesystem/MythSession.cpp -@@ -359,7 +359,7 @@ void CMythSession::SetSeasonAndEpisode(const cmyth_proginfo_t &program, int *sea - return; - } - --CMythSession::CMythSession(const CURL& url) -+CMythSession::CMythSession(const CURL& url) : CThread("CMythSession") - { - m_control = NULL; - m_event = NULL; -diff --git a/xbmc/filesystem/PipesManager.cpp b/xbmc/filesystem/PipesManager.cpp -index 73f4aa2..80a1044 100644 ---- a/xbmc/filesystem/PipesManager.cpp -+++ b/xbmc/filesystem/PipesManager.cpp -@@ -23,6 +23,8 @@ - #include "threads/SingleLock.h" - #include "Application.h" - -+#define INFINITE 0xFFFFFFFF -+ - #ifndef min - #define min(a,b) ((a) < (b) ? (a) : (b)) - #endif -diff --git a/xbmc/filesystem/RarManager.h b/xbmc/filesystem/RarManager.h -index dd4b2f0..6f93f79 100644 ---- a/xbmc/filesystem/RarManager.h -+++ b/xbmc/filesystem/RarManager.h -@@ -71,7 +71,7 @@ public: - CRarManager(); - ~CRarManager(); - bool CacheRarredFile(CStdString& strPathInCache, const CStdString& strRarPath, -- const CStdString& strPathInRar, BYTE bOptions = EXFILE_AUTODELETE, -+ const CStdString& strPathInRar, uint8_t bOptions = EXFILE_AUTODELETE, - const CStdString& strDir =RAR_DEFAULT_CACHE, const int64_t iSize=-1); - bool GetPathInCache(CStdString& strPathInCache, const CStdString& strRarPath, - const CStdString& strPathInRar = ""); -diff --git a/xbmc/filesystem/SAPDirectory.cpp b/xbmc/filesystem/SAPDirectory.cpp -index d8931b8..b997c12 100644 ---- a/xbmc/filesystem/SAPDirectory.cpp -+++ b/xbmc/filesystem/SAPDirectory.cpp -@@ -272,7 +272,7 @@ namespace SDP - using namespace SDP; - - --CSAPSessions::CSAPSessions() -+CSAPSessions::CSAPSessions() : CThread("CSAPSessions") - { - m_socket = INVALID_SOCKET; - } -@@ -486,7 +486,7 @@ namespace XFILE - - CSingleLock lock(g_sapsessions.m_section); - -- if(g_sapsessions.ThreadHandle() == NULL) -+ if(!g_sapsessions.IsRunning()) - g_sapsessions.Create(); - - // check if we can find this session in our cache -diff --git a/xbmc/interfaces/python/XBPython.cpp b/xbmc/interfaces/python/XBPython.cpp -index 9f43894..8cb3e61 100644 ---- a/xbmc/interfaces/python/XBPython.cpp -+++ b/xbmc/interfaces/python/XBPython.cpp -@@ -676,11 +676,11 @@ void XBPython::PulseGlobalEvent() - m_globalEvent.Set(); - } - --void XBPython::WaitForEvent(CEvent& hEvent, unsigned int timeout) -+void XBPython::WaitForEvent(CEvent& hEvent) - { - // wait for either this event our our global event - XbmcThreads::CEventGroup eventGroup(&hEvent, &m_globalEvent, NULL); -- eventGroup.wait(timeout); -+ eventGroup.wait(); - m_globalEvent.Reset(); - } - -diff --git a/xbmc/interfaces/python/XBPython.h b/xbmc/interfaces/python/XBPython.h -index 7737744..8877b54 100644 ---- a/xbmc/interfaces/python/XBPython.h -+++ b/xbmc/interfaces/python/XBPython.h -@@ -61,7 +61,7 @@ public: - void Process(); - - void PulseGlobalEvent(); -- void WaitForEvent(CEvent& hEvent, unsigned int timeout); -+ void WaitForEvent(CEvent& hEvent); - - int ScriptsSize(); - int GetPythonScriptId(int scriptPosition); -diff --git a/xbmc/interfaces/python/xbmcmodule/GUIPythonWindow.cpp b/xbmc/interfaces/python/xbmcmodule/GUIPythonWindow.cpp -index 4ec7e23..d44fc23 100644 ---- a/xbmc/interfaces/python/xbmcmodule/GUIPythonWindow.cpp -+++ b/xbmc/interfaces/python/xbmcmodule/GUIPythonWindow.cpp -@@ -181,9 +181,9 @@ void CGUIPythonWindow::SetCallbackWindow(void *state, void *object) - m_threadState = state; - } - --void CGUIPythonWindow::WaitForActionEvent(unsigned int timeout) -+void CGUIPythonWindow::WaitForActionEvent() - { -- g_pythonParser.WaitForEvent(m_actionEvent, timeout); -+ g_pythonParser.WaitForEvent(m_actionEvent); - m_actionEvent.Reset(); - } - -diff --git a/xbmc/interfaces/python/xbmcmodule/GUIPythonWindow.h b/xbmc/interfaces/python/xbmcmodule/GUIPythonWindow.h -index c776187..09c0d42 100644 ---- a/xbmc/interfaces/python/xbmcmodule/GUIPythonWindow.h -+++ b/xbmc/interfaces/python/xbmcmodule/GUIPythonWindow.h -@@ -51,7 +51,7 @@ public: - virtual bool OnAction(const CAction &action); - virtual bool OnBack(int actionID); - void SetCallbackWindow(void* state, void *object); -- void WaitForActionEvent(unsigned int timeout); -+ void WaitForActionEvent(); - void PulseActionEvent(); - void SetDestroyAfterDeinit(bool destroy = true); - protected: -diff --git a/xbmc/interfaces/python/xbmcmodule/GUIPythonWindowXML.cpp b/xbmc/interfaces/python/xbmcmodule/GUIPythonWindowXML.cpp -index 2db79f1..9644351 100644 ---- a/xbmc/interfaces/python/xbmcmodule/GUIPythonWindowXML.cpp -+++ b/xbmc/interfaces/python/xbmcmodule/GUIPythonWindowXML.cpp -@@ -279,9 +279,9 @@ void CGUIPythonWindowXML::ClearList() - UpdateButtons(); - } - --void CGUIPythonWindowXML::WaitForActionEvent(unsigned int timeout) -+void CGUIPythonWindowXML::WaitForActionEvent() - { -- g_pythonParser.WaitForEvent(m_actionEvent, timeout); -+ g_pythonParser.WaitForEvent(m_actionEvent); - m_actionEvent.Reset(); - } - -diff --git a/xbmc/interfaces/python/xbmcmodule/GUIPythonWindowXML.h b/xbmc/interfaces/python/xbmcmodule/GUIPythonWindowXML.h -index 27bc3a2..340be8b 100644 ---- a/xbmc/interfaces/python/xbmcmodule/GUIPythonWindowXML.h -+++ b/xbmc/interfaces/python/xbmcmodule/GUIPythonWindowXML.h -@@ -40,7 +40,7 @@ public: - virtual void AllocResources(bool forceLoad = false); - virtual void FreeResources(bool forceUnLoad = false); - void Process(unsigned int currentTime, CDirtyRegionList ®ions); -- void WaitForActionEvent(unsigned int timeout); -+ void WaitForActionEvent(); - void PulseActionEvent(); - void AddItem(CFileItemPtr fileItem,int itemPosition); - void RemoveItem(int itemPosition); -diff --git a/xbmc/interfaces/python/xbmcmodule/window.cpp b/xbmc/interfaces/python/xbmcmodule/window.cpp -index 9b9184a..1b72644 100644 ---- a/xbmc/interfaces/python/xbmcmodule/window.cpp -+++ b/xbmc/interfaces/python/xbmcmodule/window.cpp -@@ -540,11 +540,11 @@ namespace PYXBMC - - CPyThreadState pyState; - if (WindowXML_Check(self)) -- ((CGUIPythonWindowXML*)self->pWindow)->WaitForActionEvent(INFINITE); -+ ((CGUIPythonWindowXML*)self->pWindow)->WaitForActionEvent(); - else if (WindowXMLDialog_Check(self)) -- ((CGUIPythonWindowXMLDialog*)self->pWindow)->WaitForActionEvent(INFINITE); -+ ((CGUIPythonWindowXMLDialog*)self->pWindow)->WaitForActionEvent(); - else -- ((CGUIPythonWindow*)self->pWindow)->WaitForActionEvent(INFINITE); -+ ((CGUIPythonWindow*)self->pWindow)->WaitForActionEvent(); - } - } - Py_INCREF(Py_None); -diff --git a/xbmc/linux/Makefile.in b/xbmc/linux/Makefile.in -index c3a5877..43f552b 100644 ---- a/xbmc/linux/Makefile.in -+++ b/xbmc/linux/Makefile.in -@@ -10,14 +10,11 @@ SRCS=ConvUtils.cpp \ - LinuxResourceCounter.cpp \ - LinuxTimezone.cpp \ - PosixMountProvider.cpp \ -- XEventUtils.cpp \ - XFileUtils.cpp \ - XHandle.cpp \ - XLCDproc.cpp \ - XMemUtils.cpp \ -- XSyncUtils.cpp \ - XTimeUtils.cpp \ -- XThreadUtils.cpp \ - - LIB=linux.a - -diff --git a/xbmc/linux/PlatformDefs.h b/xbmc/linux/PlatformDefs.h -index 33d1c96..55d20c5 100644 ---- a/xbmc/linux/PlatformDefs.h -+++ b/xbmc/linux/PlatformDefs.h -@@ -182,8 +182,6 @@ - #define EXCEPTION_EXECUTE_HANDLER ... - //NOTE: dont try to define __except because it breaks g++ (already uses it). - --typedef pthread_t ThreadIdentifier; -- - struct CXHandle; // forward declaration - typedef CXHandle* HANDLE; - -diff --git a/xbmc/linux/PlatformInclude.h b/xbmc/linux/PlatformInclude.h -index 1f7e7e9..4e44ed8 100644 ---- a/xbmc/linux/PlatformInclude.h -+++ b/xbmc/linux/PlatformInclude.h -@@ -25,10 +25,7 @@ - #include "PlatformDefs.h" - #include "XHandlePublic.h" - #include "XFileUtils.h" --#include "XSyncUtils.h" --#include "XEventUtils.h" - #include "XTimeUtils.h" --#include "XThreadUtils.h" - #include "XMemUtils.h" - #include "ConvUtils.h" - -diff --git a/xbmc/linux/XEventUtils.cpp b/xbmc/linux/XEventUtils.cpp -deleted file mode 100644 -index 639b7b9..0000000 ---- a/xbmc/linux/XEventUtils.cpp -+++ /dev/null -@@ -1,144 +0,0 @@ --/* -- * Copyright (C) 2005-2008 Team XBMC -- * http://www.xbmc.org -- * -- * 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 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 XBMC; see the file COPYING. If not, write to -- * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. -- * http://www.gnu.org/copyleft/gpl.html -- * -- */ -- --#include "system.h" --#include "PlatformDefs.h" --#include "XEventUtils.h" --#include "XHandle.h" --#include "utils/log.h" --#include "threads/SingleLock.h" -- --using namespace std; -- --HANDLE WINAPI CreateEvent(void *pDummySec, bool bManualReset, bool bInitialState, char *szDummyName) --{ -- CXHandle *pHandle = new CXHandle(CXHandle::HND_EVENT); -- pHandle->m_bManualEvent = bManualReset; -- pHandle->m_hCond = new XbmcThreads::ConditionVariable(); -- pHandle->m_hMutex = new CCriticalSection(); -- pHandle->m_bEventSet = false; -- -- if (bInitialState) -- SetEvent(pHandle); -- -- return pHandle; --} -- --// --// The state of a manual-reset event object remains signaled until it is set explicitly to the nonsignaled --// state by the ResetEvent function. Any number of waiting threads, or threads that subsequently begin wait --// operations for the specified event object by calling one of the wait functions, can be released while the --// object's state is signaled. --// --// The state of an auto-reset event object remains signaled until a single waiting thread is released, at --// which time the system automatically sets the state to nonsignaled. If no threads are waiting, the event --// object's state remains signaled. --// --bool WINAPI SetEvent(HANDLE hEvent) --{ -- if (hEvent == NULL || hEvent->m_hCond == NULL || hEvent->m_hMutex == NULL) -- return false; -- -- CSingleLock lock(*(hEvent->m_hMutex)); -- hEvent->m_bEventSet = true; -- -- // we must guarantee that these handle's won't be deleted, until we are done -- list events = hEvent->m_hParents; -- for(list::iterator it = events.begin();it != events.end();it++) -- DuplicateHandle(GetCurrentProcess(), *it, GetCurrentProcess(), NULL, 0, FALSE, DUPLICATE_SAME_ACCESS); -- -- lock.Leave(); -- -- for(list::iterator it = events.begin();it != events.end();it++) -- { -- SetEvent(*it); -- CloseHandle(*it); -- } -- -- DuplicateHandle(GetCurrentProcess(), hEvent, GetCurrentProcess(), NULL, 0, FALSE, DUPLICATE_SAME_ACCESS); -- -- if (hEvent->m_bManualEvent == true) -- hEvent->m_hCond->notifyAll(); -- else -- hEvent->m_hCond->notify(); -- -- CloseHandle(hEvent); -- -- return true; --} -- --bool WINAPI ResetEvent(HANDLE hEvent) --{ -- if (hEvent == NULL || hEvent->m_hCond == NULL || hEvent->m_hMutex == NULL) -- return false; -- -- CSingleLock lock(*(hEvent->m_hMutex)); -- hEvent->m_bEventSet = false; -- -- return true; --} -- --bool WINAPI PulseEvent(HANDLE hEvent) --{ -- if (hEvent == NULL || hEvent->m_hCond == NULL || hEvent->m_hMutex == NULL) -- return false; -- -- CSingleLock lock(*(hEvent->m_hMutex)); -- // we must guarantee that these handle's won't be deleted, until we are done -- list events = hEvent->m_hParents; -- for(list::iterator it = events.begin();it != events.end();it++) -- DuplicateHandle(GetCurrentProcess(), *it, GetCurrentProcess(), NULL, 0, FALSE, DUPLICATE_SAME_ACCESS); -- -- if(events.size()) -- { -- CLog::Log(LOGWARNING,"PulseEvent - ineffecient multiwait detected"); -- hEvent->m_bEventSet = true; -- } -- -- lock.Leave(); -- -- for(list::iterator it = events.begin();it != events.end();it++) -- { -- SetEvent(*it); -- CloseHandle(*it); -- -- if (hEvent->m_bManualEvent == false) -- break; -- } -- -- // for multiwaits, we must yield some time to get the multiwaits to notice it was signaled -- if(events.size()) -- Sleep(10); -- -- // we should always unset the event on pulse -- { -- CSingleLock lock2(*(hEvent->m_hMutex)); -- hEvent->m_bEventSet = false; -- } -- -- if (hEvent->m_bManualEvent == true) -- hEvent->m_hCond->notifyAll(); -- else -- hEvent->m_hCond->notify(); -- -- return true; --} -- -diff --git a/xbmc/linux/XEventUtils.h b/xbmc/linux/XEventUtils.h -deleted file mode 100644 -index a77f843..0000000 ---- a/xbmc/linux/XEventUtils.h -+++ /dev/null -@@ -1,38 +0,0 @@ --#ifndef __X_EVENT_UTIL_H__ --#define __X_EVENT_UTIL_H__ -- --/* -- * Copyright (C) 2005-2008 Team XBMC -- * http://www.xbmc.org -- * -- * 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 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 XBMC; see the file COPYING. If not, write to -- * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. -- * http://www.gnu.org/copyleft/gpl.html -- * -- */ -- --#include "XHandlePublic.h" -- --#ifdef _LINUX -- --HANDLE WINAPI CreateEvent(void *pDummySec, bool bManualReset, bool bInitialState, char *szDummyName); --bool WINAPI SetEvent(HANDLE hEvent); --bool WINAPI ResetEvent(HANDLE hEvent); --bool WINAPI PulseEvent(HANDLE hEvent); -- --#endif -- -- --#endif -- -diff --git a/xbmc/linux/XHandle.cpp b/xbmc/linux/XHandle.cpp -index 61520b2..52f540a 100644 ---- a/xbmc/linux/XHandle.cpp -+++ b/xbmc/linux/XHandle.cpp -@@ -20,12 +20,15 @@ - */ - - #include "XHandle.h" --#include "XThreadUtils.h" - #include "utils/log.h" - #include "threads/SingleLock.h" - - int CXHandle::m_objectTracker[10] = {0}; - -+HANDLE WINAPI GetCurrentProcess(void) { -+ return (HANDLE)-1; // -1 a special value - pseudo handle -+} -+ - CXHandle::CXHandle() - { - Init(); -@@ -47,11 +50,6 @@ CXHandle::CXHandle(const CXHandle &src) - - Init(); - -- if (m_threadValid) -- { -- CLog::Log(LOGERROR, "%s - thread handle copied instead of passed!", __FUNCTION__); -- } -- - if (src.m_hMutex) - m_hMutex = new CCriticalSection(); - -@@ -80,7 +78,7 @@ CXHandle::~CXHandle() - CLog::Log(LOGERROR,"%s, destroying handle with ref count %d", __FUNCTION__, m_nRefCount); - assert(false); - } -- -+ - if (m_hMutex) { - delete m_hMutex; - } -@@ -93,10 +91,6 @@ CXHandle::~CXHandle() - delete m_hCond; - } - -- if (m_threadValid) { -- pthread_join(m_hThread, NULL); -- } -- - if ( fd != 0 ) { - close(fd); - } -@@ -107,11 +101,9 @@ void CXHandle::Init() - { - fd=0; - m_hMutex=NULL; -- m_threadValid=false; - m_hCond=NULL; - m_type = HND_NULL; - RecursionCount=0; -- OwningThread=0; - m_bManualEvent=FALSE; - m_bEventSet=FALSE; - m_nFindFileIterator=0 ; -diff --git a/xbmc/linux/XHandle.h b/xbmc/linux/XHandle.h -index 0e119bc..dd7f37d 100644 ---- a/xbmc/linux/XHandle.h -+++ b/xbmc/linux/XHandle.h -@@ -25,7 +25,6 @@ - #ifndef _WIN32 - - #include --#include - - #include "PlatformDefs.h" - #include "XHandlePublic.h" -@@ -36,7 +35,7 @@ - struct CXHandle { - - public: -- typedef enum { HND_NULL = 0, HND_FILE, HND_EVENT, HND_MUTEX, HND_THREAD, HND_FIND_FILE } HandleType; -+ typedef enum { HND_NULL = 0, HND_FILE, HND_EVENT, HND_MUTEX, HND_FIND_FILE } HandleType; - - CXHandle(); - CXHandle(HandleType nType); -@@ -47,8 +46,6 @@ public: - inline HandleType GetType() { return m_type; } - void ChangeType(HandleType newType); - -- ThreadIdentifier m_hThread; -- bool m_threadValid; - XbmcThreads::ConditionVariable *m_hCond; - std::list m_hParents; - -@@ -62,7 +59,6 @@ public: - // simulate mutex and critical section - CCriticalSection *m_hMutex; - int RecursionCount; // for mutex - for compatibility with WIN32 critical section -- pthread_t OwningThread; - int fd; - bool m_bManualEvent; - time_t m_tmCreation; -diff --git a/xbmc/linux/XMemUtils.cpp b/xbmc/linux/XMemUtils.cpp -index 906fe4e..c0006fe 100644 ---- a/xbmc/linux/XMemUtils.cpp -+++ b/xbmc/linux/XMemUtils.cpp -@@ -25,6 +25,10 @@ - - #include "XMemUtils.h" - -+#ifdef __APPLE__ -+#include -+#endif -+ - #undef ALIGN - #define ALIGN(value, alignment) (((value)+(alignment-1))&~(alignment-1)) - -@@ -49,4 +53,130 @@ void _aligned_free(void *p) { - free(pFull); - } - -+#ifndef _WIN32 -+ -+#if defined(_LINUX) && !defined(__APPLE__) && !defined(__FreeBSD__) -+static FILE* procMeminfoFP = NULL; -+#endif -+ -+void GlobalMemoryStatusEx(LPMEMORYSTATUSEX lpBuffer) -+{ -+ if (!lpBuffer) -+ return; -+ -+ memset(lpBuffer, 0, sizeof(MEMORYSTATUSEX)); -+ -+#ifdef __APPLE__ -+ uint64_t physmem; -+ size_t len = sizeof physmem; -+ int mib[2] = { CTL_HW, HW_MEMSIZE }; -+ size_t miblen = sizeof(mib) / sizeof(mib[0]); -+ -+ // Total physical memory. -+ if (sysctl(mib, miblen, &physmem, &len, NULL, 0) == 0 && len == sizeof (physmem)) -+ lpBuffer->ullTotalPhys = physmem; -+ -+ // Virtual memory. -+ mib[0] = CTL_VM; mib[1] = VM_SWAPUSAGE; -+ struct xsw_usage swap; -+ len = sizeof(struct xsw_usage); -+ if (sysctl(mib, miblen, &swap, &len, NULL, 0) == 0) -+ { -+ lpBuffer->ullAvailPageFile = swap.xsu_avail; -+ lpBuffer->ullTotalVirtual = lpBuffer->ullTotalPhys + swap.xsu_total; -+ } -+ -+ // In use. -+ mach_port_t stat_port = mach_host_self(); -+ vm_statistics_data_t vm_stat; -+ mach_msg_type_number_t count = sizeof(vm_stat) / sizeof(natural_t); -+ if (host_statistics(stat_port, HOST_VM_INFO, (host_info_t)&vm_stat, &count) == 0) -+ { -+ // Find page size. -+ int pageSize; -+ mib[0] = CTL_HW; mib[1] = HW_PAGESIZE; -+ len = sizeof(int); -+ if (sysctl(mib, miblen, &pageSize, &len, NULL, 0) == 0) -+ { -+ uint64_t used = (vm_stat.active_count + vm_stat.inactive_count + vm_stat.wire_count) * pageSize; -+ -+ lpBuffer->ullAvailPhys = lpBuffer->ullTotalPhys - used; -+ lpBuffer->ullAvailVirtual = lpBuffer->ullAvailPhys; // FIXME. -+ } -+ } -+#elif defined(__FreeBSD__) -+ /* sysctl hw.physmem */ -+ size_t physmem = 0, mem_free = 0, pagesize = 0, swap_free = 0; -+ size_t mem_avail = 0, mem_inactive = 0, mem_cache = 0, len = 0; -+ -+ /* physmem */ -+ len = sizeof(physmem); -+ if (sysctlbyname("hw.physmem", &physmem, &len, NULL, 0) == 0) { -+ lpBuffer->ullTotalPhys = physmem; -+ lpBuffer->ullTotalVirtual = physmem; -+ } -+ /* pagesize */ -+ len = sizeof(pagesize); -+ if (sysctlbyname("hw.pagesize", &pagesize, &len, NULL, 0) != 0) -+ pagesize = 4096; -+ /* mem_inactive */ -+ len = sizeof(mem_inactive); -+ if (sysctlbyname("vm.stats.vm.v_inactive_count", &mem_inactive, &len, NULL, 0) == 0) -+ mem_inactive *= pagesize; -+ /* mem_cache */ -+ len = sizeof(mem_cache); -+ if (sysctlbyname("vm.stats.vm.v_cache_count", &mem_cache, &len, NULL, 0) == 0) -+ mem_cache *= pagesize; -+ /* mem_free */ -+ len = sizeof(mem_free); -+ if (sysctlbyname("vm.stats.vm.v_free_count", &mem_free, &len, NULL, 0) == 0) -+ mem_free *= pagesize; -+ -+ /* mem_avail = mem_inactive + mem_cache + mem_free */ -+ lpBuffer->ullAvailPhys = mem_inactive + mem_cache + mem_free; -+ lpBuffer->ullAvailVirtual = mem_inactive + mem_cache + mem_free; -+ -+ if (sysctlbyname("vm.stats.vm.v_swappgsout", &swap_free, &len, NULL, 0) == 0) -+ lpBuffer->ullAvailPageFile = swap_free * pagesize; -+#else -+ struct sysinfo info; -+ char name[32]; -+ unsigned val; -+ if (!procMeminfoFP && (procMeminfoFP = fopen("/proc/meminfo", "r")) == NULL) -+ sysinfo(&info); -+ else -+ { -+ memset(&info, 0, sizeof(struct sysinfo)); -+ info.mem_unit = 4096; -+ while (fscanf(procMeminfoFP, "%31s %u%*[^\n]\n", name, &val) != EOF) -+ { -+ if (strncmp("MemTotal:", name, 9) == 0) -+ info.totalram = val/4; -+ else if (strncmp("MemFree:", name, 8) == 0) -+ info.freeram = val/4; -+ else if (strncmp("Buffers:", name, 8) == 0) -+ info.bufferram += val/4; -+ else if (strncmp("Cached:", name, 7) == 0) -+ info.bufferram += val/4; -+ else if (strncmp("SwapTotal:", name, 10) == 0) -+ info.totalswap = val/4; -+ else if (strncmp("SwapFree:", name, 9) == 0) -+ info.freeswap = val/4; -+ else if (strncmp("HighTotal:", name, 10) == 0) -+ info.totalhigh = val/4; -+ else if (strncmp("HighFree:", name, 9) == 0) -+ info.freehigh = val/4; -+ } -+ rewind(procMeminfoFP); -+ fflush(procMeminfoFP); -+ } -+ lpBuffer->ullAvailPageFile = (info.freeswap * info.mem_unit); -+ lpBuffer->ullAvailPhys = ((info.freeram + info.bufferram) * info.mem_unit); -+ lpBuffer->ullAvailVirtual = ((info.freeram + info.bufferram) * info.mem_unit); -+ lpBuffer->ullTotalPhys = (info.totalram * info.mem_unit); -+ lpBuffer->ullTotalVirtual = (info.totalram * info.mem_unit); -+#endif -+} -+ -+#endif - -diff --git a/xbmc/linux/XMemUtils.h b/xbmc/linux/XMemUtils.h -index d6d314a..83fc95d 100644 ---- a/xbmc/linux/XMemUtils.h -+++ b/xbmc/linux/XMemUtils.h -@@ -22,10 +22,14 @@ - * - */ - -+#include "linux/PlatformDefs.h" -+ - // aligned memory allocation and free. memory returned will be aligned to "alignTo" bytes. - // this is a linux (actually platfom free) implementation of the win32 CRT methods _aligned_malloc and _aligned_free. - void *_aligned_malloc(size_t s, size_t alignTo); - void _aligned_free(void *p) ; - -+void GlobalMemoryStatusEx(LPMEMORYSTATUSEX lpBuffer); -+ - #endif - -diff --git a/xbmc/linux/XSyncUtils.cpp b/xbmc/linux/XSyncUtils.cpp -deleted file mode 100644 -index 19c4b5a..0000000 ---- a/xbmc/linux/XSyncUtils.cpp -+++ /dev/null -@@ -1,169 +0,0 @@ --/* -- * Copyright (C) 2005-2008 Team XBMC -- * http://www.xbmc.org -- * -- * 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 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 XBMC; see the file COPYING. If not, write to -- * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. -- * http://www.gnu.org/copyleft/gpl.html -- * -- */ -- --#ifndef _WIN32 -- -- --#include --#include --#include --#include --#include --#ifdef __APPLE__ --#include --#endif -- --#include "XSyncUtils.h" --#include "XTimeUtils.h" --#include "PlatformDefs.h" --#include "XHandle.h" --#include "XEventUtils.h" -- --using namespace std; --using namespace XbmcThreads; -- --#include "../utils/log.h" --#include "../utils/TimeUtils.h" -- --#if defined(_LINUX) && !defined(__APPLE__) && !defined(__FreeBSD__) --static FILE* procMeminfoFP = NULL; --#endif -- --void GlobalMemoryStatusEx(LPMEMORYSTATUSEX lpBuffer) --{ -- if (!lpBuffer) -- return; -- -- memset(lpBuffer, 0, sizeof(MEMORYSTATUSEX)); -- --#ifdef __APPLE__ -- uint64_t physmem; -- size_t len = sizeof physmem; -- int mib[2] = { CTL_HW, HW_MEMSIZE }; -- size_t miblen = sizeof(mib) / sizeof(mib[0]); -- -- // Total physical memory. -- if (sysctl(mib, miblen, &physmem, &len, NULL, 0) == 0 && len == sizeof (physmem)) -- lpBuffer->ullTotalPhys = physmem; -- -- // Virtual memory. -- mib[0] = CTL_VM; mib[1] = VM_SWAPUSAGE; -- struct xsw_usage swap; -- len = sizeof(struct xsw_usage); -- if (sysctl(mib, miblen, &swap, &len, NULL, 0) == 0) -- { -- lpBuffer->ullAvailPageFile = swap.xsu_avail; -- lpBuffer->ullTotalVirtual = lpBuffer->ullTotalPhys + swap.xsu_total; -- } -- -- // In use. -- mach_port_t stat_port = mach_host_self(); -- vm_statistics_data_t vm_stat; -- mach_msg_type_number_t count = sizeof(vm_stat) / sizeof(natural_t); -- if (host_statistics(stat_port, HOST_VM_INFO, (host_info_t)&vm_stat, &count) == 0) -- { -- // Find page size. -- int pageSize; -- mib[0] = CTL_HW; mib[1] = HW_PAGESIZE; -- len = sizeof(int); -- if (sysctl(mib, miblen, &pageSize, &len, NULL, 0) == 0) -- { -- uint64_t used = (vm_stat.active_count + vm_stat.inactive_count + vm_stat.wire_count) * pageSize; -- -- lpBuffer->ullAvailPhys = lpBuffer->ullTotalPhys - used; -- lpBuffer->ullAvailVirtual = lpBuffer->ullAvailPhys; // FIXME. -- } -- } --#elif defined(__FreeBSD__) -- /* sysctl hw.physmem */ -- size_t physmem = 0, mem_free = 0, pagesize = 0, swap_free = 0; -- size_t mem_avail = 0, mem_inactive = 0, mem_cache = 0, len = 0; -- -- /* physmem */ -- len = sizeof(physmem); -- if (sysctlbyname("hw.physmem", &physmem, &len, NULL, 0) == 0) { -- lpBuffer->ullTotalPhys = physmem; -- lpBuffer->ullTotalVirtual = physmem; -- } -- /* pagesize */ -- len = sizeof(pagesize); -- if (sysctlbyname("hw.pagesize", &pagesize, &len, NULL, 0) != 0) -- pagesize = 4096; -- /* mem_inactive */ -- len = sizeof(mem_inactive); -- if (sysctlbyname("vm.stats.vm.v_inactive_count", &mem_inactive, &len, NULL, 0) == 0) -- mem_inactive *= pagesize; -- /* mem_cache */ -- len = sizeof(mem_cache); -- if (sysctlbyname("vm.stats.vm.v_cache_count", &mem_cache, &len, NULL, 0) == 0) -- mem_cache *= pagesize; -- /* mem_free */ -- len = sizeof(mem_free); -- if (sysctlbyname("vm.stats.vm.v_free_count", &mem_free, &len, NULL, 0) == 0) -- mem_free *= pagesize; -- -- /* mem_avail = mem_inactive + mem_cache + mem_free */ -- lpBuffer->ullAvailPhys = mem_inactive + mem_cache + mem_free; -- lpBuffer->ullAvailVirtual = mem_inactive + mem_cache + mem_free; -- -- if (sysctlbyname("vm.stats.vm.v_swappgsout", &swap_free, &len, NULL, 0) == 0) -- lpBuffer->ullAvailPageFile = swap_free * pagesize; --#else -- struct sysinfo info; -- char name[32]; -- unsigned val; -- if (!procMeminfoFP && (procMeminfoFP = fopen("/proc/meminfo", "r")) == NULL) -- sysinfo(&info); -- else -- { -- memset(&info, 0, sizeof(struct sysinfo)); -- info.mem_unit = 4096; -- while (fscanf(procMeminfoFP, "%31s %u%*[^\n]\n", name, &val) != EOF) -- { -- if (strncmp("MemTotal:", name, 9) == 0) -- info.totalram = val/4; -- else if (strncmp("MemFree:", name, 8) == 0) -- info.freeram = val/4; -- else if (strncmp("Buffers:", name, 8) == 0) -- info.bufferram += val/4; -- else if (strncmp("Cached:", name, 7) == 0) -- info.bufferram += val/4; -- else if (strncmp("SwapTotal:", name, 10) == 0) -- info.totalswap = val/4; -- else if (strncmp("SwapFree:", name, 9) == 0) -- info.freeswap = val/4; -- else if (strncmp("HighTotal:", name, 10) == 0) -- info.totalhigh = val/4; -- else if (strncmp("HighFree:", name, 9) == 0) -- info.freehigh = val/4; -- } -- rewind(procMeminfoFP); -- fflush(procMeminfoFP); -- } -- lpBuffer->ullAvailPageFile = (info.freeswap * info.mem_unit); -- lpBuffer->ullAvailPhys = ((info.freeram + info.bufferram) * info.mem_unit); -- lpBuffer->ullAvailVirtual = ((info.freeram + info.bufferram) * info.mem_unit); -- lpBuffer->ullTotalPhys = (info.totalram * info.mem_unit); -- lpBuffer->ullTotalVirtual = (info.totalram * info.mem_unit); --#endif --} -- --#endif -diff --git a/xbmc/linux/XSyncUtils.h b/xbmc/linux/XSyncUtils.h -deleted file mode 100644 -index f3ad36f..0000000 ---- a/xbmc/linux/XSyncUtils.h -+++ /dev/null -@@ -1,44 +0,0 @@ --#ifndef __X_SYNC_UTILS_ --#define __X_SYNC_UTILS_ -- --/* -- * Copyright (C) 2005-2008 Team XBMC -- * http://www.xbmc.org -- * -- * 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 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 XBMC; see the file COPYING. If not, write to -- * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. -- * http://www.gnu.org/copyleft/gpl.html -- * -- */ -- --#include "PlatformDefs.h" --#include "XHandlePublic.h" -- --#ifdef _LINUX -- --#define STATUS_WAIT_0 ((DWORD )0x00000000L) --#define WAIT_FAILED ((DWORD)0xFFFFFFFF) --#define WAIT_OBJECT_0 ((STATUS_WAIT_0 ) + 0 ) --#define WAIT_TIMEOUT 258L --#define INFINITE 0xFFFFFFFF --#define STATUS_ABANDONED_WAIT_0 0x00000080 --#define WAIT_ABANDONED ((STATUS_ABANDONED_WAIT_0 ) + 0 ) --#define WAIT_ABANDONED_0 ((STATUS_ABANDONED_WAIT_0 ) + 0 ) -- --void GlobalMemoryStatusEx(LPMEMORYSTATUSEX lpBuffer); -- --#endif -- --#endif -- -diff --git a/xbmc/linux/XThreadUtils.cpp b/xbmc/linux/XThreadUtils.cpp -deleted file mode 100644 -index 9d68481..0000000 ---- a/xbmc/linux/XThreadUtils.cpp -+++ /dev/null -@@ -1,210 +0,0 @@ --/* -- * Copyright (C) 2005-2009 Team XBMC -- * http://www.xbmc.org -- * -- * 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 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 XBMC; see the file COPYING. If not, write to -- * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. -- * http://www.gnu.org/copyleft/gpl.html -- * -- */ -- --#include "PlatformDefs.h" --#include "XHandle.h" --#include "XThreadUtils.h" --#include "XTimeUtils.h" --#include "XEventUtils.h" --#include "system.h" --#include "utils/log.h" -- --#ifdef _LINUX --#include --#include --#include -- --HANDLE WINAPI CreateThread( -- LPSECURITY_ATTRIBUTES lpThreadAttributes, -- SIZE_T dwStackSize, -- LPTHREAD_START_ROUTINE lpStartAddress, -- LPVOID lpParameter, -- DWORD dwCreationFlags, -- LPDWORD lpThreadId -- ) { -- -- // a thread handle would actually contain an event -- // the event would mark if the thread is running or not. it will be used in the Wait functions. -- HANDLE h = CreateEvent(NULL, TRUE, FALSE, NULL); -- h->ChangeType(CXHandle::HND_THREAD); --#ifdef __APPLE__ -- h->m_machThreadPort = MACH_PORT_NULL; --#endif -- pthread_attr_t attr; -- pthread_attr_init(&attr); -- if (dwStackSize > PTHREAD_STACK_MIN) -- pthread_attr_setstacksize(&attr, dwStackSize); -- if (pthread_create(&(h->m_hThread), &attr, (void*(*)(void*))lpStartAddress, lpParameter) == 0) -- h->m_threadValid = true; -- else -- { -- CloseHandle(h); -- h = NULL; -- } -- pthread_attr_destroy(&attr); -- -- if (h && lpThreadId) -- // WARNING: This can truncate thread IDs on x86_64. -- *lpThreadId = (DWORD)h->m_hThread; -- return h; --} -- -- --#if 0 // Deprecated, use CThread::GetCurrentThreadId() instead --DWORD WINAPI GetCurrentThreadId(void) { -- // WARNING: This can truncate thread IDs on x86_64. -- return (DWORD)pthread_self(); --} --#endif -- --HANDLE WINAPI GetCurrentThread(void) { -- return (HANDLE)-1; // -1 a special value - pseudo handle --} -- --HANDLE WINAPI GetCurrentProcess(void) { -- return (HANDLE)-1; // -1 a special value - pseudo handle --} -- --HANDLE _beginthreadex( -- void *security, -- unsigned stack_size, -- int ( *start_address )( void * ), -- void *arglist, -- unsigned initflag, -- unsigned *thrdaddr --) { -- -- HANDLE h = CreateThread(NULL, stack_size, start_address, arglist, initflag, (LPDWORD)thrdaddr); -- return h; -- --} -- --uintptr_t _beginthread( -- void( *start_address )( void * ), -- unsigned stack_size, -- void *arglist --) { -- HANDLE h = CreateThread(NULL, stack_size, (LPTHREAD_START_ROUTINE)start_address, arglist, 0, NULL); -- return (uintptr_t)h; --} -- --BOOL WINAPI GetThreadTimes ( -- HANDLE hThread, -- LPFILETIME lpCreationTime, -- LPFILETIME lpExitTime, -- LPFILETIME lpKernelTime, -- LPFILETIME lpUserTime --) { -- if (!hThread) -- return false; -- if (!hThread->m_threadValid) -- return false; -- -- if (hThread == (HANDLE)-1) { -- if (lpCreationTime) -- TimeTToFileTime(0,lpCreationTime); -- if (lpExitTime) -- TimeTToFileTime(time(NULL),lpExitTime); -- if (lpKernelTime) -- TimeTToFileTime(0,lpKernelTime); -- if (lpUserTime) -- TimeTToFileTime(0,lpUserTime); -- -- return true; -- } -- -- if (lpCreationTime) -- TimeTToFileTime(hThread->m_tmCreation,lpCreationTime); -- if (lpExitTime) -- TimeTToFileTime(time(NULL),lpExitTime); -- if (lpKernelTime) -- TimeTToFileTime(0,lpKernelTime); -- --#ifdef __APPLE__ -- thread_info_data_t threadInfo; -- mach_msg_type_number_t threadInfoCount = THREAD_INFO_MAX; -- -- if (hThread->m_machThreadPort == MACH_PORT_NULL) -- hThread->m_machThreadPort = pthread_mach_thread_np(hThread->m_hThread); -- -- kern_return_t ret = thread_info(hThread->m_machThreadPort, THREAD_BASIC_INFO, (thread_info_t)threadInfo, &threadInfoCount); -- if (ret == KERN_SUCCESS) -- { -- thread_basic_info_t threadBasicInfo = (thread_basic_info_t)threadInfo; -- -- if (lpUserTime) -- { -- // User time. -- unsigned long long time = ((__int64)threadBasicInfo->user_time.seconds * 10000000L) + threadBasicInfo->user_time.microseconds*10L; -- lpUserTime->dwLowDateTime = (time & 0xFFFFFFFF); -- lpUserTime->dwHighDateTime = (time >> 32); -- } -- -- if (lpKernelTime) -- { -- // System time. -- unsigned long long time = ((__int64)threadBasicInfo->system_time.seconds * 10000000L) + threadBasicInfo->system_time.microseconds*10L; -- lpKernelTime->dwLowDateTime = (time & 0xFFFFFFFF); -- lpKernelTime->dwHighDateTime = (time >> 32); -- } -- } -- else -- { -- if (lpUserTime) -- lpUserTime->dwLowDateTime = lpUserTime->dwHighDateTime = 0; -- -- if (lpKernelTime) -- lpKernelTime->dwLowDateTime = lpKernelTime->dwHighDateTime = 0; -- } --#elif _POSIX_THREAD_CPUTIME != -1 -- if(lpUserTime) -- { -- lpUserTime->dwLowDateTime = 0; -- lpUserTime->dwHighDateTime = 0; -- clockid_t clock; -- if (pthread_getcpuclockid(hThread->m_hThread, &clock) == 0) -- { -- struct timespec tp = {}; -- clock_gettime(clock, &tp); -- unsigned long long time = (unsigned long long)tp.tv_sec * 10000000 + (unsigned long long)tp.tv_nsec/100; -- lpUserTime->dwLowDateTime = (time & 0xFFFFFFFF); -- lpUserTime->dwHighDateTime = (time >> 32); -- } -- } --#else -- if (lpUserTime) -- TimeTToFileTime(0,lpUserTime); --#endif -- return true; --} -- --BOOL WINAPI SetThreadPriority(HANDLE hThread, int nPriority) --{ -- return true; --} -- --int GetThreadPriority(HANDLE hThread) --{ -- return 0; --} -- --#endif -- -diff --git a/xbmc/music/LastFmManager.cpp b/xbmc/music/LastFmManager.cpp -index 700f28a..b97fdf2 100644 ---- a/xbmc/music/LastFmManager.cpp -+++ b/xbmc/music/LastFmManager.cpp -@@ -70,7 +70,7 @@ using namespace XFILE; - - CLastFmManager* CLastFmManager::m_pInstance=NULL; - --CLastFmManager::CLastFmManager() -+CLastFmManager::CLastFmManager() : CThread("CLastFmManager") - { - m_RadioTrackQueue = new CPlayList; - } -@@ -534,7 +534,7 @@ void CLastFmManager::Update() - if (iNrCachedTracks == 0) - { - //get more tracks -- if (ThreadHandle() != NULL) -+ if (IsRunning()) - { - m_hWorkerEvent.Set(); - } -@@ -633,7 +633,7 @@ void CLastFmManager::StopRadio(bool bKillSession /*= true*/) - { - m_RadioSession = ""; - } -- if (m_ThreadHandle) -+ if (IsRunning()) - { - m_bStop = true; - m_hWorkerEvent.Set(); -diff --git a/xbmc/music/infoscanner/MusicInfoScanner.cpp b/xbmc/music/infoscanner/MusicInfoScanner.cpp -index 3400f27..445edaf 100644 ---- a/xbmc/music/infoscanner/MusicInfoScanner.cpp -+++ b/xbmc/music/infoscanner/MusicInfoScanner.cpp -@@ -57,7 +57,7 @@ using namespace MUSIC_INFO; - using namespace XFILE; - using namespace MUSIC_GRABBER; - --CMusicInfoScanner::CMusicInfoScanner() -+CMusicInfoScanner::CMusicInfoScanner() : CThread("CMusicInfoScanner") - { - m_bRunning = false; - m_pObserver = NULL; -@@ -99,7 +99,7 @@ void CMusicInfoScanner::Process() - - // Create the thread to count all files to be scanned - SetPriority( GetMinPriority() ); -- CThread fileCountReader(this); -+ CThread fileCountReader(this, "CMusicInfoScanner"); - if (m_pObserver) - fileCountReader.Create(); - -diff --git a/xbmc/music/infoscanner/MusicInfoScraper.cpp b/xbmc/music/infoscanner/MusicInfoScraper.cpp -index 09aeb14..aad726c 100644 ---- a/xbmc/music/infoscanner/MusicInfoScraper.cpp -+++ b/xbmc/music/infoscanner/MusicInfoScraper.cpp -@@ -28,7 +28,7 @@ using namespace MUSIC_GRABBER; - using namespace ADDON; - using namespace std; - --CMusicInfoScraper::CMusicInfoScraper(const ADDON::ScraperPtr &scraper) -+CMusicInfoScraper::CMusicInfoScraper(const ADDON::ScraperPtr &scraper) : CThread("CMusicInfoScraper") - { - m_bSucceeded=false; - m_bCanceled=false; -diff --git a/xbmc/network/AirPlayServer.cpp b/xbmc/network/AirPlayServer.cpp -index 7388997..1ba7871 100644 ---- a/xbmc/network/AirPlayServer.cpp -+++ b/xbmc/network/AirPlayServer.cpp -@@ -184,7 +184,7 @@ void CAirPlayServer::StopServer(bool bWait) - } - } - --CAirPlayServer::CAirPlayServer(int port, bool nonlocal) -+CAirPlayServer::CAirPlayServer(int port, bool nonlocal) : CThread("AirPlayServer") - { - m_port = port; - m_nonlocal = nonlocal; -diff --git a/xbmc/network/AirTunesServer.cpp b/xbmc/network/AirTunesServer.cpp -index f092bb4..8cafa8e 100644 ---- a/xbmc/network/AirTunesServer.cpp -+++ b/xbmc/network/AirTunesServer.cpp -@@ -292,7 +292,7 @@ void CAirTunesServer::StopServer(bool bWait) - } - } - --CAirTunesServer::CAirTunesServer(int port, bool nonlocal) -+CAirTunesServer::CAirTunesServer(int port, bool nonlocal) : CThread("CAirTunesServer") - { - m_port = port; - m_pLibShairport = new DllLibShairport(); -diff --git a/xbmc/network/Network.h b/xbmc/network/Network.h -index cb0ea52..e514e05 100644 ---- a/xbmc/network/Network.h -+++ b/xbmc/network/Network.h -@@ -24,6 +24,7 @@ - - #include - #include "utils/StdString.h" -+#include "system.h" - - enum EncMode { ENC_NONE = 0, ENC_WEP = 1, ENC_WPA = 2, ENC_WPA2 = 3 }; - enum NetworkAssignment { NETWORK_DASH = 0, NETWORK_DHCP = 1, NETWORK_STATIC = 2, NETWORK_DISABLED = 3 }; -diff --git a/xbmc/network/TCPServer.cpp b/xbmc/network/TCPServer.cpp -index 4b0d9ad..fd46236 100644 ---- a/xbmc/network/TCPServer.cpp -+++ b/xbmc/network/TCPServer.cpp -@@ -85,7 +85,7 @@ void CTCPServer::StopServer(bool bWait) - } - } - --CTCPServer::CTCPServer(int port, bool nonlocal) -+CTCPServer::CTCPServer(int port, bool nonlocal) : CThread("CTCPServer") - { - m_port = port; - m_nonlocal = nonlocal; -diff --git a/xbmc/network/UdpClient.cpp b/xbmc/network/UdpClient.cpp -index 8e1ef2e..8f49ce8 100644 ---- a/xbmc/network/UdpClient.cpp -+++ b/xbmc/network/UdpClient.cpp -@@ -35,7 +35,7 @@ - - #define UDPCLIENT_DEBUG_LEVEL LOGDEBUG - --CUdpClient::CUdpClient(void) : CThread() -+CUdpClient::CUdpClient(void) : CThread("CUdpClient") - {} - - CUdpClient::~CUdpClient(void) -diff --git a/xbmc/network/UdpClient.h b/xbmc/network/UdpClient.h -index 97acb28..a1aa597 100644 ---- a/xbmc/network/UdpClient.h -+++ b/xbmc/network/UdpClient.h -@@ -25,6 +25,7 @@ - #include "threads/CriticalSection.h" - #include - #include -+#include "system.h" - - class CUdpClient : CThread - { -diff --git a/xbmc/network/libscrobbler/scrobbler.cpp b/xbmc/network/libscrobbler/scrobbler.cpp -index cb08d1b..cf5f927 100644 ---- a/xbmc/network/libscrobbler/scrobbler.cpp -+++ b/xbmc/network/libscrobbler/scrobbler.cpp -@@ -46,7 +46,7 @@ - #define SCROBBLER_ACTION_NOWPLAYING 2 - - CScrobbler::CScrobbler(const CStdString &strHandshakeURL, const CStdString &strLogPrefix) -- : CThread() -+ : CThread("CScrobbler") - { - m_bBanned = false; - m_bBadAuth = false; -@@ -67,7 +67,7 @@ void CScrobbler::Init() - ResetState(); - LoadCredentials(); - LoadJournal(); -- if (!ThreadHandle()) -+ if (!IsRunning()) - Create(); - } - -diff --git a/xbmc/peripherals/Peripherals.cpp b/xbmc/peripherals/Peripherals.cpp -index 3868cc7..ffd78d2 100644 ---- a/xbmc/peripherals/Peripherals.cpp -+++ b/xbmc/peripherals/Peripherals.cpp -@@ -19,6 +19,7 @@ - * - */ - -+#include "system.h" - #include "Peripherals.h" - #include "bus/PeripheralBus.h" - #include "devices/PeripheralBluetooth.h" -diff --git a/xbmc/pictures/GUIWindowSlideShow.cpp b/xbmc/pictures/GUIWindowSlideShow.cpp -index a762031..beb7d28 100644 ---- a/xbmc/pictures/GUIWindowSlideShow.cpp -+++ b/xbmc/pictures/GUIWindowSlideShow.cpp -@@ -67,7 +67,7 @@ using namespace XFILE; - - static float zoomamount[10] = { 1.0f, 1.2f, 1.5f, 2.0f, 2.8f, 4.0f, 6.0f, 9.0f, 13.5f, 20.0f }; - --CBackgroundPicLoader::CBackgroundPicLoader() -+CBackgroundPicLoader::CBackgroundPicLoader() : CThread("CBackgroundPicLoader") - { - m_pCallback = NULL; - m_isLoading = false; -diff --git a/xbmc/rendering/dx/RenderSystemDX.cpp b/xbmc/rendering/dx/RenderSystemDX.cpp -index 938cb36..ed92a41 100644 ---- a/xbmc/rendering/dx/RenderSystemDX.cpp -+++ b/xbmc/rendering/dx/RenderSystemDX.cpp -@@ -569,7 +569,7 @@ bool CRenderSystemDX::PresentRenderImpl(const CDirtyRegionList &dirty) - - //CVideoReferenceClock polls GetRasterStatus too, - //polling it from two threads at the same time is bad -- if (g_advancedSettings.m_sleepBeforeFlip > 0 && g_VideoReferenceClock.ThreadHandle() == NULL) -+ if (g_advancedSettings.m_sleepBeforeFlip > 0 && !g_VideoReferenceClock.IsRunning()) - { - //save current thread priority and set thread priority to THREAD_PRIORITY_TIME_CRITICAL - int priority = GetThreadPriority(GetCurrentThread()); -diff --git a/xbmc/settings/GUISettings.cpp b/xbmc/settings/GUISettings.cpp -index 231c715..083947d 100644 ---- a/xbmc/settings/GUISettings.cpp -+++ b/xbmc/settings/GUISettings.cpp -@@ -592,6 +592,10 @@ void CGUISettings::Initialize() - #ifdef HAVE_LIBVA - AddBool(vp, "videoplayer.usevaapi", 13426, true); - #endif -+#ifdef HAVE_LIBXVBA -+ AddBool(vp, "videoplayer.usexvba", 13433, true); -+ AddBool(vp, "videoplayer.usexvbasharedsurface", 13434, true); -+#endif - #ifdef HAS_DX - AddBool(g_sysinfo.IsVistaOrHigher() ? vp: NULL, "videoplayer.usedxva2", 13427, g_sysinfo.IsVistaOrHigher() ? true : false); - #endif -diff --git a/xbmc/settings/GUIWindowSettingsCategory.cpp b/xbmc/settings/GUIWindowSettingsCategory.cpp -index dc26188..1a259a6 100644 ---- a/xbmc/settings/GUIWindowSettingsCategory.cpp -+++ b/xbmc/settings/GUIWindowSettingsCategory.cpp -@@ -936,6 +936,15 @@ void CGUIWindowSettingsCategory::UpdateSettings() - pControl->SetEnabled(enabled); - } - } -+ else if (strSetting.Equals("videoplayer.usexvbasharedsurface")) -+ { -+ CGUIControl *pControl = (CGUIControl *)GetControl(pSettingControl->GetID()); -+ if (pControl) -+ { -+ bool enabled = (g_guiSettings.GetBool("videoplayer.usexvba")); -+ pControl->SetEnabled(enabled); -+ } -+ } - else if (strSetting.Equals("weather.addonsettings")) - { - AddonPtr addon; -diff --git a/xbmc/threads/Thread.cpp b/xbmc/threads/Thread.cpp -index bd213e2..3e228df 100644 ---- a/xbmc/threads/Thread.cpp -+++ b/xbmc/threads/Thread.cpp -@@ -20,41 +20,27 @@ - - #include "threads/SystemClock.h" - #include "Thread.h" --#ifndef _LINUX --#include --#include "utils/win32exception.h" --#ifndef _MT --#pragma message( "Please compile using multithreaded run-time libraries" ) --#endif --typedef unsigned (WINAPI *PBEGINTHREADEX_THREADFUNC)(LPVOID lpThreadParameter); --#else --#include "PlatformInclude.h" --#include "XHandle.h" --#include --typedef int (*PBEGINTHREADEX_THREADFUNC)(LPVOID lpThreadParameter); --#endif -- --#if defined(__GNUC__) && !defined(__clang__) --#include --using namespace __cxxabiv1; --#endif -- - #include "utils/log.h" - #include "utils/TimeUtils.h" - #include "threads/ThreadLocal.h" - -+#define __STDC_FORMAT_MACROS -+#include -+ - static XbmcThreads::ThreadLocal currentThread; - -+#include "threads/platform/ThreadImpl.cpp" -+ - ////////////////////////////////////////////////////////////////////// - // Construction/Destruction - ////////////////////////////////////////////////////////////////////// - --CThread::CThread(const char* ThreadName) : m_StopEvent(true,true) -+CThread::CThread(const char* ThreadName) -+: m_StopEvent(true,true), m_TermEvent(true), m_StartEvent(true) - { - m_bStop = false; - - m_bAutoDelete = false; -- m_ThreadHandle = NULL; - m_ThreadId = 0; - m_iLastTime = 0; - m_iLastUsage = 0; -@@ -66,12 +52,12 @@ CThread::CThread(const char* ThreadName) : m_StopEvent(true,true) - m_ThreadName = ThreadName; - } - --CThread::CThread(IRunnable* pRunnable, const char* ThreadName) : m_StopEvent(true,true) -+CThread::CThread(IRunnable* pRunnable, const char* ThreadName) -+: m_StopEvent(true,true), m_TermEvent(true), m_StartEvent(true) - { - m_bStop = false; - - m_bAutoDelete = false; -- m_ThreadHandle = NULL; - m_ThreadId = 0; - m_iLastTime = 0; - m_iLastUsage = 0; -@@ -85,171 +71,62 @@ CThread::CThread(IRunnable* pRunnable, const char* ThreadName) : m_StopEvent(tru - - CThread::~CThread() - { -- if (m_ThreadHandle != NULL) -- { -- CloseHandle(m_ThreadHandle); -- } -- m_ThreadHandle = NULL; -- -+ StopThread(); - } - --#ifndef _WIN32 --void CThread::term_handler (int signum) -+bool CThread::IsRunning() - { -- CLog::Log(LOGERROR,"thread 0x%lx (%lu) got signal %d. calling OnException and terminating thread abnormally.", (long unsigned int)pthread_self(), (long unsigned int)pthread_self(), signum); -- -- CThread* curThread = currentThread.get(); -- if (curThread) -- { -- curThread->m_bStop = TRUE; -- curThread->m_StopEvent.Set(); -- -- curThread->OnException(); -- if( curThread->IsAutoDelete() ) -- delete curThread; -- } -- -- pthread_exit(NULL); -+ return m_ThreadId ? true : false; - } - --int CThread::staticThread(void* data) --#else --DWORD WINAPI CThread::staticThread(LPVOID* data) --#endif -+THREADFUNC CThread::staticThread(void* data) - { - CThread* pThread = (CThread*)(data); -+ std::string name; -+ ThreadIdentifier id; -+ bool autodelete; -+ - if (!pThread) { - CLog::Log(LOGERROR,"%s, sanity failed. thread is NULL.",__FUNCTION__); - return 1; - } - -- if (pThread->m_ThreadName.empty()) -- pThread->m_ThreadName = pThread->GetTypeName(); -- pThread->SetDebugCallStackName(pThread->m_ThreadName.c_str()); -+ name = pThread->m_ThreadName; -+ id = pThread->m_ThreadId; -+ autodelete = pThread->m_bAutoDelete; - -- CLog::Log(LOGDEBUG,"Thread %s start, auto delete: %d", pThread->m_ThreadName.c_str(), pThread->IsAutoDelete()); -+ pThread->SetThreadInfo(); -+ -+ CLog::Log(LOGNOTICE,"Thread %s start, auto delete: %s", name.c_str(), (autodelete ? "true" : "false")); - - currentThread.set(pThread); --#ifndef _LINUX -- /* install win32 exception translator */ -- win32_exception::install_handler(); --#else -- struct sigaction action; -- action.sa_handler = term_handler; -- sigemptyset (&action.sa_mask); -- action.sa_flags = 0; -- //sigaction (SIGABRT, &action, NULL); -- //sigaction (SIGSEGV, &action, NULL); --#endif -- -- -- try -- { -- pThread->OnStartup(); -- } --#ifndef _LINUX -- catch (const win32_exception &e) -- { -- e.writelog(__FUNCTION__); -- if( pThread->IsAutoDelete() ) -- { -- delete pThread; -- _endthreadex(123); -- return 0; -- } -- } --#endif -- catch(...) -- { -- CLog::Log(LOGERROR, "%s - thread %s, Unhandled exception caught in thread startup, aborting. auto delete: %d", __FUNCTION__, pThread->m_ThreadName.c_str(), pThread->IsAutoDelete()); -- if( pThread->IsAutoDelete() ) -- { -- delete pThread; --#ifndef _LINUX -- _endthreadex(123); --#endif -- return 0; -- } -- } -+ pThread->m_StartEvent.Set(); - -- try -- { -- pThread->Process(); -- } --#ifndef _LINUX -- catch (const access_violation &e) -- { -- e.writelog(__FUNCTION__); -- } -- catch (const win32_exception &e) -- { -- e.writelog(__FUNCTION__); -- } --#endif -- catch(...) -- { -- CLog::Log(LOGERROR, "%s - thread %s, Unhandled exception caught in thread process, attemping cleanup in OnExit", __FUNCTION__, pThread->m_ThreadName.c_str()); -- } -+ pThread->OnStartup(); -+ pThread->Process(); -+ pThread->OnExit(); - -- try -- { -- pThread->OnExit(); -- } --#ifndef _LINUX -- catch (const access_violation &e) -- { -- e.writelog(__FUNCTION__); -- } -- catch (const win32_exception &e) -- { -- e.writelog(__FUNCTION__); -- } --#endif -- catch(...) -- { -- CLog::Log(LOGERROR, "%s - thread %s, Unhandled exception caught in thread exit", __FUNCTION__, pThread->m_ThreadName.c_str()); -- } -+ // lock during termination -+ CSingleLock lock(pThread->m_CriticalSection); -+ -+ pThread->m_ThreadId = 0; -+ pThread->m_TermEvent.Set(); -+ pThread->TermHandler(); - -- if ( pThread->IsAutoDelete() ) -+ lock.Leave(); -+ -+ if (autodelete) - { -- CLog::Log(LOGDEBUG,"Thread %s %"PRIu64" terminating (autodelete)", pThread->m_ThreadName.c_str(), (uint64_t)CThread::GetCurrentThreadId()); -+ CLog::Log(LOGDEBUG,"Thread %s %"PRIu64" terminating (autodelete)", name.c_str(), (uint64_t)id); - delete pThread; - pThread = NULL; - } - else -- CLog::Log(LOGDEBUG,"Thread %s %"PRIu64" terminating", pThread->m_ThreadName.c_str(), (uint64_t)CThread::GetCurrentThreadId()); -- --// DXMERGE - this looks like it might have used to have been useful for something... --// g_graphicsContext.DeleteThreadContext(); -+ CLog::Log(LOGDEBUG,"Thread %s %"PRIu64" terminating", name.c_str(), (uint64_t)id); - --#ifndef _LINUX -- _endthreadex(123); --#endif - return 0; - } - --void CThread::Create(bool bAutoDelete, unsigned stacksize) --{ -- if (m_ThreadHandle != NULL) -- { -- throw 1; //ERROR should not b possible!!! -- } -- m_iLastTime = XbmcThreads::SystemClockMillis() * 10000; -- m_iLastUsage = 0; -- m_fLastUsage = 0.0f; -- m_bAutoDelete = bAutoDelete; -- m_bStop = false; -- m_StopEvent.Reset(); -- -- m_ThreadHandle = (HANDLE)_beginthreadex(NULL, stacksize, (PBEGINTHREADEX_THREADFUNC)staticThread, (void*)this, 0, &m_ThreadId); -- --#ifdef _LINUX -- if (m_ThreadHandle && m_ThreadHandle->m_threadValid && m_bAutoDelete) -- // FIXME: WinAPI can truncate 64bit pthread ids -- pthread_detach(m_ThreadHandle->m_hThread); --#endif --} -- - bool CThread::IsAutoDelete() const - { - return m_bAutoDelete; -@@ -259,213 +136,17 @@ void CThread::StopThread(bool bWait /*= true*/) - { - m_bStop = true; - m_StopEvent.Set(); -- if (m_ThreadHandle && bWait) -+ CSingleLock lock(m_CriticalSection); -+ if (m_ThreadId && bWait) - { -- WaitForThreadExit(INFINITE); -- CloseHandle(m_ThreadHandle); -- m_ThreadHandle = NULL; -+ lock.Leave(); -+ WaitForThreadExit(0xFFFFFFFF); - } - } - - ThreadIdentifier CThread::ThreadId() const - { --#ifdef _LINUX -- if (m_ThreadHandle && m_ThreadHandle->m_threadValid) -- return m_ThreadHandle->m_hThread; -- else -- return 0; --#else - return m_ThreadId; --#endif --} -- -- --CThread::operator HANDLE() --{ -- return m_ThreadHandle; --} -- --CThread::operator HANDLE() const --{ -- return m_ThreadHandle; --} -- --bool CThread::SetPriority(const int iPriority) --// Set thread priority --// Return true for success --{ -- bool rtn = false; -- -- if (m_ThreadHandle) -- { -- rtn = SetThreadPriority( m_ThreadHandle, iPriority ) == TRUE; -- } -- -- return(rtn); --} -- --void CThread::SetPrioritySched_RR(void) --{ --#ifdef __APPLE__ -- // Changing to SCHED_RR is safe under OSX, you don't need elevated privileges and the -- // OSX scheduler will monitor SCHED_RR threads and drop to SCHED_OTHER if it detects -- // the thread running away. OSX automatically does this with the CoreAudio audio -- // device handler thread. -- int32_t result; -- thread_extended_policy_data_t theFixedPolicy; -- -- // make thread fixed, set to 'true' for a non-fixed thread -- theFixedPolicy.timeshare = false; -- result = thread_policy_set(pthread_mach_thread_np(ThreadId()), THREAD_EXTENDED_POLICY, -- (thread_policy_t)&theFixedPolicy, THREAD_EXTENDED_POLICY_COUNT); -- -- int policy; -- struct sched_param param; -- result = pthread_getschedparam(ThreadId(), &policy, ¶m ); -- // change from default SCHED_OTHER to SCHED_RR -- policy = SCHED_RR; -- result = pthread_setschedparam(ThreadId(), policy, ¶m ); --#endif --} -- --int CThread::GetMinPriority(void) --{ --#if 0 --//#if defined(__APPLE__) -- struct sched_param sched; -- int rtn, policy; -- -- rtn = pthread_getschedparam(ThreadId(), &policy, &sched); -- int min = sched_get_priority_min(policy); -- -- return(min); --#else -- return(THREAD_PRIORITY_IDLE); --#endif --} -- --int CThread::GetMaxPriority(void) --{ --#if 0 --//#if defined(__APPLE__) -- struct sched_param sched; -- int rtn, policy; -- -- rtn = pthread_getschedparam(ThreadId(), &policy, &sched); -- int max = sched_get_priority_max(policy); -- -- return(max); --#else -- return(THREAD_PRIORITY_HIGHEST); --#endif --} -- --int CThread::GetNormalPriority(void) --{ --#if 0 --//#if defined(__APPLE__) -- struct sched_param sched; -- int rtn, policy; -- -- rtn = pthread_getschedparam(ThreadId(), &policy, &sched); -- int min = sched_get_priority_min(policy); -- int max = sched_get_priority_max(policy); -- -- return( min + ((max-min) / 2) ); --#else -- return(THREAD_PRIORITY_NORMAL); --#endif --} -- -- --void CThread::SetDebugCallStackName( const char *name ) --{ --#ifdef _WIN32 -- const unsigned int MS_VC_EXCEPTION = 0x406d1388; -- struct THREADNAME_INFO -- { -- DWORD dwType; // must be 0x1000 -- LPCSTR szName; // pointer to name (in same addr space) -- DWORD dwThreadID; // thread ID (-1 caller thread) -- DWORD dwFlags; // reserved for future use, most be zero -- } info; -- -- info.dwType = 0x1000; -- info.szName = name; -- info.dwThreadID = m_ThreadId; -- info.dwFlags = 0; -- -- try -- { -- RaiseException(MS_VC_EXCEPTION, 0, sizeof(info) / sizeof(ULONG_PTR), (ULONG_PTR *)&info); -- } -- catch(...) -- { -- } --#endif --} -- --// Get the thread name using the implementation dependant typeid() class --// and attempt to clean it. --std::string CThread::GetTypeName(void) --{ -- std::string name = typeid(*this).name(); -- --#if defined(_MSC_VER) -- // Visual Studio 2010 returns the name as "class CThread" etc -- if (name.substr(0, 6) == "class ") -- name = name.substr(6, name.length() - 6); --#elif defined(__GNUC__) && !defined(__clang__) -- // gcc provides __cxa_demangle to demangle the name -- char* demangled = NULL; -- int status; -- -- demangled = __cxa_demangle(name.c_str(), NULL, 0, &status); -- if (status == 0) -- name = demangled; -- else -- CLog::Log(LOGDEBUG,"%s, __cxa_demangle(%s) failed with status %d", __FUNCTION__, name.c_str(), status); -- -- if (demangled) -- free(demangled); --#endif -- -- return name; --} -- --bool CThread::WaitForThreadExit(unsigned int milliseconds) --// Waits for thread to exit, timeout in given number of msec. --// Returns true when thread ended --{ -- if (!m_ThreadHandle) return true; -- --#ifndef _LINUX -- // boost priority of thread we are waiting on to same as caller -- int callee = GetThreadPriority(m_ThreadHandle); -- int caller = GetThreadPriority(GetCurrentThread()); -- if(caller > callee) -- SetThreadPriority(m_ThreadHandle, caller); -- -- if (::WaitForSingleObject(m_ThreadHandle, milliseconds) != WAIT_TIMEOUT) -- return true; -- -- // restore thread priority if thread hasn't exited -- if(caller > callee) -- SetThreadPriority(m_ThreadHandle, callee); --#else -- if (!(m_ThreadHandle->m_threadValid) || pthread_join(m_ThreadHandle->m_hThread, NULL) == 0) -- { -- m_ThreadHandle->m_threadValid = false; -- return true; -- } --#endif -- -- return false; --} -- --HANDLE CThread::ThreadHandle() --{ -- return m_ThreadHandle; - } - - void CThread::Process() -@@ -474,54 +155,14 @@ void CThread::Process() - m_pRunnable->Run(); - } - --float CThread::GetRelativeUsage() --{ -- unsigned __int64 iTime = XbmcThreads::SystemClockMillis(); -- iTime *= 10000; // convert into 100ns tics -- -- // only update every 1 second -- if( iTime < m_iLastTime + 1000*10000 ) return m_fLastUsage; -- -- FILETIME CreationTime, ExitTime, UserTime, KernelTime; -- if( GetThreadTimes( m_ThreadHandle, &CreationTime, &ExitTime, &KernelTime, &UserTime ) ) -- { -- unsigned __int64 iUsage = 0; -- iUsage += (((unsigned __int64)UserTime.dwHighDateTime) << 32) + ((unsigned __int64)UserTime.dwLowDateTime); -- iUsage += (((unsigned __int64)KernelTime.dwHighDateTime) << 32) + ((unsigned __int64)KernelTime.dwLowDateTime); -- -- if(m_iLastUsage > 0 && m_iLastTime > 0) -- m_fLastUsage = (float)( iUsage - m_iLastUsage ) / (float)( iTime - m_iLastTime ); -- -- m_iLastUsage = iUsage; -- m_iLastTime = iTime; -- -- return m_fLastUsage; -- } -- return 0.0f; --} -- - bool CThread::IsCurrentThread() const - { - return IsCurrentThread(ThreadId()); - } - -- --ThreadIdentifier CThread::GetCurrentThreadId() --{ --#ifdef _LINUX -- return pthread_self(); --#else -- return ::GetCurrentThreadId(); --#endif --} -- --bool CThread::IsCurrentThread(const ThreadIdentifier tid) -+CThread* CThread::GetCurrentThread() - { --#ifdef _LINUX -- return pthread_equal(pthread_self(), tid); --#else -- return (::GetCurrentThreadId() == tid); --#endif -+ return currentThread.get(); - } - - void CThread::Sleep(unsigned int milliseconds) -@@ -529,7 +170,7 @@ void CThread::Sleep(unsigned int milliseconds) - if(milliseconds > 10 && IsCurrentThread()) - m_StopEvent.WaitMSec(milliseconds); - else -- ::Sleep(milliseconds); -+ XbmcThreads::ThreadSleep(milliseconds); - } - - -diff --git a/xbmc/threads/Thread.h b/xbmc/threads/Thread.h -index 768d6f8..bebd9ee 100644 ---- a/xbmc/threads/Thread.h -+++ b/xbmc/threads/Thread.h -@@ -23,19 +23,13 @@ - // - ////////////////////////////////////////////////////////////////////// - --#if !defined(AFX_THREAD_H__ACFB7357_B961_4AC1_9FB2_779526219817__INCLUDED_) && !defined(AFX_THREAD_H__67621B15_8724_4B5D_9343_7667075C89F2__INCLUDED_) --#define AFX_THREAD_H__ACFB7357_B961_4AC1_9FB2_779526219817__INCLUDED_ -- --#if _MSC_VER > 1000 - #pragma once --#endif // _MSC_VER > 1000 - - #include --#include "system.h" // for HANDLE --#ifdef _LINUX --#include "PlatformInclude.h" --#endif -+#include - #include "Event.h" -+#include "threads/ThreadImpl.h" -+#include "threads/ThreadLocal.h" - - class IRunnable - { -@@ -44,37 +38,36 @@ public: - virtual ~IRunnable() {} - }; - --#ifdef CTHREAD --#undef CTHREAD --#endif -- - // minimum as mandated by XTL - #define THREAD_MINSTACKSIZE 0x10000 - - class CThread - { - public: -- CThread(const char* ThreadName = NULL); -- CThread(IRunnable* pRunnable, const char* ThreadName = NULL); -+ CThread(const char* ThreadName); -+ CThread(IRunnable* pRunnable, const char* ThreadName); - virtual ~CThread(); - void Create(bool bAutoDelete = false, unsigned stacksize = 0); - bool WaitForThreadExit(unsigned int milliseconds); - void Sleep(unsigned int milliseconds); - bool SetPriority(const int iPriority); -- void SetPrioritySched_RR(void); -+ int GetPriority(void); - int GetMinPriority(void); - int GetMaxPriority(void); - int GetNormalPriority(void); -- HANDLE ThreadHandle(); -- operator HANDLE(); -- operator HANDLE() const; -+ int GetSchedRRPriority(void); -+ bool SetPrioritySched_RR(int iPriority); - bool IsAutoDelete() const; - virtual void StopThread(bool bWait = true); - float GetRelativeUsage(); // returns the relative cpu usage of this thread since last call -+ int64_t GetAbsoluteUsage(); - bool IsCurrentThread() const; -+ bool IsRunning(); - - static bool IsCurrentThread(const ThreadIdentifier tid); - static ThreadIdentifier GetCurrentThreadId(); -+ static CThread* GetCurrentThread(); -+ static int64_t GetCurrentThreadUsage(); - protected: - virtual void OnStartup(){}; - virtual void OnExit(){}; -@@ -82,7 +75,6 @@ protected: - virtual void Process(); - - volatile bool m_bStop; -- HANDLE m_ThreadHandle; - - enum WaitResponse { WAIT_INTERRUPTED = -1, WAIT_SIGNALED = 0, WAIT_TIMEDOUT = 1 }; - -@@ -108,36 +100,22 @@ protected: - } - - private: -- /*! \brief set the threadname for the debugger/callstack, implementation dependent. -- */ -- void SetDebugCallStackName( const char *threadName ); -- std::string GetTypeName(void); -- --private: -+ static THREADFUNC staticThread(void *data); - ThreadIdentifier ThreadId() const; -+ void SetThreadInfo(); -+ void TermHandler(); -+ -+ ThreadIdentifier m_ThreadId; -+ ThreadOpaque m_ThreadOpaque; - bool m_bAutoDelete; - CEvent m_StopEvent; -- unsigned m_ThreadId; // This value is unreliable on platforms using pthreads -- // Use m_ThreadHandle->m_hThread instead -+ CEvent m_TermEvent; -+ CEvent m_StartEvent; -+ CCriticalSection m_CriticalSection; - IRunnable* m_pRunnable; -- -- unsigned __int64 m_iLastUsage; -- unsigned __int64 m_iLastTime; -+ uint64_t m_iLastUsage; -+ uint64_t m_iLastTime; - float m_fLastUsage; - - std::string m_ThreadName; -- --#ifdef _LINUX -- static void term_handler (int signum); --#endif -- --#ifndef _WIN32 -- static int staticThread(void* data); --#else -- static DWORD WINAPI staticThread(LPVOID* data); --#endif -- --private: - }; -- --#endif // !defined(AFX_THREAD_H__ACFB7357_B961_4AC1_9FB2_779526219817__INCLUDED_) -diff --git a/xbmc/threads/ThreadImpl.h b/xbmc/threads/ThreadImpl.h -new file mode 100644 -index 0000000..ad10e3b ---- /dev/null -+++ b/xbmc/threads/ThreadImpl.h -@@ -0,0 +1,25 @@ -+/* -+ * Copyright (C) 2005-2011 Team XBMC -+ * http://www.xbmc.org -+ * -+ * 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 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 XBMC; see the file COPYING. If not, write to -+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. -+ * http://www.gnu.org/copyleft/gpl.html -+ * -+ */ -+ -+#pragma once -+ -+#include "threads/platform/ThreadImpl.h" -+ -diff --git a/xbmc/threads/platform/ThreadImpl.cpp b/xbmc/threads/platform/ThreadImpl.cpp -new file mode 100644 -index 0000000..7f0213b ---- /dev/null -+++ b/xbmc/threads/platform/ThreadImpl.cpp -@@ -0,0 +1,34 @@ -+/* -+ * Copyright (C) 2005-2011 Team XBMC -+ * http://www.xbmc.org -+ * -+ * 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 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 XBMC; see the file COPYING. If not, write to -+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. -+ * http://www.gnu.org/copyleft/gpl.html -+ * -+ */ -+ -+#pragma once -+ -+#if (defined TARGET_POSIX) -+#include "threads/platform/pthreads/ThreadImpl.cpp" -+#if defined(TARGET_DARWIN_IOS) -+#include "threads/platform/darwin/ThreadSchedImpl.cpp" -+#else -+#include "threads/platform/linux/ThreadSchedImpl.cpp" -+#endif -+#elif (defined TARGET_WINDOWS) -+#include "threads/platform/win/ThreadImpl.cpp" -+#endif -+ -diff --git a/xbmc/threads/platform/ThreadImpl.h b/xbmc/threads/platform/ThreadImpl.h -new file mode 100644 -index 0000000..f37709e ---- /dev/null -+++ b/xbmc/threads/platform/ThreadImpl.h -@@ -0,0 +1,28 @@ -+/* -+ * Copyright (C) 2005-2011 Team XBMC -+ * http://www.xbmc.org -+ * -+ * 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 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 XBMC; see the file COPYING. If not, write to -+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. -+ * http://www.gnu.org/copyleft/gpl.html -+ * -+ */ -+ -+#pragma once -+ -+#if (defined TARGET_POSIX) -+#include "threads/platform/pthreads/ThreadImpl.h" -+#elif (defined TARGET_WINDOWS) -+#include "threads/platform/win/ThreadImpl.h" -+#endif -diff --git a/xbmc/threads/platform/darwin/ThreadSchedImpl.cpp b/xbmc/threads/platform/darwin/ThreadSchedImpl.cpp -new file mode 100644 -index 0000000..7612fe7 ---- /dev/null -+++ b/xbmc/threads/platform/darwin/ThreadSchedImpl.cpp -@@ -0,0 +1,47 @@ -+/* -+ * Copyright (C) 2005-2011 Team XBMC -+ * http://www.xbmc.org -+ * -+ * 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 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 XBMC; see the file COPYING. If not, write to -+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. -+ * http://www.gnu.org/copyleft/gpl.html -+ * -+ */ -+ -+int CThread::GetSchedRRPriority(void) -+{ -+ return 96; -+} -+ -+bool CThread::SetPrioritySched_RR(int iPriority) -+{ -+ // Changing to SCHED_RR is safe under OSX, you don't need elevated privileges and the -+ // OSX scheduler will monitor SCHED_RR threads and drop to SCHED_OTHER if it detects -+ // the thread running away. OSX automatically does this with the CoreAudio audio -+ // device handler thread. -+ int32_t result; -+ thread_extended_policy_data_t theFixedPolicy; -+ -+ // make thread fixed, set to 'true' for a non-fixed thread -+ theFixedPolicy.timeshare = false; -+ result = thread_policy_set(pthread_mach_thread_np(ThreadId()), THREAD_EXTENDED_POLICY, -+ (thread_policy_t)&theFixedPolicy, THREAD_EXTENDED_POLICY_COUNT); -+ -+ int policy; -+ struct sched_param param; -+ result = pthread_getschedparam(ThreadId(), &policy, ¶m ); -+ // change from default SCHED_OTHER to SCHED_RR -+ policy = SCHED_RR; -+ result = pthread_setschedparam(ThreadId(), policy, ¶m ); -+} -diff --git a/xbmc/threads/platform/linux/ThreadSchedImpl.cpp b/xbmc/threads/platform/linux/ThreadSchedImpl.cpp -new file mode 100644 -index 0000000..034a100 ---- /dev/null -+++ b/xbmc/threads/platform/linux/ThreadSchedImpl.cpp -@@ -0,0 +1,30 @@ -+/* -+ * Copyright (C) 2005-2011 Team XBMC -+ * http://www.xbmc.org -+ * -+ * 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 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 XBMC; see the file COPYING. If not, write to -+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. -+ * http://www.gnu.org/copyleft/gpl.html -+ * -+ */ -+ -+int CThread::GetSchedRRPriority(void) -+{ -+ return GetNormalPriority(); -+} -+ -+bool CThread::SetPrioritySched_RR(int iPriority) -+{ -+ return false; -+} -diff --git a/xbmc/threads/platform/pthreads/ThreadImpl.cpp b/xbmc/threads/platform/pthreads/ThreadImpl.cpp -new file mode 100644 -index 0000000..58b602c ---- /dev/null -+++ b/xbmc/threads/platform/pthreads/ThreadImpl.cpp -@@ -0,0 +1,220 @@ -+/* -+ * Copyright (C) 2005-2011 Team XBMC -+ * http://www.xbmc.org -+ * -+ * 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 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 XBMC; see the file COPYING. If not, write to -+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. -+ * http://www.gnu.org/copyleft/gpl.html -+ * -+ */ -+ -+#include -+#include -+#include -+#include -+ -+void CThread::Create(bool bAutoDelete, unsigned stacksize) -+{ -+ if (m_ThreadId != 0) -+ { -+ CLog::Log(LOGERROR, "%s - fatal error creating thread- old thread id not null", __FUNCTION__); -+ exit(1); -+ } -+ m_iLastTime = XbmcThreads::SystemClockMillis() * 10000; -+ m_iLastUsage = 0; -+ m_fLastUsage = 0.0f; -+ m_bAutoDelete = bAutoDelete; -+ m_bStop = false; -+ m_StopEvent.Reset(); -+ m_TermEvent.Reset(); -+ m_StartEvent.Reset(); -+ -+ pthread_attr_t attr; -+ pthread_attr_init(&attr); -+ if (stacksize > PTHREAD_STACK_MIN) -+ pthread_attr_setstacksize(&attr, stacksize); -+ pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); -+ if (pthread_create(&m_ThreadId, &attr, (void*(*)(void*))staticThread, this) != 0) -+ { -+ CLog::Log(LOGNOTICE, "%s - fatal error creating thread",__FUNCTION__); -+ } -+ pthread_attr_destroy(&attr); -+} -+ -+void CThread::TermHandler() -+{ -+ -+} -+ -+void CThread::SetThreadInfo() -+{ -+ m_ThreadOpaque.LwpId = syscall(SYS_gettid); -+ -+ // start thread with nice level of appication -+ int appNice = getpriority(PRIO_PROCESS, getpid()); -+ if (setpriority(PRIO_PROCESS, m_ThreadOpaque.LwpId, appNice) != 0) -+ CLog::Log(LOGERROR, "%s: error %s", __FUNCTION__, strerror(errno)); -+} -+ -+ThreadIdentifier CThread::GetCurrentThreadId() -+{ -+ return pthread_self(); -+} -+ -+bool CThread::IsCurrentThread(const ThreadIdentifier tid) -+{ -+ return pthread_equal(pthread_self(), tid); -+} -+ -+int CThread::GetMinPriority(void) -+{ -+ // one level lower than application -+ return -1; -+} -+ -+int CThread::GetMaxPriority(void) -+{ -+ // one level higher than application -+ return 1; -+} -+ -+int CThread::GetNormalPriority(void) -+{ -+ // same level as application -+ return 0; -+} -+ -+bool CThread::SetPriority(const int iPriority) -+{ -+ bool bReturn = false; -+ -+ // wait until thread is running, it needs to get its lwp id -+ m_StartEvent.Wait(); -+ -+ CSingleLock lock(m_CriticalSection); -+ -+ // get min prio for SCHED_RR -+ int minRR = GetMaxPriority() + 1; -+ -+ if (!m_ThreadId) -+ bReturn = false; -+ else if (iPriority >= minRR) -+ bReturn = SetPrioritySched_RR(iPriority); -+ else -+ { -+ // get user max prio -+ struct rlimit limit; -+ int userMaxPrio; -+ if (getrlimit(RLIMIT_NICE, &limit) == 0) -+ { -+ userMaxPrio = limit.rlim_cur - 20; -+ } -+ else -+ userMaxPrio = 0; -+ -+ // keep priority in bounds -+ int prio = iPriority; -+ if (prio >= GetMaxPriority()) -+ prio = std::min(GetMaxPriority(), userMaxPrio); -+ if (prio < GetMinPriority()) -+ prio = GetMinPriority(); -+ -+ // nice level of application -+ int appNice = getpriority(PRIO_PROCESS, getpid()); -+ if (prio) -+ prio = prio > 0 ? appNice-1 : appNice+1; -+ -+ if (setpriority(PRIO_PROCESS, m_ThreadOpaque.LwpId, prio) == 0) -+ bReturn = true; -+ else -+ CLog::Log(LOGERROR, "%s: error %s", __FUNCTION__, strerror(errno)); -+ } -+ -+ return bReturn; -+} -+ -+int CThread::GetPriority() -+{ -+ int iReturn; -+ -+ // lwp id is valid after start signel has fired -+ m_StartEvent.Wait(); -+ -+ CSingleLock lock(m_CriticalSection); -+ -+ int appNice = getpriority(PRIO_PROCESS, getpid()); -+ int prio = getpriority(PRIO_PROCESS, m_ThreadOpaque.LwpId); -+ iReturn = appNice - prio; -+ -+ return iReturn; -+} -+ -+bool CThread::WaitForThreadExit(unsigned int milliseconds) -+{ -+ bool bReturn = m_TermEvent.WaitMSec(milliseconds); -+ -+ return bReturn; -+} -+ -+int64_t CThread::GetAbsoluteUsage() -+{ -+ CSingleLock lock(m_CriticalSection); -+ -+ if (!m_ThreadId) -+ return 0; -+ -+ clockid_t clock; -+ int64_t time = 0; -+ if (pthread_getcpuclockid(m_ThreadId, &clock) == 0) -+ { -+ struct timespec tp; -+ clock_gettime(clock, &tp); -+ time = (int64_t)tp.tv_sec * 10000000 + tp.tv_nsec/100; -+ } -+ return time; -+} -+ -+float CThread::GetRelativeUsage() -+{ -+ unsigned int iTime = XbmcThreads::SystemClockMillis(); -+ iTime *= 10000; // convert into 100ns tics -+ -+ // only update every 1 second -+ if( iTime < m_iLastTime + 1000*10000 ) return m_fLastUsage; -+ -+ int64_t iUsage = GetAbsoluteUsage(); -+ -+ if (m_iLastUsage > 0 && m_iLastTime > 0) -+ m_fLastUsage = (float)( iUsage - m_iLastUsage ) / (float)( iTime - m_iLastTime ); -+ -+ m_iLastUsage = iUsage; -+ m_iLastTime = iTime; -+ -+ return m_fLastUsage; -+} -+ -+int64_t CThread::GetCurrentThreadUsage() -+{ -+ pthread_t tid = pthread_self(); -+ clockid_t clock; -+ int64_t time = 0; -+ if (pthread_getcpuclockid(tid, &clock) == 0) -+ { -+ struct timespec tp; -+ clock_gettime(clock, &tp); -+ time = (int64_t)tp.tv_sec * 10000000 + tp.tv_nsec/100; -+ } -+ return time; -+} -+ -diff --git a/xbmc/threads/platform/pthreads/ThreadImpl.h b/xbmc/threads/platform/pthreads/ThreadImpl.h -new file mode 100644 -index 0000000..3f4dd39 ---- /dev/null -+++ b/xbmc/threads/platform/pthreads/ThreadImpl.h -@@ -0,0 +1,39 @@ -+/* -+* Copyright (C) 2005-2011 Team XBMC -+* http://www.xbmc.org -+* -+* 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 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 XBMC; see the file COPYING. If not, write to -+* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. -+* http://www.gnu.org/copyleft/gpl.html -+* -+*/ -+ -+#pragma once -+ -+#include -+ -+struct threadOpaque -+{ -+ pid_t LwpId; -+}; -+ -+typedef pthread_t ThreadIdentifier; -+typedef threadOpaque ThreadOpaque; -+typedef int THREADFUNC; -+ -+namespace XbmcThreads -+{ -+ inline static void ThreadSleep(unsigned int millis) { usleep(millis*1000); } -+} -+ -diff --git a/xbmc/threads/platform/win/ThreadImpl.cpp b/xbmc/threads/platform/win/ThreadImpl.cpp -new file mode 100644 -index 0000000..6650ee6 ---- /dev/null -+++ b/xbmc/threads/platform/win/ThreadImpl.cpp -@@ -0,0 +1,207 @@ -+/* -+ * Copyright (C) 2005-2011 Team XBMC -+ * http://www.xbmc.org -+ * -+ * 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 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 XBMC; see the file COPYING. If not, write to -+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. -+ * http://www.gnu.org/copyleft/gpl.html -+ * -+ */ -+ -+#include -+ -+ -+void CThread::Create(bool bAutoDelete, unsigned stacksize) -+{ -+ if (m_ThreadId != 0) -+ { -+ CLog::Log(LOGERROR, "%s - fatal error creating thread- old thread id not null", __FUNCTION__); -+ exit(1); -+ } -+ m_iLastTime = XbmcThreads::SystemClockMillis() * 10000; -+ m_iLastUsage = 0; -+ m_fLastUsage = 0.0f; -+ m_bAutoDelete = bAutoDelete; -+ m_bStop = false; -+ m_StopEvent.Reset(); -+ m_TermEvent.Reset(); -+ m_StartEvent.Reset(); -+ -+ m_ThreadOpaque.handle = CreateThread(NULL,stacksize, (LPTHREAD_START_ROUTINE)&staticThread, this, 0, &m_ThreadId); -+ if (m_ThreadOpaque.handle == NULL) -+ { -+ CLog::Log(LOGERROR, "%s - fatal error creating thread", __FUNCTION__); -+ } -+} -+ -+void CThread::TermHandler() -+{ -+ CloseHandle(m_ThreadOpaque.handle); -+ m_ThreadOpaque.handle = NULL; -+} -+ -+void CThread::SetThreadInfo() -+{ -+ const unsigned int MS_VC_EXCEPTION = 0x406d1388; -+ struct THREADNAME_INFO -+ { -+ DWORD dwType; // must be 0x1000 -+ LPCSTR szName; // pointer to name (in same addr space) -+ DWORD dwThreadID; // thread ID (-1 caller thread) -+ DWORD dwFlags; // reserved for future use, most be zero -+ } info; -+ -+ info.dwType = 0x1000; -+ info.szName = m_ThreadName.c_str(); -+ info.dwThreadID = m_ThreadId; -+ info.dwFlags = 0; -+ -+ try -+ { -+ RaiseException(MS_VC_EXCEPTION, 0, sizeof(info) / sizeof(ULONG_PTR), (ULONG_PTR *)&info); -+ } -+ catch(...) -+ { -+ } -+} -+ -+ThreadIdentifier CThread::GetCurrentThreadId() -+{ -+ return ::GetCurrentThreadId(); -+} -+ -+bool CThread::IsCurrentThread(const ThreadIdentifier tid) -+{ -+ return (::GetCurrentThreadId() == tid); -+} -+ -+int CThread::GetMinPriority(void) -+{ -+ return(THREAD_PRIORITY_IDLE); -+} -+ -+int CThread::GetMaxPriority(void) -+{ -+ return(THREAD_PRIORITY_HIGHEST); -+} -+ -+int CThread::GetNormalPriority(void) -+{ -+ return(THREAD_PRIORITY_NORMAL); -+} -+ -+int CThread::GetSchedRRPriority(void) -+{ -+ return GetNormalPriority(); -+} -+ -+bool CThread::SetPriority(const int iPriority) -+{ -+ bool bReturn = false; -+ -+ CSingleLock lock(m_CriticalSection); -+ if (m_ThreadOpaque.handle) -+ { -+ bReturn = SetThreadPriority(m_ThreadOpaque.handle, iPriority) == TRUE; -+ } -+ -+ return bReturn; -+} -+ -+int CThread::GetPriority() -+{ -+ CSingleLock lock(m_CriticalSection); -+ -+ int iReturn = THREAD_PRIORITY_NORMAL; -+ if (m_ThreadOpaque.handle) -+ { -+ iReturn = GetThreadPriority(m_ThreadOpaque.handle); -+ } -+ return iReturn; -+} -+ -+bool CThread::WaitForThreadExit(unsigned int milliseconds) -+{ -+ bool bReturn = true; -+ -+ CSingleLock lock(m_CriticalSection); -+ if (m_ThreadId && m_ThreadOpaque.handle != NULL) -+ { -+ // boost priority of thread we are waiting on to same as caller -+ int callee = GetThreadPriority(m_ThreadOpaque.handle); -+ int caller = GetThreadPriority(GetCurrentThread()); -+ if(caller > callee) -+ SetThreadPriority(m_ThreadOpaque.handle, caller); -+ -+ lock.Leave(); -+ bReturn = m_TermEvent.WaitMSec(milliseconds); -+ lock.Enter(); -+ -+ // restore thread priority if thread hasn't exited -+ if(caller > callee && m_ThreadOpaque.handle) -+ SetThreadPriority(m_ThreadOpaque.handle, callee); -+ } -+ return bReturn; -+} -+ -+int64_t CThread::GetAbsoluteUsage() -+{ -+ CSingleLock lock(m_CriticalSection); -+ -+ if (!m_ThreadOpaque.handle) -+ return 0; -+ -+ uint64_t time = 0; -+ FILETIME CreationTime, ExitTime, UserTime, KernelTime; -+ if( GetThreadTimes(m_ThreadOpaque.handle, &CreationTime, &ExitTime, &KernelTime, &UserTime ) ) -+ { -+ time = (((uint64_t)UserTime.dwHighDateTime) << 32) + ((uint64_t)UserTime.dwLowDateTime); -+ time += (((uint64_t)KernelTime.dwHighDateTime) << 32) + ((uint64_t)KernelTime.dwLowDateTime); -+ } -+ return time; -+} -+ -+float CThread::GetRelativeUsage() -+{ -+ unsigned int iTime = XbmcThreads::SystemClockMillis(); -+ iTime *= 10000; // convert into 100ns tics -+ -+ // only update every 1 second -+ if( iTime < m_iLastTime + 1000*10000 ) return m_fLastUsage; -+ -+ int64_t iUsage = GetAbsoluteUsage(); -+ -+ if (m_iLastUsage > 0 && m_iLastTime > 0) -+ m_fLastUsage = (float)( iUsage - m_iLastUsage ) / (float)( iTime - m_iLastTime ); -+ -+ m_iLastUsage = iUsage; -+ m_iLastTime = iTime; -+ -+ return m_fLastUsage; -+} -+ -+int64_t CThread::GetCurrentThreadUsage() -+{ -+ HANDLE h = GetCurrentThread(); -+ -+ uint64_t time = 0; -+ FILETIME CreationTime, ExitTime, UserTime, KernelTime; -+ if( GetThreadTimes(h, &CreationTime, &ExitTime, &KernelTime, &UserTime ) ) -+ { -+ time = (((uint64_t)UserTime.dwHighDateTime) << 32) + ((uint64_t)UserTime.dwLowDateTime); -+ time += (((uint64_t)KernelTime.dwHighDateTime) << 32) + ((uint64_t)KernelTime.dwLowDateTime); -+ } -+ return time; -+} -+ -diff --git a/xbmc/threads/platform/win/ThreadImpl.h b/xbmc/threads/platform/win/ThreadImpl.h -new file mode 100644 -index 0000000..ea9a0db ---- /dev/null -+++ b/xbmc/threads/platform/win/ThreadImpl.h -@@ -0,0 +1,40 @@ -+/* -+* Copyright (C) 2005-2011 Team XBMC -+* http://www.xbmc.org -+* -+* 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 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 XBMC; see the file COPYING. If not, write to -+* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. -+* http://www.gnu.org/copyleft/gpl.html -+* -+*/ -+ -+#pragma once -+ -+#include -+ -+ -+struct threadOpaque -+{ -+ HANDLE handle; -+}; -+ -+typedef DWORD ThreadIdentifier; -+typedef threadOpaque ThreadOpaque; -+typedef DWORD THREADFUNC; -+ -+namespace XbmcThreads -+{ -+ inline static void ThreadSleep(unsigned int millis) { Sleep(millis); } -+} -+ -diff --git a/xbmc/utils/AlarmClock.cpp b/xbmc/utils/AlarmClock.cpp -index 09c9619..6ca327f 100644 ---- a/xbmc/utils/AlarmClock.cpp -+++ b/xbmc/utils/AlarmClock.cpp -@@ -28,7 +28,7 @@ - - using namespace std; - --CAlarmClock::CAlarmClock() : m_bIsRunning(false) -+CAlarmClock::CAlarmClock() : CThread("CAlarmClock"), m_bIsRunning(false) - { - } - -diff --git a/xbmc/utils/AsyncFileCopy.cpp b/xbmc/utils/AsyncFileCopy.cpp -index e9b7bc0..44e7043 100644 ---- a/xbmc/utils/AsyncFileCopy.cpp -+++ b/xbmc/utils/AsyncFileCopy.cpp -@@ -26,7 +26,7 @@ - #include "log.h" - #include "utils/TimeUtils.h" - --CAsyncFileCopy::CAsyncFileCopy() -+CAsyncFileCopy::CAsyncFileCopy() : CThread("CAsyncFileCopy") - { - m_cancelled = false; - m_succeeded = false; -diff --git a/xbmc/utils/DownloadQueue.cpp b/xbmc/utils/DownloadQueue.cpp -index 4101090..0210241 100644 ---- a/xbmc/utils/DownloadQueue.cpp -+++ b/xbmc/utils/DownloadQueue.cpp -@@ -32,7 +32,7 @@ using namespace XFILE; - - WORD CDownloadQueue::m_wNextQueueId = 0; - --CDownloadQueue::CDownloadQueue(void) : CThread() -+CDownloadQueue::CDownloadQueue(void) : CThread("CDownloadQueue") - { - m_bStop = false; - m_wQueueId = m_wNextQueueId++; -diff --git a/xbmc/utils/DownloadQueue.h b/xbmc/utils/DownloadQueue.h -index c314792..543a825 100644 ---- a/xbmc/utils/DownloadQueue.h -+++ b/xbmc/utils/DownloadQueue.h -@@ -26,6 +26,8 @@ - #include "threads/CriticalSection.h" - #include "StdString.h" - -+#include "system.h" -+ - struct TICKET - { - TICKET(WORD aQueueId, DWORD aItemId) -diff --git a/xbmc/utils/DownloadQueueManager.h b/xbmc/utils/DownloadQueueManager.h -index 3fb0d9f..9bda3ea 100644 ---- a/xbmc/utils/DownloadQueueManager.h -+++ b/xbmc/utils/DownloadQueueManager.h -@@ -22,6 +22,7 @@ - */ - - #include "DownloadQueue.h" -+#include "system.h" - - #define MAX_DOWNLOAD_QUEUES 3 - -diff --git a/xbmc/utils/JobManager.cpp b/xbmc/utils/JobManager.cpp -index dd7b28d..07c9502 100644 ---- a/xbmc/utils/JobManager.cpp -+++ b/xbmc/utils/JobManager.cpp -@@ -23,6 +23,9 @@ - #include - #include "threads/SingleLock.h" - -+#include "system.h" -+ -+ - using namespace std; - - bool CJob::ShouldCancel(unsigned int progress, unsigned int total) const -diff --git a/xbmc/utils/LCD.h b/xbmc/utils/LCD.h -index b60bcf2..888e5ac 100644 ---- a/xbmc/utils/LCD.h -+++ b/xbmc/utils/LCD.h -@@ -68,8 +68,9 @@ public: - void LoadSkin(const CStdString &xmlFile); - void Reset(); - void Render(LCD_MODE mode); -- ILCD() : m_disableOnPlay(DISABLE_ON_PLAY_NONE), -- m_eCurrentCharset(CUSTOM_CHARSET_DEFAULT) {} -+ ILCD() : CThread("ILCD"), -+ m_disableOnPlay(DISABLE_ON_PLAY_NONE), -+ m_eCurrentCharset(CUSTOM_CHARSET_DEFAULT) {} - protected: - virtual void Process() = 0; - void StringToLCDCharSet(CStdString& strText); -diff --git a/xbmc/utils/RssReader.cpp b/xbmc/utils/RssReader.cpp -index 18fcdb4..fff6f5e 100644 ---- a/xbmc/utils/RssReader.cpp -+++ b/xbmc/utils/RssReader.cpp -@@ -44,7 +44,7 @@ using namespace XFILE; - // Construction/Destruction - ////////////////////////////////////////////////////////////////////// - --CRssReader::CRssReader() : CThread() -+CRssReader::CRssReader() : CThread("CRssReader") - { - m_pObserver = NULL; - m_spacesBetweenFeeds = 0; -diff --git a/xbmc/utils/RssReader.h b/xbmc/utils/RssReader.h -index f94e2be..d202b37 100644 ---- a/xbmc/utils/RssReader.h -+++ b/xbmc/utils/RssReader.h -@@ -39,6 +39,9 @@ - - #include "tinyXML/tinyxml.h" - -+#include "system.h" -+ -+ - #define RSS_COLOR_BODY 0 - #define RSS_COLOR_HEADLINE 1 - #define RSS_COLOR_CHANNEL 2 -diff --git a/xbmc/utils/Splash.cpp b/xbmc/utils/Splash.cpp -index 58093b0..a53c90e 100644 ---- a/xbmc/utils/Splash.cpp -+++ b/xbmc/utils/Splash.cpp -@@ -31,7 +31,7 @@ - - using namespace XFILE; - --CSplash::CSplash(const CStdString& imageName) -+CSplash::CSplash(const CStdString& imageName) : CThread("CSplash") - { - m_ImageName = imageName; - fade = 0.5; -@@ -139,5 +139,5 @@ void CSplash::Stop() - - bool CSplash::IsRunning() - { -- return (m_ThreadHandle != NULL); -+ return (IsRunning()); - } -diff --git a/xbmc/utils/TuxBoxUtil.cpp b/xbmc/utils/TuxBoxUtil.cpp -index c15b634..ab5a5ce 100644 ---- a/xbmc/utils/TuxBoxUtil.cpp -+++ b/xbmc/utils/TuxBoxUtil.cpp -@@ -48,7 +48,7 @@ using namespace std; - CTuxBoxUtil g_tuxbox; - CTuxBoxService g_tuxboxService; - --CTuxBoxService::CTuxBoxService() -+CTuxBoxService::CTuxBoxService() : CThread("CTuxBoxService") - { - } - CTuxBoxService::~CTuxBoxService() -diff --git a/xbmc/video/VideoInfoDownloader.cpp b/xbmc/video/VideoInfoDownloader.cpp -index 3185d2b..5a46034 100644 ---- a/xbmc/video/VideoInfoDownloader.cpp -+++ b/xbmc/video/VideoInfoDownloader.cpp -@@ -116,7 +116,7 @@ int CVideoInfoDownloader::FindMovie(const CStdString &strMovie, - m_state = FIND_MOVIE; - m_strMovie = strMovie; - m_found = 0; -- if (ThreadHandle()) -+ if (IsRunning()) - StopThread(); - Create(); - while (m_state != DO_NOTHING) -@@ -160,7 +160,7 @@ bool CVideoInfoDownloader::GetDetails(const CScraperUrl &url, - { // threaded version - m_state = GET_DETAILS; - m_found = 0; -- if (ThreadHandle()) -+ if (IsRunning()) - StopThread(); - Create(); - while (!m_found) -@@ -195,7 +195,7 @@ bool CVideoInfoDownloader::GetEpisodeDetails(const CScraperUrl &url, - { // threaded version - m_state = GET_EPISODE_DETAILS; - m_found = 0; -- if (ThreadHandle()) -+ if (IsRunning()) - StopThread(); - Create(); - while (!m_found) -@@ -230,7 +230,7 @@ bool CVideoInfoDownloader::GetEpisodeList(const CScraperUrl& url, - { // threaded version - m_state = GET_EPISODE_LIST; - m_found = 0; -- if (ThreadHandle()) -+ if (IsRunning()) - StopThread(); - Create(); - while (!m_found) -diff --git a/xbmc/video/VideoInfoDownloader.h b/xbmc/video/VideoInfoDownloader.h -index b91477d..8a05568 100644 ---- a/xbmc/video/VideoInfoDownloader.h -+++ b/xbmc/video/VideoInfoDownloader.h -@@ -42,7 +42,7 @@ typedef std::vector MOVIELIST; - class CVideoInfoDownloader : public CThread - { - public: -- CVideoInfoDownloader(const ADDON::ScraperPtr &scraper) : m_info(scraper) {} -+ CVideoInfoDownloader(const ADDON::ScraperPtr &scraper) : CThread("CVideoInfoDownloader"), m_info(scraper) {} - virtual ~CVideoInfoDownloader() {} - - // threaded lookup functions -diff --git a/xbmc/video/VideoInfoScanner.cpp b/xbmc/video/VideoInfoScanner.cpp -index 1b680f3..f2f50e8 100644 ---- a/xbmc/video/VideoInfoScanner.cpp -+++ b/xbmc/video/VideoInfoScanner.cpp -@@ -54,7 +54,7 @@ using namespace ADDON; - namespace VIDEO - { - -- CVideoInfoScanner::CVideoInfoScanner() -+ CVideoInfoScanner::CVideoInfoScanner() : CThread("CVideoInfoScanner") - { - m_bRunning = false; - m_pObserver = NULL; -diff --git a/xbmc/video/VideoReferenceClock.cpp b/xbmc/video/VideoReferenceClock.cpp -index ea72ee8..1c00b6b 100644 ---- a/xbmc/video/VideoReferenceClock.cpp -+++ b/xbmc/video/VideoReferenceClock.cpp -@@ -107,7 +107,7 @@ using namespace std; - - #endif - --CVideoReferenceClock::CVideoReferenceClock() -+CVideoReferenceClock::CVideoReferenceClock() : CThread("CVideoReferenceClock") - { - m_SystemFrequency = CurrentHostFrequency(); - m_ClockSpeed = 1.0; -@@ -161,6 +161,8 @@ void CVideoReferenceClock::Process() - m_RefreshChanged = 0; - m_Started.Set(); - -+ SetPriority(1); -+ - if (SetupSuccess) - { - m_UseVblank = true; //tell other threads we're using vblank as clock -diff --git a/xbmc/win32/PlatformDefs.h b/xbmc/win32/PlatformDefs.h -index 57cab8f..74e3d53 100644 ---- a/xbmc/win32/PlatformDefs.h -+++ b/xbmc/win32/PlatformDefs.h -@@ -33,7 +33,6 @@ typedef __int64 off64_t; - typedef __int64 fpos64_t; - typedef __int64 __off64_t; - typedef long __off_t; --typedef unsigned long ThreadIdentifier; - - #define ssize_t int - -diff --git a/xbmc/win32/WindowHelper.cpp b/xbmc/win32/WindowHelper.cpp -index 56856ac..8aa7da9 100644 ---- a/xbmc/win32/WindowHelper.cpp -+++ b/xbmc/win32/WindowHelper.cpp -@@ -28,7 +28,7 @@ using namespace std; - - CWHelper g_windowHelper; - --CWHelper::CWHelper(void) -+CWHelper::CWHelper(void) : CThread("CWHelper") - { - m_hwnd = NULL; - m_hProcess = NULL; -diff --git a/xbmc/windowing/X11/WinSystemX11.cpp b/xbmc/windowing/X11/WinSystemX11.cpp -index 201b0ad..c686e6e 100644 ---- a/xbmc/windowing/X11/WinSystemX11.cpp -+++ b/xbmc/windowing/X11/WinSystemX11.cpp -@@ -35,6 +35,8 @@ - #include - #include "cores/VideoRenderers/RenderManager.h" - #include "utils/TimeUtils.h" -+#include "settings/AdvancedSettings.h" -+#include "settings/GUISettings.h" - - #if defined(HAS_XRANDR) - #include -@@ -52,6 +54,7 @@ CWinSystemX11::CWinSystemX11() : CWinSystemBase() - m_wmWindow = 0; - m_bWasFullScreenBeforeMinimize = false; - m_dpyLostTime = 0; -+ m_internalModeSwitch = false; - - XSetErrorHandler(XErrorHandler); - } -@@ -178,6 +181,45 @@ bool CWinSystemX11::ResizeWindow(int newWidth, int newHeight, int newLeft, int n - return false; - } - -+void CWinSystemX11::RefreshWindow() -+{ -+ // save current mode if this is not an internal request -+ if (!m_internalModeSwitch) -+ { -+ CLog::Log(LOGNOTICE, "CWinSystemX11::RefreshWindow - external or initial xrandr event"); -+ m_xrandrOut = g_xrandr.GetCurrentOutput(); -+ m_xrandrMode = g_xrandr.GetCurrentMode(m_xrandrOut.name); -+ } -+ m_internalModeSwitch = false; -+ -+ g_xrandr.Query(true); -+ XOutput out = g_xrandr.GetCurrentOutput(); -+ XMode mode = g_xrandr.GetCurrentMode(out.name); -+ -+ RESOLUTION_INFO res; -+ unsigned int i; -+ bool found(false); -+ for (i = RES_DESKTOP; i < g_settings.m_ResInfo.size(); ++i) -+ { -+ if (g_settings.m_ResInfo[i].strId == mode.id) -+ { -+ found = true; -+ break; -+ } -+ } -+ -+ if (!found) -+ { -+ CLog::Log(LOGERROR, "CWinSystemX11::RefreshWindow - could not find resolution"); -+ return; -+ } -+ -+ g_graphicsContext.SetVideoResolution((RESOLUTION)i, true); -+ g_guiSettings.SetInt("window.width", mode.w); -+ g_guiSettings.SetInt("window.height", mode.h); -+ g_settings.Save(); -+} -+ - bool CWinSystemX11::SetFullScreen(bool fullScreen, RESOLUTION_INFO& res, bool blankOtherDisplays) - { - m_nWidth = res.iWidth; -@@ -193,13 +235,32 @@ bool CWinSystemX11::SetFullScreen(bool fullScreen, RESOLUTION_INFO& res, bool bl - mode.hz = res.fRefreshRate; - mode.id = res.strId; - -- if(m_bFullScreen) -+ XOutput currout = g_xrandr.GetCurrentOutput(); -+ XMode currmode = g_xrandr.GetCurrentMode(currout.name); -+ -+ if (m_xrandrOut.name.empty()) -+ { -+ m_xrandrOut = currout; -+ m_xrandrMode = currmode; -+ } -+ -+ if(!m_bFullScreen) - { -+ // reset to mode we had before internal mode switch -+ out = m_xrandrOut; -+ mode = m_xrandrMode; -+ } -+ -+ // only call xrandr if mode changes -+ if (currout.name != out.name || currmode.w != mode.w || currmode.h != mode.h || -+ currmode.hz != mode.hz || currmode.id != mode.id) -+ { -+ CLog::Log(LOGNOTICE, "CWinSystemX11::SetFullScreen - calling xrandr"); - OnLostDevice(); -+ m_internalModeSwitch = true; - g_xrandr.SetMode(out, mode); - } -- else -- g_xrandr.RestoreState(); -+ - #endif - - int options = SDL_OPENGL; -@@ -493,6 +554,7 @@ void CWinSystemX11::CheckDisplayEvents() - if (bGotEvent || bTimeout) - { - CLog::Log(LOGDEBUG, "%s - notify display reset event", __FUNCTION__); -+ RefreshWindow(); - - CSingleLock lock(m_resourceSection); - -diff --git a/xbmc/windowing/X11/WinSystemX11.h b/xbmc/windowing/X11/WinSystemX11.h -index a77c4d5..dcc63ff 100644 ---- a/xbmc/windowing/X11/WinSystemX11.h -+++ b/xbmc/windowing/X11/WinSystemX11.h -@@ -27,6 +27,7 @@ - #include "utils/Stopwatch.h" - #include - #include "threads/CriticalSection.h" -+#include "XRandR.h" - - class IDispResource; - -@@ -60,6 +61,7 @@ public: - // Local to WinSystemX11 only - Display* GetDisplay() { return m_dpy; } - GLXWindow GetWindow() { return m_glWindow; } -+ void RefreshWindow(); - - protected: - bool RefreshGlxContext(); -@@ -76,6 +78,9 @@ protected: - CCriticalSection m_resourceSection; - std::vector m_resources; - uint64_t m_dpyLostTime; -+ XOutput m_xrandrOut; -+ XMode m_xrandrMode; -+ bool m_internalModeSwitch; - - private: - bool IsSuitableVisual(XVisualInfo *vInfo); diff --git a/packages/mediacenter/xbmc/patches/xbmc-11.0.1-902.01-xvba_support_vdpau_rework-c633159.patch b/packages/mediacenter/xbmc/patches/xbmc-11.0.1-902.01-xvba_support_vdpau_rework-c633159.patch new file mode 100644 index 0000000000..807ade8595 --- /dev/null +++ b/packages/mediacenter/xbmc/patches/xbmc-11.0.1-902.01-xvba_support_vdpau_rework-c633159.patch @@ -0,0 +1,15378 @@ +diff -Naur xbmc-11.0.1/configure.in xbmc-11.0.1.patch/configure.in +--- xbmc-11.0.1/configure.in 2012-03-21 23:57:58.000000000 +0100 ++++ xbmc-11.0.1.patch/configure.in 2012-05-13 22:08:46.942192804 +0200 +@@ -98,6 +98,8 @@ + vaapi_disabled="== VAAPI support manually disabled. ==" + crystalhd_not_found="== Could not find libcrystalhd. CrystalHD support disabled. ==" + crystalhd_disabled="== CrystalHD support manually disabled. ==" ++xvba_not_found="== Could not find amdxvba.h. XVBA support disabled. ==" ++xvba_disabled="== XVBA support manually disabled. ==" + vdadecoder_enabled="== VDADecoder support enabled. ==" + vdadecoder_disabled="== VDADecoder support manually disabled. ==" + vtbdecoder_enabled="== VTBDecoder support enabled. ==" +@@ -204,6 +206,12 @@ + [enable CrystalHD decoding (default is auto)])], + [use_crystalhd=$enableval], + [use_crystalhd=auto]) ++ ++AC_ARG_ENABLE([xvba], ++ [AS_HELP_STRING([--enable-xvba], ++ [enable XVBA decoding (default is auto)])], ++ [use_xvba=$enableval], ++ [use_xvba=auto]) + + AC_ARG_ENABLE([vdadecoder], + [AS_HELP_STRING([--enable-vdadecoder], +@@ -1382,6 +1390,38 @@ + USE_CRYSTALHD=0 + fi + ++# XVBA ++if test "x$use_xvba" != "xno"; then ++ if test "$host_vendor" = "apple" ; then ++ if test "x$use_xvba" = "xyes"; then ++ AC_MSG_ERROR([XVBA not supported on this platform]) ++ else ++ use_xvba="no" ++ AC_MSG_NOTICE($xvba_disabled) ++ fi ++ USE_XVBA=0 ++ else ++ initial_val=$use_xvba ++ AC_CHECK_HEADER([amd/amdxvba.h],, use_xvba=no, [#include ]) ++ ++ if test "x$use_xvba" = "xno"; then ++ if test "x$initial_val" = "xyes"; then ++ AC_MSG_ERROR($xvba_not_found) ++ else ++ AC_MSG_RESULT($xvba_not_found) ++ fi ++ USE_XVBA=0 ++ else ++ AC_DEFINE([HAVE_LIBXVBA], [1], [Define to 1 if you have the 'xvba' header (amdxvba.h)]) ++ USE_XVBA=1 ++ fi ++ fi ++else ++ AC_MSG_NOTICE($xvba_disabled) ++ USE_XVBA=0 ++fi ++ ++ + # VDADecoder + if test "x$use_vdadecoder" != "xno"; then + if test "$host_vendor" = "apple" ; then +@@ -1578,6 +1618,12 @@ + final_message="$final_message\n CrystalHD:\tNo" + fi + ++if test "x$use_xvba" != "xno"; then ++ final_message="$final_message\n XVBA:\t\tYes" ++else ++ final_message="$final_message\n XVBA:\t\tNo" ++fi ++ + if test "x$use_vdadecoder" != "xno"; then + final_message="$final_message\n VDADecoder:\tYes" + else +@@ -1943,6 +1989,7 @@ + AC_SUBST(USE_VDPAU) + AC_SUBST(USE_VAAPI) + AC_SUBST(USE_CRYSTALHD) ++AC_SUBST(USE_XVBA) + AC_SUBST(USE_LIBSMBCLIENT) + AC_SUBST(USE_LIBNFS) + AC_SUBST(USE_LIBAFPCLIENT) +@@ -2085,6 +2132,7 @@ + --enable-gpl \ + `if test "x$use_vdpau" != "xno"; then echo --enable-vdpau; else echo --disable-vdpau; fi` \ + `if test "x$use_vaapi" != "xno"; then echo --enable-vaapi; else echo --disable-vaapi; fi` \ ++ `if test "x$use_xvba" != "xno"; then echo --enable-xvba; else echo --disable-xvba; fi` \ + --enable-protocol=http \ + --enable-pthreads \ + --enable-runtime-cpudetect \ +diff -Naur xbmc-11.0.1/language/Dutch/strings.xml xbmc-11.0.1.patch/language/Dutch/strings.xml +--- xbmc-11.0.1/language/Dutch/strings.xml 2012-03-21 23:57:54.000000000 +0100 ++++ xbmc-11.0.1.patch/language/Dutch/strings.xml 2012-05-13 22:16:42.908637517 +0200 +@@ -1233,7 +1233,8 @@ + Hardwareversnelling inschakelen (OpenMax) + Pixelshaders + Hardware acceleratie toestaan (VideoToolbox) +- ++ Vdpau OpenGL interop RGB inschakelen ++ Vdpau OpenGL interop YUV inschakelen + A/V-synchronisatiemethode + Audiosignaal + Videosignaal (Drop/Dupe audio) +@@ -1539,6 +1540,7 @@ + Spline36 + Spline36 geoptimaliseerd + Software menging ++ VDPAU Bob + + Kwaliteitsverbetering video + +diff -Naur xbmc-11.0.1/language/English/strings.xml xbmc-11.0.1.patch/language/English/strings.xml +--- xbmc-11.0.1/language/English/strings.xml 2012-03-21 23:57:54.000000000 +0100 ++++ xbmc-11.0.1.patch/language/English/strings.xml 2012-05-13 22:16:30.975400722 +0200 +@@ -1232,6 +1232,9 @@ + Allow hardware acceleration (OpenMax) + Pixel Shaders + Allow hardware acceleration (VideoToolbox) ++ Allow Vdpau OpenGL interop RGB ++ Allow Vdpau OpenGL interop YUV ++ Allow hardware acceleration (XVBA) + + A/V sync method + Audio clock +@@ -1538,6 +1541,8 @@ + Spline36 + Spline36 optimized + Software Blend ++ VDPAU Bob ++ XVBA + + Post-processing + +diff -Naur xbmc-11.0.1/language/German/strings.xml xbmc-11.0.1.patch/language/German/strings.xml +--- xbmc-11.0.1/language/German/strings.xml 2012-03-21 23:57:54.000000000 +0100 ++++ xbmc-11.0.1.patch/language/German/strings.xml 2012-05-13 22:08:46.676187527 +0200 +@@ -1266,6 +1266,8 @@ + Hardwarebeschleunigung erlauben (OpenMax) + Pixel Shaders + Hardwarebeschleunigung erlauben (VideoToolbox) ++ Vdpau OpenGL interop RGB erlauben ++ Vdpau OpenGL interop YUV erlauben + + A/V Sync Methode + Audio Takt +@@ -1565,6 +1567,7 @@ + Zeitlich (Hälfte) + Zeitlich/Räumlich (Hälfte) + DXVA ++ VDPAU Bob + + Video Nachbearbeitung + Deaktiviert +diff -Naur xbmc-11.0.1/language/Swedish/strings.xml xbmc-11.0.1.patch/language/Swedish/strings.xml +--- xbmc-11.0.1/language/Swedish/strings.xml 2012-03-21 23:57:54.000000000 +0100 ++++ xbmc-11.0.1.patch/language/Swedish/strings.xml 2012-05-13 22:08:46.663187269 +0200 +@@ -1412,6 +1412,7 @@ + Spline36 + Spline36-optimerad + Mjukvarublandning ++ VDPAU Bob + Efterbearbetning + Visa insommningstimeout + Byt till kanal +diff -Naur xbmc-11.0.1/lib/ffmpeg/configure xbmc-11.0.1.patch/lib/ffmpeg/configure +--- xbmc-11.0.1/lib/ffmpeg/configure 2012-03-21 23:57:44.000000000 +0100 ++++ xbmc-11.0.1.patch/lib/ffmpeg/configure 2012-05-13 22:08:46.926192488 +0200 +@@ -111,6 +111,7 @@ + --disable-vaapi disable VAAPI code + --disable-vdpau disable VDPAU code + --disable-dxva2 disable DXVA2 code ++ --disable-xvba disable XVBA code + --enable-runtime-cpudetect detect cpu capabilities at runtime (bigger binary) + --enable-hardcoded-tables use hardcoded tables instead of runtime generation + --enable-memalign-hack emulate memalign, interferes with memory debuggers +@@ -932,6 +933,7 @@ + swscale_alpha + vaapi + vdpau ++ xvba + version3 + x11grab + zlib +@@ -1240,6 +1242,7 @@ + h264_dxva2_hwaccel_deps="dxva2api_h" + h264_dxva2_hwaccel_select="dxva2 h264_decoder" + h264_vaapi_hwaccel_select="vaapi" ++h264_xvba_hwaccel_select="xvba" + h264_vdpau_decoder_select="vdpau h264_decoder" + imc_decoder_select="fft mdct" + jpegls_decoder_select="golomb" +@@ -1263,6 +1266,7 @@ + mpeg2_dxva2_hwaccel_select="dxva2 mpeg2video_decoder" + mpeg2_vaapi_hwaccel_select="vaapi mpeg2video_decoder" + mpeg4_vaapi_hwaccel_select="vaapi mpeg4_decoder" ++mpeg2_xvba_hwaccel_select="xvba mpeg2video_decoder" + mpeg4_vdpau_decoder_deps="vdpau_vdpau_h vdpau_vdpau_x11_h vdpau_mpeg4_support" + mpeg4_vdpau_decoder_select="vdpau mpeg4_decoder" + mpeg_xvmc_decoder_deps="X11_extensions_XvMClib_h" +@@ -1306,6 +1310,7 @@ + vc1_dxva2_hwaccel_deps="dxva2api_h DXVA_PictureParameters_wDecodedPictureIndex" + vc1_dxva2_hwaccel_select="dxva2 vc1_decoder" + vc1_vaapi_hwaccel_select="vaapi vc1_decoder" ++vc1_xvba_hwaccel_select="xvba vc1_decoder" + vc1_vdpau_decoder_select="vdpau vc1_decoder" + vorbis_decoder_select="mdct" + vorbis_encoder_select="mdct" +@@ -1327,12 +1332,14 @@ + wmv3_dxva2_hwaccel_select="vc1_dxva2_hwaccel" + wmv3_vaapi_hwaccel_select="vc1_vaapi_hwaccel" + wmv3_vdpau_decoder_select="vc1_vdpau_decoder" ++wmv3_xvba_hwaccel_select="vc1_xvba_hwaccel" + zlib_decoder_select="zlib" + zlib_encoder_select="zlib" + zmbv_decoder_select="zlib" + zmbv_encoder_select="zlib" + + vaapi_deps="va_va_h" ++xvba_deps="amd_amdxvba_h" + vdpau_deps="vdpau_vdpau_h vdpau_vdpau_x11_h" + + # parsers +@@ -2762,6 +2769,7 @@ + check_header termios.h + check_header vdpau/vdpau.h + check_header vdpau/vdpau_x11.h ++check_header amd/amdxvba.h + check_cpp_condition vdpau/vdpau.h "defined(VDP_DECODER_PROFILE_MPEG4_PART2_SP)" && enable vdpau_mpeg4_support + + check_header X11/extensions/XvMClib.h +diff -Naur xbmc-11.0.1/lib/ffmpeg/libavcodec/allcodecs.c xbmc-11.0.1.patch/lib/ffmpeg/libavcodec/allcodecs.c +--- xbmc-11.0.1/lib/ffmpeg/libavcodec/allcodecs.c 2012-03-21 23:57:47.000000000 +0100 ++++ xbmc-11.0.1.patch/lib/ffmpeg/libavcodec/allcodecs.c 2012-05-13 22:08:46.928192528 +0200 +@@ -57,13 +57,17 @@ + REGISTER_HWACCEL (H263_VAAPI, h263_vaapi); + REGISTER_HWACCEL (H264_DXVA2, h264_dxva2); + REGISTER_HWACCEL (H264_VAAPI, h264_vaapi); ++ REGISTER_HWACCEL (H264_XVBA, h264_xvba); + REGISTER_HWACCEL (MPEG2_DXVA2, mpeg2_dxva2); + REGISTER_HWACCEL (MPEG2_VAAPI, mpeg2_vaapi); + REGISTER_HWACCEL (MPEG4_VAAPI, mpeg4_vaapi); ++ REGISTER_HWACCEL (MPEG2_XVBA, mpeg2_xvba); + REGISTER_HWACCEL (VC1_DXVA2, vc1_dxva2); + REGISTER_HWACCEL (VC1_VAAPI, vc1_vaapi); ++ REGISTER_HWACCEL (VC1_XVBA, vc1_xvba); + REGISTER_HWACCEL (WMV3_DXVA2, wmv3_dxva2); + REGISTER_HWACCEL (WMV3_VAAPI, wmv3_vaapi); ++ REGISTER_HWACCEL (WMV3_XVBA, wmv3_xvba); + + /* video codecs */ + REGISTER_ENCODER (A64MULTI, a64multi); +diff -Naur xbmc-11.0.1/lib/ffmpeg/libavcodec/h264.c xbmc-11.0.1.patch/lib/ffmpeg/libavcodec/h264.c +--- xbmc-11.0.1/lib/ffmpeg/libavcodec/h264.c 2012-03-21 23:57:45.000000000 +0100 ++++ xbmc-11.0.1.patch/lib/ffmpeg/libavcodec/h264.c 2012-05-13 22:08:46.930192568 +0200 +@@ -55,6 +55,7 @@ + static const enum PixelFormat hwaccel_pixfmt_list_h264_jpeg_420[] = { + PIX_FMT_DXVA2_VLD, + PIX_FMT_VAAPI_VLD, ++ PIX_FMT_XVBA_VLD, + PIX_FMT_YUVJ420P, + PIX_FMT_NONE + }; +diff -Naur xbmc-11.0.1/lib/ffmpeg/libavcodec/Makefile xbmc-11.0.1.patch/lib/ffmpeg/libavcodec/Makefile +--- xbmc-11.0.1/lib/ffmpeg/libavcodec/Makefile 2012-03-21 23:57:45.000000000 +0100 ++++ xbmc-11.0.1.patch/lib/ffmpeg/libavcodec/Makefile 2012-05-13 22:08:46.927192508 +0200 +@@ -3,7 +3,7 @@ + NAME = avcodec + FFLIBS = avcore avutil + +-HEADERS = avcodec.h avfft.h dxva2.h opt.h vaapi.h vdpau.h xvmc.h ++HEADERS = avcodec.h avfft.h dxva2.h opt.h vaapi.h vdpau.h xvmc.h xvba.h + + OBJS = allcodecs.o \ + audioconvert.o \ +@@ -43,6 +43,7 @@ + OBJS-$(CONFIG_RDFT) += rdft.o $(RDFT-OBJS-yes) + OBJS-$(CONFIG_VAAPI) += vaapi.o + OBJS-$(CONFIG_VDPAU) += vdpau.o ++OBJS-$(CONFIG_XVBA) += xvba.o + + # decoders/encoders/hardware accelerators + OBJS-$(CONFIG_A64MULTI_ENCODER) += a64multienc.o elbg.o +@@ -169,6 +170,7 @@ + mpegvideo.o error_resilience.o + OBJS-$(CONFIG_H264_DXVA2_HWACCEL) += dxva2_h264.o + OBJS-$(CONFIG_H264_VAAPI_HWACCEL) += vaapi_h264.o ++OBJS-$(CONFIG_H264_XVBA_HWACCEL) += xvba_h264.o + OBJS-$(CONFIG_HUFFYUV_DECODER) += huffyuv.o + OBJS-$(CONFIG_HUFFYUV_ENCODER) += huffyuv.o + OBJS-$(CONFIG_IDCIN_DECODER) += idcinvideo.o +@@ -246,6 +248,7 @@ + mpegvideo.o error_resilience.o + OBJS-$(CONFIG_MPEG2_DXVA2_HWACCEL) += dxva2_mpeg2.o + OBJS-$(CONFIG_MPEG2_VAAPI_HWACCEL) += vaapi_mpeg2.o ++OBJS-$(CONFIG_MPEG2_XVBA_HWACCEL) += xvba_mpeg2.o + OBJS-$(CONFIG_MPEG2VIDEO_DECODER) += mpeg12.o mpeg12data.o \ + mpegvideo.o error_resilience.o + OBJS-$(CONFIG_MPEG2VIDEO_ENCODER) += mpeg12enc.o mpegvideo_enc.o \ +@@ -379,6 +382,7 @@ + intrax8.o intrax8dsp.o + OBJS-$(CONFIG_VC1_DXVA2_HWACCEL) += dxva2_vc1.o + OBJS-$(CONFIG_VC1_VAAPI_HWACCEL) += vaapi_vc1.o ++OBJS-$(CONFIG_VC1_XVBA_HWACCEL) += xvba_vc1.o + OBJS-$(CONFIG_VCR1_DECODER) += vcr1.o + OBJS-$(CONFIG_VCR1_ENCODER) += vcr1.o + OBJS-$(CONFIG_VMDAUDIO_DECODER) += vmdav.o +@@ -647,6 +651,7 @@ + SKIPHEADERS-$(CONFIG_LIBDIRAC) += libdirac.h + SKIPHEADERS-$(CONFIG_LIBSCHROEDINGER) += libschroedinger.h + SKIPHEADERS-$(CONFIG_VAAPI) += vaapi_internal.h ++SKIPHEADERS-$(CONFIG_XVBA) += xvba_internal.h + SKIPHEADERS-$(CONFIG_VDPAU) += vdpau.h + SKIPHEADERS-$(CONFIG_XVMC) += xvmc.h + SKIPHEADERS += mpegaudio3.h +diff -Naur xbmc-11.0.1/lib/ffmpeg/libavcodec/mpegvideo.c xbmc-11.0.1.patch/lib/ffmpeg/libavcodec/mpegvideo.c +--- xbmc-11.0.1/lib/ffmpeg/libavcodec/mpegvideo.c 2012-03-21 23:57:45.000000000 +0100 ++++ xbmc-11.0.1.patch/lib/ffmpeg/libavcodec/mpegvideo.c 2012-05-13 22:08:46.933192627 +0200 +@@ -117,6 +117,7 @@ + const enum PixelFormat ff_hwaccel_pixfmt_list_420[] = { + PIX_FMT_DXVA2_VLD, + PIX_FMT_VAAPI_VLD, ++ PIX_FMT_XVBA_VLD, + PIX_FMT_YUV420P, + PIX_FMT_NONE + }; +diff -Naur xbmc-11.0.1/lib/ffmpeg/libavcodec/xvba.c xbmc-11.0.1.patch/lib/ffmpeg/libavcodec/xvba.c +--- xbmc-11.0.1/lib/ffmpeg/libavcodec/xvba.c 1970-01-01 01:00:00.000000000 +0100 ++++ xbmc-11.0.1.patch/lib/ffmpeg/libavcodec/xvba.c 2012-05-13 22:08:46.934192647 +0200 +@@ -0,0 +1,65 @@ ++/* ++ * HW decode acceleration for MPEG-2, H.264 and VC-1 ++ * ++ * Copyright (C) 2005-2011 Team XBMC ++ * ++ * This file is part of FFmpeg. ++ * ++ * FFmpeg is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU Lesser General Public ++ * License as published by the Free Software Foundation; either ++ * version 2.1 of the License, or (at your option) any later version. ++ * ++ * FFmpeg 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 ++ * Lesser General Public License for more details. ++ * ++ * You should have received a copy of the GNU Lesser General Public ++ * License along with FFmpeg; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++ ++ ++/** ++ * \addtogroup XVBA_Decoding ++ * ++ * @{ ++ */ ++ ++#include ++#include "xvba.h" ++#include "avcodec.h" ++ ++int ff_xvba_translate_profile(int profile) { ++ ++ if (profile == 66) ++ return 1; ++ else if (profile == 77) ++ return 2; ++ else if (profile == 100) ++ return 3; ++ else if (profile == 0) ++ return 4; ++ else if (profile == 1) ++ return 5; ++ else if (profile == 3) ++ return 6; ++ else ++ return -1; ++} ++ ++void ff_xvba_add_slice_data(struct xvba_render_state *render, const void *buffer, uint32_t size) { ++ ++ render->buffers = av_fast_realloc( ++ render->buffers, ++ &render->buffers_alllocated, ++ sizeof(struct xvba_bitstream_buffers)*(render->num_slices + 1) ++ ); ++ ++ render->buffers[render->num_slices].buffer = buffer; ++ render->buffers[render->num_slices].size = size; ++ ++ render->num_slices++; ++} ++ +diff -Naur xbmc-11.0.1/lib/ffmpeg/libavcodec/xvba.h xbmc-11.0.1.patch/lib/ffmpeg/libavcodec/xvba.h +--- xbmc-11.0.1/lib/ffmpeg/libavcodec/xvba.h 1970-01-01 01:00:00.000000000 +0100 ++++ xbmc-11.0.1.patch/lib/ffmpeg/libavcodec/xvba.h 2012-05-13 22:08:46.935192667 +0200 +@@ -0,0 +1,71 @@ ++/* ++ * HW decode acceleration for MPEG-2, H.264 and VC-1 ++ * ++ * Copyright (C) 2005-2011 Team XBMC ++ * ++ * This file is part of FFmpeg. ++ * ++ * FFmpeg is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU Lesser General Public ++ * License as published by the Free Software Foundation; either ++ * version 2.1 of the License, or (at your option) any later version. ++ * ++ * FFmpeg 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 ++ * Lesser General Public License for more details. ++ * ++ * You should have received a copy of the GNU Lesser General Public ++ * License along with FFmpeg; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++ ++#ifndef AVCODEC_XVBA_H ++#define AVCODEC_XVBA_H ++ ++#include ++#include ++#include ++ ++ ++/** ++ * \defgroup XVBA_Decoding VA API Decoding ++ * \ingroup Decoder ++ * @{ ++ */ ++ ++/** \brief The videoSurface is used for rendering. */ ++#define FF_XVBA_STATE_USED_FOR_RENDER 1 ++ ++/** ++ * \brief The videoSurface is needed for reference/prediction. ++ * The codec manipulates this. ++ */ ++#define FF_XVBA_STATE_USED_FOR_REFERENCE 2 ++ ++/** ++ * \brief The videoSurface holds a decoded frame. ++ * The codec manipulates this. ++ */ ++#define FF_XVBA_STATE_DECODED 4 ++ ++/* @} */ ++ ++struct xvba_bitstream_buffers ++{ ++ const void *buffer; ++ unsigned int size; ++}; ++ ++struct xvba_render_state { ++ ++ int state; ///< Holds FF_XVBA_STATE_* values. ++ void *surface; ++ XVBAPictureDescriptor *picture_descriptor; ++ XVBAQuantMatrixAvc *iq_matrix; ++ int num_slices; ++ struct xvba_bitstream_buffers *buffers; ++ uint32_t buffers_alllocated; ++}; ++ ++#endif /* AVCODEC_XVBA_H */ +diff -Naur xbmc-11.0.1/lib/ffmpeg/libavcodec/xvba_h264.c xbmc-11.0.1.patch/lib/ffmpeg/libavcodec/xvba_h264.c +--- xbmc-11.0.1/lib/ffmpeg/libavcodec/xvba_h264.c 1970-01-01 01:00:00.000000000 +0100 ++++ xbmc-11.0.1.patch/lib/ffmpeg/libavcodec/xvba_h264.c 2012-05-13 22:08:46.936192687 +0200 +@@ -0,0 +1,180 @@ ++/* ++ * H.264 HW decode acceleration through XVBA ++ * ++ * Copyright (C) 2005-2011 Team XBMC ++ * ++ * This file is part of FFmpeg. ++ * ++ * FFmpeg is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU Lesser General Public ++ * License as published by the Free Software Foundation; either ++ * version 2.1 of the License, or (at your option) any later version. ++ * ++ * FFmpeg 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 ++ * Lesser General Public License for more details. ++ * ++ * You should have received a copy of the GNU Lesser General Public ++ * License along with FFmpeg; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++ ++#include "xvba.h" ++#include "xvba_internal.h" ++#include "h264.h" ++#include ++ ++/** @file ++ * This file implements the glue code between FFmpeg's and XvBA API's ++ * structures for H.264 decoding. ++ */ ++ ++ ++/** Initialize and start decoding a frame with XVBA. */ ++static int start_frame(AVCodecContext *avctx, ++ av_unused const uint8_t *buffer, ++ av_unused uint32_t size) ++{ ++ H264Context * const h = avctx->priv_data; ++ MpegEncContext * const s = &h->s; ++ struct xvba_render_state *render; ++ XVBAPictureDescriptor *pic_descriptor; ++ int i; ++ ++ render = (struct xvba_render_state *)s->current_picture_ptr->data[0]; ++ assert(render); ++ ++ if (render->picture_descriptor == 0) ++ return -1; ++ ++ pic_descriptor = render->picture_descriptor; ++ ++ for (i = 0; i < 2; ++i) { ++ int foc = s->current_picture_ptr->field_poc[i]; ++ if (foc == INT_MAX) ++ foc = 0; ++ pic_descriptor->avc_curr_field_order_cnt_list[i] = foc; ++ } ++ ++ pic_descriptor->avc_frame_num = h->frame_num; ++ ++ render->num_slices = 0; ++ ++ return 0; ++} ++ ++/** End a hardware decoding based frame. */ ++static int end_frame(AVCodecContext *avctx) ++{ ++ H264Context * const h = avctx->priv_data; ++ MpegEncContext * const s = &h->s; ++ struct xvba_render_state *render; ++ XVBAPictureDescriptor *pic_descriptor; ++ XVBAQuantMatrixAvc *iq_matrix; ++ ++ render = (struct xvba_render_state *)s->current_picture_ptr->data[0]; ++ assert(render); ++ ++ if (render->picture_descriptor == 0 || render->iq_matrix == 0) ++ return -1; ++ ++ pic_descriptor = render->picture_descriptor; ++ iq_matrix = render->iq_matrix; ++ ++ av_dlog(avctx, "end_frame()\n"); ++ ++ /* Fill in Picture Parameters*/ ++ pic_descriptor->profile = ff_xvba_translate_profile(avctx->profile); ++ pic_descriptor->level = avctx->level; ++ pic_descriptor->width_in_mb = s->mb_width; ++ pic_descriptor->height_in_mb = s->mb_height; ++ pic_descriptor->picture_structure = s->picture_structure; ++ pic_descriptor->chroma_format = s->chroma_format ? s->chroma_format : 1; ++ pic_descriptor->avc_intra_flag = (h->slice_type == FF_I_TYPE) ? 1 : 0; ++ pic_descriptor->avc_reference = (s->current_picture_ptr->reference & 3) ? 1 : 0; ++ ++ pic_descriptor->avc_bit_depth_luma_minus8 = h->sps.bit_depth_luma - 8; ++ pic_descriptor->avc_bit_depth_chroma_minus8 = h->sps.bit_depth_chroma - 8; ++ pic_descriptor->avc_log2_max_frame_num_minus4 = h->sps.log2_max_frame_num -4; ++ pic_descriptor->avc_pic_order_cnt_type = h->sps.poc_type; ++ pic_descriptor->avc_log2_max_pic_order_cnt_lsb_minus4 = h->sps.log2_max_poc_lsb - 4; ++ pic_descriptor->avc_num_ref_frames = h->sps.ref_frame_count; ++ pic_descriptor->avc_reserved_8bit = 0; ++ ++ pic_descriptor->avc_num_slice_groups_minus1 = h->pps.slice_group_count - 1; ++ pic_descriptor->avc_num_ref_idx_l0_active_minus1 = h->pps.ref_count[0] - 1; ++ pic_descriptor->avc_num_ref_idx_l1_active_minus1 = h->pps.ref_count[1] - 1; ++ ++ pic_descriptor->avc_pic_init_qp_minus26 = h->pps.init_qp - 26; ++ pic_descriptor->avc_pic_init_qs_minus26 = h->pps.init_qs - 26; ++ pic_descriptor->avc_chroma_qp_index_offset = h->pps.chroma_qp_index_offset[0]; ++ pic_descriptor->avc_second_chroma_qp_index_offset = h->pps.chroma_qp_index_offset[1]; ++ pic_descriptor->avc_slice_group_change_rate_minus1 = 0; // not implemented in ffmpeg ++ pic_descriptor->avc_reserved_16bit = 0; // must be 0 ++ memset(pic_descriptor->avc_field_order_cnt_list,0,sizeof(pic_descriptor->avc_field_order_cnt_list)); // must be 0 ++ memset(pic_descriptor->avc_slice_group_map,0,sizeof(pic_descriptor->avc_slice_group_map)); // must be 0 ++ ++ // sps ++ pic_descriptor->sps_info.avc.delta_pic_always_zero_flag = h->sps.delta_pic_order_always_zero_flag; ++ pic_descriptor->sps_info.avc.direct_8x8_inference_flag = h->sps.direct_8x8_inference_flag; ++ pic_descriptor->sps_info.avc.frame_mbs_only_flag = h->sps.frame_mbs_only_flag; ++ pic_descriptor->sps_info.avc.gaps_in_frame_num_value_allowed_flag = h->sps.gaps_in_frame_num_allowed_flag; ++ pic_descriptor->sps_info.avc.mb_adaptive_frame_field_flag = h->sps.mb_aff; ++ pic_descriptor->sps_info.avc.residual_colour_transform_flag = h->sps.residual_color_transform_flag; ++ pic_descriptor->sps_info.avc.xvba_avc_sps_reserved = 0; ++ ++ // pps ++ pic_descriptor->pps_info.avc.entropy_coding_mode_flag = h->pps.cabac; ++ pic_descriptor->pps_info.avc.pic_order_present_flag = h->pps.pic_order_present; ++ pic_descriptor->pps_info.avc.weighted_pred_flag = h->pps.weighted_pred; ++ pic_descriptor->pps_info.avc.weighted_bipred_idc = h->pps.weighted_bipred_idc; ++ pic_descriptor->pps_info.avc.deblocking_filter_control_present_flag = h->pps.deblocking_filter_parameters_present; ++ pic_descriptor->pps_info.avc.constrained_intra_pred_flag = h->pps.constrained_intra_pred; ++ pic_descriptor->pps_info.avc.redundant_pic_cnt_present_flag = h->pps.redundant_pic_cnt_present; ++ pic_descriptor->pps_info.avc.transform_8x8_mode_flag = h->pps.transform_8x8_mode; ++ pic_descriptor->pps_info.avc.xvba_avc_pps_reserved = 0; // must be 0 ++ ++ memcpy(iq_matrix->bScalingLists4x4, h->pps.scaling_matrix4, sizeof(iq_matrix->bScalingLists4x4)); ++ memcpy(iq_matrix->bScalingLists8x8, h->pps.scaling_matrix8, sizeof(iq_matrix->bScalingLists8x8)); ++ ++ // Wait for an I-frame before start decoding. Workaround for ATI UVD and UVD+ GPUs ++ if (!h->got_first_iframe) { ++ if (h->slice_type != FF_I_TYPE && h->slice_type != FF_SI_TYPE) ++ return -1; ++ h->got_first_iframe = 1; ++ } ++ ++ ff_draw_horiz_band(s, 0, s->avctx->height); ++ ++ return 0; ++} ++ ++/** Decode the given H.264 slice with VA API. */ ++static int decode_slice(AVCodecContext *avctx, ++ const uint8_t *buffer, ++ uint32_t size) ++{ ++ H264Context * const h = avctx->priv_data; ++ MpegEncContext * const s = &h->s; ++ struct xvba_render_state *render; ++ ++ render = (struct xvba_render_state *)s->current_picture_ptr->data[0]; ++ assert(render); ++ ++ ff_xvba_add_slice_data(render, buffer, size); ++ ++ return 0; ++} ++ ++AVHWAccel ff_h264_xvba_hwaccel = { ++ .name = "h264_xvba", ++ .type = AVMEDIA_TYPE_VIDEO, ++ .id = CODEC_ID_H264, ++ .pix_fmt = PIX_FMT_XVBA_VLD, ++ .capabilities = 0, ++ .start_frame = start_frame, ++ .end_frame = end_frame, ++ .decode_slice = decode_slice, ++ .priv_data_size = 0, ++}; +diff -Naur xbmc-11.0.1/lib/ffmpeg/libavcodec/xvba_internal.h xbmc-11.0.1.patch/lib/ffmpeg/libavcodec/xvba_internal.h +--- xbmc-11.0.1/lib/ffmpeg/libavcodec/xvba_internal.h 1970-01-01 01:00:00.000000000 +0100 ++++ xbmc-11.0.1.patch/lib/ffmpeg/libavcodec/xvba_internal.h 2012-05-13 22:08:46.936192687 +0200 +@@ -0,0 +1,24 @@ ++/* ++ * HW decode acceleration for MPEG-2, H.264 and VC-1 ++ * ++ * Copyright (C) 2005-2011 Team XBMC ++ * ++ * This file is part of FFmpeg. ++ * ++ * FFmpeg is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU Lesser General Public ++ * License as published by the Free Software Foundation; either ++ * version 2.1 of the License, or (at your option) any later version. ++ * ++ * FFmpeg 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 ++ * Lesser General Public License for more details. ++ * ++ * You should have received a copy of the GNU Lesser General Public ++ * License along with FFmpeg; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++ ++int ff_xvba_translate_profile(int profile); ++void ff_xvba_add_slice_data(struct xvba_render_state *render, const uint8_t *buffer, uint32_t size); +diff -Naur xbmc-11.0.1/lib/ffmpeg/libavcodec/xvba_mpeg2.c xbmc-11.0.1.patch/lib/ffmpeg/libavcodec/xvba_mpeg2.c +--- xbmc-11.0.1/lib/ffmpeg/libavcodec/xvba_mpeg2.c 1970-01-01 01:00:00.000000000 +0100 ++++ xbmc-11.0.1.patch/lib/ffmpeg/libavcodec/xvba_mpeg2.c 2012-05-13 22:08:46.937192706 +0200 +@@ -0,0 +1,52 @@ ++/* ++ * MPEG-2 HW decode acceleration through XVBA ++ * ++ * Copyright (C) 2005-2011 Team XBMC ++ * ++ * This file is part of FFmpeg. ++ * ++ * FFmpeg is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU Lesser General Public ++ * License as published by the Free Software Foundation; either ++ * version 2.1 of the License, or (at your option) any later version. ++ * ++ * FFmpeg 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 ++ * Lesser General Public License for more details. ++ * ++ * You should have received a copy of the GNU Lesser General Public ++ * License along with FFmpeg; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++ ++#include "dsputil.h" ++ ++static int start_frame(AVCodecContext *avctx, av_unused const uint8_t *buffer, av_unused uint32_t size) ++{ ++ struct MpegEncContext * const s = avctx->priv_data; ++ return 0; ++} ++ ++static int end_frame(AVCodecContext *avctx) ++{ ++ return 0; ++} ++ ++static int decode_slice(AVCodecContext *avctx, const uint8_t *buffer, uint32_t size) ++{ ++ struct MpegEncContext * const s = avctx->priv_data; ++ return 0; ++} ++ ++AVHWAccel ff_mpeg2_xvba_hwaccel = { ++ .name = "mpeg2_xvba", ++ .type = AVMEDIA_TYPE_VIDEO, ++ .id = CODEC_ID_MPEG2VIDEO, ++ .pix_fmt = PIX_FMT_XVBA_VLD, ++ .capabilities = 0, ++ .start_frame = start_frame, ++ .end_frame = end_frame, ++ .decode_slice = decode_slice, ++ .priv_data_size = 0, ++}; +diff -Naur xbmc-11.0.1/lib/ffmpeg/libavcodec/xvba_vc1.c xbmc-11.0.1.patch/lib/ffmpeg/libavcodec/xvba_vc1.c +--- xbmc-11.0.1/lib/ffmpeg/libavcodec/xvba_vc1.c 1970-01-01 01:00:00.000000000 +0100 ++++ xbmc-11.0.1.patch/lib/ffmpeg/libavcodec/xvba_vc1.c 2012-05-13 22:08:46.937192706 +0200 +@@ -0,0 +1,194 @@ ++/* ++ * VC-1 HW decode acceleration through XVBA ++ * ++ * Copyright (C) 2005-2011 Team XBMC ++ * ++ * This file is part of FFmpeg. ++ * ++ * FFmpeg is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU Lesser General Public ++ * License as published by the Free Software Foundation; either ++ * version 2.1 of the License, or (at your option) any later version. ++ * ++ * FFmpeg 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 ++ * Lesser General Public License for more details. ++ * ++ * You should have received a copy of the GNU Lesser General Public ++ * License along with FFmpeg; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++ ++#include "xvba.h" ++#include "xvba_internal.h" ++#include "vc1.h" ++#include "vc1data.h" ++#include ++ ++ ++/** @file ++ * Implement structures of ffmpeg <-> XvBA ++ */ ++ ++/* Initialize and start decoding a frame with XvBA */ ++static int start_frame(AVCodecContext *avctx, ++ av_unused const uint8_t *buffer, ++ av_unused uint32_t size) ++{ ++ VC1Context * const v = avctx->priv_data; ++ MpegEncContext * const s = &v->s; ++ struct xvba_render_state *render; ++ ++ render = (struct xvba_render_state *)s->current_picture_ptr->data[0]; ++ assert(render); ++ ++ render->num_slices = 0; ++ return 0; ++} ++ ++/* End a hardware decoding based frame */ ++static int end_frame(AVCodecContext *avctx) ++{ ++ VC1Context* const v = avctx->priv_data; ++ MpegEncContext* const s = &v->s; ++ struct xvba_render_state *render, *last, *next; ++ XVBAPictureDescriptor *pic_descriptor; ++ ++ render = (struct xvba_render_state *)s->current_picture_ptr->data[0]; ++ assert(render); ++ ++ if (render->picture_descriptor == 0) ++ return -1; ++ ++ pic_descriptor = render->picture_descriptor; ++ ++ av_dlog(avctx, "xvba_vc1_end_frame()\n"); ++ ++ memset(pic_descriptor, 0, sizeof(*pic_descriptor)); ++ ++ /* Fill in Parameters - for reference see AMD sdk documentation */ ++ pic_descriptor->profile = ff_xvba_translate_profile(v->profile); ++ pic_descriptor->level = v->level; ++ //done like in va-driver and vaapi ++ if (v->profile == PROFILE_ADVANCED) { ++ pic_descriptor->width_in_mb = s->avctx->coded_width; ++ pic_descriptor->height_in_mb = s->avctx->coded_height; ++ } else { ++ pic_descriptor->width_in_mb = s->mb_width; ++ pic_descriptor->height_in_mb = s->mb_height; ++ } ++ pic_descriptor->picture_structure = s->picture_structure; ++ // xvba-video set this to 1 only 4:2:0 supported ++ // doc says: if not set, choose 1 - we try this ++ pic_descriptor->chroma_format = 1; ++ pic_descriptor->avc_intra_flag = s->pict_type == FF_I_TYPE || v->bi_type == 1; ++ pic_descriptor->avc_reference = (s->current_picture_ptr->reference & 3) ? 1 : 0; ++ ++ // VC-1 explicit parameters see page 30 of sdk ++ // sps_info ++ pic_descriptor->sps_info.vc1.postprocflag = v->postprocflag; ++ ++ // done as in vaapi ++ pic_descriptor->sps_info.vc1.pulldown = v->broadcast; ++ pic_descriptor->sps_info.vc1.interlace = v->interlace; ++ pic_descriptor->sps_info.vc1.tfcntrflag = v->tfcntrflag; ++ pic_descriptor->sps_info.vc1.finterpflag = v->finterpflag; ++ pic_descriptor->sps_info.vc1.reserved = 1; ++ // eventually check if this makes sense together with interlace ++ pic_descriptor->sps_info.vc1.psf = v->psf; ++ // what about if it is a frame (page 31) ++ // looked at xvba-driver ++ pic_descriptor->sps_info.vc1.second_field = !s->first_field; ++ pic_descriptor->sps_info.vc1.xvba_vc1_sps_reserved = 0; ++ ++ // VC-1 explicit parameters see page 30 of sdk ++ // pps_info ++ pic_descriptor->pps_info.vc1.panscan_flag = v->panscanflag; ++ pic_descriptor->pps_info.vc1.refdist_flag = v->refdist_flag; ++ pic_descriptor->pps_info.vc1.loopfilter = s->loop_filter; ++ pic_descriptor->pps_info.vc1.fastuvmc = v->fastuvmc; ++ pic_descriptor->pps_info.vc1.extended_mv = v->extended_mv; ++ pic_descriptor->pps_info.vc1.dquant = v->dquant; ++ pic_descriptor->pps_info.vc1.vstransform = v->vstransform; ++ pic_descriptor->pps_info.vc1.overlap = v->overlap; ++ pic_descriptor->pps_info.vc1.quantizer = v->quantizer_mode; ++ pic_descriptor->pps_info.vc1.extended_dmv = v->extended_dmv; ++ pic_descriptor->pps_info.vc1.maxbframes = s->avctx->max_b_frames; ++ pic_descriptor->pps_info.vc1.rangered = (pic_descriptor->profile == PROFILE_SIMPLE) ? 0 : v->rangered; ++ pic_descriptor->pps_info.vc1.syncmarker = (pic_descriptor->profile == PROFILE_SIMPLE) ? 0 : s->resync_marker; ++ pic_descriptor->pps_info.vc1.multires = v->multires; ++ pic_descriptor->pps_info.vc1.reserved = 1; ++ pic_descriptor->pps_info.vc1.range_mapy_flag = v->range_mapy_flag; ++ pic_descriptor->pps_info.vc1.range_mapy = v->range_mapy; ++ pic_descriptor->pps_info.vc1.range_mapuv_flag = v->range_mapuv_flag; ++ pic_descriptor->pps_info.vc1.range_mapuv = v->range_mapuv; ++ pic_descriptor->pps_info.vc1.xvba_vc1_pps_reserved = 0; ++ ++ pic_descriptor->past_surface = 0; ++ pic_descriptor->future_surface = 0; ++ switch (s->pict_type) { ++ case FF_B_TYPE: ++ next = (struct xvba_render_state *)s->next_picture.data[0]; ++ assert(next); ++ if (next) ++ pic_descriptor->past_surface = next->surface; ++ // fall-through ++ case FF_P_TYPE: ++ last = (struct xvba_render_state *)s->last_picture.data[0]; ++ assert(last); ++ if (last) ++ pic_descriptor->future_surface = last->surface; ++ break; ++ } ++ ++ ff_draw_horiz_band(s, 0, s->avctx->height); ++ ++ return 0; ++} ++ ++static int decode_slice(AVCodecContext *avctx, const uint8_t *buffer, uint32_t size) ++{ ++ VC1Context* const v = avctx->priv_data; ++ MpegEncContext* const s = &v->s; ++ struct xvba_render_state *render; ++ ++ render = (struct xvba_render_state *)s->current_picture_ptr->data[0]; ++ assert(render); ++ ++ if (avctx->codec_id == CODEC_ID_VC1 && ++ size >= 4 && IS_MARKER(AV_RB32(buffer))) { ++ buffer += 4; ++ size -= 4; ++ } ++ ++ ff_xvba_add_slice_data(render, buffer, size); ++ ++ return 0; ++} ++ ++#if CONFIG_WMV3_XVBA_HWACCEL ++AVHWAccel ff_wmv3_xvba_hwaccel = { ++ .name = "wmv3_xvba", ++ .type = AVMEDIA_TYPE_VIDEO, ++ .id = CODEC_ID_WMV3, ++ .pix_fmt = PIX_FMT_XVBA_VLD, ++ .capabilities = 0, ++ .start_frame = start_frame, ++ .end_frame = end_frame, ++ .decode_slice = decode_slice, ++ .priv_data_size = 0, ++}; ++#endif ++ ++AVHWAccel ff_vc1_xvba_hwaccel = { ++ .name = "vc1_xvba", ++ .type = AVMEDIA_TYPE_VIDEO, ++ .id = CODEC_ID_VC1, ++ .pix_fmt = PIX_FMT_XVBA_VLD, ++ .capabilities = 0, ++ .start_frame = start_frame, ++ .end_frame = end_frame, ++ .decode_slice = decode_slice, ++ .priv_data_size = 0, ++}; +diff -Naur xbmc-11.0.1/lib/ffmpeg/libavcodec/xvmc_internal.h xbmc-11.0.1.patch/lib/ffmpeg/libavcodec/xvmc_internal.h +--- xbmc-11.0.1/lib/ffmpeg/libavcodec/xvmc_internal.h 2012-03-21 23:57:47.000000000 +0100 ++++ xbmc-11.0.1.patch/lib/ffmpeg/libavcodec/xvmc_internal.h 2012-05-13 22:08:46.938192726 +0200 +@@ -1,5 +1,7 @@ + /* +- * XVideo Motion Compensation internal functions ++ * HW decode acceleration for MPEG-2, H.264 and VC-1 ++ * ++ * Copyright (C) 2005-2011 Team XBMC + * + * This file is part of FFmpeg. + * +diff -Naur xbmc-11.0.1/lib/ffmpeg/libavutil/pixdesc.c xbmc-11.0.1.patch/lib/ffmpeg/libavutil/pixdesc.c +--- xbmc-11.0.1/lib/ffmpeg/libavutil/pixdesc.c 2012-03-21 23:57:44.000000000 +0100 ++++ xbmc-11.0.1.patch/lib/ffmpeg/libavutil/pixdesc.c 2012-05-13 22:08:46.939192746 +0200 +@@ -717,6 +717,12 @@ + .log2_chroma_h = 1, + .flags = PIX_FMT_HWACCEL, + }, ++ [PIX_FMT_XVBA_VLD] = { ++ .name = "xvba_vld", ++ .log2_chroma_w = 1, ++ .log2_chroma_h = 1, ++ .flags = PIX_FMT_HWACCEL, ++ }, + [PIX_FMT_YUV420P16LE] = { + .name = "yuv420p16le", + .nb_components= 3, +diff -Naur xbmc-11.0.1/lib/ffmpeg/libavutil/pixfmt.h xbmc-11.0.1.patch/lib/ffmpeg/libavutil/pixfmt.h +--- xbmc-11.0.1/lib/ffmpeg/libavutil/pixfmt.h 2012-03-21 23:57:44.000000000 +0100 ++++ xbmc-11.0.1.patch/lib/ffmpeg/libavutil/pixfmt.h 2012-05-13 22:08:46.939192746 +0200 +@@ -127,6 +127,7 @@ + PIX_FMT_YUV444P16BE, ///< planar YUV 4:4:4, 48bpp, (1 Cr & Cb sample per 1x1 Y samples), big-endian + PIX_FMT_VDPAU_MPEG4, ///< MPEG4 HW decoding with VDPAU, data[0] contains a vdpau_render_state struct which contains the bitstream of the slices as well as various fields extracted from headers + PIX_FMT_DXVA2_VLD, ///< HW decoding through DXVA2, Picture.data[3] contains a LPDIRECT3DSURFACE9 pointer ++ PIX_FMT_XVBA_VLD, ///< HW decoding through DXVA2, Picture.data[3] contains a vaapi_render_state struct which contains the bitstream of the slices as well as various fields extracted from headers + + PIX_FMT_RGB444BE, ///< packed RGB 4:4:4, 16bpp, (msb)4A 4R 4G 4B(lsb), big-endian, most significant bits to 0 + PIX_FMT_RGB444LE, ///< packed RGB 4:4:4, 16bpp, (msb)4A 4R 4G 4B(lsb), little-endian, most significant bits to 0 +diff -Naur xbmc-11.0.1/lib/UnrarXLib/extract.cpp xbmc-11.0.1.patch/lib/UnrarXLib/extract.cpp +--- xbmc-11.0.1/lib/UnrarXLib/extract.cpp 2012-03-21 23:57:35.000000000 +0100 ++++ xbmc-11.0.1.patch/lib/UnrarXLib/extract.cpp 2012-05-13 22:08:46.773189450 +0200 +@@ -1,9 +1,5 @@ + #include "rar.hpp" + #include "Util.h" +-#ifdef _LINUX +-#include "XSyncUtils.h" +-#include "XEventUtils.h" +-#endif + + // a cautious wrapper around strncpy + char *strncpy_null_terminated(char *dest, const char *src, size_t n) +diff -Naur xbmc-11.0.1/lib/UnrarXLib/unpack15.cpp xbmc-11.0.1.patch/lib/UnrarXLib/unpack15.cpp +--- xbmc-11.0.1/lib/UnrarXLib/unpack15.cpp 2012-03-21 23:57:35.000000000 +0100 ++++ xbmc-11.0.1.patch/lib/UnrarXLib/unpack15.cpp 2012-05-13 22:08:46.774189470 +0200 +@@ -1,7 +1,3 @@ +-#ifdef _LINUX +-#include "XSyncUtils.h" +-#endif +- + #define STARTL1 2 + static unsigned int DecL1[]={0x8000,0xa000,0xc000,0xd000,0xe000,0xea00, + 0xee00,0xf000,0xf200,0xf200,0xffff}; +diff -Naur xbmc-11.0.1/lib/UnrarXLib/unpack.cpp xbmc-11.0.1.patch/lib/UnrarXLib/unpack.cpp +--- xbmc-11.0.1/lib/UnrarXLib/unpack.cpp 2012-03-21 23:57:35.000000000 +0100 ++++ xbmc-11.0.1.patch/lib/UnrarXLib/unpack.cpp 2012-05-13 22:08:46.774189470 +0200 +@@ -8,11 +8,6 @@ + #include "unpack20.cpp" + #endif + +-#ifdef _LINUX +-#include "XSyncUtils.h" +-#include "XEventUtils.h" +-#endif +- + Unpack::Unpack(ComprDataIO *DataIO) + { + UnpIO=DataIO; +diff -Naur xbmc-11.0.1/system/shaders/yuv2rgb_basic.glsl xbmc-11.0.1.patch/system/shaders/yuv2rgb_basic.glsl +--- xbmc-11.0.1/system/shaders/yuv2rgb_basic.glsl 2012-03-21 23:57:58.000000000 +0100 ++++ xbmc-11.0.1.patch/system/shaders/yuv2rgb_basic.glsl 2012-05-13 22:01:28.506492824 +0200 +@@ -70,6 +70,18 @@ + rgb.a = gl_Color.a; + gl_FragColor = rgb; + ++#elif defined(XBMC_VDPAU_NV12) ++ ++ vec4 yuv, rgb; ++ yuv.rgba = vec4( texture2D(m_sampY, stretch(m_cordY)).r ++ , texture2D(m_sampU, stretch(m_cordU)).r ++ , texture2D(m_sampV, stretch(m_cordV)).g ++ , 1.0 ); ++ ++ rgb = m_yuvmat * yuv; ++ rgb.a = gl_Color.a; ++ gl_FragColor = rgb; ++ + #elif defined(XBMC_YUY2) || defined(XBMC_UYVY) + + #if(XBMC_texture_rectangle) +diff -Naur xbmc-11.0.1/xbmc/Application.cpp xbmc-11.0.1.patch/xbmc/Application.cpp +--- xbmc-11.0.1/xbmc/Application.cpp 2012-03-21 23:57:32.000000000 +0100 ++++ xbmc-11.0.1.patch/xbmc/Application.cpp 2012-05-13 22:08:46.751189015 +0200 +@@ -369,8 +369,6 @@ + #endif + m_currentStack = new CFileItemList; + +- m_frameCount = 0; +- + m_bPresentFrame = false; + m_bPlatformDirectories = true; + +@@ -1965,28 +1963,18 @@ + + bool CApplication::WaitFrame(unsigned int timeout) + { +- bool done = false; +- + // Wait for all other frames to be presented +- CSingleLock lock(m_frameMutex); +- //wait until event is set, but modify remaining time ++ m_frameEvent.Reset(); + +- TightConditionVariable > cv(m_frameCond, InversePredicate(m_frameCount)); +- cv.wait(lock,timeout); +- done = m_frameCount == 0; ++ if (!g_renderManager.HasFrame() && !m_frameEvent.WaitMSec(timeout)) ++ return false; + +- return done; ++ return g_renderManager.HasFrame(); + } + + void CApplication::NewFrame() + { +- // We just posted another frame. Keep track and notify. +- { +- CSingleLock lock(m_frameMutex); +- m_frameCount++; +- } +- +- m_frameCond.notifyAll(); ++ m_frameEvent.Set(); + } + + void CApplication::Render() +@@ -2020,12 +2008,13 @@ + m_bPresentFrame = false; + if (!extPlayerActive && g_graphicsContext.IsFullScreenVideo() && !IsPaused()) + { +- CSingleLock lock(m_frameMutex); +- +- TightConditionVariable cv(m_frameCond,m_frameCount); +- cv.wait(lock,100); ++ uint64_t timeout = CurrentHostCounter() + CurrentHostFrequency()/10; ++ while (!g_renderManager.HasFrame() && CurrentHostCounter() < timeout) ++ { ++ m_frameEvent.WaitMSec(100); ++ } ++ m_bPresentFrame = g_renderManager.HasFrame(); + +- m_bPresentFrame = m_frameCount > 0; + decrement = m_bPresentFrame; + hasRendered = true; + } +@@ -2108,18 +2097,14 @@ + m_lastFrameTime = XbmcThreads::SystemClockMillis(); + + if (flip) ++ { + g_graphicsContext.Flip(dirtyRegions); ++ g_renderManager.NotifyDisplayFlip(); ++ } + CTimeUtils::UpdateFrameTime(flip); + + g_renderManager.UpdateResolution(); + g_renderManager.ManageCaptures(); +- +- { +- CSingleLock lock(m_frameMutex); +- if(m_frameCount > 0 && decrement) +- m_frameCount--; +- } +- m_frameCond.notifyAll(); + } + + void CApplication::SetStandAlone(bool value) +@@ -5303,12 +5288,6 @@ + // See if we're playing a video, and are in GUI mode + if ( IsPlayingVideo() && g_windowManager.GetActiveWindow() != WINDOW_FULLSCREEN_VIDEO) + { +- // Reset frame count so that timing is FPS will be correct. +- { +- CSingleLock lock(m_frameMutex); +- m_frameCount = 0; +- } +- + // then switch to fullscreen mode + g_windowManager.ActivateWindow(WINDOW_FULLSCREEN_VIDEO); + return true; +@@ -5479,7 +5458,6 @@ + + bool CApplication::IsPresentFrame() + { +- CSingleLock lock(m_frameMutex); + bool ret = m_bPresentFrame; + + return ret; +diff -Naur xbmc-11.0.1/xbmc/Application.h xbmc-11.0.1.patch/xbmc/Application.h +--- xbmc-11.0.1/xbmc/Application.h 2012-03-21 23:57:35.000000000 +0100 ++++ xbmc-11.0.1.patch/xbmc/Application.h 2012-05-13 22:08:46.752189035 +0200 +@@ -343,9 +343,7 @@ + bool m_bTestMode; + bool m_bSystemScreenSaverEnable; + +- int m_frameCount; +- CCriticalSection m_frameMutex; +- XbmcThreads::ConditionVariable m_frameCond; ++ CEvent m_frameEvent; + + void Mute(); + void UnMute(); +diff -Naur xbmc-11.0.1/xbmc/ApplicationMessenger.cpp xbmc-11.0.1.patch/xbmc/ApplicationMessenger.cpp +--- xbmc-11.0.1/xbmc/ApplicationMessenger.cpp 2012-03-21 23:57:32.000000000 +0100 ++++ xbmc-11.0.1.patch/xbmc/ApplicationMessenger.cpp 2012-05-13 22:08:46.776189511 +0200 +@@ -73,7 +73,7 @@ + + using namespace std; + +-CDelayedMessage::CDelayedMessage(ThreadMessage& msg, unsigned int delay) ++CDelayedMessage::CDelayedMessage(ThreadMessage& msg, unsigned int delay) : CThread("CDelayedMessage") + { + m_msg.dwMessage = msg.dwMessage; + m_msg.dwParam1 = msg.dwParam1; +diff -Naur xbmc-11.0.1/xbmc/cdrip/CDDAReader.cpp xbmc-11.0.1.patch/xbmc/cdrip/CDDAReader.cpp +--- xbmc-11.0.1/xbmc/cdrip/CDDAReader.cpp 2012-03-21 23:57:32.000000000 +0100 ++++ xbmc-11.0.1.patch/xbmc/cdrip/CDDAReader.cpp 2012-05-13 22:08:46.776189511 +0200 +@@ -29,7 +29,7 @@ + + #define SECTOR_COUNT 52 + +-CCDDAReader::CCDDAReader() ++CCDDAReader::CCDDAReader() : CThread("CCDDAReader") + { + m_sRipBuffer[0].pbtStream = NULL; + m_sRipBuffer[1].pbtStream = NULL; +diff -Naur xbmc-11.0.1/xbmc/cores/DllLoader/exports/emu_kernel32.cpp xbmc-11.0.1.patch/xbmc/cores/DllLoader/exports/emu_kernel32.cpp +--- xbmc-11.0.1/xbmc/cores/DllLoader/exports/emu_kernel32.cpp 2012-03-21 23:57:35.000000000 +0100 ++++ xbmc-11.0.1.patch/xbmc/cores/DllLoader/exports/emu_kernel32.cpp 2012-05-13 22:08:46.777189531 +0200 +@@ -240,15 +240,6 @@ + #endif + } + +-extern "C" BOOL WINAPI dllGetProcessTimes(HANDLE hProcess, LPFILETIME lpCreationTime, LPFILETIME lpExitTime, LPFILETIME lpKernelTime, LPFILETIME lpUserTime) +-{ +- // since the xbox has only one process, we just take the current thread +- HANDLE h = GetCurrentThread(); +- BOOL res = GetThreadTimes(h, lpCreationTime, lpExitTime, lpKernelTime, lpUserTime); +- +- return res; +-} +- + extern "C" int WINAPI dllDuplicateHandle(HANDLE hSourceProcessHandle, // handle to source process + HANDLE hSourceHandle, // handle to duplicate + HANDLE hTargetProcessHandle, // handle to target process +diff -Naur xbmc-11.0.1/xbmc/cores/DllLoader/exports/emu_kernel32.h xbmc-11.0.1.patch/xbmc/cores/DllLoader/exports/emu_kernel32.h +--- xbmc-11.0.1/xbmc/cores/DllLoader/exports/emu_kernel32.h 2012-03-21 23:57:35.000000000 +0100 ++++ xbmc-11.0.1.patch/xbmc/cores/DllLoader/exports/emu_kernel32.h 2012-05-13 22:08:46.778189551 +0200 +@@ -686,7 +686,6 @@ + + extern "C" HGLOBAL WINAPI dllLoadResource(HMODULE module, HRSRC res); + extern "C" HRSRC WINAPI dllFindResourceA(HMODULE module, LPCTSTR name, LPCTSTR type); +-extern "C" BOOL WINAPI dllGetProcessTimes(HANDLE hProcess, LPFILETIME lpCreationTime, LPFILETIME lpExitTime, LPFILETIME lpKernelTime, LPFILETIME lpUserTime); + extern "C" int WINAPI dllGetLocaleInfoA(LCID Locale, LCTYPE LCType, LPTSTR lpLCData, int cchData); + extern "C" UINT WINAPI dllGetConsoleCP(); + extern "C" UINT WINAPI dllGetConsoleOutputCP(); +diff -Naur xbmc-11.0.1/xbmc/cores/DummyVideoPlayer.cpp xbmc-11.0.1.patch/xbmc/cores/DummyVideoPlayer.cpp +--- xbmc-11.0.1/xbmc/cores/DummyVideoPlayer.cpp 2012-03-21 23:57:34.000000000 +0100 ++++ xbmc-11.0.1.patch/xbmc/cores/DummyVideoPlayer.cpp 2012-05-13 22:08:46.778189551 +0200 +@@ -33,7 +33,7 @@ + + CDummyVideoPlayer::CDummyVideoPlayer(IPlayerCallback& callback) + : IPlayer(callback), +- CThread() ++ CThread("CDummyVideoPlayer") + { + m_paused = false; + m_clock = 0; +diff -Naur xbmc-11.0.1/xbmc/cores/dvdplayer/DVDCodecs/Video/CrystalHD.cpp xbmc-11.0.1.patch/xbmc/cores/dvdplayer/DVDCodecs/Video/CrystalHD.cpp +--- xbmc-11.0.1/xbmc/cores/dvdplayer/DVDCodecs/Video/CrystalHD.cpp 2012-03-21 23:57:34.000000000 +0100 ++++ xbmc-11.0.1.patch/xbmc/cores/dvdplayer/DVDCodecs/Video/CrystalHD.cpp 2012-05-13 22:08:46.780189591 +0200 +@@ -325,7 +325,7 @@ + #pragma mark - + #endif + CMPCOutputThread::CMPCOutputThread(void *device, DllLibCrystalHD *dll, bool has_bcm70015) : +- CThread(), ++ CThread("CMPCOutputThread"), + m_dll(dll), + m_device(device), + m_has_bcm70015(has_bcm70015), +diff -Naur xbmc-11.0.1/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp xbmc-11.0.1.patch/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp +--- xbmc-11.0.1/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp 2012-03-21 23:57:34.000000000 +0100 ++++ xbmc-11.0.1.patch/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp 2012-05-13 22:08:46.978193519 +0200 +@@ -56,6 +56,9 @@ + #ifdef HAVE_LIBVA + #include "VAAPI.h" + #endif ++#ifdef HAVE_LIBXVBA ++#include "XVBA.h" ++#endif + + using namespace boost; + +@@ -71,14 +74,14 @@ + while(*cur != PIX_FMT_NONE) + { + #ifdef HAVE_LIBVDPAU +- if(CVDPAU::IsVDPAUFormat(*cur) && g_guiSettings.GetBool("videoplayer.usevdpau")) ++ if(VDPAU::CDecoder::IsVDPAUFormat(*cur) && g_guiSettings.GetBool("videoplayer.usevdpau")) + { + if(ctx->GetHardware()) + return *cur; + + CLog::Log(LOGNOTICE,"CDVDVideoCodecFFmpeg::GetFormat - Creating VDPAU(%ix%i)", avctx->width, avctx->height); +- CVDPAU* vdp = new CVDPAU(); +- if(vdp->Open(avctx, *cur)) ++ VDPAU::CDecoder* vdp = new VDPAU::CDecoder(); ++ if(vdp->Open(avctx, *cur, ctx->m_uSurfacesCount)) + { + ctx->SetHardware(vdp); + return *cur; +@@ -100,6 +103,19 @@ + dec->Release(); + } + #endif ++#ifdef HAVE_LIBXVBA ++ if(*cur == PIX_FMT_XVBA_VLD && g_guiSettings.GetBool("videoplayer.usexvba")) ++ { ++ XVBA::CDecoder* dec = new XVBA::CDecoder(); ++ if(dec->Open(avctx, *cur)) ++ { ++ ctx->SetHardware(dec); ++ return *cur; ++ } ++ else ++ dec->Release(); ++ } ++#endif + #ifdef HAVE_LIBVA + // mpeg4 vaapi decoding is disabled + if(*cur == PIX_FMT_VAAPI_VLD && g_guiSettings.GetBool("videoplayer.usevaapi") +@@ -142,6 +158,7 @@ + m_iLastKeyframe = 0; + m_dts = DVD_NOPTS_VALUE; + m_started = false; ++ m_decoderPts = DVD_NOPTS_VALUE; + } + + CDVDVideoCodecFFmpeg::~CDVDVideoCodecFFmpeg() +@@ -195,13 +212,25 @@ + continue; + + CLog::Log(LOGNOTICE,"CDVDVideoCodecFFmpeg::Open() Creating VDPAU(%ix%i, %d)",hints.width, hints.height, hints.codec); +- CVDPAU* vdp = new CVDPAU(); ++ VDPAU::CDecoder* vdp = new VDPAU::CDecoder(); + m_pCodecContext->codec_id = hints.codec; + m_pCodecContext->width = hints.width; + m_pCodecContext->height = hints.height; + m_pCodecContext->coded_width = hints.width; + m_pCodecContext->coded_height = hints.height; +- if(vdp->Open(m_pCodecContext, pCodec->pix_fmts ? pCodec->pix_fmts[0] : PIX_FMT_NONE)) ++ ++ // check number of surfaces used in renderer ++ unsigned int surfaces = 0; ++ for(CDVDCodecOptions::iterator it = options.begin(); it != options.end(); it++) ++ { ++ if (it->m_name == "surfaces") ++ { ++ surfaces = std::atoi(it->m_value.c_str()); ++ break; ++ } ++ } ++ ++ if(vdp->Open(m_pCodecContext, pCodec->pix_fmts ? pCodec->pix_fmts[0] : PIX_FMT_NONE, surfaces)) + { + m_pHardware = vdp; + m_pCodecContext->codec_id = CODEC_ID_NONE; // ffmpeg will complain if this has been set +@@ -338,6 +367,14 @@ + { + if( m_pCodecContext ) + { ++ if (bDrop && m_pHardware && m_pHardware->CanSkipDeint()) ++ { ++ m_requestSkipDeint = true; ++ bDrop = false; ++ } ++ else ++ m_requestSkipDeint = false; ++ + // i don't know exactly how high this should be set + // couldn't find any good docs on it. think it varies + // from codec to codec on what it does +@@ -558,6 +595,7 @@ + void CDVDVideoCodecFFmpeg::Reset() + { + m_started = false; ++ m_decoderPts = DVD_NOPTS_VALUE; + m_iLastKeyframe = m_pCodecContext->has_b_frames; + m_dllAvCodec.avcodec_flush_buffers(m_pCodecContext); + +@@ -663,6 +701,22 @@ + else + pDvdVideoPicture->pts = DVD_NOPTS_VALUE; + ++ if (pDvdVideoPicture->pts != DVD_NOPTS_VALUE) ++ m_decoderPts = pDvdVideoPicture->pts; ++ else ++ m_decoderPts = m_dts; ++ ++ if (m_requestSkipDeint) ++ { ++ pDvdVideoPicture->iFlags |= DVP_FLAG_DROPDEINT; ++ m_skippedDeint = 1; ++ } ++ else ++ m_skippedDeint = 0; ++ ++ m_requestSkipDeint = false; ++ pDvdVideoPicture->iFlags |= m_codecControlState; ++ + if(!m_started) + pDvdVideoPicture->iFlags |= DVP_FLAG_DROPPED; + +@@ -883,3 +937,14 @@ + else + return 0; + } ++ ++void CDVDVideoCodecFFmpeg::SetSpeed(int speed) ++{ ++ if (m_pHardware) ++ m_pHardware->SetSpeed(speed); ++} ++ ++void CDVDVideoCodecFFmpeg::SetCodecControl(int state) ++{ ++ m_codecControlState = state; ++} +diff -Naur xbmc-11.0.1/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.h xbmc-11.0.1.patch/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.h +--- xbmc-11.0.1/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.h 2012-03-21 23:57:34.000000000 +0100 ++++ xbmc-11.0.1.patch/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.h 2012-05-13 22:08:46.989193738 +0200 +@@ -29,7 +29,6 @@ + #include "DllSwScale.h" + #include "DllAvFilter.h" + +-class CVDPAU; + class CCriticalSection; + + class CDVDVideoCodecFFmpeg : public CDVDVideoCodec +@@ -45,6 +44,8 @@ + virtual bool GetPicture(AVCodecContext* avctx, AVFrame* frame, DVDVideoPicture* picture) = 0; + virtual int Check (AVCodecContext* avctx) = 0; + virtual void Reset () {} ++ virtual bool CanSkipDeint() {return false; } ++ virtual void SetSpeed(int speed) {} + virtual const std::string Name() = 0; + virtual CCriticalSection* Section() { return NULL; } + }; +@@ -61,6 +62,9 @@ + virtual unsigned int SetFilters(unsigned int filters); + virtual const char* GetName() { return m_name.c_str(); }; // m_name is never changed after open + virtual unsigned GetConvergeCount(); ++ virtual bool GetPts(double &pts, int &skippedDeint, int &interlaced) {pts=m_decoderPts; skippedDeint=m_skippedDeint; if (m_pFrame) interlaced = m_pFrame->interlaced_frame; return true;} ++ virtual void SetSpeed(int speed); ++ virtual void SetCodecControl(int state); + + bool IsHardwareAllowed() { return !m_bSoftware; } + IHardwareDecoder * GetHardware() { return m_pHardware; }; +@@ -109,4 +113,8 @@ + int m_iLastKeyframe; + double m_dts; + bool m_started; ++ double m_decoderPts, m_decoderInterval; ++ int m_skippedDeint; ++ bool m_requestSkipDeint; ++ int m_codecControlState; + }; +diff -Naur xbmc-11.0.1/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodec.h xbmc-11.0.1.patch/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodec.h +--- xbmc-11.0.1/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodec.h 2012-03-21 23:57:34.000000000 +0100 ++++ xbmc-11.0.1.patch/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodec.h 2012-05-13 22:08:46.989193738 +0200 +@@ -34,7 +34,8 @@ + + namespace DXVA { class CSurfaceContext; } + namespace VAAPI { struct CHolder; } +-class CVDPAU; ++namespace VDPAU { class CVdpauRenderPicture; } ++namespace XVBA { class CXvbaRenderPicture; } + class COpenMax; + class COpenMaxVideo; + struct OpenMaxVideoBuffer; +@@ -59,11 +60,14 @@ + DXVA::CSurfaceContext* context; + }; + struct { +- CVDPAU* vdpau; ++ VDPAU::CVdpauRenderPicture* vdpau; + }; + struct { + VAAPI::CHolder* vaapi; + }; ++ struct { ++ XVBA::CXvbaRenderPicture* xvba; ++ }; + + struct { + COpenMax *openMax; +@@ -102,6 +106,7 @@ + enum EFormat { + FMT_YUV420P = 0, + FMT_VDPAU, ++ FMT_VDPAU_420, + FMT_NV12, + FMT_UYVY, + FMT_YUY2, +@@ -109,6 +114,7 @@ + FMT_VAAPI, + FMT_OMXEGL, + FMT_CVBREF, ++ FMT_XVBA, + } format; + }; + +@@ -125,6 +131,10 @@ + + #define DVP_FLAG_NOSKIP 0x00000010 // indicate this picture should never be dropped + #define DVP_FLAG_DROPPED 0x00000020 // indicate that this picture has been dropped in decoder stage, will have no data ++#define DVP_FLAG_DROPDEINT 0x00000040 // indicate that this picture was requested to have been dropped in deint stage ++ ++#define DVP_FLAG_SKIP_PROC 0x00000100 ++#define DVP_FLAG_DRAIN 0x00000200 + + // DVP_FLAG 0x00000100 - 0x00000f00 is in use by libmpeg2! + +@@ -143,6 +153,10 @@ + #define VC_PICTURE 0x00000004 // the decoder got a picture, call Decode(NULL, 0) again to parse the rest of the data + #define VC_USERDATA 0x00000008 // the decoder found some userdata, call Decode(NULL, 0) again to parse the rest of the data + #define VC_FLUSHED 0x00000010 // the decoder lost it's state, we need to restart decoding again ++#define VC_DROPPED 0x00000020 // needed to identify if a picture was dropped ++#define VC_HURRY 0x00000040 ++#define VC_SKIPPROC 0x00000080 ++ + class CDVDVideoCodec + { + public: +@@ -207,7 +221,6 @@ + */ + virtual void SetDropState(bool bDrop) = 0; + +- + enum EFilterFlags { + FILTER_NONE = 0x0, + FILTER_DEINTERLACE_YADIF = 0x1, /* use first deinterlace mode */ +@@ -237,4 +250,16 @@ + { + return 0; + } ++ ++ virtual bool GetPts(double &pts, int &skippedDeint, int &interlaced) ++ { ++ return false; ++ } ++ ++ virtual void SetSpeed(int speed) ++ { ++ return; ++ } ++ ++ virtual void SetCodecControl(int state) {} + }; +diff -Naur xbmc-11.0.1/xbmc/cores/dvdplayer/DVDCodecs/Video/Makefile.in xbmc-11.0.1.patch/xbmc/cores/dvdplayer/DVDCodecs/Video/Makefile.in +--- xbmc-11.0.1/xbmc/cores/dvdplayer/DVDCodecs/Video/Makefile.in 2012-03-21 23:57:34.000000000 +0100 ++++ xbmc-11.0.1.patch/xbmc/cores/dvdplayer/DVDCodecs/Video/Makefile.in 2012-05-13 22:08:46.950192964 +0200 +@@ -17,6 +17,10 @@ + DVDVideoCodecCrystalHD.cpp \ + + endif ++ifeq (@USE_XVBA@,1) ++SRCS+= XVBA.cpp \ ++ ++endif + ifeq (@USE_VDA@,1) + SRCS+= DVDVideoCodecVDA.cpp \ + +diff -Naur xbmc-11.0.1/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp xbmc-11.0.1.patch/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp +--- xbmc-11.0.1/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp 2012-03-21 23:57:34.000000000 +0100 ++++ xbmc-11.0.1.patch/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp 2012-05-13 22:08:47.058195107 +0200 +@@ -1,5 +1,5 @@ + /* +- * Copyright (C) 2005-2009 Team XBMC ++ * Copyright (C) 2005-2011 Team XBMC + * http://www.xbmc.org + * + * This Program is free software; you can redistribute it and/or modify +@@ -33,11 +33,16 @@ + #include "settings/AdvancedSettings.h" + #include "Application.h" + #include "utils/MathUtils.h" ++#include "utils/TimeUtils.h" + #include "DVDCodecs/DVDCodecUtils.h" ++#include "cores/VideoRenderers/RenderFlags.h" ++ ++using namespace VDPAU; ++#define NUM_RENDER_PICS 9 + + #define ARSIZE(x) (sizeof(x) / sizeof((x)[0])) + +-CVDPAU::Desc decoder_profiles[] = { ++CDecoder::Desc decoder_profiles[] = { + {"MPEG1", VDP_DECODER_PROFILE_MPEG1}, + {"MPEG2_SIMPLE", VDP_DECODER_PROFILE_MPEG2_SIMPLE}, + {"MPEG2_MAIN", VDP_DECODER_PROFILE_MPEG2_MAIN}, +@@ -51,14 +56,16 @@ + {"MPEG4_PART2_ASP", VDP_DECODER_PROFILE_MPEG4_PART2_ASP}, + #endif + }; +-const size_t decoder_profile_count = sizeof(decoder_profiles)/sizeof(CVDPAU::Desc); ++const size_t decoder_profile_count = sizeof(decoder_profiles)/sizeof(CDecoder::Desc); + +-static float studioCSC[3][4] = +-{ +- { 1.0f, 0.0f, 1.57480000f,-0.78740000f}, +- { 1.0f,-0.18737736f,-0.46813736f, 0.32775736f}, +- { 1.0f, 1.85556000f, 0.0f,-0.92780000f} +-}; ++//static float studioCSC[3][4] = ++//{ ++// { 1.0f, 0.0f, 1.57480000f,-0.78740000f}, ++// { 1.0f,-0.18737736f,-0.46813736f, 0.32775736f}, ++// { 1.0f, 1.85556000f, 0.0f,-0.92780000f} ++//}; ++static float studioCSCKCoeffs601[3] = {0.299, 0.587, 0.114}; //BT601 {Kr, Kg, Kb} ++static float studioCSCKCoeffs709[3] = {0.2126, 0.7152, 0.0722}; //BT709 {Kr, Kg, Kb} + + static struct SInterlaceMapping + { +@@ -69,59 +76,32 @@ + , {VS_INTERLACEMETHOD_VDPAU_TEMPORAL_HALF , VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL} + , {VS_INTERLACEMETHOD_VDPAU_TEMPORAL_SPATIAL , VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL_SPATIAL} + , {VS_INTERLACEMETHOD_VDPAU_TEMPORAL_SPATIAL_HALF, VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL_SPATIAL} +-, {VS_INTERLACEMETHOD_VDPAU_INVERSE_TELECINE , VDP_VIDEO_MIXER_FEATURE_INVERSE_TELECINE} ++, {VS_INTERLACEMETHOD_VDPAU_INVERSE_TELECINE , VDP_VIDEO_MIXER_FEATURE_INVERSE_TELECINE} + , {VS_INTERLACEMETHOD_NONE , (VdpVideoMixerFeature)-1} + }; + + //since libvdpau 0.4, vdp_device_create_x11() installs a callback on the Display*, + //if we unload libvdpau with dlclose(), we segfault on XCloseDisplay, + //so we just keep a static handle to libvdpau around +-void* CVDPAU::dl_handle; +- +-CVDPAU::CVDPAU() +-{ +- glXBindTexImageEXT = NULL; +- glXReleaseTexImageEXT = NULL; +- vdp_device = VDP_INVALID_HANDLE; +- surfaceNum = presentSurfaceNum = 0; +- picAge.b_age = picAge.ip_age[0] = picAge.ip_age[1] = 256*256*256*64; +- vdpauConfigured = false; +- m_DisplayState = VDPAU_OPEN; +- m_mixerfield = VDP_VIDEO_MIXER_PICTURE_STRUCTURE_FRAME; +- m_mixerstep = 0; ++void* CDecoder::dl_handle; + +- m_glPixmap = 0; +- m_Pixmap = 0; +- if (!glXBindTexImageEXT) +- glXBindTexImageEXT = (PFNGLXBINDTEXIMAGEEXTPROC)glXGetProcAddress((GLubyte *) "glXBindTexImageEXT"); +- if (!glXReleaseTexImageEXT) +- glXReleaseTexImageEXT = (PFNGLXRELEASETEXIMAGEEXTPROC)glXGetProcAddress((GLubyte *) "glXReleaseTexImageEXT"); +- +- totalAvailableOutputSurfaces = 0; +- outputSurface = presentSurface = VDP_INVALID_HANDLE; +- vdp_flip_target = VDP_INVALID_HANDLE; +- vdp_flip_queue = VDP_INVALID_HANDLE; +- vid_width = vid_height = OutWidth = OutHeight = 0; +- memset(&outRect, 0, sizeof(VdpRect)); +- memset(&outRectVid, 0, sizeof(VdpRect)); +- +- tmpBrightness = 0; +- tmpContrast = 0; +- tmpDeintMode = 0; +- tmpDeintGUI = 0; +- tmpDeint = 0; +- max_references = 0; +- +- for (int i = 0; i < NUM_OUTPUT_SURFACES; i++) +- outputSurfaces[i] = VDP_INVALID_HANDLE; ++//----------------------------------------------------------------------------- ++// CVDPAU ++//----------------------------------------------------------------------------- + +- videoMixer = VDP_INVALID_HANDLE; +- m_BlackBar = NULL; ++CDecoder::CDecoder() : m_vdpauOutput(&m_inMsgEvent) ++{ ++ m_vdpauConfig.vdpDevice = VDP_INVALID_HANDLE; ++ m_vdpauConfig.videoSurfaces = &m_videoSurfaces; ++ m_vdpauConfig.videoSurfaceSec = &m_videoSurfaceSec; + +- upScale = g_advancedSettings.m_videoVDPAUScaling; ++ m_picAge.b_age = m_picAge.ip_age[0] = m_picAge.ip_age[1] = 256*256*256*64; ++ m_vdpauConfigured = false; ++ m_DisplayState = VDPAU_OPEN; ++ m_speed = DVD_PLAYSPEED_NORMAL; + } + +-bool CVDPAU::Open(AVCodecContext* avctx, const enum PixelFormat, unsigned int surfaces) ++bool CDecoder::Open(AVCodecContext* avctx, const enum PixelFormat, unsigned int surfaces) + { + if(avctx->coded_width == 0 + || avctx->coded_height == 0) +@@ -129,6 +109,8 @@ + CLog::Log(LOGWARNING,"(VDPAU) no width/height available, can't init"); + return false; + } ++ m_vdpauConfig.numRenderBuffers = surfaces; ++ m_decoderThread = CThread::GetCurrentThreadId(); + + if (!dl_handle) + { +@@ -140,8 +122,6 @@ + error = "dlerror() returned NULL"; + + CLog::Log(LOGNOTICE,"(VDPAU) Unable to get handle to libvdpau: %s", error); +- //g_application.m_guiDialogKaiToast.QueueNotification(CGUIDialogKaiToast::Error, "VDPAU", error, 10000); +- + return false; + } + } +@@ -150,8 +130,9 @@ + return false; + + InitVDPAUProcs(); ++ m_presentPicture = 0; + +- if (vdp_device != VDP_INVALID_HANDLE) ++ if (m_vdpauConfig.vdpDevice != VDP_INVALID_HANDLE) + { + SpewHardwareAvailable(); + +@@ -169,25 +150,23 @@ + + /* attempt to create a decoder with this width/height, some sizes are not supported by hw */ + VdpStatus vdp_st; +- vdp_st = vdp_decoder_create(vdp_device, profile, avctx->coded_width, avctx->coded_height, 5, &decoder); ++ vdp_st = m_vdpauConfig.vdpProcs.vdp_decoder_create(m_vdpauConfig.vdpDevice, profile, avctx->coded_width, avctx->coded_height, 5, &m_vdpauConfig.vdpDecoder); + + if(vdp_st != VDP_STATUS_OK) + { +- CLog::Log(LOGERROR, " (VDPAU) Error: %s(%d) checking for decoder support\n", vdp_get_error_string(vdp_st), vdp_st); ++ CLog::Log(LOGERROR, " (VDPAU) Error: %s(%d) checking for decoder support\n", m_vdpauConfig.vdpProcs.vdp_get_error_string(vdp_st), vdp_st); + FiniVDPAUProcs(); + return false; + } + +- vdp_decoder_destroy(decoder); ++ m_vdpauConfig.vdpProcs.vdp_decoder_destroy(m_vdpauConfig.vdpDecoder); + CheckStatus(vdp_st, __LINE__); + } + +- InitCSCMatrix(avctx->coded_height); +- + /* finally setup ffmpeg */ +- avctx->get_buffer = CVDPAU::FFGetBuffer; +- avctx->release_buffer = CVDPAU::FFReleaseBuffer; +- avctx->draw_horiz_band = CVDPAU::FFDrawSlice; ++ avctx->get_buffer = CDecoder::FFGetBuffer; ++ avctx->release_buffer = CDecoder::FFReleaseBuffer; ++ avctx->draw_horiz_band = CDecoder::FFDrawSlice; + avctx->slice_flags=SLICE_FLAG_CODED_ORDER|SLICE_FLAG_ALLOW_FIELD; + + g_Windowing.Register(this); +@@ -196,17 +175,20 @@ + return false; + } + +-CVDPAU::~CVDPAU() ++CDecoder::~CDecoder() + { + Close(); + } + +-void CVDPAU::Close() ++void CDecoder::Close() + { + CLog::Log(LOGNOTICE, " (VDPAU) %s", __FUNCTION__); + ++ CSingleLock lock(m_DecoderSection); ++ + FiniVDPAUOutput(); + FiniVDPAUProcs(); ++ m_vdpauOutput.Dispose(); + + while (!m_videoSurfaces.empty()) + { +@@ -222,188 +204,118 @@ + m_dllAvUtil.Unload(); + } + +-bool CVDPAU::MakePixmapGL() ++long CDecoder::Release() + { +- int num=0; +- int fbConfigIndex = 0; +- +- int doubleVisAttributes[] = { +- GLX_RENDER_TYPE, GLX_RGBA_BIT, +- GLX_RED_SIZE, 8, +- GLX_GREEN_SIZE, 8, +- GLX_BLUE_SIZE, 8, +- GLX_ALPHA_SIZE, 8, +- GLX_DEPTH_SIZE, 8, +- GLX_DRAWABLE_TYPE, GLX_PIXMAP_BIT, +- GLX_BIND_TO_TEXTURE_RGBA_EXT, True, +- GLX_DOUBLEBUFFER, True, +- GLX_Y_INVERTED_EXT, True, +- GLX_X_RENDERABLE, True, +- None +- }; +- +- int pixmapAttribs[] = { +- GLX_TEXTURE_TARGET_EXT, GLX_TEXTURE_2D_EXT, +- GLX_TEXTURE_FORMAT_EXT, GLX_TEXTURE_FORMAT_RGBA_EXT, +- None +- }; ++ // check if we should do some pre-cleanup here ++ // a second decoder might need resources ++ if (m_vdpauConfigured == true) ++ { ++ CSingleLock lock(m_DecoderSection); ++ CLog::Log(LOGNOTICE,"CVDPAU::Release pre-cleanup"); ++ ++ Message *reply; ++ if (m_vdpauOutput.m_controlPort.SendOutMessageSync(COutputControlProtocol::PRECLEANUP, ++ &reply, ++ 2000)) ++ { ++ bool success = reply->signal == COutputControlProtocol::ACC ? true : false; ++ reply->Release(); ++ if (!success) ++ { ++ CLog::Log(LOGERROR, "VDPAU::%s - pre-cleanup returned error", __FUNCTION__); ++ m_DisplayState = VDPAU_ERROR; ++ } ++ } ++ else ++ { ++ CLog::Log(LOGERROR, "VDPAU::%s - pre-cleanup timed out", __FUNCTION__); ++ m_DisplayState = VDPAU_ERROR; ++ } + +- GLXFBConfig *fbConfigs; +- fbConfigs = glXChooseFBConfig(m_Display, DefaultScreen(m_Display), doubleVisAttributes, &num); +- if (fbConfigs==NULL) +- { +- CLog::Log(LOGERROR, "GLX Error: MakePixmap: No compatible framebuffers found"); +- return false; ++ for(unsigned int i = 0; i < m_videoSurfaces.size(); ++i) ++ { ++ vdpau_render_state *render = m_videoSurfaces[i]; ++ if (render->surface != VDP_INVALID_HANDLE && !(render->state & FF_VDPAU_STATE_USED_FOR_RENDER)) ++ { ++ m_vdpauConfig.vdpProcs.vdp_video_surface_destroy(render->surface); ++ render->surface = VDP_INVALID_HANDLE; ++ } ++ } + } +- CLog::Log(LOGDEBUG, "Found %d fbconfigs.", num); +- fbConfigIndex = 0; +- CLog::Log(LOGDEBUG, "Using fbconfig index %d.", fbConfigIndex); ++ IHardwareDecoder::Release(); ++} + +- m_glPixmap = glXCreatePixmap(m_Display, fbConfigs[fbConfigIndex], m_Pixmap, pixmapAttribs); ++long CDecoder::ReleasePicReference() ++{ ++ return IHardwareDecoder::Release(); ++} + +- if (!m_glPixmap) ++void CDecoder::SetWidthHeight(int width, int height) ++{ ++ int vdpauMaxHeight = g_advancedSettings.m_videoVDPAUmaxHeight; ++ if (vdpauMaxHeight > 0 && height > vdpauMaxHeight) + { +- CLog::Log(LOGINFO, "GLX Error: Could not create Pixmap"); +- XFree(fbConfigs); +- return false; ++ width = MathUtils::round_int((double)width * vdpauMaxHeight / height); ++ height = vdpauMaxHeight; + } +- XFree(fbConfigs); + +- return true; +-} ++ m_vdpauConfig.upscale = g_advancedSettings.m_videoVDPAUScaling; + +-bool CVDPAU::MakePixmap(int width, int height) +-{ + //pick the smallest dimensions, so we downscale with vdpau and upscale with opengl when appropriate + //this requires the least amount of gpu memory bandwidth +- if (g_graphicsContext.GetWidth() < width || g_graphicsContext.GetHeight() < height || upScale) ++ if (g_graphicsContext.GetWidth() < width || g_graphicsContext.GetHeight() < height || m_vdpauConfig.upscale >= 0) + { + //scale width to desktop size if the aspect ratio is the same or bigger than the desktop + if ((double)height * g_graphicsContext.GetWidth() / width <= (double)g_graphicsContext.GetHeight()) + { +- OutWidth = g_graphicsContext.GetWidth(); +- OutHeight = MathUtils::round_int((double)height * g_graphicsContext.GetWidth() / width); ++ m_vdpauConfig.outWidth = g_graphicsContext.GetWidth(); ++ m_vdpauConfig.outHeight = MathUtils::round_int((double)height * g_graphicsContext.GetWidth() / width); + } + else //scale height to the desktop size if the aspect ratio is smaller than the desktop + { +- OutHeight = g_graphicsContext.GetHeight(); +- OutWidth = MathUtils::round_int((double)width * g_graphicsContext.GetHeight() / height); ++ m_vdpauConfig.outHeight = g_graphicsContext.GetHeight(); ++ m_vdpauConfig.outWidth = MathUtils::round_int((double)width * g_graphicsContext.GetHeight() / height); + } + } + else + { //let opengl scale +- OutWidth = width; +- OutHeight = height; +- } +- +- CLog::Log(LOGNOTICE,"Creating %ix%i pixmap", OutWidth, OutHeight); +- +- // Get our window attribs. +- XWindowAttributes wndattribs; +- XGetWindowAttributes(m_Display, DefaultRootWindow(m_Display), &wndattribs); // returns a status but I don't know what success is +- +- m_Pixmap = XCreatePixmap(m_Display, +- DefaultRootWindow(m_Display), +- OutWidth, +- OutHeight, +- wndattribs.depth); +- if (!m_Pixmap) +- { +- CLog::Log(LOGERROR, "GLX Error: MakePixmap: Unable to create XPixmap"); +- return false; +- } +- +- XGCValues values = {}; +- GC xgc; +- values.foreground = BlackPixel (m_Display, DefaultScreen (m_Display)); +- xgc = XCreateGC(m_Display, m_Pixmap, GCForeground, &values); +- XFillRectangle(m_Display, m_Pixmap, xgc, 0, 0, OutWidth, OutHeight); +- XFreeGC(m_Display, xgc); +- +- if(!MakePixmapGL()) +- return false; +- +- return true; +-} +- +-void CVDPAU::BindPixmap() +-{ +- CSharedLock lock(m_DecoderSection); +- +- { CSharedLock dLock(m_DisplaySection); +- if (m_DisplayState != VDPAU_OPEN) +- return; +- } +- +- if (m_glPixmap) +- { +- if(presentSurface != VDP_INVALID_HANDLE) +- { +- VdpPresentationQueueStatus status; +- VdpTime time; +- VdpStatus vdp_st; +- vdp_st = vdp_presentation_queue_query_surface_status( +- vdp_flip_queue, presentSurface, &status, &time); +- CheckStatus(vdp_st, __LINE__); +- while(status != VDP_PRESENTATION_QUEUE_STATUS_VISIBLE && vdp_st == VDP_STATUS_OK) +- { +- Sleep(1); +- vdp_st = vdp_presentation_queue_query_surface_status( +- vdp_flip_queue, presentSurface, &status, &time); +- CheckStatus(vdp_st, __LINE__); +- } +- } +- +- glXBindTexImageEXT(m_Display, m_glPixmap, GLX_FRONT_LEFT_EXT, NULL); +- } +- else CLog::Log(LOGERROR,"(VDPAU) BindPixmap called without valid pixmap"); +-} +- +-void CVDPAU::ReleasePixmap() +-{ +- CSharedLock lock(m_DecoderSection); +- +- { CSharedLock dLock(m_DisplaySection); +- if (m_DisplayState != VDPAU_OPEN) +- return; +- } +- +- if (m_glPixmap) +- { +- glXReleaseTexImageEXT(m_Display, m_glPixmap, GLX_FRONT_LEFT_EXT); ++ m_vdpauConfig.outWidth = width; ++ m_vdpauConfig.outHeight = height; + } +- else CLog::Log(LOGERROR,"(VDPAU) ReleasePixmap called without valid pixmap"); ++ CLog::Log(LOGDEBUG, "CVDPAU::SetWidthHeight Setting OutWidth: %i OutHeight: %i vdpauMaxHeight: %i", m_vdpauConfig.outWidth, m_vdpauConfig.outHeight, vdpauMaxHeight); + } + +-void CVDPAU::OnLostDevice() ++void CDecoder::OnLostDevice() + { + CLog::Log(LOGNOTICE,"CVDPAU::OnLostDevice event"); + +- CExclusiveLock lock(m_DecoderSection); ++ CSingleLock lock(m_DecoderSection); + FiniVDPAUOutput(); + FiniVDPAUProcs(); + + m_DisplayState = VDPAU_LOST; ++ lock.Leave(); + m_DisplayEvent.Reset(); + } + +-void CVDPAU::OnResetDevice() ++void CDecoder::OnResetDevice() + { + CLog::Log(LOGNOTICE,"CVDPAU::OnResetDevice event"); + +- CExclusiveLock lock(m_DisplaySection); ++ CSingleLock lock(m_DecoderSection); + if (m_DisplayState == VDPAU_LOST) + { + m_DisplayState = VDPAU_RESET; ++ lock.Leave(); + m_DisplayEvent.Set(); + } + } + +-int CVDPAU::Check(AVCodecContext* avctx) ++int CDecoder::Check(AVCodecContext* avctx) + { + EDisplayState state; + +- { CSharedLock lock(m_DisplaySection); ++ { CSingleLock lock(m_DecoderSection); + state = m_DisplayState; + } + +@@ -417,16 +329,13 @@ + } + else + { +- CSharedLock lock(m_DisplaySection); ++ CSingleLock lock(m_DecoderSection); + state = m_DisplayState; + } + } + if (state == VDPAU_RESET || state == VDPAU_ERROR) + { +- CLog::Log(LOGNOTICE,"Attempting recovery"); +- +- CSingleLock gLock(g_graphicsContext); +- CExclusiveLock lock(m_DecoderSection); ++ CSingleLock lock(m_DecoderSection); + + FiniVDPAUOutput(); + FiniVDPAUProcs(); +@@ -441,7 +350,7 @@ + return 0; + } + +-bool CVDPAU::IsVDPAUFormat(PixelFormat format) ++bool CDecoder::IsVDPAUFormat(PixelFormat format) + { + if ((format >= PIX_FMT_VDPAU_H264) && (format <= PIX_FMT_VDPAU_VC1)) return true; + #if (defined PIX_FMT_VDPAU_MPEG4_IN_AVUTIL) +@@ -450,90 +359,28 @@ + else return false; + } + +-void CVDPAU::CheckFeatures() +-{ +- if (videoMixer == VDP_INVALID_HANDLE) +- { +- CLog::Log(LOGNOTICE, " (VDPAU) Creating the video mixer"); +- // Creation of VideoMixer. +- VdpVideoMixerParameter parameters[] = { +- VDP_VIDEO_MIXER_PARAMETER_VIDEO_SURFACE_WIDTH, +- VDP_VIDEO_MIXER_PARAMETER_VIDEO_SURFACE_HEIGHT, +- VDP_VIDEO_MIXER_PARAMETER_CHROMA_TYPE +- }; +- +- void const * parameter_values[] = { +- &surface_width, +- &surface_height, +- &vdp_chroma_type +- }; +- +- tmpBrightness = 0; +- tmpContrast = 0; +- tmpNoiseReduction = 0; +- tmpSharpness = 0; +- +- VdpStatus vdp_st = VDP_STATUS_ERROR; +- vdp_st = vdp_video_mixer_create(vdp_device, +- m_feature_count, +- m_features, +- ARSIZE(parameters), +- parameters, +- parameter_values, +- &videoMixer); +- CheckStatus(vdp_st, __LINE__); +- +- SetHWUpscaling(); +- } +- +- if (tmpBrightness != g_settings.m_currentVideoSettings.m_Brightness || +- tmpContrast != g_settings.m_currentVideoSettings.m_Contrast) +- { +- SetColor(); +- tmpBrightness = g_settings.m_currentVideoSettings.m_Brightness; +- tmpContrast = g_settings.m_currentVideoSettings.m_Contrast; +- } +- if (tmpNoiseReduction != g_settings.m_currentVideoSettings.m_NoiseReduction) +- { +- tmpNoiseReduction = g_settings.m_currentVideoSettings.m_NoiseReduction; +- SetNoiseReduction(); +- } +- if (tmpSharpness != g_settings.m_currentVideoSettings.m_Sharpness) +- { +- tmpSharpness = g_settings.m_currentVideoSettings.m_Sharpness; +- SetSharpness(); +- } +- if ( tmpDeintMode != g_settings.m_currentVideoSettings.m_DeinterlaceMode || +- tmpDeintGUI != g_settings.m_currentVideoSettings.m_InterlaceMethod || +- (tmpDeintGUI == VS_INTERLACEMETHOD_AUTO && tmpDeint != AutoInterlaceMethod())) +- { +- tmpDeintMode = g_settings.m_currentVideoSettings.m_DeinterlaceMode; +- tmpDeintGUI = g_settings.m_currentVideoSettings.m_InterlaceMethod; +- if (tmpDeintGUI == VS_INTERLACEMETHOD_AUTO) +- tmpDeint = AutoInterlaceMethod(); +- else +- tmpDeint = tmpDeintGUI; +- +- SetDeinterlacing(); +- } +-} +- +-bool CVDPAU::Supports(VdpVideoMixerFeature feature) ++bool CDecoder::Supports(VdpVideoMixerFeature feature) + { +- for(int i = 0; i < m_feature_count; i++) ++ for(int i = 0; i < m_vdpauConfig.featureCount; i++) + { +- if(m_features[i] == feature) ++ if(m_vdpauConfig.vdpFeatures[i] == feature) + return true; + } + return false; + } + +-bool CVDPAU::Supports(EINTERLACEMETHOD method) ++bool CDecoder::Supports(EINTERLACEMETHOD method) + { + if(method == VS_INTERLACEMETHOD_VDPAU_BOB + || method == VS_INTERLACEMETHOD_AUTO) + return true; + ++ if (g_guiSettings.GetBool("videoplayer.usevdpauinteropyuv")) ++ { ++ if (method == VS_INTERLACEMETHOD_RENDER_BOB) ++ return true; ++ } ++ + for(SInterlaceMapping* p = g_interlace_mapping; p->method != VS_INTERLACEMETHOD_NONE; p++) + { + if(p->method == method) +@@ -542,149 +389,12 @@ + return false; + } + +-EINTERLACEMETHOD CVDPAU::AutoInterlaceMethod() +-{ +- return VS_INTERLACEMETHOD_VDPAU_TEMPORAL; +-} +- +-void CVDPAU::SetColor() +-{ +- VdpStatus vdp_st; +- +- if (tmpBrightness != g_settings.m_currentVideoSettings.m_Brightness) +- m_Procamp.brightness = (float)((g_settings.m_currentVideoSettings.m_Brightness)-50) / 100; +- if (tmpContrast != g_settings.m_currentVideoSettings.m_Contrast) +- m_Procamp.contrast = (float)((g_settings.m_currentVideoSettings.m_Contrast)+50) / 100; +- +- if(vid_height >= 600 || vid_width > 1024) +- vdp_st = vdp_generate_csc_matrix(&m_Procamp, VDP_COLOR_STANDARD_ITUR_BT_709, &m_CSCMatrix); +- else +- vdp_st = vdp_generate_csc_matrix(&m_Procamp, VDP_COLOR_STANDARD_ITUR_BT_601, &m_CSCMatrix); +- +- VdpVideoMixerAttribute attributes[] = { VDP_VIDEO_MIXER_ATTRIBUTE_CSC_MATRIX }; +- if (g_guiSettings.GetBool("videoplayer.vdpaustudiolevel")) +- { +- void const * pm_CSCMatix[] = { &studioCSC }; +- vdp_st = vdp_video_mixer_set_attribute_values(videoMixer, ARSIZE(attributes), attributes, pm_CSCMatix); +- } +- else +- { +- void const * pm_CSCMatix[] = { &m_CSCMatrix }; +- vdp_st = vdp_video_mixer_set_attribute_values(videoMixer, ARSIZE(attributes), attributes, pm_CSCMatix); +- } +- CheckStatus(vdp_st, __LINE__); +-} +- +-void CVDPAU::SetNoiseReduction() +-{ +- if(!Supports(VDP_VIDEO_MIXER_FEATURE_NOISE_REDUCTION)) +- return; +- +- VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_NOISE_REDUCTION }; +- VdpVideoMixerAttribute attributes[] = { VDP_VIDEO_MIXER_ATTRIBUTE_NOISE_REDUCTION_LEVEL }; +- VdpStatus vdp_st; +- +- if (!g_settings.m_currentVideoSettings.m_NoiseReduction) +- { +- VdpBool enabled[]= {0}; +- vdp_st = vdp_video_mixer_set_feature_enables(videoMixer, ARSIZE(feature), feature, enabled); +- CheckStatus(vdp_st, __LINE__); +- return; +- } +- VdpBool enabled[]={1}; +- vdp_st = vdp_video_mixer_set_feature_enables(videoMixer, ARSIZE(feature), feature, enabled); +- CheckStatus(vdp_st, __LINE__); +- void* nr[] = { &g_settings.m_currentVideoSettings.m_NoiseReduction }; +- CLog::Log(LOGNOTICE,"Setting Noise Reduction to %f",g_settings.m_currentVideoSettings.m_NoiseReduction); +- vdp_st = vdp_video_mixer_set_attribute_values(videoMixer, ARSIZE(attributes), attributes, nr); +- CheckStatus(vdp_st, __LINE__); +-} +- +-void CVDPAU::SetSharpness() +-{ +- if(!Supports(VDP_VIDEO_MIXER_FEATURE_SHARPNESS)) +- return; +- +- VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_SHARPNESS }; +- VdpVideoMixerAttribute attributes[] = { VDP_VIDEO_MIXER_ATTRIBUTE_SHARPNESS_LEVEL }; +- VdpStatus vdp_st; +- +- if (!g_settings.m_currentVideoSettings.m_Sharpness) +- { +- VdpBool enabled[]={0}; +- vdp_st = vdp_video_mixer_set_feature_enables(videoMixer, ARSIZE(feature), feature, enabled); +- CheckStatus(vdp_st, __LINE__); +- return; +- } +- VdpBool enabled[]={1}; +- vdp_st = vdp_video_mixer_set_feature_enables(videoMixer, ARSIZE(feature), feature, enabled); +- CheckStatus(vdp_st, __LINE__); +- void* sh[] = { &g_settings.m_currentVideoSettings.m_Sharpness }; +- CLog::Log(LOGNOTICE,"Setting Sharpness to %f",g_settings.m_currentVideoSettings.m_Sharpness); +- vdp_st = vdp_video_mixer_set_attribute_values(videoMixer, ARSIZE(attributes), attributes, sh); +- CheckStatus(vdp_st, __LINE__); +-} +- +-void CVDPAU::SetHWUpscaling() +-{ +-#ifdef VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L1 +- if(!Supports(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L1) || !upScale) +- return; +- +- VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L1 }; +- VdpStatus vdp_st; +- VdpBool enabled[]={1}; +- vdp_st = vdp_video_mixer_set_feature_enables(videoMixer, ARSIZE(feature), feature, enabled); +- CheckStatus(vdp_st, __LINE__); +-#endif +-} +- +-void CVDPAU::SetDeinterlacing() ++EINTERLACEMETHOD CDecoder::AutoInterlaceMethod() + { +- VdpStatus vdp_st; +- EDEINTERLACEMODE mode = g_settings.m_currentVideoSettings.m_DeinterlaceMode; +- EINTERLACEMETHOD method = g_settings.m_currentVideoSettings.m_InterlaceMethod; +- if (method == VS_INTERLACEMETHOD_AUTO) +- method = AutoInterlaceMethod(); +- +- VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL, +- VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL_SPATIAL, +- VDP_VIDEO_MIXER_FEATURE_INVERSE_TELECINE }; +- if (mode == VS_DEINTERLACEMODE_OFF) +- { +- VdpBool enabled[]={0,0,0}; +- vdp_st = vdp_video_mixer_set_feature_enables(videoMixer, ARSIZE(feature), feature, enabled); +- } +- else +- { +- if (method == VS_INTERLACEMETHOD_VDPAU_TEMPORAL +- || method == VS_INTERLACEMETHOD_VDPAU_TEMPORAL_HALF) +- { +- VdpBool enabled[]={1,0,0}; +- vdp_st = vdp_video_mixer_set_feature_enables(videoMixer, ARSIZE(feature), feature, enabled); +- } +- else if (method == VS_INTERLACEMETHOD_VDPAU_TEMPORAL_SPATIAL +- || method == VS_INTERLACEMETHOD_VDPAU_TEMPORAL_SPATIAL_HALF) +- { +- VdpBool enabled[]={1,1,0}; +- vdp_st = vdp_video_mixer_set_feature_enables(videoMixer, ARSIZE(feature), feature, enabled); +- } +- else if (method == VS_INTERLACEMETHOD_VDPAU_INVERSE_TELECINE) +- { +- VdpBool enabled[]={1,0,1}; +- vdp_st = vdp_video_mixer_set_feature_enables(videoMixer, ARSIZE(feature), feature, enabled); +- } +- else +- { +- VdpBool enabled[]={0,0,0}; +- vdp_st = vdp_video_mixer_set_feature_enables(videoMixer, ARSIZE(feature), feature, enabled); +- } +- } +- +- CheckStatus(vdp_st, __LINE__); ++ return VS_INTERLACEMETHOD_RENDER_BOB; + } + +-void CVDPAU::InitVDPAUProcs() ++void CDecoder::InitVDPAUProcs() + { + char* error; + +@@ -694,151 +404,115 @@ + if (error) + { + CLog::Log(LOGERROR,"(VDPAU) - %s in %s",error,__FUNCTION__); +- vdp_device = VDP_INVALID_HANDLE; +- +- //g_application.m_guiDialogKaiToast.QueueNotification(CGUIDialogKaiToast::Error, "VDPAU", error, 10000); +- ++ m_vdpauConfig.vdpDevice = VDP_INVALID_HANDLE; + return; + } + + if (dl_vdp_device_create_x11) + { +- CSingleLock lock(g_graphicsContext); +- m_Display = g_Windowing.GetDisplay(); ++ m_Display = XOpenDisplay(NULL); + } + + int mScreen = DefaultScreen(m_Display); + VdpStatus vdp_st; + + // Create Device +- // tested on 64bit Ubuntu 11.10 and it deadlocked without this +- XLockDisplay(m_Display); + vdp_st = dl_vdp_device_create_x11(m_Display, //x_display, + mScreen, //x_screen, +- &vdp_device, +- &vdp_get_proc_address); +- XUnlockDisplay(m_Display); ++ &m_vdpauConfig.vdpDevice, ++ &m_vdpauConfig.vdpProcs.vdp_get_proc_address); + +- CLog::Log(LOGNOTICE,"vdp_device = 0x%08x vdp_st = 0x%08x",vdp_device,vdp_st); ++ CLog::Log(LOGNOTICE,"vdp_device = 0x%08x vdp_st = 0x%08x",m_vdpauConfig.vdpDevice,vdp_st); + if (vdp_st != VDP_STATUS_OK) + { + CLog::Log(LOGERROR,"(VDPAU) unable to init VDPAU - vdp_st = 0x%x. Falling back.",vdp_st); +- vdp_device = VDP_INVALID_HANDLE; ++ m_vdpauConfig.vdpDevice = VDP_INVALID_HANDLE; + return; + } + +- if (vdp_st != VDP_STATUS_OK) +- { +- CLog::Log(LOGERROR,"(VDPAU) - Unable to create X11 device in %s",__FUNCTION__); +- vdp_device = VDP_INVALID_HANDLE; +- return; +- } + #define VDP_PROC(id, proc) \ + do { \ +- vdp_st = vdp_get_proc_address(vdp_device, id, (void**)&proc); \ ++ vdp_st = m_vdpauConfig.vdpProcs.vdp_get_proc_address(m_vdpauConfig.vdpDevice, id, (void**)&proc); \ + CheckStatus(vdp_st, __LINE__); \ + } while(0); + +- VDP_PROC(VDP_FUNC_ID_GET_ERROR_STRING , vdp_get_error_string); +- VDP_PROC(VDP_FUNC_ID_DEVICE_DESTROY , vdp_device_destroy); +- VDP_PROC(VDP_FUNC_ID_GENERATE_CSC_MATRIX , vdp_generate_csc_matrix); +- VDP_PROC(VDP_FUNC_ID_VIDEO_SURFACE_CREATE , vdp_video_surface_create); +- VDP_PROC(VDP_FUNC_ID_VIDEO_SURFACE_DESTROY , vdp_video_surface_destroy); +- VDP_PROC(VDP_FUNC_ID_VIDEO_SURFACE_PUT_BITS_Y_CB_CR , vdp_video_surface_put_bits_y_cb_cr); +- VDP_PROC(VDP_FUNC_ID_VIDEO_SURFACE_GET_BITS_Y_CB_CR , vdp_video_surface_get_bits_y_cb_cr); +- VDP_PROC(VDP_FUNC_ID_OUTPUT_SURFACE_PUT_BITS_Y_CB_CR , vdp_output_surface_put_bits_y_cb_cr); +- VDP_PROC(VDP_FUNC_ID_OUTPUT_SURFACE_PUT_BITS_NATIVE , vdp_output_surface_put_bits_native); +- VDP_PROC(VDP_FUNC_ID_OUTPUT_SURFACE_CREATE , vdp_output_surface_create); +- VDP_PROC(VDP_FUNC_ID_OUTPUT_SURFACE_DESTROY , vdp_output_surface_destroy); +- VDP_PROC(VDP_FUNC_ID_OUTPUT_SURFACE_GET_BITS_NATIVE , vdp_output_surface_get_bits_native); +- VDP_PROC(VDP_FUNC_ID_OUTPUT_SURFACE_RENDER_OUTPUT_SURFACE, vdp_output_surface_render_output_surface); +- VDP_PROC(VDP_FUNC_ID_OUTPUT_SURFACE_PUT_BITS_INDEXED , vdp_output_surface_put_bits_indexed); +- VDP_PROC(VDP_FUNC_ID_VIDEO_MIXER_CREATE , vdp_video_mixer_create); +- VDP_PROC(VDP_FUNC_ID_VIDEO_MIXER_SET_FEATURE_ENABLES , vdp_video_mixer_set_feature_enables); +- VDP_PROC(VDP_FUNC_ID_VIDEO_MIXER_DESTROY , vdp_video_mixer_destroy); +- VDP_PROC(VDP_FUNC_ID_VIDEO_MIXER_RENDER , vdp_video_mixer_render); +- VDP_PROC(VDP_FUNC_ID_VIDEO_MIXER_SET_ATTRIBUTE_VALUES , vdp_video_mixer_set_attribute_values); +- VDP_PROC(VDP_FUNC_ID_VIDEO_MIXER_QUERY_PARAMETER_SUPPORT , vdp_video_mixer_query_parameter_support); +- VDP_PROC(VDP_FUNC_ID_VIDEO_MIXER_QUERY_FEATURE_SUPPORT , vdp_video_mixer_query_feature_support); +- VDP_PROC(VDP_FUNC_ID_DECODER_CREATE , vdp_decoder_create); +- VDP_PROC(VDP_FUNC_ID_DECODER_DESTROY , vdp_decoder_destroy); +- VDP_PROC(VDP_FUNC_ID_DECODER_RENDER , vdp_decoder_render); +- VDP_PROC(VDP_FUNC_ID_DECODER_QUERY_CAPABILITIES , vdp_decoder_query_caps); +- VDP_PROC(VDP_FUNC_ID_PREEMPTION_CALLBACK_REGISTER , vdp_preemption_callback_register); +- VDP_PROC(VDP_FUNC_ID_PRESENTATION_QUEUE_TARGET_DESTROY , vdp_presentation_queue_target_destroy); +- VDP_PROC(VDP_FUNC_ID_PRESENTATION_QUEUE_CREATE , vdp_presentation_queue_create); +- VDP_PROC(VDP_FUNC_ID_PRESENTATION_QUEUE_DESTROY , vdp_presentation_queue_destroy); +- VDP_PROC(VDP_FUNC_ID_PRESENTATION_QUEUE_DISPLAY , vdp_presentation_queue_display); +- VDP_PROC(VDP_FUNC_ID_PRESENTATION_QUEUE_BLOCK_UNTIL_SURFACE_IDLE, vdp_presentation_queue_block_until_surface_idle); +- VDP_PROC(VDP_FUNC_ID_PRESENTATION_QUEUE_TARGET_CREATE_X11 , vdp_presentation_queue_target_create_x11); +- VDP_PROC(VDP_FUNC_ID_PRESENTATION_QUEUE_QUERY_SURFACE_STATUS , vdp_presentation_queue_query_surface_status); +- VDP_PROC(VDP_FUNC_ID_PRESENTATION_QUEUE_GET_TIME , vdp_presentation_queue_get_time); +- ++ VDP_PROC(VDP_FUNC_ID_GET_ERROR_STRING , m_vdpauConfig.vdpProcs.vdp_get_error_string); ++ VDP_PROC(VDP_FUNC_ID_DEVICE_DESTROY , m_vdpauConfig.vdpProcs.vdp_device_destroy); ++ VDP_PROC(VDP_FUNC_ID_GENERATE_CSC_MATRIX , m_vdpauConfig.vdpProcs.vdp_generate_csc_matrix); ++ VDP_PROC(VDP_FUNC_ID_VIDEO_SURFACE_CREATE , m_vdpauConfig.vdpProcs.vdp_video_surface_create); ++ VDP_PROC(VDP_FUNC_ID_VIDEO_SURFACE_DESTROY , m_vdpauConfig.vdpProcs.vdp_video_surface_destroy); ++ VDP_PROC(VDP_FUNC_ID_VIDEO_SURFACE_PUT_BITS_Y_CB_CR , m_vdpauConfig.vdpProcs.vdp_video_surface_put_bits_y_cb_cr); ++ VDP_PROC(VDP_FUNC_ID_VIDEO_SURFACE_GET_BITS_Y_CB_CR , m_vdpauConfig.vdpProcs.vdp_video_surface_get_bits_y_cb_cr); ++ VDP_PROC(VDP_FUNC_ID_OUTPUT_SURFACE_PUT_BITS_Y_CB_CR , m_vdpauConfig.vdpProcs.vdp_output_surface_put_bits_y_cb_cr); ++ VDP_PROC(VDP_FUNC_ID_OUTPUT_SURFACE_PUT_BITS_NATIVE , m_vdpauConfig.vdpProcs.vdp_output_surface_put_bits_native); ++ VDP_PROC(VDP_FUNC_ID_OUTPUT_SURFACE_CREATE , m_vdpauConfig.vdpProcs.vdp_output_surface_create); ++ VDP_PROC(VDP_FUNC_ID_OUTPUT_SURFACE_DESTROY , m_vdpauConfig.vdpProcs.vdp_output_surface_destroy); ++ VDP_PROC(VDP_FUNC_ID_OUTPUT_SURFACE_GET_BITS_NATIVE , m_vdpauConfig.vdpProcs.vdp_output_surface_get_bits_native); ++ VDP_PROC(VDP_FUNC_ID_OUTPUT_SURFACE_RENDER_OUTPUT_SURFACE, m_vdpauConfig.vdpProcs.vdp_output_surface_render_output_surface); ++ VDP_PROC(VDP_FUNC_ID_OUTPUT_SURFACE_PUT_BITS_INDEXED , m_vdpauConfig.vdpProcs.vdp_output_surface_put_bits_indexed); ++ VDP_PROC(VDP_FUNC_ID_VIDEO_MIXER_CREATE , m_vdpauConfig.vdpProcs.vdp_video_mixer_create); ++ VDP_PROC(VDP_FUNC_ID_VIDEO_MIXER_SET_FEATURE_ENABLES , m_vdpauConfig.vdpProcs.vdp_video_mixer_set_feature_enables); ++ VDP_PROC(VDP_FUNC_ID_VIDEO_MIXER_DESTROY , m_vdpauConfig.vdpProcs.vdp_video_mixer_destroy); ++ VDP_PROC(VDP_FUNC_ID_VIDEO_MIXER_RENDER , m_vdpauConfig.vdpProcs.vdp_video_mixer_render); ++ VDP_PROC(VDP_FUNC_ID_VIDEO_MIXER_SET_ATTRIBUTE_VALUES , m_vdpauConfig.vdpProcs.vdp_video_mixer_set_attribute_values); ++ VDP_PROC(VDP_FUNC_ID_VIDEO_MIXER_QUERY_PARAMETER_SUPPORT , m_vdpauConfig.vdpProcs.vdp_video_mixer_query_parameter_support); ++ VDP_PROC(VDP_FUNC_ID_VIDEO_MIXER_QUERY_FEATURE_SUPPORT , m_vdpauConfig.vdpProcs.vdp_video_mixer_query_feature_support); ++ VDP_PROC(VDP_FUNC_ID_DECODER_CREATE , m_vdpauConfig.vdpProcs.vdp_decoder_create); ++ VDP_PROC(VDP_FUNC_ID_DECODER_DESTROY , m_vdpauConfig.vdpProcs.vdp_decoder_destroy); ++ VDP_PROC(VDP_FUNC_ID_DECODER_RENDER , m_vdpauConfig.vdpProcs.vdp_decoder_render); ++ VDP_PROC(VDP_FUNC_ID_DECODER_QUERY_CAPABILITIES , m_vdpauConfig.vdpProcs.vdp_decoder_query_caps); ++ VDP_PROC(VDP_FUNC_ID_PRESENTATION_QUEUE_TARGET_DESTROY , m_vdpauConfig.vdpProcs.vdp_presentation_queue_target_destroy); ++ VDP_PROC(VDP_FUNC_ID_PRESENTATION_QUEUE_CREATE , m_vdpauConfig.vdpProcs.vdp_presentation_queue_create); ++ VDP_PROC(VDP_FUNC_ID_PRESENTATION_QUEUE_DESTROY , m_vdpauConfig.vdpProcs.vdp_presentation_queue_destroy); ++ VDP_PROC(VDP_FUNC_ID_PRESENTATION_QUEUE_DISPLAY , m_vdpauConfig.vdpProcs.vdp_presentation_queue_display); ++ VDP_PROC(VDP_FUNC_ID_PRESENTATION_QUEUE_BLOCK_UNTIL_SURFACE_IDLE, m_vdpauConfig.vdpProcs.vdp_presentation_queue_block_until_surface_idle); ++ VDP_PROC(VDP_FUNC_ID_PRESENTATION_QUEUE_TARGET_CREATE_X11 , m_vdpauConfig.vdpProcs.vdp_presentation_queue_target_create_x11); ++ VDP_PROC(VDP_FUNC_ID_PRESENTATION_QUEUE_QUERY_SURFACE_STATUS , m_vdpauConfig.vdpProcs.vdp_presentation_queue_query_surface_status); ++ VDP_PROC(VDP_FUNC_ID_PRESENTATION_QUEUE_GET_TIME , m_vdpauConfig.vdpProcs.vdp_presentation_queue_get_time); ++ + #undef VDP_PROC + + // set all vdpau resources to invalid +- vdp_flip_target = VDP_INVALID_HANDLE; +- vdp_flip_queue = VDP_INVALID_HANDLE; +- videoMixer = VDP_INVALID_HANDLE; +- totalAvailableOutputSurfaces = 0; +- presentSurface = VDP_INVALID_HANDLE; +- outputSurface = VDP_INVALID_HANDLE; +- for (int i = 0; i < NUM_OUTPUT_SURFACES; i++) +- outputSurfaces[i] = VDP_INVALID_HANDLE; +- +- m_vdpauOutputMethod = OUTPUT_NONE; +- +- CExclusiveLock lock(m_DisplaySection); + m_DisplayState = VDPAU_OPEN; +- vdpauConfigured = false; ++ m_vdpauConfigured = false; + } + +-void CVDPAU::FiniVDPAUProcs() ++void CDecoder::FiniVDPAUProcs() + { +- if (vdp_device == VDP_INVALID_HANDLE) return; ++ if (m_vdpauConfig.vdpDevice == VDP_INVALID_HANDLE) return; + + VdpStatus vdp_st; +- vdp_st = vdp_device_destroy(vdp_device); ++ vdp_st = m_vdpauConfig.vdpProcs.vdp_device_destroy(m_vdpauConfig.vdpDevice); + CheckStatus(vdp_st, __LINE__); +- vdp_device = VDP_INVALID_HANDLE; +- vdpauConfigured = false; ++ m_vdpauConfig.vdpDevice = VDP_INVALID_HANDLE; + } + +-void CVDPAU::InitCSCMatrix(int Height) ++void CDecoder::FiniVDPAUOutput() + { ++ if (m_vdpauConfig.vdpDevice == VDP_INVALID_HANDLE || !m_vdpauConfigured) return; ++ ++ CLog::Log(LOGNOTICE, " (VDPAU) %s", __FUNCTION__); ++ ++ // uninit output ++ m_vdpauOutput.Dispose(); ++ m_vdpauConfigured = false; ++ + VdpStatus vdp_st; +- m_Procamp.struct_version = VDP_PROCAMP_VERSION; +- m_Procamp.brightness = 0.0; +- m_Procamp.contrast = 1.0; +- m_Procamp.saturation = 1.0; +- m_Procamp.hue = 0; +- vdp_st = vdp_generate_csc_matrix(&m_Procamp, +- (Height < 720)? VDP_COLOR_STANDARD_ITUR_BT_601 : VDP_COLOR_STANDARD_ITUR_BT_709, +- &m_CSCMatrix); +- CheckStatus(vdp_st, __LINE__); +-} +- +-void CVDPAU::FiniVDPAUOutput() +-{ +- FiniOutputMethod(); +- +- if (vdp_device == VDP_INVALID_HANDLE || !vdpauConfigured) return; + +- CLog::Log(LOGNOTICE, " (VDPAU) %s", __FUNCTION__); +- +- VdpStatus vdp_st; +- +- vdp_st = vdp_decoder_destroy(decoder); ++ vdp_st = m_vdpauConfig.vdpProcs.vdp_decoder_destroy(m_vdpauConfig.vdpDecoder); + if (CheckStatus(vdp_st, __LINE__)) + return; +- decoder = VDP_INVALID_HANDLE; ++ m_vdpauConfig.vdpDecoder = VDP_INVALID_HANDLE; + +- for (unsigned int i = 0; i < m_videoSurfaces.size(); ++i) ++ CSingleLock lock(m_videoSurfaceSec); ++ CLog::Log(LOGDEBUG, "CVDPAU::FiniVDPAUOutput destroying %d video surfaces", (int)m_videoSurfaces.size()); ++ ++ for(unsigned int i = 0; i < m_videoSurfaces.size(); ++i) + { + vdpau_render_state *render = m_videoSurfaces[i]; + if (render->surface != VDP_INVALID_HANDLE) + { +- vdp_st = vdp_video_surface_destroy(render->surface); ++ vdp_st = m_vdpauConfig.vdpProcs.vdp_video_surface_destroy(render->surface); + render->surface = VDP_INVALID_HANDLE; + } + if (CheckStatus(vdp_st, __LINE__)) +@@ -846,8 +520,7 @@ + } + } + +- +-void CVDPAU::ReadFormatOf( PixelFormat fmt ++void CDecoder::ReadFormatOf( PixelFormat fmt + , VdpDecoderProfile &vdp_decoder_profile + , VdpChromaType &vdp_chroma_type) + { +@@ -885,170 +558,78 @@ + } + } + +- +-bool CVDPAU::ConfigVDPAU(AVCodecContext* avctx, int ref_frames) ++bool CDecoder::ConfigVDPAU(AVCodecContext* avctx, int ref_frames) + { + FiniVDPAUOutput(); + + VdpStatus vdp_st; + VdpDecoderProfile vdp_decoder_profile; +- vid_width = avctx->width; +- vid_height = avctx->height; +- surface_width = avctx->coded_width; +- surface_height = avctx->coded_height; +- +- past[1] = past[0] = current = future = NULL; +- CLog::Log(LOGNOTICE, " (VDPAU) screenWidth:%i vidWidth:%i surfaceWidth:%i",OutWidth,vid_width,surface_width); +- CLog::Log(LOGNOTICE, " (VDPAU) screenHeight:%i vidHeight:%i surfaceHeight:%i",OutHeight,vid_height,surface_height); +- ReadFormatOf(avctx->pix_fmt, vdp_decoder_profile, vdp_chroma_type); ++ ++ m_vdpauConfig.vidWidth = avctx->width; ++ m_vdpauConfig.vidHeight = avctx->height; ++ m_vdpauConfig.surfaceWidth = avctx->coded_width; ++ m_vdpauConfig.surfaceHeight = avctx->coded_height; ++ ++ SetWidthHeight(avctx->width,avctx->height); ++ ++ CLog::Log(LOGNOTICE, " (VDPAU) screenWidth:%i vidWidth:%i surfaceWidth:%i",m_vdpauConfig.outWidth,m_vdpauConfig.vidWidth,m_vdpauConfig.surfaceWidth); ++ CLog::Log(LOGNOTICE, " (VDPAU) screenHeight:%i vidHeight:%i surfaceHeight:%i",m_vdpauConfig.outHeight,m_vdpauConfig.vidHeight,m_vdpauConfig.surfaceHeight); ++ ++ ReadFormatOf(avctx->pix_fmt, vdp_decoder_profile, m_vdpauConfig.vdpChromaType); + + if(avctx->pix_fmt == PIX_FMT_VDPAU_H264) + { +- max_references = ref_frames; +- if (max_references > 16) max_references = 16; +- if (max_references < 5) max_references = 5; ++ m_vdpauConfig.maxReferences = ref_frames; ++ if (m_vdpauConfig.maxReferences > 16) m_vdpauConfig.maxReferences = 16; ++ if (m_vdpauConfig.maxReferences < 5) m_vdpauConfig.maxReferences = 5; + } + else +- max_references = 2; ++ m_vdpauConfig.maxReferences = 2; + +- vdp_st = vdp_decoder_create(vdp_device, ++ vdp_st = m_vdpauConfig.vdpProcs.vdp_decoder_create(m_vdpauConfig.vdpDevice, + vdp_decoder_profile, +- surface_width, +- surface_height, +- max_references, +- &decoder); +- if (CheckStatus(vdp_st, __LINE__)) +- return false; +- +- m_vdpauOutputMethod = OUTPUT_NONE; +- +- vdpauConfigured = true; +- return true; +-} +- +-bool CVDPAU::ConfigOutputMethod(AVCodecContext *avctx, AVFrame *pFrame) +-{ +- VdpStatus vdp_st; +- +- if (m_vdpauOutputMethod == OUTPUT_PIXMAP) +- return true; +- +- FiniOutputMethod(); +- +- MakePixmap(avctx->width,avctx->height); +- +- vdp_st = vdp_presentation_queue_target_create_x11(vdp_device, +- m_Pixmap, //x_window, +- &vdp_flip_target); +- if (CheckStatus(vdp_st, __LINE__)) +- return false; +- +- vdp_st = vdp_presentation_queue_create(vdp_device, +- vdp_flip_target, +- &vdp_flip_queue); ++ m_vdpauConfig.surfaceWidth, ++ m_vdpauConfig.surfaceHeight, ++ m_vdpauConfig.maxReferences, ++ &m_vdpauConfig.vdpDecoder); + if (CheckStatus(vdp_st, __LINE__)) + return false; + +- totalAvailableOutputSurfaces = 0; +- +- int tmpMaxOutputSurfaces = NUM_OUTPUT_SURFACES; +- if (vid_width == FULLHD_WIDTH) +- tmpMaxOutputSurfaces = NUM_OUTPUT_SURFACES_FOR_FULLHD; +- +- // Creation of outputSurfaces +- for (int i = 0; i < NUM_OUTPUT_SURFACES && i < tmpMaxOutputSurfaces; i++) +- { +- vdp_st = vdp_output_surface_create(vdp_device, +- VDP_RGBA_FORMAT_B8G8R8A8, +- OutWidth, +- OutHeight, +- &outputSurfaces[i]); +- if (CheckStatus(vdp_st, __LINE__)) ++ // initialize output ++ CSingleLock lock(g_graphicsContext); ++ m_vdpauConfig.stats = &m_bufferStats; ++ m_vdpauConfig.vdpau = this; ++ m_bufferStats.Reset(); ++ m_vdpauOutput.Start(); ++ Message *reply; ++ if (m_vdpauOutput.m_controlPort.SendOutMessageSync(COutputControlProtocol::INIT, ++ &reply, ++ 2000, ++ &m_vdpauConfig, ++ sizeof(m_vdpauConfig))) ++ { ++ bool success = reply->signal == COutputControlProtocol::ACC ? true : false; ++ reply->Release(); ++ if (!success) ++ { ++ CLog::Log(LOGERROR, "VDPAU::%s - vdpau output returned error", __FUNCTION__); ++ m_vdpauOutput.Dispose(); + return false; +- totalAvailableOutputSurfaces++; +- } +- CLog::Log(LOGNOTICE, " (VDPAU) Total Output Surfaces Available: %i of a max (tmp: %i const: %i)", +- totalAvailableOutputSurfaces, +- tmpMaxOutputSurfaces, +- NUM_OUTPUT_SURFACES); +- +- // create 3 pitches of black lines needed for clipping top +- // and bottom lines when de-interlacing +- m_BlackBar = new uint32_t[3*OutWidth]; +- memset(m_BlackBar, 0, 3*OutWidth*sizeof(uint32_t)); +- +- surfaceNum = presentSurfaceNum = 0; +- outputSurface = presentSurface = VDP_INVALID_HANDLE; +- videoMixer = VDP_INVALID_HANDLE; +- +- m_vdpauOutputMethod = OUTPUT_PIXMAP; +- +- return true; +-} +- +-bool CVDPAU::FiniOutputMethod() +-{ +- VdpStatus vdp_st; +- +- if (vdp_flip_queue != VDP_INVALID_HANDLE) +- { +- vdp_st = vdp_presentation_queue_destroy(vdp_flip_queue); +- vdp_flip_queue = VDP_INVALID_HANDLE; +- CheckStatus(vdp_st, __LINE__); +- } +- +- if (vdp_flip_target != VDP_INVALID_HANDLE) +- { +- vdp_st = vdp_presentation_queue_target_destroy(vdp_flip_target); +- vdp_flip_target = VDP_INVALID_HANDLE; +- CheckStatus(vdp_st, __LINE__); +- } +- +- if (m_glPixmap) +- { +- CLog::Log(LOGDEBUG, "GLX: Destroying glPixmap"); +- glXDestroyPixmap(m_Display, m_glPixmap); +- m_glPixmap = None; +- } +- +- if (m_Pixmap) +- { +- CLog::Log(LOGDEBUG, "GLX: Destroying XPixmap"); +- XFreePixmap(m_Display, m_Pixmap); +- m_Pixmap = None; +- } +- +- outputSurface = presentSurface = VDP_INVALID_HANDLE; +- +- for (int i = 0; i < totalAvailableOutputSurfaces; i++) +- { +- if (outputSurfaces[i] == VDP_INVALID_HANDLE) +- continue; +- vdp_st = vdp_output_surface_destroy(outputSurfaces[i]); +- outputSurfaces[i] = VDP_INVALID_HANDLE; +- CheckStatus(vdp_st, __LINE__); +- } +- +- if (videoMixer != VDP_INVALID_HANDLE) +- { +- vdp_st = vdp_video_mixer_destroy(videoMixer); +- videoMixer = VDP_INVALID_HANDLE; +- if (CheckStatus(vdp_st, __LINE__)); ++ } + } +- +- if (m_BlackBar) ++ else + { +- delete [] m_BlackBar; +- m_BlackBar = NULL; ++ CLog::Log(LOGERROR, "VDPAU::%s - failed to init output", __FUNCTION__); ++ m_vdpauOutput.Dispose(); ++ return false; + } + +- while (!m_DVDVideoPics.empty()) +- m_DVDVideoPics.pop(); +- ++ m_inMsgEvent.Reset(); ++ m_vdpauConfigured = true; + return true; + } + +-void CVDPAU::SpewHardwareAvailable() //Copyright (c) 2008 Wladimir J. van der Laan -- VDPInfo ++void CDecoder::SpewHardwareAvailable() //CopyrighVDPAUt (c) 2008 Wladimir J. van der Laan -- VDPInfo + { + VdpStatus rv; + CLog::Log(LOGNOTICE,"VDPAU Decoder capabilities:"); +@@ -1058,7 +639,7 @@ + { + VdpBool is_supported = false; + uint32_t max_level, max_macroblocks, max_width, max_height; +- rv = vdp_decoder_query_caps(vdp_device, decoder_profiles[x].id, ++ rv = m_vdpauConfig.vdpProcs.vdp_decoder_query_caps(m_vdpauConfig.vdpDevice, decoder_profiles[x].id, + &is_supported, &max_level, &max_macroblocks, &max_width, &max_height); + if(rv == VDP_STATUS_OK && is_supported) + { +@@ -1067,13 +648,13 @@ + } + } + CLog::Log(LOGNOTICE,"------------------------------------"); +- m_feature_count = 0; ++ m_vdpauConfig.featureCount = 0; + #define CHECK_SUPPORT(feature) \ + do { \ + VdpBool supported; \ +- if(vdp_video_mixer_query_feature_support(vdp_device, feature, &supported) == VDP_STATUS_OK && supported) { \ ++ if(m_vdpauConfig.vdpProcs.vdp_video_mixer_query_feature_support(m_vdpauConfig.vdpDevice, feature, &supported) == VDP_STATUS_OK && supported) { \ + CLog::Log(LOGNOTICE, "Mixer feature: "#feature); \ +- m_features[m_feature_count++] = feature; \ ++ m_vdpauConfig.vdpFeatures[m_vdpauConfig.featureCount++] = feature; \ + } \ + } while(false) + +@@ -1097,7 +678,7 @@ + + } + +-bool CVDPAU::IsSurfaceValid(vdpau_render_state *render) ++bool CDecoder::IsSurfaceValid(vdpau_render_state *render) + { + // find render state in queue + bool found(false); +@@ -1124,34 +705,34 @@ + return true; + } + +-int CVDPAU::FFGetBuffer(AVCodecContext *avctx, AVFrame *pic) ++int CDecoder::FFGetBuffer(AVCodecContext *avctx, AVFrame *pic) + { + //CLog::Log(LOGNOTICE,"%s",__FUNCTION__); + CDVDVideoCodecFFmpeg* ctx = (CDVDVideoCodecFFmpeg*)avctx->opaque; +- CVDPAU* vdp = (CVDPAU*)ctx->GetHardware(); +- struct pictureAge* pA = &vdp->picAge; ++ CDecoder* vdp = (CDecoder*)ctx->GetHardware(); ++ struct PictureAge* pA = &vdp->m_picAge; + + // while we are waiting to recover we can't do anything +- CSharedLock lock(vdp->m_DecoderSection); ++ CSingleLock lock(vdp->m_DecoderSection); + +- { CSharedLock dLock(vdp->m_DisplaySection); +- if(vdp->m_DisplayState != VDPAU_OPEN) +- { +- CLog::Log(LOGWARNING, "CVDPAU::FFGetBuffer - returning due to awaiting recovery"); +- return -1; +- } ++ if(vdp->m_DisplayState != VDPAU_OPEN) ++ { ++ CLog::Log(LOGWARNING, "CVDPAU::FFGetBuffer - returning due to awaiting recovery"); ++ return -1; + } + + vdpau_render_state * render = NULL; + + // find unused surface +- for(unsigned int i = 0; i < vdp->m_videoSurfaces.size(); i++) +- { +- if(!(vdp->m_videoSurfaces[i]->state & (FF_VDPAU_STATE_USED_FOR_REFERENCE | FF_VDPAU_STATE_USED_FOR_RENDER))) ++ { CSingleLock lock(vdp->m_videoSurfaceSec); ++ for(unsigned int i = 0; i < vdp->m_videoSurfaces.size(); i++) + { +- render = vdp->m_videoSurfaces[i]; +- render->state = 0; +- break; ++ if(!(vdp->m_videoSurfaces[i]->state & (FF_VDPAU_STATE_USED_FOR_REFERENCE | FF_VDPAU_STATE_USED_FOR_RENDER))) ++ { ++ render = vdp->m_videoSurfaces[i]; ++ render->state = 0; ++ break; ++ } + } + } + +@@ -1160,21 +741,22 @@ + { + // create a new surface + VdpDecoderProfile profile; +- ReadFormatOf(avctx->pix_fmt, profile, vdp->vdp_chroma_type); ++ ReadFormatOf(avctx->pix_fmt, profile, vdp->m_vdpauConfig.vdpChromaType); + render = (vdpau_render_state*)calloc(sizeof(vdpau_render_state), 1); + if (render == NULL) + { + CLog::Log(LOGWARNING, "CVDPAU::FFGetBuffer - calloc failed"); + return -1; + } ++ CSingleLock lock(vdp->m_videoSurfaceSec); + render->surface = VDP_INVALID_HANDLE; + vdp->m_videoSurfaces.push_back(render); + } + + if (render->surface == VDP_INVALID_HANDLE) + { +- vdp_st = vdp->vdp_video_surface_create(vdp->vdp_device, +- vdp->vdp_chroma_type, ++ vdp_st = vdp->m_vdpauConfig.vdpProcs.vdp_video_surface_create(vdp->m_vdpauConfig.vdpDevice, ++ vdp->m_vdpauConfig.vdpChromaType, + avctx->coded_width, + avctx->coded_height, + &render->surface); +@@ -1216,15 +798,16 @@ + return 0; + } + +-void CVDPAU::FFReleaseBuffer(AVCodecContext *avctx, AVFrame *pic) ++void CDecoder::FFReleaseBuffer(AVCodecContext *avctx, AVFrame *pic) + { + //CLog::Log(LOGNOTICE,"%s",__FUNCTION__); + CDVDVideoCodecFFmpeg* ctx = (CDVDVideoCodecFFmpeg*)avctx->opaque; +- CVDPAU* vdp = (CVDPAU*)ctx->GetHardware(); ++ CDecoder* vdp = (CDecoder*)ctx->GetHardware(); ++ + vdpau_render_state * render; + unsigned int i; + +- CSharedLock lock(vdp->m_DecoderSection); ++ CSingleLock lock(vdp->m_DecoderSection); + + render=(vdpau_render_state*)pic->data[0]; + if(!render) +@@ -1233,6 +816,8 @@ + return; + } + ++ CSingleLock vLock(vdp->m_videoSurfaceSec); ++ render->state &= ~FF_VDPAU_STATE_USED_FOR_REFERENCE; + for(i=0; i<4; i++) + pic->data[i]= NULL; + +@@ -1247,21 +832,18 @@ + } + + +-void CVDPAU::FFDrawSlice(struct AVCodecContext *s, ++void CDecoder::FFDrawSlice(struct AVCodecContext *s, + const AVFrame *src, int offset[4], + int y, int type, int height) + { + CDVDVideoCodecFFmpeg* ctx = (CDVDVideoCodecFFmpeg*)s->opaque; +- CVDPAU* vdp = (CVDPAU*)ctx->GetHardware(); ++ CDecoder* vdp = (CDecoder*)ctx->GetHardware(); + + // while we are waiting to recover we can't do anything +- CSharedLock lock(vdp->m_DecoderSection); +- +- { CSharedLock dLock(vdp->m_DisplaySection); +- if(vdp->m_DisplayState != VDPAU_OPEN) +- return; +- } ++ CSingleLock lock(vdp->m_DecoderSection); + ++ if(vdp->m_DisplayState != VDPAU_OPEN) ++ return; + + if(src->linesize[0] || src->linesize[1] || src->linesize[2] + || offset[0] || offset[1] || offset[2]) +@@ -1291,59 +873,41 @@ + if(s->pix_fmt == PIX_FMT_VDPAU_H264) + max_refs = render->info.h264.num_ref_frames; + +- if(vdp->decoder == VDP_INVALID_HANDLE +- || vdp->vdpauConfigured == false +- || vdp->max_references < max_refs) ++ if(vdp->m_vdpauConfig.vdpDecoder == VDP_INVALID_HANDLE ++ || vdp->m_vdpauConfigured == false ++ || vdp->m_vdpauConfig.maxReferences < max_refs) + { + if(!vdp->ConfigVDPAU(s, max_refs)) + return; + } + +- vdp_st = vdp->vdp_decoder_render(vdp->decoder, ++ uint64_t startTime = CurrentHostCounter(); ++ uint16_t decoded, processed, rend; ++ vdp->m_bufferStats.Get(decoded, processed, rend); ++ vdp_st = vdp->m_vdpauConfig.vdpProcs.vdp_decoder_render(vdp->m_vdpauConfig.vdpDecoder, + render->surface, + (VdpPictureInfo const *)&(render->info), + render->bitstream_buffers_used, + render->bitstream_buffers); + vdp->CheckStatus(vdp_st, __LINE__); ++ uint64_t diff = CurrentHostCounter() - startTime; ++ if (diff*1000/CurrentHostFrequency() > 30) ++ CLog::Log(LOGWARNING,"CVDPAU::DrawSlice - VdpDecoderRender long decoding: %d ms, dec: %d, proc: %d, rend: %d", (int)((diff*1000)/CurrentHostFrequency()), decoded, processed, rend); ++ + } + +-int CVDPAU::Decode(AVCodecContext *avctx, AVFrame *pFrame) +-{ +- //CLog::Log(LOGNOTICE,"%s",__FUNCTION__); +- VdpStatus vdp_st; +- VdpTime time; + ++int CDecoder::Decode(AVCodecContext *avctx, AVFrame *pFrame, bool bSoftDrain, bool bHardDrain) ++{ + int result = Check(avctx); + if (result) + return result; + +- CSharedLock lock(m_DecoderSection); ++ CSingleLock lock(m_DecoderSection); + +- if (!vdpauConfigured) ++ if (!m_vdpauConfigured) + return VC_ERROR; + +- // configure vdpau output +- if (!ConfigOutputMethod(avctx, pFrame)) +- return VC_FLUSHED; +- +- outputSurface = outputSurfaces[surfaceNum]; +- +- CheckFeatures(); +- +- if (( (int)outRectVid.x1 != OutWidth ) || +- ( (int)outRectVid.y1 != OutHeight )) +- { +- outRectVid.x0 = 0; +- outRectVid.y0 = 0; +- outRectVid.x1 = OutWidth; +- outRectVid.y1 = OutHeight; +- } +- +- EDEINTERLACEMODE mode = g_settings.m_currentVideoSettings.m_DeinterlaceMode; +- EINTERLACEMETHOD method = g_settings.m_currentVideoSettings.m_InterlaceMethod; +- if (method == VS_INTERLACEMETHOD_AUTO) +- method = AutoInterlaceMethod(); +- + if(pFrame) + { // we have a new frame from decoder + +@@ -1351,7 +915,10 @@ + if(!render) // old style ffmpeg gave data on plane 0 + render = (vdpau_render_state*)pFrame->data[0]; + if(!render) ++ { ++ CLog::Log(LOGERROR, "CVDPAU::Decode: no valid frame"); + return VC_ERROR; ++ } + + // ffmpeg vc-1 decoder does not flush, make sure the data buffer is still valid + if (!IsSurfaceValid(render)) +@@ -1360,256 +927,175 @@ + return VC_BUFFER; + } + ++ CSingleLock lock(m_videoSurfaceSec); + render->state |= FF_VDPAU_STATE_USED_FOR_RENDER; ++ lock.Leave(); ++ ++ // send frame to output for processing ++ CVdpauDecodedPicture pic; ++ memset(&pic.DVDPic, 0, sizeof(pic.DVDPic)); ++ ((CDVDVideoCodecFFmpeg*)avctx->opaque)->GetPictureCommon(&pic.DVDPic); ++ pic.render = render; ++ m_bufferStats.IncDecoded(); ++ m_vdpauOutput.m_dataPort.SendOutMessage(COutputDataProtocol::NEWFRAME, &pic, sizeof(pic)); + +- ClearUsedForRender(&past[0]); +- past[0] = past[1]; +- past[1] = current; +- current = future; +- future = render; +- +- DVDVideoPicture DVDPic; +- memset(&DVDPic, 0, sizeof(DVDVideoPicture)); +- ((CDVDVideoCodecFFmpeg*)avctx->opaque)->GetPictureCommon(&DVDPic); +- m_DVDVideoPics.push(DVDPic); +- +- int pics = m_DVDVideoPics.size(); +- if (pics < 2) +- return VC_BUFFER; +- else if (pics > 2) +- { +- // this should not normally happen +- CLog::Log(LOGERROR, "CVDPAU::Decode - invalid number of pictures in queue"); +- while (pics-- != 2) +- m_DVDVideoPics.pop(); ++ m_codecControl = pic.DVDPic.iFlags & (DVP_FLAG_DRAIN | DVP_FLAG_SKIP_PROC); ++ if (m_codecControl & DVP_FLAG_SKIP_PROC) ++ { ++ m_bufferStats.SetCmd(DVP_FLAG_SKIP_PROC); + } ++ } + +- if (mode == VS_DEINTERLACEMODE_FORCE +- || (mode == VS_DEINTERLACEMODE_AUTO && m_DVDVideoPics.front().iFlags & DVP_FLAG_INTERLACED)) ++ int retval = 0; ++ uint16_t decoded, processed, render; ++ Message *msg; ++ while (m_vdpauOutput.m_controlPort.ReceiveInMessage(&msg)) ++ { ++ if (msg->signal == COutputControlProtocol::ERROR) + { +- if((method == VS_INTERLACEMETHOD_VDPAU_BOB +- || method == VS_INTERLACEMETHOD_VDPAU_TEMPORAL +- || method == VS_INTERLACEMETHOD_VDPAU_TEMPORAL_HALF +- || method == VS_INTERLACEMETHOD_VDPAU_TEMPORAL_SPATIAL +- || method == VS_INTERLACEMETHOD_VDPAU_TEMPORAL_SPATIAL_HALF +- || method == VS_INTERLACEMETHOD_VDPAU_INVERSE_TELECINE )) ++ m_DisplayState = VDPAU_ERROR; ++ retval |= VC_ERROR; ++ } ++ msg->Release(); ++ } ++ ++ m_bufferStats.Get(decoded, processed, render); ++ ++ uint64_t startTime = CurrentHostCounter(); ++ while (!retval) ++ { ++ if (m_vdpauOutput.m_dataPort.ReceiveInMessage(&msg)) ++ { ++ if (msg->signal == COutputDataProtocol::PICTURE) + { +- if(method == VS_INTERLACEMETHOD_VDPAU_TEMPORAL_HALF +- || method == VS_INTERLACEMETHOD_VDPAU_TEMPORAL_SPATIAL_HALF +- || avctx->skip_frame == AVDISCARD_NONREF) +- m_mixerstep = 0; +- else +- m_mixerstep = 1; +- +- if(m_DVDVideoPics.front().iFlags & DVP_FLAG_TOP_FIELD_FIRST) +- m_mixerfield = VDP_VIDEO_MIXER_PICTURE_STRUCTURE_TOP_FIELD; +- else +- m_mixerfield = VDP_VIDEO_MIXER_PICTURE_STRUCTURE_BOTTOM_FIELD; ++ if (m_presentPicture) ++ { ++ m_presentPicture->ReturnUnused(); ++ m_presentPicture = 0; ++ } ++ ++ m_presentPicture = *(CVdpauRenderPicture**)msg->data; ++ m_presentPicture->vdpau = this; ++ m_bufferStats.DecRender(); ++ m_bufferStats.Get(decoded, processed, render); ++ retval |= VC_PICTURE; ++ msg->Release(); ++ break; ++ } ++ msg->Release(); ++ } ++ else if (m_vdpauOutput.m_controlPort.ReceiveInMessage(&msg)) ++ { ++ if (msg->signal == COutputControlProtocol::STATS) ++ { ++ m_bufferStats.Get(decoded, processed, render); + } + else + { +- m_mixerstep = 0; +- m_mixerfield = VDP_VIDEO_MIXER_PICTURE_STRUCTURE_FRAME; ++ m_DisplayState = VDPAU_ERROR; ++ retval |= VC_ERROR; + } ++ msg->Release(); + } +- else ++ ++ if ((m_codecControl & DVP_FLAG_DRAIN)) + { +- m_mixerstep = 0; +- m_mixerfield = VDP_VIDEO_MIXER_PICTURE_STRUCTURE_FRAME; ++ if (decoded + processed + render < 4) ++ { ++ retval |= VC_BUFFER; ++ } + } +- +- } +- else if(m_mixerstep == 1) +- { // no new frame given, output second field of old frame +- +- if(avctx->skip_frame == AVDISCARD_NONREF) ++ else + { +- ClearUsedForRender(&past[1]); +- m_DVDVideoPics.pop(); +- return VC_BUFFER; ++ if (decoded < 4 && (processed + render) < 3) ++ { ++ retval |= VC_BUFFER; ++ } + } + +- m_mixerstep = 2; +- if(m_mixerfield == VDP_VIDEO_MIXER_PICTURE_STRUCTURE_TOP_FIELD) +- m_mixerfield = VDP_VIDEO_MIXER_PICTURE_STRUCTURE_BOTTOM_FIELD; +- else +- m_mixerfield = VDP_VIDEO_MIXER_PICTURE_STRUCTURE_TOP_FIELD; ++ if (!retval && !m_inMsgEvent.WaitMSec(2000)) ++ break; + } +- else ++ uint64_t diff = CurrentHostCounter() - startTime; ++ if (retval & VC_PICTURE) + { +- CLog::Log(LOGERROR, "CVDPAU::Decode - invalid mixer state reached"); +- return VC_BUFFER; ++ m_bufferStats.SetParams(diff, m_speed); + } ++ if (diff*1000/CurrentHostFrequency() > 50) ++ CLog::Log(LOGDEBUG,"CVDPAU::Decode long wait: %d", (int)((diff*1000)/CurrentHostFrequency())); + +- VdpVideoSurface past_surfaces[2] = { VDP_INVALID_HANDLE, VDP_INVALID_HANDLE }; +- VdpVideoSurface futu_surfaces[1] = { VDP_INVALID_HANDLE }; +- +- if(m_mixerfield == VDP_VIDEO_MIXER_PICTURE_STRUCTURE_FRAME) +- { +- if (past[0]) +- past_surfaces[1] = past[0]->surface; +- if (past[1]) +- past_surfaces[0] = past[1]->surface; +- futu_surfaces[0] = future->surface; +- } +- else ++ if (!retval) + { +- if(m_mixerstep == 1) +- { // first field +- if (past[1]) +- { +- past_surfaces[1] = past[1]->surface; +- past_surfaces[0] = past[1]->surface; +- } +- futu_surfaces[0] = current->surface; +- } +- else +- { // second field +- if (past[1]) +- past_surfaces[1] = past[1]->surface; +- past_surfaces[0] = current->surface; +- futu_surfaces[0] = future->surface; +- } ++ CLog::Log(LOGERROR, "VDPAU::%s - timed out waiting for output message", __FUNCTION__); ++ m_DisplayState = VDPAU_ERROR; ++ retval |= VC_ERROR; + } + +- vdp_st = vdp_presentation_queue_block_until_surface_idle(vdp_flip_queue,outputSurface,&time); +- +- VdpRect sourceRect = {0,0,vid_width, vid_height}; +- +- vdp_st = vdp_video_mixer_render(videoMixer, +- VDP_INVALID_HANDLE, +- 0, +- m_mixerfield, +- 2, +- past_surfaces, +- current->surface, +- 1, +- futu_surfaces, +- &sourceRect, +- outputSurface, +- &(outRectVid), +- &(outRectVid), +- 0, +- NULL); +- CheckStatus(vdp_st, __LINE__); +- +- surfaceNum++; +- if (surfaceNum >= totalAvailableOutputSurfaces) surfaceNum = 0; ++ return retval; ++} + +- if(m_mixerfield == VDP_VIDEO_MIXER_PICTURE_STRUCTURE_FRAME) +- { +- ClearUsedForRender(&past[0]); +- return VC_BUFFER | VC_PICTURE; +- } +- else +- { +- // in order to clip top and bottom lines when de-interlacing +- // we black those lines as a work around for not working +- // background colour using the mixer +- // pixel perfect is preferred over overscanning or zooming ++bool CDecoder::GetPicture(AVCodecContext* avctx, AVFrame* frame, DVDVideoPicture* picture) ++{ ++ CSingleLock lock(m_DecoderSection); + +- VdpRect clipRect = outRectVid; +- clipRect.y1 = clipRect.y0 + 2; +- uint32_t *data[] = {m_BlackBar}; +- uint32_t pitches[] = {outRectVid.x1}; +- vdp_st = vdp_output_surface_put_bits_native(outputSurface, +- (void**)data, +- pitches, +- &clipRect); +- CheckStatus(vdp_st, __LINE__); ++ if (m_DisplayState != VDPAU_OPEN) ++ return false; + +- clipRect = outRectVid; +- clipRect.y0 = clipRect.y1 - 2; +- vdp_st = vdp_output_surface_put_bits_native(outputSurface, +- (void**)data, +- pitches, +- &clipRect); +- CheckStatus(vdp_st, __LINE__); ++ *picture = m_presentPicture->DVDPic; ++ picture->vdpau = m_presentPicture; + +- if(m_mixerstep == 1) +- return VC_PICTURE; +- else +- { +- ClearUsedForRender(&past[1]); +- return VC_BUFFER | VC_PICTURE; +- } +- } ++ return true; + } + +-bool CVDPAU::GetPicture(AVCodecContext* avctx, AVFrame* frame, DVDVideoPicture* picture) ++void CDecoder::Reset() + { +- CSharedLock lock(m_DecoderSection); +- +- { CSharedLock dLock(m_DisplaySection); +- if (m_DisplayState != VDPAU_OPEN) +- return false; +- } ++ CSingleLock lock(m_DecoderSection); + +- *picture = m_DVDVideoPics.front(); +- // if this is the first field of an interlaced frame, we'll need +- // this same picture for the second field later +- if (m_mixerstep != 1) +- m_DVDVideoPics.pop(); +- +- picture->format = DVDVideoPicture::FMT_VDPAU; +- picture->iFlags &= DVP_FLAG_DROPPED; +- picture->iWidth = OutWidth; +- picture->iHeight = OutHeight; +- picture->vdpau = this; ++ if (!m_vdpauConfigured) ++ return; + +- if(m_mixerstep) +- { +- picture->iRepeatPicture = -0.5; +- if(m_mixerstep > 1) ++ Message *reply; ++ if (m_vdpauOutput.m_controlPort.SendOutMessageSync(COutputControlProtocol::FLUSH, ++ &reply, ++ 2000)) ++ { ++ bool success = reply->signal == COutputControlProtocol::ACC ? true : false; ++ reply->Release(); ++ if (!success) + { +- picture->dts = DVD_NOPTS_VALUE; +- picture->pts = DVD_NOPTS_VALUE; ++ CLog::Log(LOGERROR, "VDPAU::%s - flush returned error", __FUNCTION__); ++ m_DisplayState = VDPAU_ERROR; + } ++ else ++ m_bufferStats.Reset(); ++ } ++ else ++ { ++ CLog::Log(LOGERROR, "VDPAU::%s - flush timed out", __FUNCTION__); ++ m_DisplayState = VDPAU_ERROR; + } +- return true; + } + +-void CVDPAU::Reset() ++bool CDecoder::CanSkipDeint() + { +- // invalidate surfaces and picture queue when seeking +- ClearUsedForRender(&past[0]); +- ClearUsedForRender(&past[1]); +- ClearUsedForRender(¤t); +- ClearUsedForRender(&future); +- +- while (!m_DVDVideoPics.empty()) +- m_DVDVideoPics.pop(); ++ return m_bufferStats.CanSkipDeint(); + } + +-void CVDPAU::Present() ++void CDecoder::SetSpeed(int speed) + { +- //CLog::Log(LOGNOTICE,"%s",__FUNCTION__); +- VdpStatus vdp_st; +- +- CSharedLock lock(m_DecoderSection); +- +- { CSharedLock dLock(m_DisplaySection); +- if (m_DisplayState != VDPAU_OPEN) +- return; +- } +- +- presentSurface = outputSurface; ++ m_speed = speed; ++} + +- vdp_st = vdp_presentation_queue_display(vdp_flip_queue, +- presentSurface, +- 0, +- 0, +- 0); +- CheckStatus(vdp_st, __LINE__); ++void CDecoder::ReturnRenderPicture(CVdpauRenderPicture *renderPic) ++{ ++ m_vdpauOutput.m_dataPort.SendOutMessage(COutputDataProtocol::RETURNPIC, &renderPic, sizeof(renderPic)); + } + +-bool CVDPAU::CheckStatus(VdpStatus vdp_st, int line) ++bool CDecoder::CheckStatus(VdpStatus vdp_st, int line) + { + if (vdp_st != VDP_STATUS_OK) + { +- CLog::Log(LOGERROR, " (VDPAU) Error: %s(%d) at %s:%d\n", vdp_get_error_string(vdp_st), vdp_st, __FILE__, line); +- +- CExclusiveLock lock(m_DisplaySection); ++ CLog::Log(LOGERROR, " (VDPAU) Error: %s(%d) at %s:%d\n", m_vdpauConfig.vdpProcs.vdp_get_error_string(vdp_st), vdp_st, __FILE__, line); + + if(m_DisplayState == VDPAU_OPEN) + { +@@ -1627,4 +1113,2432 @@ + return false; + } + ++//----------------------------------------------------------------------------- ++// RenderPicture ++//----------------------------------------------------------------------------- ++ ++CVdpauRenderPicture* CVdpauRenderPicture::Acquire() ++{ ++ CSingleLock lock(*renderPicSection); ++ ++ if (refCount == 0) ++ vdpau->Acquire(); ++ ++ refCount++; ++ return this; ++} ++ ++long CVdpauRenderPicture::Release() ++{ ++ CSingleLock lock(*renderPicSection); ++ ++ refCount--; ++ if (refCount > 0) ++ return refCount; ++ ++ lock.Leave(); ++ vdpau->ReturnRenderPicture(this); ++ vdpau->ReleasePicReference(); ++ ++ return refCount; ++} ++ ++void CVdpauRenderPicture::ReturnUnused() ++{ ++ { CSingleLock lock(*renderPicSection); ++ if (refCount > 0) ++ return; ++ } ++ if (vdpau) ++ vdpau->ReturnRenderPicture(this); ++} ++ ++//----------------------------------------------------------------------------- ++// Mixer ++//----------------------------------------------------------------------------- ++CMixer::CMixer(CEvent *inMsgEvent) : ++ CThread("Vdpau Mixer Thread"), ++ m_controlPort("ControlPort", inMsgEvent, &m_outMsgEvent), ++ m_dataPort("DataPort", inMsgEvent, &m_outMsgEvent) ++{ ++ m_inMsgEvent = inMsgEvent; ++} ++ ++CMixer::~CMixer() ++{ ++ Dispose(); ++} ++ ++void CMixer::Start() ++{ ++ Create(); ++} ++ ++void CMixer::Dispose() ++{ ++ m_bStop = true; ++ m_outMsgEvent.Set(); ++ StopThread(); ++ ++ m_controlPort.Purge(); ++ m_dataPort.Purge(); ++} ++ ++void CMixer::OnStartup() ++{ ++ CLog::Log(LOGNOTICE, "CMixer::OnStartup: Output Thread created"); ++} ++ ++void CMixer::OnExit() ++{ ++ CLog::Log(LOGNOTICE, "CMixer::OnExit: Output Thread terminated"); ++} ++ ++enum MIXER_STATES ++{ ++ M_TOP = 0, // 0 ++ M_TOP_ERROR, // 1 ++ M_TOP_UNCONFIGURED, // 2 ++ M_TOP_CONFIGURED, // 3 ++ M_TOP_CONFIGURED_WAIT1, // 4 ++ M_TOP_CONFIGURED_STEP1, // 5 ++ M_TOP_CONFIGURED_WAIT2, // 6 ++ M_TOP_CONFIGURED_STEP2, // 7 ++}; ++ ++int MIXER_parentStates[] = { ++ -1, ++ 0, //TOP_ERROR ++ 0, //TOP_UNCONFIGURED ++ 0, //TOP_CONFIGURED ++ 3, //TOP_CONFIGURED_WAIT1 ++ 3, //TOP_CONFIGURED_STEP1 ++ 3, //TOP_CONFIGURED_WAIT2 ++ 3, //TOP_CONFIGURED_STEP2 ++}; ++ ++void CMixer::StateMachine(int signal, Protocol *port, Message *msg) ++{ ++ for (int state = m_state; ; state = MIXER_parentStates[state]) ++ { ++ switch (state) ++ { ++ case M_TOP: // TOP ++ if (port == &m_controlPort) ++ { ++ switch (signal) ++ { ++ case CMixerControlProtocol::FLUSH: ++ Flush(); ++ msg->Reply(CMixerControlProtocol::ACC); ++ return; ++ default: ++ break; ++ } ++ } ++ { ++ std::string portName = port == NULL ? "timer" : port->portName; ++ CLog::Log(LOGWARNING, "CMixer::%s - signal: %d form port: %s not handled for state: %d", __FUNCTION__, signal, portName.c_str(), m_state); ++ } ++ return; ++ ++ case M_TOP_ERROR: // TOP ++ break; ++ ++ case M_TOP_UNCONFIGURED: ++ if (port == &m_controlPort) ++ { ++ switch (signal) ++ { ++ case CMixerControlProtocol::INIT: ++ CVdpauConfig *data; ++ data = (CVdpauConfig*)msg->data; ++ if (data) ++ { ++ m_config = *data; ++ } ++ Init(); ++ if (!m_vdpError) ++ { ++ m_state = M_TOP_CONFIGURED_WAIT1; ++ msg->Reply(CMixerControlProtocol::ACC); ++ } ++ else ++ { ++ msg->Reply(CMixerControlProtocol::ERROR); ++ } ++ return; ++ default: ++ break; ++ } ++ } ++ break; ++ ++ case M_TOP_CONFIGURED: ++ if (port == &m_dataPort) ++ { ++ switch (signal) ++ { ++ case CMixerDataProtocol::FRAME: ++ CVdpauDecodedPicture *frame; ++ frame = (CVdpauDecodedPicture*)msg->data; ++ if (frame) ++ { ++ m_decodedPics.push(*frame); ++ } ++ m_extTimeout = 0; ++ return; ++ case CMixerDataProtocol::BUFFER: ++ VdpOutputSurface *surf; ++ surf = (VdpOutputSurface*)msg->data; ++ if (surf) ++ { ++ m_outputSurfaces.push(*surf); ++ } ++ m_extTimeout = 0; ++ return; ++ default: ++ break; ++ } ++ } ++ break; ++ ++ case M_TOP_CONFIGURED_WAIT1: ++ if (port == NULL) // timeout ++ { ++ switch (signal) ++ { ++ case CMixerControlProtocol::TIMEOUT: ++ if (!m_decodedPics.empty() && !m_outputSurfaces.empty()) ++ { ++ m_state = M_TOP_CONFIGURED_STEP1; ++ m_bStateMachineSelfTrigger = true; ++ } ++ else ++ { ++// if (m_extTimeout != 0) ++// { ++// SetPostProcFeatures(false); ++// CLog::Log(LOGWARNING,"CVDPAU::Mixer timeout - decoded: %d, outputSurf: %d", (int)m_decodedPics.size(), (int)m_outputSurfaces.size()); ++// } ++ m_extTimeout = 100; ++ } ++ return; ++ default: ++ break; ++ } ++ } ++ break; ++ ++ case M_TOP_CONFIGURED_STEP1: ++ if (port == NULL) // timeout ++ { ++ switch (signal) ++ { ++ case CMixerControlProtocol::TIMEOUT: ++ m_mixerInput.push_front(m_decodedPics.front()); ++ m_decodedPics.pop(); ++ if (m_mixerInput.size() < 2) ++ { ++ m_state = M_TOP_CONFIGURED_WAIT1; ++ m_extTimeout = 0; ++ return; ++ } ++ InitCycle(); ++ ProcessPicture(); ++ if (m_vdpError) ++ { ++ m_state = M_TOP_CONFIGURED_WAIT1; ++ m_extTimeout = 1000; ++ return; ++ } ++ if (m_processPicture.DVDPic.format != DVDVideoPicture::FMT_VDPAU_420) ++ m_outputSurfaces.pop(); ++ m_config.stats->IncProcessed(); ++ m_config.stats->DecDecoded(); ++ m_dataPort.SendInMessage(CMixerDataProtocol::PICTURE,&m_processPicture,sizeof(m_processPicture)); ++ if (m_mixersteps > 1) ++ { ++ m_state = M_TOP_CONFIGURED_WAIT2; ++ m_extTimeout = 0; ++ } ++ else ++ { ++ FiniCycle(); ++ m_state = M_TOP_CONFIGURED_WAIT1; ++ m_extTimeout = 0; ++ } ++ return; ++ default: ++ break; ++ } ++ } ++ break; ++ ++ case M_TOP_CONFIGURED_WAIT2: ++ if (port == NULL) // timeout ++ { ++ switch (signal) ++ { ++ case CMixerControlProtocol::TIMEOUT: ++ if (!m_outputSurfaces.empty()) ++ { ++ m_state = M_TOP_CONFIGURED_STEP2; ++ m_bStateMachineSelfTrigger = true; ++ } ++ else ++ { ++// if (m_extTimeout != 0) ++// { ++// SetPostProcFeatures(false); ++// CLog::Log(LOGNOTICE,"---mixer wait2 decoded: %d, outputSurf: %d", (int)m_decodedPics.size(), (int)m_outputSurfaces.size()); ++// } ++ m_extTimeout = 100; ++ } ++ return; ++ default: ++ break; ++ } ++ } ++ break; ++ ++ case M_TOP_CONFIGURED_STEP2: ++ if (port == NULL) // timeout ++ { ++ switch (signal) ++ { ++ case CMixerControlProtocol::TIMEOUT: ++ m_processPicture.outputSurface = m_outputSurfaces.front(); ++ m_mixerstep = 1; ++ ProcessPicture(); ++ if (m_vdpError) ++ { ++ m_state = M_TOP_CONFIGURED_WAIT1; ++ m_extTimeout = 1000; ++ return; ++ } ++ if (m_processPicture.DVDPic.format != DVDVideoPicture::FMT_VDPAU_420) ++ m_outputSurfaces.pop(); ++ m_config.stats->IncProcessed(); ++ m_dataPort.SendInMessage(CMixerDataProtocol::PICTURE,&m_processPicture,sizeof(m_processPicture)); ++ FiniCycle(); ++ m_state = M_TOP_CONFIGURED_WAIT1; ++ m_extTimeout = 0; ++ return; ++ default: ++ break; ++ } ++ } ++ break; ++ ++ default: // we are in no state, should not happen ++ CLog::Log(LOGERROR, "CMixer::%s - no valid state: %d", __FUNCTION__, m_state); ++ return; ++ } ++ } // for ++} ++ ++void CMixer::Process() ++{ ++ Message *msg; ++ Protocol *port; ++ bool gotMsg; ++ ++ m_state = M_TOP_UNCONFIGURED; ++ m_extTimeout = 1000; ++ m_bStateMachineSelfTrigger = false; ++ ++ while (!m_bStop) ++ { ++ gotMsg = false; ++ ++ if (m_bStateMachineSelfTrigger) ++ { ++ m_bStateMachineSelfTrigger = false; ++ // self trigger state machine ++ StateMachine(msg->signal, port, msg); ++ if (!m_bStateMachineSelfTrigger) ++ { ++ msg->Release(); ++ msg = NULL; ++ } ++ continue; ++ } ++ // check control port ++ else if (m_controlPort.ReceiveOutMessage(&msg)) ++ { ++ gotMsg = true; ++ port = &m_controlPort; ++ } ++ // check data port ++ else if (m_dataPort.ReceiveOutMessage(&msg)) ++ { ++ gotMsg = true; ++ port = &m_dataPort; ++ } ++ ++ if (gotMsg) ++ { ++ StateMachine(msg->signal, port, msg); ++ if (!m_bStateMachineSelfTrigger) ++ { ++ msg->Release(); ++ msg = NULL; ++ } ++ continue; ++ } ++ ++ // wait for message ++ else if (m_outMsgEvent.WaitMSec(m_extTimeout)) ++ { ++ continue; ++ } ++ // time out ++ else ++ { ++ msg = m_controlPort.GetMessage(); ++ msg->signal = CMixerControlProtocol::TIMEOUT; ++ port = 0; ++ // signal timeout to state machine ++ StateMachine(msg->signal, port, msg); ++ if (!m_bStateMachineSelfTrigger) ++ { ++ msg->Release(); ++ msg = NULL; ++ } ++ } ++ } ++ Uninit(); ++} ++ ++void CMixer::CreateVdpauMixer() ++{ ++ CLog::Log(LOGNOTICE, " (VDPAU) Creating the video mixer"); ++ ++ InitCSCMatrix(m_config.vidWidth); ++ ++ VdpVideoMixerParameter parameters[] = { ++ VDP_VIDEO_MIXER_PARAMETER_VIDEO_SURFACE_WIDTH, ++ VDP_VIDEO_MIXER_PARAMETER_VIDEO_SURFACE_HEIGHT, ++ VDP_VIDEO_MIXER_PARAMETER_CHROMA_TYPE}; ++ ++ void const * parameter_values[] = { ++ &m_config.surfaceWidth, ++ &m_config.surfaceHeight, ++ &m_config.vdpChromaType}; ++ ++ VdpStatus vdp_st = VDP_STATUS_ERROR; ++ vdp_st = m_config.vdpProcs.vdp_video_mixer_create(m_config.vdpDevice, ++ m_config.featureCount, ++ m_config.vdpFeatures, ++ ARSIZE(parameters), ++ parameters, ++ parameter_values, ++ &m_videoMixer); ++ CheckStatus(vdp_st, __LINE__); ++ ++ // create 3 pitches of black lines needed for clipping top ++ // and bottom lines when de-interlacing ++ m_BlackBar = new uint32_t[3*m_config.outWidth]; ++ memset(m_BlackBar, 0, 3*m_config.outWidth*sizeof(uint32_t)); ++ ++} ++ ++void CMixer::InitCSCMatrix(int Width) ++{ ++ VdpStatus vdp_st; ++ m_Procamp.struct_version = VDP_PROCAMP_VERSION; ++ m_Procamp.brightness = 0.0; ++ m_Procamp.contrast = 1.0; ++ m_Procamp.saturation = 1.0; ++ m_Procamp.hue = 0; ++ vdp_st = m_config.vdpProcs.vdp_generate_csc_matrix(&m_Procamp, ++ (Width < 1000)? VDP_COLOR_STANDARD_ITUR_BT_601 : VDP_COLOR_STANDARD_ITUR_BT_709, ++ &m_CSCMatrix); ++ CheckStatus(vdp_st, __LINE__); ++} ++ ++void CMixer::CheckFeatures() ++{ ++ if (m_Upscale != m_config.upscale) ++ { ++ SetHWUpscaling(); ++ m_Upscale = m_config.upscale; ++ } ++ if (m_Brightness != g_settings.m_currentVideoSettings.m_Brightness || ++ m_Contrast != g_settings.m_currentVideoSettings.m_Contrast) ++ { ++ SetColor(); ++ m_Brightness = g_settings.m_currentVideoSettings.m_Brightness; ++ m_Contrast = g_settings.m_currentVideoSettings.m_Contrast; ++ } ++ if (m_NoiseReduction != g_settings.m_currentVideoSettings.m_NoiseReduction) ++ { ++ m_NoiseReduction = g_settings.m_currentVideoSettings.m_NoiseReduction; ++ SetNoiseReduction(); ++ } ++ if (m_Sharpness != g_settings.m_currentVideoSettings.m_Sharpness) ++ { ++ m_Sharpness = g_settings.m_currentVideoSettings.m_Sharpness; ++ SetSharpness(); ++ } ++ if (m_DeintMode != g_settings.m_currentVideoSettings.m_DeinterlaceMode || ++ m_Deint != g_settings.m_currentVideoSettings.m_InterlaceMethod) ++ { ++ m_DeintMode = g_settings.m_currentVideoSettings.m_DeinterlaceMode; ++ m_Deint = g_settings.m_currentVideoSettings.m_InterlaceMethod; ++ SetDeinterlacing(); ++ } ++} ++ ++void CMixer::SetPostProcFeatures(bool postProcEnabled) ++{ ++ if (m_PostProc != postProcEnabled) ++ { ++ if (postProcEnabled) ++ { ++ SetNoiseReduction(); ++ SetSharpness(); ++ SetDeinterlacing(); ++ SetHWUpscaling(); ++ } ++ else ++ PostProcOff(); ++ m_PostProc = postProcEnabled; ++ } ++} ++ ++void CMixer::PostProcOff() ++{ ++ VdpStatus vdp_st; ++ ++ if (m_videoMixer == VDP_INVALID_HANDLE) ++ return; ++ ++ VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL, ++ VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL_SPATIAL, ++ VDP_VIDEO_MIXER_FEATURE_INVERSE_TELECINE}; ++ ++ VdpBool enabled[]={0,0,0}; ++ vdp_st = m_config.vdpProcs.vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled); ++ CheckStatus(vdp_st, __LINE__); ++ ++ if(m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_NOISE_REDUCTION)) ++ { ++ VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_NOISE_REDUCTION}; ++ ++ VdpBool enabled[]={0}; ++ vdp_st = m_config.vdpProcs.vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled); ++ CheckStatus(vdp_st, __LINE__); ++ } ++ ++ if(m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_SHARPNESS)) ++ { ++ VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_SHARPNESS}; ++ ++ VdpBool enabled[]={0}; ++ vdp_st = m_config.vdpProcs.vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled); ++ CheckStatus(vdp_st, __LINE__); ++ } ++ ++ DisableHQScaling(); ++} ++ ++ ++bool CMixer::GenerateStudioCSCMatrix(VdpColorStandard colorStandard, VdpCSCMatrix &studioCSCMatrix) ++{ ++ // instead use studioCSCKCoeffs601[3], studioCSCKCoeffs709[3] to generate float[3][4] matrix (float studioCSC[3][4]) ++ // m00 = mRY = red: luma factor (contrast factor) (1.0) ++ // m10 = mGY = green: luma factor (contrast factor) (1.0) ++ // m20 = mBY = blue: luma factor (contrast factor) (1.0) ++ // ++ // m01 = mRB = red: blue color diff coeff (0.0) ++ // m11 = mGB = green: blue color diff coeff (-2Kb(1-Kb)/(Kg)) ++ // m21 = mBB = blue: blue color diff coeff ((1-Kb)/0.5) ++ // ++ // m02 = mRR = red: red color diff coeff ((1-Kr)/0.5) ++ // m12 = mGR = green: red color diff coeff (-2Kr(1-Kr)/(Kg)) ++ // m22 = mBR = blue: red color diff coeff (0.0) ++ // ++ // m03 = mRC = red: colour zero offset (brightness factor) (-(1-Kr)/0.5 * (128/255)) ++ // m13 = mGC = green: colour zero offset (brightness factor) ((256/255) * (Kb(1-Kb) + Kr(1-Kr)) / Kg) ++ // m23 = mBC = blue: colour zero offset (brightness factor) (-(1-Kb)/0.5 * (128/255)) ++ ++ // columns ++ int Y = 0; ++ int Cb = 1; ++ int Cr = 2; ++ int C = 3; ++ // rows ++ int R = 0; ++ int G = 1; ++ int B = 2; ++ // colour standard coefficients for red, geen, blue ++ double Kr, Kg, Kb; ++ // colour diff zero position (use standard 8-bit coding precision) ++ double CDZ = 128; //256*0.5 ++ // range excursion (use standard 8-bit coding precision) ++ double EXC = 255; //256-1 ++ ++ if (colorStandard == VDP_COLOR_STANDARD_ITUR_BT_601) ++ { ++ Kr = studioCSCKCoeffs601[0]; ++ Kg = studioCSCKCoeffs601[1]; ++ Kb = studioCSCKCoeffs601[2]; ++ } ++ else // assume VDP_COLOR_STANDARD_ITUR_BT_709 ++ { ++ Kr = studioCSCKCoeffs709[0]; ++ Kg = studioCSCKCoeffs709[1]; ++ Kb = studioCSCKCoeffs709[2]; ++ } ++ // we keep luma unscaled to retain the levels present in source so that 16-235 luma is converted to RGB 16-235 ++ studioCSCMatrix[R][Y] = 1.0; ++ studioCSCMatrix[G][Y] = 1.0; ++ studioCSCMatrix[B][Y] = 1.0; ++ ++ studioCSCMatrix[R][Cb] = 0.0; ++ studioCSCMatrix[G][Cb] = (double)-2 * Kb * (1 - Kb) / Kg; ++ studioCSCMatrix[B][Cb] = (double)(1 - Kb) / 0.5; ++ ++ studioCSCMatrix[R][Cr] = (double)(1 - Kr) / 0.5; ++ studioCSCMatrix[G][Cr] = (double)-2 * Kr * (1 - Kr) / Kg; ++ studioCSCMatrix[B][Cr] = 0.0; ++ ++ studioCSCMatrix[R][C] = (double)-1 * studioCSCMatrix[R][Cr] * CDZ/EXC; ++ studioCSCMatrix[G][C] = (double)-1 * (studioCSCMatrix[G][Cb] + studioCSCMatrix[G][Cr]) * CDZ/EXC; ++ studioCSCMatrix[B][C] = (double)-1 * studioCSCMatrix[B][Cb] * CDZ/EXC; ++ ++ return true; ++} ++ ++void CMixer::SetColor() ++{ ++ VdpStatus vdp_st; ++ ++ if (m_Brightness != g_settings.m_currentVideoSettings.m_Brightness) ++ m_Procamp.brightness = (float)((g_settings.m_currentVideoSettings.m_Brightness)-50) / 100; ++ if (m_Contrast != g_settings.m_currentVideoSettings.m_Contrast) ++ m_Procamp.contrast = (float)((g_settings.m_currentVideoSettings.m_Contrast)+50) / 100; ++ ++ VdpColorStandard colorStandard; ++// if(vid_height >= 600 || vid_width > 1024) ++ if(m_config.surfaceWidth > 1000) ++ colorStandard = VDP_COLOR_STANDARD_ITUR_BT_709; ++ //vdp_st = vdp_generate_csc_matrix(&m_Procamp, VDP_COLOR_STANDARD_ITUR_BT_709, &m_CSCMatrix); ++ else ++ colorStandard = VDP_COLOR_STANDARD_ITUR_BT_601; ++ //vdp_st = vdp_generate_csc_matrix(&m_Procamp, VDP_COLOR_STANDARD_ITUR_BT_601, &m_CSCMatrix); ++ ++ VdpVideoMixerAttribute attributes[] = { VDP_VIDEO_MIXER_ATTRIBUTE_CSC_MATRIX }; ++ if (g_guiSettings.GetBool("videoplayer.vdpaustudiolevel")) ++ { ++ float studioCSC[3][4]; ++ GenerateStudioCSCMatrix(colorStandard, studioCSC); ++ void const * pm_CSCMatix[] = { &studioCSC }; ++ vdp_st = m_config.vdpProcs.vdp_video_mixer_set_attribute_values(m_videoMixer, ARSIZE(attributes), attributes, pm_CSCMatix); ++ } ++ else ++ { ++ vdp_st = m_config.vdpProcs.vdp_generate_csc_matrix(&m_Procamp, colorStandard, &m_CSCMatrix); ++ void const * pm_CSCMatix[] = { &m_CSCMatrix }; ++ vdp_st = m_config.vdpProcs.vdp_video_mixer_set_attribute_values(m_videoMixer, ARSIZE(attributes), attributes, pm_CSCMatix); ++ } ++ CheckStatus(vdp_st, __LINE__); ++} ++ ++void CMixer::SetNoiseReduction() ++{ ++ if(!m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_NOISE_REDUCTION)) ++ return; ++ ++ VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_NOISE_REDUCTION }; ++ VdpVideoMixerAttribute attributes[] = { VDP_VIDEO_MIXER_ATTRIBUTE_NOISE_REDUCTION_LEVEL }; ++ VdpStatus vdp_st; ++ ++ if (!g_settings.m_currentVideoSettings.m_NoiseReduction) ++ { ++ VdpBool enabled[]= {0}; ++ vdp_st = m_config.vdpProcs.vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled); ++ CheckStatus(vdp_st, __LINE__); ++ return; ++ } ++ VdpBool enabled[]={1}; ++ vdp_st = m_config.vdpProcs.vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled); ++ CheckStatus(vdp_st, __LINE__); ++ void* nr[] = { &g_settings.m_currentVideoSettings.m_NoiseReduction }; ++ CLog::Log(LOGNOTICE,"Setting Noise Reduction to %f",g_settings.m_currentVideoSettings.m_NoiseReduction); ++ vdp_st = m_config.vdpProcs.vdp_video_mixer_set_attribute_values(m_videoMixer, ARSIZE(attributes), attributes, nr); ++ CheckStatus(vdp_st, __LINE__); ++} ++ ++void CMixer::SetSharpness() ++{ ++ if(!m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_SHARPNESS)) ++ return; ++ ++ VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_SHARPNESS }; ++ VdpVideoMixerAttribute attributes[] = { VDP_VIDEO_MIXER_ATTRIBUTE_SHARPNESS_LEVEL }; ++ VdpStatus vdp_st; ++ ++ if (!g_settings.m_currentVideoSettings.m_Sharpness) ++ { ++ VdpBool enabled[]={0}; ++ vdp_st = m_config.vdpProcs.vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled); ++ CheckStatus(vdp_st, __LINE__); ++ return; ++ } ++ VdpBool enabled[]={1}; ++ vdp_st = m_config.vdpProcs.vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled); ++ CheckStatus(vdp_st, __LINE__); ++ void* sh[] = { &g_settings.m_currentVideoSettings.m_Sharpness }; ++ CLog::Log(LOGNOTICE,"Setting Sharpness to %f",g_settings.m_currentVideoSettings.m_Sharpness); ++ vdp_st = m_config.vdpProcs.vdp_video_mixer_set_attribute_values(m_videoMixer, ARSIZE(attributes), attributes, sh); ++ CheckStatus(vdp_st, __LINE__); ++} ++ ++EINTERLACEMETHOD CMixer::GetDeinterlacingMethod(bool log /* = false */) ++{ ++ EINTERLACEMETHOD method = g_settings.m_currentVideoSettings.m_InterlaceMethod; ++ if (method == VS_INTERLACEMETHOD_AUTO) ++ { ++ int deint = -1; ++ if (m_config.outHeight >= 720) ++ deint = g_advancedSettings.m_videoVDPAUdeintHD; ++ else ++ deint = g_advancedSettings.m_videoVDPAUdeintSD; ++ ++ if (deint != -1) ++ { ++ if (m_config.vdpau->Supports(EINTERLACEMETHOD(deint))) ++ { ++ method = EINTERLACEMETHOD(deint); ++ if (log) ++ CLog::Log(LOGNOTICE, "CVDPAU::GetDeinterlacingMethod: set de-interlacing to %d", deint); ++ } ++ else ++ { ++ if (log) ++ CLog::Log(LOGWARNING, "CVDPAU::GetDeinterlacingMethod: method for de-interlacing (advanced settings) not supported"); ++ } ++ } ++ } ++ return method; ++} ++ ++void CMixer::SetDeinterlacing() ++{ ++ VdpStatus vdp_st; ++ ++ if (m_videoMixer == VDP_INVALID_HANDLE) ++ return; ++ ++ EDEINTERLACEMODE mode = g_settings.m_currentVideoSettings.m_DeinterlaceMode; ++ EINTERLACEMETHOD method = GetDeinterlacingMethod(true); ++ ++ VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL, ++ VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL_SPATIAL, ++ VDP_VIDEO_MIXER_FEATURE_INVERSE_TELECINE }; ++ ++ if (mode == VS_DEINTERLACEMODE_OFF) ++ { ++ VdpBool enabled[] = {0,0,0}; ++ vdp_st = m_config.vdpProcs.vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled); ++ } ++ else ++ { ++ if (method == VS_INTERLACEMETHOD_AUTO) ++ { ++ VdpBool enabled[] = {1,1,0}; ++ if (g_advancedSettings.m_videoVDPAUtelecine) ++ enabled[2] = 1; ++ vdp_st = m_config.vdpProcs.vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled); ++ } ++ else if (method == VS_INTERLACEMETHOD_VDPAU_TEMPORAL ++ || method == VS_INTERLACEMETHOD_VDPAU_TEMPORAL_HALF) ++ { ++ VdpBool enabled[] = {1,0,0}; ++ if (g_advancedSettings.m_videoVDPAUtelecine) ++ enabled[2] = 1; ++ vdp_st = m_config.vdpProcs.vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled); ++ } ++ else if (method == VS_INTERLACEMETHOD_VDPAU_TEMPORAL_SPATIAL ++ || method == VS_INTERLACEMETHOD_VDPAU_TEMPORAL_SPATIAL_HALF) ++ { ++ VdpBool enabled[] = {1,1,0}; ++ if (g_advancedSettings.m_videoVDPAUtelecine) ++ enabled[2] = 1; ++ vdp_st = m_config.vdpProcs.vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled); ++ } ++ else ++ { ++ VdpBool enabled[]={0,0,0}; ++ vdp_st = m_config.vdpProcs.vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled); ++ } ++ } ++ CheckStatus(vdp_st, __LINE__); ++ ++ SetDeintSkipChroma(); ++ ++ m_config.useInteropYuv = g_guiSettings.GetBool("videoplayer.usevdpauinteropyuv"); ++} ++ ++void CMixer::SetDeintSkipChroma() ++{ ++ VdpVideoMixerAttribute attribute[] = { VDP_VIDEO_MIXER_ATTRIBUTE_SKIP_CHROMA_DEINTERLACE}; ++ VdpStatus vdp_st; ++ ++ uint8_t val; ++ if (g_advancedSettings.m_videoVDPAUdeintSkipChromaHD && m_config.outHeight >= 720) ++ val = 1; ++ else ++ val = 0; ++ ++ void const *values[]={&val}; ++ vdp_st = m_config.vdpProcs.vdp_video_mixer_set_attribute_values(m_videoMixer, ARSIZE(attribute), attribute, values); ++ ++ CheckStatus(vdp_st, __LINE__); ++} ++ ++void CMixer::SetHWUpscaling() ++{ ++#ifdef VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L1 ++ ++ VdpStatus vdp_st; ++ VdpBool enabled[]={1}; ++ switch (m_config.upscale) ++ { ++ case 9: ++ if (m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L9)) ++ { ++ VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L9 }; ++ vdp_st = m_config.vdpProcs.vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled); ++ break; ++ } ++ case 8: ++ if (m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L8)) ++ { ++ VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L8 }; ++ vdp_st = m_config.vdpProcs.vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled); ++ break; ++ } ++ case 7: ++ if (m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L7)) ++ { ++ VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L7 }; ++ vdp_st = m_config.vdpProcs.vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled); ++ break; ++ } ++ case 6: ++ if (m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L6)) ++ { ++ VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L6 }; ++ vdp_st = m_config.vdpProcs.vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled); ++ break; ++ } ++ case 5: ++ if (m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L5)) ++ { ++ VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L5 }; ++ vdp_st = m_config.vdpProcs.vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled); ++ break; ++ } ++ case 4: ++ if (m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L4)) ++ { ++ VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L4 }; ++ vdp_st = m_config.vdpProcs.vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled); ++ break; ++ } ++ case 3: ++ if (m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L3)) ++ { ++ VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L3 }; ++ vdp_st = m_config.vdpProcs.vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled); ++ break; ++ } ++ case 2: ++ if (m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L2)) ++ { ++ VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L2 }; ++ vdp_st = m_config.vdpProcs.vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled); ++ break; ++ } ++ case 1: ++ if (m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L1)) ++ { ++ VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L1 }; ++ vdp_st = m_config.vdpProcs.vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled); ++ break; ++ } ++ default: ++ DisableHQScaling(); ++ return; ++ } ++ CheckStatus(vdp_st, __LINE__); ++#endif ++} ++ ++void CMixer::DisableHQScaling() ++{ ++ VdpStatus vdp_st; ++ ++ if (m_videoMixer == VDP_INVALID_HANDLE) ++ return; ++ ++ if(m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L1)) ++ { ++ VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L1 }; ++ VdpBool enabled[]={0}; ++ vdp_st = m_config.vdpProcs.vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled); ++ CheckStatus(vdp_st, __LINE__); ++ } ++ ++ if(m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L2)) ++ { ++ VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L2 }; ++ VdpBool enabled[]={0}; ++ vdp_st = m_config.vdpProcs.vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled); ++ CheckStatus(vdp_st, __LINE__); ++ } ++ ++ if(m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L3)) ++ { ++ VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L3 }; ++ VdpBool enabled[]={0}; ++ vdp_st = m_config.vdpProcs.vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled); ++ CheckStatus(vdp_st, __LINE__); ++ } ++ ++ if(m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L4)) ++ { ++ VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L4 }; ++ VdpBool enabled[]={0}; ++ vdp_st = m_config.vdpProcs.vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled); ++ CheckStatus(vdp_st, __LINE__); ++ } ++ ++ if(m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L5)) ++ { ++ VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L5 }; ++ VdpBool enabled[]={0}; ++ vdp_st = m_config.vdpProcs.vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled); ++ CheckStatus(vdp_st, __LINE__); ++ } ++ ++ if(m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L6)) ++ { ++ VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L6 }; ++ VdpBool enabled[]={0}; ++ vdp_st = m_config.vdpProcs.vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled); ++ CheckStatus(vdp_st, __LINE__); ++ } ++ ++ if(m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L7)) ++ { ++ VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L7 }; ++ VdpBool enabled[]={0}; ++ vdp_st = m_config.vdpProcs.vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled); ++ CheckStatus(vdp_st, __LINE__); ++ } ++ ++ if(m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L8)) ++ { ++ VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L8 }; ++ VdpBool enabled[]={0}; ++ vdp_st = m_config.vdpProcs.vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled); ++ CheckStatus(vdp_st, __LINE__); ++ } ++ ++ if(m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L9)) ++ { ++ VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L9 }; ++ VdpBool enabled[]={0}; ++ vdp_st = m_config.vdpProcs.vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled); ++ CheckStatus(vdp_st, __LINE__); ++ } ++} ++ ++ ++void CMixer::Init() ++{ ++ m_Brightness = 0.0; ++ m_Contrast = 0.0; ++ m_NoiseReduction = 0.0; ++ m_Sharpness = 0.0; ++ m_DeintMode = 0; ++ m_Deint = 0; ++ m_PostProc = false; ++ m_vdpError = false; ++ ++ m_config.upscale = g_advancedSettings.m_videoVDPAUScaling; ++ m_config.useInteropYuv = g_guiSettings.GetBool("videoplayer.usevdpauinteropyuv"); ++ ++ CreateVdpauMixer(); ++} ++ ++void CMixer::Uninit() ++{ ++ Flush(); ++ while (!m_outputSurfaces.empty()) ++ { ++ m_outputSurfaces.pop(); ++ } ++ m_config.vdpProcs.vdp_video_mixer_destroy(m_videoMixer); ++} ++ ++void CMixer::Flush() ++{ ++ while (!m_mixerInput.empty()) ++ { ++ CVdpauDecodedPicture pic = m_mixerInput.back(); ++ m_mixerInput.pop_back(); ++ CSingleLock lock(*m_config.videoSurfaceSec); ++ if (pic.render) ++ pic.render->state &= ~FF_VDPAU_STATE_USED_FOR_RENDER; ++ } ++ while (!m_decodedPics.empty()) ++ { ++ CVdpauDecodedPicture pic = m_decodedPics.front(); ++ m_decodedPics.pop(); ++ CSingleLock lock(*m_config.videoSurfaceSec); ++ if (pic.render) ++ pic.render->state &= ~FF_VDPAU_STATE_USED_FOR_RENDER; ++ } ++ Message *msg; ++ while (m_dataPort.ReceiveOutMessage(&msg)) ++ { ++ if (msg->signal == CMixerDataProtocol::FRAME) ++ { ++ CVdpauDecodedPicture pic = *(CVdpauDecodedPicture*)msg->data; ++ CSingleLock lock(*m_config.videoSurfaceSec); ++ if (pic.render) ++ pic.render->state &= ~FF_VDPAU_STATE_USED_FOR_RENDER; ++ } ++ else if (msg->signal == CMixerDataProtocol::BUFFER) ++ { ++ VdpOutputSurface *surf; ++ surf = (VdpOutputSurface*)msg->data; ++ m_outputSurfaces.push(*surf); ++ } ++ msg->Release(); ++ } ++} ++ ++void CMixer::InitCycle() ++{ ++ CheckFeatures(); ++ uint64_t latency; ++ int speed; ++ m_config.stats->GetParams(latency, speed); ++ latency = (latency*1000)/CurrentHostFrequency(); ++ if (speed != DVD_PLAYSPEED_NORMAL) ++ SetPostProcFeatures(false); ++ else ++ SetPostProcFeatures(true); ++ ++ m_config.stats->SetCanSkipDeint(false); ++ ++ EDEINTERLACEMODE mode = g_settings.m_currentVideoSettings.m_DeinterlaceMode; ++ EINTERLACEMETHOD method = GetDeinterlacingMethod(); ++ bool interlaced = m_mixerInput[1].DVDPic.iFlags & DVP_FLAG_INTERLACED; ++ ++ if (mode == VS_DEINTERLACEMODE_FORCE || ++ (mode == VS_DEINTERLACEMODE_AUTO && interlaced)) ++ { ++ if((method == VS_INTERLACEMETHOD_AUTO && interlaced) ++ || method == VS_INTERLACEMETHOD_VDPAU_BOB ++ || method == VS_INTERLACEMETHOD_VDPAU_TEMPORAL ++ || method == VS_INTERLACEMETHOD_VDPAU_TEMPORAL_HALF ++ || method == VS_INTERLACEMETHOD_VDPAU_TEMPORAL_SPATIAL ++ || method == VS_INTERLACEMETHOD_VDPAU_TEMPORAL_SPATIAL_HALF ++ || method == VS_INTERLACEMETHOD_VDPAU_INVERSE_TELECINE ) ++ { ++ if(method == VS_INTERLACEMETHOD_VDPAU_TEMPORAL_HALF ++ || method == VS_INTERLACEMETHOD_VDPAU_TEMPORAL_SPATIAL_HALF ++ || !g_graphicsContext.IsFullScreenVideo()) ++ m_mixersteps = 1; ++ else ++ { ++ m_mixersteps = 2; ++ m_config.stats->SetCanSkipDeint(true); ++ } ++ ++ if (m_mixerInput[1].DVDPic.iFlags & DVP_FLAG_DROPDEINT) ++ { ++ m_mixersteps = 1; ++ } ++ ++ if(m_mixerInput[1].DVDPic.iFlags & DVP_FLAG_TOP_FIELD_FIRST) ++ m_mixerfield = VDP_VIDEO_MIXER_PICTURE_STRUCTURE_TOP_FIELD; ++ else ++ m_mixerfield = VDP_VIDEO_MIXER_PICTURE_STRUCTURE_BOTTOM_FIELD; ++ ++ m_mixerInput[1].DVDPic.format = DVDVideoPicture::FMT_VDPAU; ++ m_mixerInput[1].DVDPic.iFlags &= ~(DVP_FLAG_TOP_FIELD_FIRST | ++ DVP_FLAG_REPEAT_TOP_FIELD | ++ DVP_FLAG_INTERLACED); ++ m_config.useInteropYuv = false; ++ } ++ else if (method == VS_INTERLACEMETHOD_RENDER_BOB && m_config.useInteropYuv) ++ { ++ m_mixersteps = 1; ++ m_mixerfield = VDP_VIDEO_MIXER_PICTURE_STRUCTURE_FRAME; ++ m_mixerInput[1].DVDPic.format = DVDVideoPicture::FMT_VDPAU_420; ++ } ++ else ++ { ++ CLog::Log(LOGERROR, "CMixer::%s - interlace method not supported", __FUNCTION__); ++ m_mixersteps = 1; ++ m_mixerfield = VDP_VIDEO_MIXER_PICTURE_STRUCTURE_FRAME; ++ m_mixerInput[1].DVDPic.format = DVDVideoPicture::FMT_VDPAU; ++ m_mixerInput[1].DVDPic.iFlags &= ~(DVP_FLAG_TOP_FIELD_FIRST | ++ DVP_FLAG_REPEAT_TOP_FIELD | ++ DVP_FLAG_INTERLACED); ++ } ++ } ++ else ++ { ++ m_mixersteps = 1; ++ m_mixerfield = VDP_VIDEO_MIXER_PICTURE_STRUCTURE_FRAME; ++ ++ if (m_config.useInteropYuv) ++ m_mixerInput[1].DVDPic.format = DVDVideoPicture::FMT_VDPAU_420; ++ else ++ { ++ m_mixerInput[1].DVDPic.format = DVDVideoPicture::FMT_VDPAU; ++ m_mixerInput[1].DVDPic.iFlags &= ~(DVP_FLAG_TOP_FIELD_FIRST | ++ DVP_FLAG_REPEAT_TOP_FIELD | ++ DVP_FLAG_INTERLACED); ++ } ++ } ++ m_mixerstep = 0; ++ ++ if (m_mixerInput[1].DVDPic.format == DVDVideoPicture::FMT_VDPAU) ++ { ++ m_processPicture.outputSurface = m_outputSurfaces.front(); ++ m_mixerInput[1].DVDPic.iWidth = m_config.outWidth; ++ m_mixerInput[1].DVDPic.iHeight = m_config.outHeight; ++ } ++ else ++ { ++ m_mixerInput[1].DVDPic.iWidth = m_config.vidWidth; ++ m_mixerInput[1].DVDPic.iHeight = m_config.vidHeight; ++ } ++ ++ m_processPicture.DVDPic = m_mixerInput[1].DVDPic; ++ m_processPicture.render = m_mixerInput[1].render; ++} ++ ++void CMixer::FiniCycle() ++{ ++ while (m_mixerInput.size() > 3) ++ { ++ CVdpauDecodedPicture &tmp = m_mixerInput.back(); ++ if (tmp.render && m_processPicture.DVDPic.format != DVDVideoPicture::FMT_VDPAU_420) ++ { ++ CSingleLock lock(*m_config.videoSurfaceSec); ++ tmp.render->state &= ~FF_VDPAU_STATE_USED_FOR_RENDER; ++ } ++ m_mixerInput.pop_back(); ++// m_config.stats->DecDecoded(); ++ } ++} ++ ++void CMixer::ProcessPicture() ++{ ++ if (m_processPicture.DVDPic.format == DVDVideoPicture::FMT_VDPAU_420) ++ return; ++ ++ int cmd = 0; ++ m_config.stats->GetCmd(cmd); ++ if (cmd & DVP_FLAG_SKIP_PROC) ++ { ++ m_processPicture.DVDPic.iFlags |= DVP_FLAG_DROPPED; ++ return; ++ } ++ ++ VdpStatus vdp_st; ++ ++ if (m_mixerstep == 1) ++ { ++ if(m_mixerfield == VDP_VIDEO_MIXER_PICTURE_STRUCTURE_TOP_FIELD) ++ m_mixerfield = VDP_VIDEO_MIXER_PICTURE_STRUCTURE_BOTTOM_FIELD; ++ else ++ m_mixerfield = VDP_VIDEO_MIXER_PICTURE_STRUCTURE_TOP_FIELD; ++ } ++ ++ VdpVideoSurface past_surfaces[4] = { VDP_INVALID_HANDLE, VDP_INVALID_HANDLE, VDP_INVALID_HANDLE, VDP_INVALID_HANDLE }; ++ VdpVideoSurface futu_surfaces[2] = { VDP_INVALID_HANDLE, VDP_INVALID_HANDLE }; ++ uint32_t pastCount = 4; ++ uint32_t futuCount = 2; ++ ++ if(m_mixerfield == VDP_VIDEO_MIXER_PICTURE_STRUCTURE_FRAME) ++ { ++ // use only 2 past 1 future for progressive/weave ++ // (only used for postproc anyway eg noise reduction) ++ if (m_mixerInput.size() > 3) ++ past_surfaces[1] = m_mixerInput[3].render->surface; ++ if (m_mixerInput.size() > 2) ++ past_surfaces[0] = m_mixerInput[2].render->surface; ++ futu_surfaces[0] = m_mixerInput[0].render->surface; ++ pastCount = 2; ++ futuCount = 1; ++ } ++ else ++ { ++ if(m_mixerstep == 0) ++ { // first field ++ if (m_mixerInput.size() > 3) ++ { ++ past_surfaces[3] = m_mixerInput[3].render->surface; ++ past_surfaces[2] = m_mixerInput[3].render->surface; ++ } ++ if (m_mixerInput.size() > 2) ++ { ++ past_surfaces[1] = m_mixerInput[2].render->surface; ++ past_surfaces[0] = m_mixerInput[2].render->surface; ++ } ++ futu_surfaces[0] = m_mixerInput[1].render->surface; ++ futu_surfaces[1] = m_mixerInput[0].render->surface;; ++ } ++ else ++ { // second field ++ if (m_mixerInput.size() > 3) ++ { ++ past_surfaces[3] = m_mixerInput[3].render->surface; ++ } ++ if (m_mixerInput.size() > 2) ++ { ++ past_surfaces[2] = m_mixerInput[2].render->surface; ++ past_surfaces[1] = m_mixerInput[2].render->surface; ++ } ++ past_surfaces[0] = m_mixerInput[1].render->surface; ++ futu_surfaces[0] = m_mixerInput[1].render->surface; ++ futu_surfaces[1] = m_mixerInput[1].render->surface; ++ ++ m_processPicture.DVDPic.pts = DVD_NOPTS_VALUE; ++ m_processPicture.DVDPic.dts = DVD_NOPTS_VALUE; ++ } ++ m_processPicture.DVDPic.iRepeatPicture = 0.0; ++ } // interlaced ++ ++ VdpRect sourceRect; ++ sourceRect.x0 = 0; ++ sourceRect.y0 = 0; ++ sourceRect.x1 = m_config.vidWidth; ++ sourceRect.y1 = m_config.vidHeight; ++ ++ VdpRect destRect; ++ destRect.x0 = 0; ++ destRect.y0 = 0; ++ destRect.x1 = m_config.outWidth; ++ destRect.y1 = m_config.outHeight; ++ ++ // start vdpau video mixer ++ vdp_st = m_config.vdpProcs.vdp_video_mixer_render(m_videoMixer, ++ VDP_INVALID_HANDLE, ++ 0, ++ m_mixerfield, ++ pastCount, ++ past_surfaces, ++ m_mixerInput[1].render->surface, ++ futuCount, ++ futu_surfaces, ++ &sourceRect, ++ m_processPicture.outputSurface, ++ &destRect, ++ &destRect, ++ 0, ++ NULL); ++ CheckStatus(vdp_st, __LINE__); ++ ++ if (m_mixerfield != VDP_VIDEO_MIXER_PICTURE_STRUCTURE_FRAME) ++ { ++ // in order to clip top and bottom lines when de-interlacing ++ // we black those lines as a work around for not working ++ // background colour using the mixer ++ // pixel perfect is preferred over overscanning or zooming ++ ++ VdpRect clipRect = destRect; ++ clipRect.y1 = clipRect.y0 + 2; ++ uint32_t *data[] = {m_BlackBar}; ++ uint32_t pitches[] = {destRect.x1}; ++ vdp_st = m_config.vdpProcs.vdp_output_surface_put_bits_native(m_processPicture.outputSurface, ++ (void**)data, ++ pitches, ++ &clipRect); ++ CheckStatus(vdp_st, __LINE__); ++ ++ clipRect = destRect; ++ clipRect.y0 = clipRect.y1 - 2; ++ vdp_st = m_config.vdpProcs.vdp_output_surface_put_bits_native(m_processPicture.outputSurface, ++ (void**)data, ++ pitches, ++ &clipRect); ++ CheckStatus(vdp_st, __LINE__); ++ } ++} ++ ++ ++bool CMixer::CheckStatus(VdpStatus vdp_st, int line) ++{ ++ if (vdp_st != VDP_STATUS_OK) ++ { ++ CLog::Log(LOGERROR, " (VDPAU) Error: %s(%d) at %s:%d\n", m_config.vdpProcs.vdp_get_error_string(vdp_st), vdp_st, __FILE__, line); ++ m_vdpError = true; ++ return true; ++ } ++ return false; ++} ++ ++//----------------------------------------------------------------------------- ++// Output ++//----------------------------------------------------------------------------- ++COutput::COutput(CEvent *inMsgEvent) : ++ CThread("Vdpau Output Thread"), ++ m_controlPort("OutputControlPort", inMsgEvent, &m_outMsgEvent), ++ m_dataPort("OutputDataPort", inMsgEvent, &m_outMsgEvent), ++ m_mixer(&m_outMsgEvent) ++{ ++ m_inMsgEvent = inMsgEvent; ++ ++ CVdpauRenderPicture pic; ++ pic.renderPicSection = &m_bufferPool.renderPicSec; ++ pic.refCount = 0; ++ for (unsigned int i = 0; i < NUM_RENDER_PICS; i++) ++ { ++ m_bufferPool.allRenderPics.push_back(pic); ++ } ++ for (unsigned int i = 0; i < m_bufferPool.allRenderPics.size(); ++i) ++ { ++ m_bufferPool.freeRenderPics.push_back(&m_bufferPool.allRenderPics[i]); ++ } ++} ++ ++void COutput::Start() ++{ ++ Create(); ++} ++ ++COutput::~COutput() ++{ ++ Dispose(); ++ ++ m_bufferPool.freeRenderPics.clear(); ++ m_bufferPool.usedRenderPics.clear(); ++ m_bufferPool.allRenderPics.clear(); ++} ++ ++void COutput::Dispose() ++{ ++ CSingleLock lock(g_graphicsContext); ++ m_bStop = true; ++ m_outMsgEvent.Set(); ++ StopThread(); ++ m_controlPort.Purge(); ++ m_dataPort.Purge(); ++} ++ ++void COutput::OnStartup() ++{ ++ CLog::Log(LOGNOTICE, "COutput::OnStartup: Output Thread created"); ++} ++ ++void COutput::OnExit() ++{ ++ CLog::Log(LOGNOTICE, "COutput::OnExit: Output Thread terminated"); ++} ++ ++enum OUTPUT_STATES ++{ ++ O_TOP = 0, // 0 ++ O_TOP_ERROR, // 1 ++ O_TOP_UNCONFIGURED, // 2 ++ O_TOP_CONFIGURED, // 3 ++ O_TOP_CONFIGURED_IDLE, // 4 ++ O_TOP_CONFIGURED_WORK, // 5 ++}; ++ ++int VDPAU_OUTPUT_parentStates[] = { ++ -1, ++ 0, //TOP_ERROR ++ 0, //TOP_UNCONFIGURED ++ 0, //TOP_CONFIGURED ++ 3, //TOP_CONFIGURED_IDLE ++ 3, //TOP_CONFIGURED_WORK ++}; ++ ++void COutput::StateMachine(int signal, Protocol *port, Message *msg) ++{ ++ for (int state = m_state; ; state = VDPAU_OUTPUT_parentStates[state]) ++ { ++ switch (state) ++ { ++ case O_TOP: // TOP ++ if (port == &m_controlPort) ++ { ++ switch (signal) ++ { ++ case COutputControlProtocol::FLUSH: ++ msg->Reply(COutputControlProtocol::ACC); ++ return; ++ case COutputControlProtocol::PRECLEANUP: ++ msg->Reply(COutputControlProtocol::ACC); ++ return; ++ default: ++ break; ++ } ++ } ++ else if (port == &m_dataPort) ++ { ++ switch (signal) ++ { ++ case COutputDataProtocol::RETURNPIC: ++ CVdpauRenderPicture *pic; ++ pic = *((CVdpauRenderPicture**)msg->data); ++ ProcessReturnPicture(pic); ++ return; ++ default: ++ break; ++ } ++ } ++ { ++ std::string portName = port == NULL ? "timer" : port->portName; ++ CLog::Log(LOGWARNING, "COutput::%s - signal: %d form port: %s not handled for state: %d", __FUNCTION__, signal, portName.c_str(), m_state); ++ } ++ return; ++ ++ case O_TOP_ERROR: ++ break; ++ ++ case O_TOP_UNCONFIGURED: ++ if (port == &m_controlPort) ++ { ++ switch (signal) ++ { ++ case COutputControlProtocol::INIT: ++ CVdpauConfig *data; ++ data = (CVdpauConfig*)msg->data; ++ if (data) ++ { ++ m_config = *data; ++ } ++ Init(); ++ Message *reply; ++ if (m_mixer.m_controlPort.SendOutMessageSync(CMixerControlProtocol::INIT, ++ &reply, 1000, &m_config, sizeof(m_config))) ++ { ++ if (reply->signal != CMixerControlProtocol::ACC) ++ m_vdpError = true; ++ reply->Release(); ++ } ++ ++ // set initial number of ++ m_bufferPool.numOutputSurfaces = 4; ++ EnsureBufferPool(); ++ if (!m_vdpError) ++ { ++ m_state = O_TOP_CONFIGURED_IDLE; ++ msg->Reply(COutputControlProtocol::ACC); ++ } ++ else ++ { ++ m_state = O_TOP_ERROR; ++ msg->Reply(COutputControlProtocol::ERROR); ++ } ++ return; ++ default: ++ break; ++ } ++ } ++ break; ++ ++ case O_TOP_CONFIGURED: ++ if (port == &m_controlPort) ++ { ++ switch (signal) ++ { ++ case COutputControlProtocol::FLUSH: ++ Flush(); ++ msg->Reply(COutputControlProtocol::ACC); ++ return; ++ case COutputControlProtocol::PRECLEANUP: ++ Flush(); ++ msg->Reply(COutputControlProtocol::ACC); ++ return; ++ default: ++ break; ++ } ++ } ++ else if (port == &m_dataPort) ++ { ++ switch (signal) ++ { ++ case COutputDataProtocol::NEWFRAME: ++ CVdpauDecodedPicture *frame; ++ frame = (CVdpauDecodedPicture*)msg->data; ++ if (frame) ++ { ++ m_mixer.m_dataPort.SendOutMessage(CMixerDataProtocol::FRAME, ++ frame,sizeof(CVdpauDecodedPicture)); ++ } ++ return; ++ case COutputDataProtocol::RETURNPIC: ++ CVdpauRenderPicture *pic; ++ pic = *((CVdpauRenderPicture**)msg->data); ++ ProcessReturnPicture(pic); ++ m_controlPort.SendInMessage(COutputControlProtocol::STATS); ++ m_state = O_TOP_CONFIGURED_WORK; ++ m_extTimeout = 0; ++ return; ++ default: ++ break; ++ } ++ } ++ else if (port == &m_mixer.m_dataPort) ++ { ++ switch (signal) ++ { ++ case CMixerDataProtocol::PICTURE: ++ CVdpauProcessedPicture *pic; ++ pic = (CVdpauProcessedPicture*)msg->data; ++ m_bufferPool.processedPics.push(*pic); ++ m_state = O_TOP_CONFIGURED_WORK; ++ m_extTimeout = 0; ++ return; ++ default: ++ break; ++ } ++ } ++ break; ++ ++ case O_TOP_CONFIGURED_IDLE: ++ if (port == NULL) // timeout ++ { ++ switch (signal) ++ { ++ case COutputControlProtocol::TIMEOUT: ++// uint16_t decoded, processed, render; ++// m_config.stats->Get(decoded, processed, render); ++// CLog::Log(LOGDEBUG, "CVDPAU::COutput - timeout idle: decoded: %d, proc: %d, render: %d", decoded, processed, render); ++ return; ++ default: ++ break; ++ } ++ } ++ break; ++ ++ case O_TOP_CONFIGURED_WORK: ++ if (port == NULL) // timeout ++ { ++ switch (signal) ++ { ++ case COutputControlProtocol::TIMEOUT: ++ if (HasWork()) ++ { ++ CVdpauRenderPicture *pic; ++ pic = ProcessMixerPicture(); ++ if (pic) ++ { ++ m_config.stats->DecProcessed(); ++ m_config.stats->IncRender(); ++ m_dataPort.SendInMessage(COutputDataProtocol::PICTURE, &pic, sizeof(pic)); ++ } ++ m_extTimeout = 1; ++ } ++ else ++ { ++ m_state = O_TOP_CONFIGURED_IDLE; ++ m_extTimeout = 100; ++ } ++ return; ++ default: ++ break; ++ } ++ } ++ break; ++ ++ default: // we are in no state, should not happen ++ CLog::Log(LOGERROR, "COutput::%s - no valid state: %d", __FUNCTION__, m_state); ++ return; ++ } ++ } // for ++} ++ ++void COutput::Process() ++{ ++ Message *msg; ++ Protocol *port; ++ bool gotMsg; ++ ++ m_state = O_TOP_UNCONFIGURED; ++ m_extTimeout = 1000; ++ m_bStateMachineSelfTrigger = false; ++ ++ while (!m_bStop) ++ { ++ gotMsg = false; ++ ++ if (m_bStateMachineSelfTrigger) ++ { ++ m_bStateMachineSelfTrigger = false; ++ // self trigger state machine ++ StateMachine(msg->signal, port, msg); ++ if (!m_bStateMachineSelfTrigger) ++ { ++ msg->Release(); ++ msg = NULL; ++ } ++ continue; ++ } ++ // check control port ++ else if (m_controlPort.ReceiveOutMessage(&msg)) ++ { ++ gotMsg = true; ++ port = &m_controlPort; ++ } ++ // check data port ++ else if (m_dataPort.ReceiveOutMessage(&msg)) ++ { ++ gotMsg = true; ++ port = &m_dataPort; ++ } ++ // check mixer data port ++ else if (m_mixer.m_dataPort.ReceiveInMessage(&msg)) ++ { ++ gotMsg = true; ++ port = &m_mixer.m_dataPort; ++ } ++ if (gotMsg) ++ { ++ StateMachine(msg->signal, port, msg); ++ if (!m_bStateMachineSelfTrigger) ++ { ++ msg->Release(); ++ msg = NULL; ++ } ++ continue; ++ } ++ ++ // wait for message ++ else if (m_outMsgEvent.WaitMSec(m_extTimeout)) ++ { ++ continue; ++ } ++ // time out ++ else ++ { ++ msg = m_controlPort.GetMessage(); ++ msg->signal = COutputControlProtocol::TIMEOUT; ++ port = 0; ++ // signal timeout to state machine ++ StateMachine(msg->signal, port, msg); ++ if (!m_bStateMachineSelfTrigger) ++ { ++ msg->Release(); ++ msg = NULL; ++ } ++ } ++ } ++ Flush(); ++ Uninit(); ++} ++ ++bool COutput::Init() ++{ ++ if (!CreateGlxContext()) ++ return false; ++ ++ if (!GLInit()) ++ return false; ++ ++ m_mixer.Start(); ++ m_vdpError = false; ++ ++ return true; ++} ++ ++bool COutput::Uninit() ++{ ++ m_mixer.Dispose(); ++ GLUnmapSurfaces(); ++ GLUnbindPixmaps(); ++ ReleaseBufferPool(); ++ DestroyGlxContext(); ++ return true; ++} ++ ++void COutput::Flush() ++{ ++ Message *reply; ++ if (m_mixer.m_controlPort.SendOutMessageSync(CMixerControlProtocol::FLUSH, ++ &reply, ++ 2000)) ++ { ++ reply->Release(); ++ } ++ else ++ CLog::Log(LOGERROR, "Coutput::%s - failed to flush mixer", __FUNCTION__); ++ ++ Message *msg; ++ while (m_mixer.m_dataPort.ReceiveInMessage(&msg)) ++ { ++ if (msg->signal == CMixerDataProtocol::PICTURE) ++ { ++ CVdpauProcessedPicture pic = *(CVdpauProcessedPicture*)msg->data; ++ if (pic.DVDPic.format == DVDVideoPicture::FMT_VDPAU_420) ++ { ++ CSingleLock lock(*m_config.videoSurfaceSec); ++ if (pic.render) ++ pic.render->state &= ~FF_VDPAU_STATE_USED_FOR_RENDER; ++ } ++ } ++ msg->Release(); ++ } ++ ++ while (m_dataPort.ReceiveOutMessage(&msg)) ++ { ++ if (msg->signal == COutputDataProtocol::NEWFRAME) ++ { ++ CVdpauDecodedPicture pic = *(CVdpauDecodedPicture*)msg->data; ++ CSingleLock lock(*m_config.videoSurfaceSec); ++ if (pic.render) ++ pic.render->state &= ~FF_VDPAU_STATE_USED_FOR_RENDER; ++ } ++ else if (msg->signal == COutputDataProtocol::RETURNPIC) ++ { ++ CVdpauRenderPicture *pic; ++ pic = *((CVdpauRenderPicture**)msg->data); ++ ProcessReturnPicture(pic); ++ } ++ msg->Release(); ++ } ++ ++ while (m_dataPort.ReceiveInMessage(&msg)) ++ { ++ if (msg->signal == COutputDataProtocol::PICTURE) ++ { ++ CVdpauRenderPicture *pic; ++ pic = *((CVdpauRenderPicture**)msg->data); ++ ProcessReturnPicture(pic); ++ } ++ } ++ ++ // reset used render flag which was cleared on mixer flush ++ std::deque::iterator it; ++ for (it = m_bufferPool.usedRenderPics.begin(); it != m_bufferPool.usedRenderPics.end(); ++it) ++ { ++ if ((*it)->DVDPic.format == DVDVideoPicture::FMT_VDPAU_420) ++ { ++ std::map::iterator it2; ++ it2 = m_bufferPool.glVideoSurfaceMap.find((*it)->sourceIdx); ++ if (it2 == m_bufferPool.glVideoSurfaceMap.end()) ++ { ++ CLog::Log(LOGDEBUG, "COutput::Flush - gl surface not found"); ++ continue; ++ } ++ vdpau_render_state *render = it2->second.sourceVuv; ++ if (render) ++ render->state |= FF_VDPAU_STATE_USED_FOR_RENDER; ++ } ++ } ++} ++ ++bool COutput::HasWork() ++{ ++ if (m_config.usePixmaps) ++ { ++ if (!m_bufferPool.processedPics.empty() && FindFreePixmap() >= 0) ++ return true; ++ if (!m_bufferPool.notVisiblePixmaps.empty() && !m_bufferPool.freeRenderPics.empty()) ++ return true; ++ return false; ++ } ++ else ++ { ++ if (!m_bufferPool.processedPics.empty() && !m_bufferPool.freeRenderPics.empty()) ++ return true; ++ return false; ++ } ++} ++ ++CVdpauRenderPicture* COutput::ProcessMixerPicture() ++{ ++ CVdpauRenderPicture *retPic = 0; ++ ++ if (m_config.usePixmaps) ++ { ++ if (!m_bufferPool.processedPics.empty() && FindFreePixmap() >= 0) ++ { ++ unsigned int i = FindFreePixmap(); ++ VdpauBufferPool::Pixmaps *pixmap = &m_bufferPool.pixmaps[i]; ++ pixmap->used = true; ++ CVdpauProcessedPicture pic = m_bufferPool.processedPics.front(); ++ m_bufferPool.processedPics.pop(); ++ pixmap->surface = pic.outputSurface; ++ pixmap->DVDPic = pic.DVDPic; ++ pixmap->id = i; ++ m_bufferPool.notVisiblePixmaps.push_back(pixmap); ++ VdpStatus vdp_st; ++ m_config.vdpProcs.vdp_presentation_queue_display(pixmap->vdp_flip_queue, ++ pixmap->surface,0,0,0); ++ } ++ if (!m_bufferPool.notVisiblePixmaps.empty() && !m_bufferPool.freeRenderPics.empty()) ++ { ++ VdpStatus vdp_st; ++ VdpTime time; ++ VdpPresentationQueueStatus status; ++ VdpauBufferPool::Pixmaps *pixmap = m_bufferPool.notVisiblePixmaps.front(); ++ vdp_st = m_config.vdpProcs.vdp_presentation_queue_query_surface_status( ++ pixmap->vdp_flip_queue, pixmap->surface, &status, &time); ++ ++ if (vdp_st == VDP_STATUS_OK && status == VDP_PRESENTATION_QUEUE_STATUS_VISIBLE) ++ { ++ retPic = m_bufferPool.freeRenderPics.front(); ++ m_bufferPool.freeRenderPics.pop_front(); ++ m_bufferPool.usedRenderPics.push_back(retPic); ++ retPic->sourceIdx = pixmap->id; ++ retPic->DVDPic = pixmap->DVDPic; ++ retPic->valid = true; ++ retPic->texture[0] = pixmap->texture; ++ retPic->crop = CRect(0,0,0,0); ++ m_bufferPool.notVisiblePixmaps.pop_front(); ++ m_mixer.m_dataPort.SendOutMessage(CMixerDataProtocol::BUFFER, &pixmap->surface, sizeof(pixmap->surface)); ++ } ++ } ++ } // pixmap ++ else if (!m_bufferPool.processedPics.empty() && !m_bufferPool.freeRenderPics.empty()) ++ { ++ retPic = m_bufferPool.freeRenderPics.front(); ++ m_bufferPool.freeRenderPics.pop_front(); ++ m_bufferPool.usedRenderPics.push_back(retPic); ++ CVdpauProcessedPicture procPic = m_bufferPool.processedPics.front(); ++ m_bufferPool.processedPics.pop(); ++ ++ retPic->DVDPic = procPic.DVDPic; ++ retPic->valid = true; ++ if (retPic->DVDPic.format == DVDVideoPicture::FMT_VDPAU) ++ { ++ m_config.useInteropYuv = false; ++ m_bufferPool.numOutputSurfaces = NUM_RENDER_PICS; ++ EnsureBufferPool(); ++ GLMapSurfaces(); ++ retPic->sourceIdx = procPic.outputSurface; ++ retPic->texture[0] = m_bufferPool.glOutputSurfaceMap[procPic.outputSurface].texture[0]; ++ retPic->crop = CRect(0,0,0,0); ++ } ++ else ++ { ++ m_config.useInteropYuv = true; ++ GLMapSurfaces(); ++ retPic->sourceIdx = procPic.render->surface; ++ for (unsigned int i=0; i<4; ++i) ++ retPic->texture[i] = m_bufferPool.glVideoSurfaceMap[procPic.render->surface].texture[i]; ++ retPic->texWidth = m_config.surfaceWidth; ++ retPic->texHeight = m_config.surfaceHeight; ++ retPic->crop.x1 = 0; ++ retPic->crop.y1 = 0; ++ retPic->crop.x2 = m_config.surfaceWidth - m_config.vidWidth; ++ retPic->crop.y2 = m_config.surfaceHeight - m_config.vidHeight; ++ } ++ } ++ return retPic; ++} ++ ++void COutput::ProcessReturnPicture(CVdpauRenderPicture *pic) ++{ ++ std::deque::iterator it; ++ it = std::find(m_bufferPool.usedRenderPics.begin(), m_bufferPool.usedRenderPics.end(), pic); ++ if (it == m_bufferPool.usedRenderPics.end()) ++ { ++ CLog::Log(LOGWARNING, "COutput::ProcessReturnPicture - pic not found"); ++ return; ++ } ++ m_bufferPool.usedRenderPics.erase(it); ++ m_bufferPool.freeRenderPics.push_back(pic); ++ if (!pic->valid) ++ { ++ CLog::Log(LOGDEBUG, "COutput::%s - return of invalid render pic", __FUNCTION__); ++ return; ++ } ++ ++ if (m_config.usePixmaps) ++ { ++ m_bufferPool.pixmaps[pic->sourceIdx].used = false; ++ return; ++ } ++ else if (pic->DVDPic.format == DVDVideoPicture::FMT_VDPAU_420) ++ { ++ std::map::iterator it; ++ it = m_bufferPool.glVideoSurfaceMap.find(pic->sourceIdx); ++ if (it == m_bufferPool.glVideoSurfaceMap.end()) ++ { ++ CLog::Log(LOGDEBUG, "COutput::ProcessReturnPicture - gl surface not found"); ++ return; ++ } ++ vdpau_render_state *render = it->second.sourceVuv; ++ CSingleLock lock(*m_config.videoSurfaceSec); ++ render->state &= ~FF_VDPAU_STATE_USED_FOR_RENDER; ++ } ++ else if (pic->DVDPic.format == DVDVideoPicture::FMT_VDPAU) ++ { ++ std::map::iterator it; ++ it = m_bufferPool.glOutputSurfaceMap.find(pic->sourceIdx); ++ if (it == m_bufferPool.glOutputSurfaceMap.end()) ++ { ++ CLog::Log(LOGDEBUG, "COutput::ProcessReturnPicture - gl surface not found"); ++ return; ++ } ++ VdpOutputSurface outSurf = it->second.sourceRgb; ++ m_mixer.m_dataPort.SendOutMessage(CMixerDataProtocol::BUFFER, &outSurf, sizeof(outSurf)); ++ } ++} ++ ++int COutput::FindFreePixmap() ++{ ++ // find free pixmap ++ unsigned int i; ++ for (i = 0; i < m_bufferPool.pixmaps.size(); ++i) ++ { ++ if (!m_bufferPool.pixmaps[i].used) ++ break; ++ } ++ if (i == m_bufferPool.pixmaps.size()) ++ return -1; ++ else ++ return i; ++} ++ ++bool COutput::EnsureBufferPool() ++{ ++ VdpStatus vdp_st; ++ ++ // Creation of outputSurfaces ++ VdpOutputSurface outputSurface; ++ for (int i = m_bufferPool.outputSurfaces.size(); i < m_bufferPool.numOutputSurfaces; i++) ++ { ++ vdp_st = m_config.vdpProcs.vdp_output_surface_create(m_config.vdpDevice, ++ VDP_RGBA_FORMAT_B8G8R8A8, ++ m_config.outWidth, ++ m_config.outHeight, ++ &outputSurface); ++ if (CheckStatus(vdp_st, __LINE__)) ++ return false; ++ m_bufferPool.outputSurfaces.push_back(outputSurface); ++ ++ m_mixer.m_dataPort.SendOutMessage(CMixerDataProtocol::BUFFER, ++ &outputSurface, ++ sizeof(VdpOutputSurface)); ++ CLog::Log(LOGNOTICE, "VDPAU::COutput::InitBufferPool - Output Surface created"); ++ } ++ ++ ++ if (m_config.usePixmaps && m_bufferPool.pixmaps.empty()) ++ { ++ // create pixmpas ++ VdpauBufferPool::Pixmaps pixmap; ++ int numPixmaps = NUM_RENDER_PICS; ++ for (unsigned int i = 0; i < numPixmaps; i++) ++ { ++ pixmap.pixmap = None; ++ pixmap.glPixmap = None; ++ pixmap.vdp_flip_queue = VDP_INVALID_HANDLE; ++ pixmap.vdp_flip_target = VDP_INVALID_HANDLE; ++ MakePixmap(pixmap); ++ glXMakeCurrent(m_Display, None, NULL); ++ vdp_st = m_config.vdpProcs.vdp_presentation_queue_target_create_x11(m_config.vdpDevice, ++ pixmap.pixmap, //x_window, ++ &pixmap.vdp_flip_target); ++ ++ CheckStatus(vdp_st, __LINE__); ++ ++ vdp_st = m_config.vdpProcs.vdp_presentation_queue_create(m_config.vdpDevice, ++ pixmap.vdp_flip_target, ++ &pixmap.vdp_flip_queue); ++ CheckStatus(vdp_st, __LINE__); ++ glXMakeCurrent(m_Display, m_glPixmap, m_glContext); ++ ++ pixmap.id = i; ++ pixmap.used = false; ++ m_bufferPool.pixmaps.push_back(pixmap); ++ } ++ GLBindPixmaps(); ++ } ++ ++ return true; ++} ++ ++void COutput::ReleaseBufferPool() ++{ ++ VdpStatus vdp_st; ++ ++ CSingleLock lock(m_bufferPool.renderPicSec); ++ ++ if (m_config.usePixmaps) ++ { ++ for (unsigned int i = 0; i < m_bufferPool.pixmaps.size(); ++i) ++ { ++ if (m_bufferPool.pixmaps[i].vdp_flip_queue != VDP_INVALID_HANDLE) ++ { ++ vdp_st = m_config.vdpProcs.vdp_presentation_queue_destroy(m_bufferPool.pixmaps[i].vdp_flip_queue); ++ CheckStatus(vdp_st, __LINE__); ++ } ++ if (m_bufferPool.pixmaps[i].vdp_flip_target != VDP_INVALID_HANDLE) ++ { ++ vdp_st = m_config.vdpProcs.vdp_presentation_queue_target_destroy(m_bufferPool.pixmaps[i].vdp_flip_target); ++ CheckStatus(vdp_st, __LINE__); ++ } ++ if (m_bufferPool.pixmaps[i].glPixmap) ++ { ++ glXDestroyPixmap(m_Display, m_bufferPool.pixmaps[i].glPixmap); ++ } ++ if (m_bufferPool.pixmaps[i].pixmap) ++ { ++ XFreePixmap(m_Display, m_bufferPool.pixmaps[i].pixmap); ++ } ++ } ++ m_bufferPool.pixmaps.clear(); ++ } ++ ++ // release all output surfaces ++ for (unsigned int i = 0; i < m_bufferPool.outputSurfaces.size(); ++i) ++ { ++ if (m_bufferPool.outputSurfaces[i] == VDP_INVALID_HANDLE) ++ continue; ++ vdp_st = m_config.vdpProcs.vdp_output_surface_destroy(m_bufferPool.outputSurfaces[i]); ++ CheckStatus(vdp_st, __LINE__); ++ } ++ m_bufferPool.outputSurfaces.clear(); ++ ++ // invalidate all used render pictures ++ for (unsigned int i = 0; i < m_bufferPool.usedRenderPics.size(); ++i) ++ { ++ m_bufferPool.usedRenderPics[i]->valid = false; ++ } ++} ++ ++void COutput::InitMixer() ++{ ++ for (unsigned int i = 0; i < m_bufferPool.outputSurfaces.size(); ++i) ++ { ++ m_mixer.m_dataPort.SendOutMessage(CMixerDataProtocol::BUFFER, ++ &m_bufferPool.outputSurfaces[i], ++ sizeof(VdpOutputSurface)); ++ } ++} ++ ++bool COutput::MakePixmap(VdpauBufferPool::Pixmaps &pixmap) ++{ ++ CLog::Log(LOGNOTICE,"Creating %ix%i pixmap", m_config.outWidth, m_config.outHeight); ++ ++ // Get our window attribs. ++ XWindowAttributes wndattribs; ++ XGetWindowAttributes(m_Display, DefaultRootWindow(m_Display), &wndattribs); ++ ++ pixmap.pixmap = XCreatePixmap(m_Display, ++ DefaultRootWindow(m_Display), ++ m_config.outWidth, ++ m_config.outHeight, ++ wndattribs.depth); ++ if (!pixmap.pixmap) ++ { ++ CLog::Log(LOGERROR, "VDPAU::COUtput::MakePixmap - GLX Error: MakePixmap: Unable to create XPixmap"); ++ return false; ++ } ++ ++// XGCValues values = {}; ++// GC xgc; ++// values.foreground = BlackPixel (m_Display, DefaultScreen (m_Display)); ++// xgc = XCreateGC(m_Display, pixmap.pixmap, GCForeground, &values); ++// XFillRectangle(m_Display, pixmap.pixmap, xgc, 0, 0, m_config.outWidth, m_config.outHeight); ++// XFreeGC(m_Display, xgc); ++ ++ if(!MakePixmapGL(pixmap)) ++ return false; ++ ++ return true; ++} ++ ++bool COutput::MakePixmapGL(VdpauBufferPool::Pixmaps &pixmap) ++{ ++ int num=0; ++ int fbConfigIndex = 0; ++ ++ int doubleVisAttributes[] = { ++ GLX_RENDER_TYPE, GLX_RGBA_BIT, ++ GLX_RED_SIZE, 8, ++ GLX_GREEN_SIZE, 8, ++ GLX_BLUE_SIZE, 8, ++ GLX_ALPHA_SIZE, 8, ++ GLX_DEPTH_SIZE, 8, ++ GLX_DRAWABLE_TYPE, GLX_PIXMAP_BIT, ++ GLX_BIND_TO_TEXTURE_RGBA_EXT, True, ++ GLX_DOUBLEBUFFER, False, ++ GLX_Y_INVERTED_EXT, True, ++ GLX_X_RENDERABLE, True, ++ None ++ }; ++ ++ int pixmapAttribs[] = { ++ GLX_TEXTURE_TARGET_EXT, GLX_TEXTURE_2D_EXT, ++ GLX_TEXTURE_FORMAT_EXT, GLX_TEXTURE_FORMAT_RGBA_EXT, ++ None ++ }; ++ ++ GLXFBConfig *fbConfigs; ++ fbConfigs = glXChooseFBConfig(m_Display, DefaultScreen(m_Display), doubleVisAttributes, &num); ++ if (fbConfigs==NULL) ++ { ++ CLog::Log(LOGERROR, "VDPAU::COutput::MakPixmapGL - No compatible framebuffers found"); ++ return false; ++ } ++ fbConfigIndex = 0; ++ ++ pixmap.glPixmap = glXCreatePixmap(m_Display, fbConfigs[fbConfigIndex], pixmap.pixmap, pixmapAttribs); ++ ++ if (!pixmap.glPixmap) ++ { ++ CLog::Log(LOGERROR, "VDPAU::COutput::MakPixmapGL - Could not create Pixmap"); ++ XFree(fbConfigs); ++ return false; ++ } ++ XFree(fbConfigs); ++ return true; ++} ++ ++bool COutput::GLInit() ++{ ++ glXBindTexImageEXT = NULL; ++ glXReleaseTexImageEXT = NULL; ++#ifdef GL_NV_vdpau_interop ++ glVDPAUInitNV = NULL; ++ glVDPAUFiniNV = NULL; ++ glVDPAURegisterOutputSurfaceNV = NULL; ++ glVDPAURegisterVideoSurfaceNV = NULL; ++ glVDPAUIsSurfaceNV = NULL; ++ glVDPAUUnregisterSurfaceNV = NULL; ++ glVDPAUSurfaceAccessNV = NULL; ++ glVDPAUMapSurfacesNV = NULL; ++ glVDPAUUnmapSurfacesNV = NULL; ++ glVDPAUGetSurfaceivNV = NULL; ++#endif ++ ++ m_config.usePixmaps = !g_guiSettings.GetBool("videoplayer.usevdpauinteroprgb"); ++ ++#ifdef GL_NV_vdpau_interop ++ if (glewIsSupported("GL_NV_vdpau_interop")) ++ { ++ if (!glVDPAUInitNV) ++ glVDPAUInitNV = (PFNGLVDPAUINITNVPROC)glXGetProcAddress((GLubyte *) "glVDPAUInitNV"); ++ if (!glVDPAUFiniNV) ++ glVDPAUFiniNV = (PFNGLVDPAUFININVPROC)glXGetProcAddress((GLubyte *) "glVDPAUFiniNV"); ++ if (!glVDPAURegisterOutputSurfaceNV) ++ glVDPAURegisterOutputSurfaceNV = (PFNGLVDPAUREGISTEROUTPUTSURFACENVPROC)glXGetProcAddress((GLubyte *) "glVDPAURegisterOutputSurfaceNV"); ++ if (!glVDPAURegisterVideoSurfaceNV) ++ glVDPAURegisterVideoSurfaceNV = (PFNGLVDPAUREGISTERVIDEOSURFACENVPROC)glXGetProcAddress((GLubyte *) "glVDPAURegisterVideoSurfaceNV"); ++ if (!glVDPAUIsSurfaceNV) ++ glVDPAUIsSurfaceNV = (PFNGLVDPAUISSURFACENVPROC)glXGetProcAddress((GLubyte *) "glVDPAUIsSurfaceNV"); ++ if (!glVDPAUUnregisterSurfaceNV) ++ glVDPAUUnregisterSurfaceNV = (PFNGLVDPAUUNREGISTERSURFACENVPROC)glXGetProcAddress((GLubyte *) "glVDPAUUnregisterSurfaceNV"); ++ if (!glVDPAUSurfaceAccessNV) ++ glVDPAUSurfaceAccessNV = (PFNGLVDPAUSURFACEACCESSNVPROC)glXGetProcAddress((GLubyte *) "glVDPAUSurfaceAccessNV"); ++ if (!glVDPAUMapSurfacesNV) ++ glVDPAUMapSurfacesNV = (PFNGLVDPAUMAPSURFACESNVPROC)glXGetProcAddress((GLubyte *) "glVDPAUMapSurfacesNV"); ++ if (!glVDPAUUnmapSurfacesNV) ++ glVDPAUUnmapSurfacesNV = (PFNGLVDPAUUNMAPSURFACESNVPROC)glXGetProcAddress((GLubyte *) "glVDPAUUnmapSurfacesNV"); ++ if (!glVDPAUGetSurfaceivNV) ++ glVDPAUGetSurfaceivNV = (PFNGLVDPAUGETSURFACEIVNVPROC)glXGetProcAddress((GLubyte *) "glVDPAUGetSurfaceivNV"); ++ ++ CLog::Log(LOGNOTICE, "VDPAU::COutput GL interop supported"); ++ } ++ else ++#endif ++ { ++ m_config.usePixmaps = true; ++ g_guiSettings.SetBool("videoplayer.usevdpauinteroprgb",false); ++ g_guiSettings.SetBool("videoplayer.usevdpauinteropyuv",false); ++ } ++ if (!glXBindTexImageEXT) ++ glXBindTexImageEXT = (PFNGLXBINDTEXIMAGEEXTPROC)glXGetProcAddress((GLubyte *) "glXBindTexImageEXT"); ++ if (!glXReleaseTexImageEXT) ++ glXReleaseTexImageEXT = (PFNGLXRELEASETEXIMAGEEXTPROC)glXGetProcAddress((GLubyte *) "glXReleaseTexImageEXT"); ++ ++#ifdef GL_NV_vdpau_interop ++ if (!m_config.usePixmaps) ++ { ++ while (glGetError() != GL_NO_ERROR); ++ glVDPAUInitNV(reinterpret_cast(m_config.vdpDevice), reinterpret_cast(m_config.vdpProcs.vdp_get_proc_address)); ++ if (glGetError() != GL_NO_ERROR) ++ { ++ CLog::Log(LOGERROR, "VDPAU::COutput - GLInitInterop glVDPAUInitNV failed"); ++ m_vdpError = true; ++ return false; ++ } ++ CLog::Log(LOGNOTICE, "VDPAU::COutput: vdpau gl interop initialized"); ++ } ++#endif ++ return true; ++} ++ ++void COutput::GLMapSurfaces() ++{ ++#ifdef GL_NV_vdpau_interop ++ if (m_config.usePixmaps) ++ return; ++ ++ if (m_config.useInteropYuv) ++ { ++ VdpauBufferPool::GLVideoSurface glSurface; ++ if (m_config.videoSurfaces->size() != m_bufferPool.glVideoSurfaceMap.size()) ++ { ++ CSingleLock lock(*m_config.videoSurfaceSec); ++ for (int i = 0; i < m_config.videoSurfaces->size(); i++) ++ { ++ if ((*m_config.videoSurfaces)[i]->surface == VDP_INVALID_HANDLE) ++ continue; ++ ++ if (m_bufferPool.glVideoSurfaceMap.find((*m_config.videoSurfaces)[i]->surface) == m_bufferPool.glVideoSurfaceMap.end()) ++ { ++ glSurface.sourceVuv = (*m_config.videoSurfaces)[i]; ++ while (glGetError() != GL_NO_ERROR) ; ++ glGenTextures(4, glSurface.texture); ++ if (glGetError() != GL_NO_ERROR) ++ { ++ CLog::Log(LOGERROR, "VDPAU::COutput error creating texture"); ++ m_vdpError = true; ++ } ++ glSurface.glVdpauSurface = glVDPAURegisterVideoSurfaceNV(reinterpret_cast((*m_config.videoSurfaces)[i]->surface), ++ GL_TEXTURE_2D, 4, glSurface.texture); ++ ++ if (glGetError() != GL_NO_ERROR) ++ { ++ CLog::Log(LOGERROR, "VDPAU::COutput error register video surface"); ++ m_vdpError = true; ++ } ++ glVDPAUSurfaceAccessNV(glSurface.glVdpauSurface, GL_READ_ONLY); ++ if (glGetError() != GL_NO_ERROR) ++ { ++ CLog::Log(LOGERROR, "VDPAU::COutput error setting access"); ++ m_vdpError = true; ++ } ++ glVDPAUMapSurfacesNV(1, &glSurface.glVdpauSurface); ++ if (glGetError() != GL_NO_ERROR) ++ { ++ CLog::Log(LOGERROR, "VDPAU::COutput error mapping surface"); ++ m_vdpError = true; ++ } ++ m_bufferPool.glVideoSurfaceMap[(*m_config.videoSurfaces)[i]->surface] = glSurface; ++ if (m_vdpError) ++ return; ++ CLog::Log(LOGNOTICE, "VDPAU::COutput registered surface"); ++ } ++ } ++ } ++ } ++ else ++ { ++ if (m_bufferPool.glOutputSurfaceMap.size() != m_bufferPool.numOutputSurfaces) ++ { ++ VdpauBufferPool::GLVideoSurface glSurface; ++ for (int i=m_bufferPool.glOutputSurfaceMap.size(); i(m_bufferPool.outputSurfaces[i]), ++ GL_TEXTURE_2D, 1, glSurface.texture); ++ if (glGetError() != GL_NO_ERROR) ++ { ++ CLog::Log(LOGERROR, "VDPAU::COutput error register output surface"); ++ m_vdpError = true; ++ } ++ glVDPAUSurfaceAccessNV(glSurface.glVdpauSurface, GL_READ_ONLY); ++ if (glGetError() != GL_NO_ERROR) ++ { ++ CLog::Log(LOGERROR, "VDPAU::COutput error setting access"); ++ m_vdpError = true; ++ } ++ glVDPAUMapSurfacesNV(1, &glSurface.glVdpauSurface); ++ if (glGetError() != GL_NO_ERROR) ++ { ++ CLog::Log(LOGERROR, "VDPAU::COutput error mapping surface"); ++ m_vdpError = true; ++ } ++ m_bufferPool.glOutputSurfaceMap[m_bufferPool.outputSurfaces[i]] = glSurface; ++ if (m_vdpError) ++ return; ++ } ++ CLog::Log(LOGNOTICE, "VDPAU::COutput registered output surfaces"); ++ } ++ } ++#endif ++} ++ ++void COutput::GLUnmapSurfaces() ++{ ++#ifdef GL_NV_vdpau_interop ++ if (m_config.usePixmaps) ++ return; ++ ++ { CSingleLock lock(*m_config.videoSurfaceSec); ++ std::map::iterator it; ++ for (it = m_bufferPool.glVideoSurfaceMap.begin(); it != m_bufferPool.glVideoSurfaceMap.end(); ++it) ++ { ++ glVDPAUUnregisterSurfaceNV(it->second.glVdpauSurface); ++ glDeleteTextures(4, it->second.texture); ++ } ++ m_bufferPool.glVideoSurfaceMap.clear(); ++ } ++ ++ std::map::iterator it; ++ for (it = m_bufferPool.glOutputSurfaceMap.begin(); it != m_bufferPool.glOutputSurfaceMap.end(); ++it) ++ { ++ glVDPAUUnregisterSurfaceNV(it->second.glVdpauSurface); ++ glDeleteTextures(1, it->second.texture); ++ } ++ m_bufferPool.glOutputSurfaceMap.clear(); ++ ++ glVDPAUFiniNV(); ++ ++ CLog::Log(LOGNOTICE, "VDPAU::COutput: vdpau gl interop finished"); ++ ++#endif ++} ++ ++void COutput::GLBindPixmaps() ++{ ++ if (!m_config.usePixmaps) ++ return; ++ ++ for (unsigned int i = 0; i < m_bufferPool.pixmaps.size(); i++) ++ { ++ // create texture ++ glGenTextures(1, &m_bufferPool.pixmaps[i].texture); ++ ++ //bind texture ++ glBindTexture(GL_TEXTURE_2D, m_bufferPool.pixmaps[i].texture); ++ ++ // bind pixmap ++ glXBindTexImageEXT(m_Display, m_bufferPool.pixmaps[i].glPixmap, GLX_FRONT_LEFT_EXT, NULL); ++ ++ glBindTexture(GL_TEXTURE_2D, 0); ++ } ++ ++ CLog::Log(LOGNOTICE, "VDPAU::COutput: bound pixmaps"); ++} ++ ++void COutput::GLUnbindPixmaps() ++{ ++ if (!m_config.usePixmaps) ++ return; ++ ++ for (unsigned int i = 0; i < m_bufferPool.pixmaps.size(); i++) ++ { ++ // create texture ++ if (!glIsTexture(m_bufferPool.pixmaps[i].texture)) ++ continue; ++ ++ //bind texture ++ glBindTexture(GL_TEXTURE_2D, m_bufferPool.pixmaps[i].texture); ++ ++ // release pixmap ++ glXReleaseTexImageEXT(m_Display, m_bufferPool.pixmaps[i].glPixmap, GLX_FRONT_LEFT_EXT); ++ ++ glBindTexture(GL_TEXTURE_2D, 0); ++ ++ glDeleteTextures(1, &m_bufferPool.pixmaps[i].texture); ++ } ++ CLog::Log(LOGNOTICE, "VDPAU::COutput: unbound pixmaps"); ++} ++ ++bool COutput::CheckStatus(VdpStatus vdp_st, int line) ++{ ++ if (vdp_st != VDP_STATUS_OK) ++ { ++ CLog::Log(LOGERROR, " (VDPAU) Error: %s(%d) at %s:%d\n", m_config.vdpProcs.vdp_get_error_string(vdp_st), vdp_st, __FILE__, line); ++ m_vdpError = true; ++ return true; ++ } ++ return false; ++} ++ ++bool COutput::CreateGlxContext() ++{ ++ GLXContext glContext; ++ Window window; ++ ++ m_Display = g_Windowing.GetDisplay(); ++ glContext = g_Windowing.GetGlxContext(); ++ m_Window = g_Windowing.GetWmWindow(); ++ ++ // Get our window attribs. ++ XWindowAttributes wndattribs; ++ XGetWindowAttributes(m_Display, m_Window, &wndattribs); ++ ++ // Get visual Info ++ XVisualInfo visInfo; ++ visInfo.visualid = wndattribs.visual->visualid; ++ int nvisuals = 0; ++ XVisualInfo* visuals = XGetVisualInfo(m_Display, VisualIDMask, &visInfo, &nvisuals); ++ if (nvisuals != 1) ++ { ++ CLog::Log(LOGERROR, "VDPAU::COutput::CreateGlxContext - could not find visual"); ++ return false; ++ } ++ visInfo = visuals[0]; ++ XFree(visuals); ++ ++ m_pixmap = XCreatePixmap(m_Display, ++ DefaultRootWindow(m_Display), ++ 192, ++ 108, ++ visInfo.depth); ++ if (!m_pixmap) ++ { ++ CLog::Log(LOGERROR, "VDPAU::COutput::CreateGlxContext - Unable to create XPixmap"); ++ return false; ++ } ++ ++ // create gl pixmap ++ m_glPixmap = glXCreateGLXPixmap(m_Display, &visInfo, m_pixmap); ++ ++ if (!m_glPixmap) ++ { ++ CLog::Log(LOGINFO, "VDPAU::COutput::CreateGlxContext - Could not create glPixmap"); ++ return false; ++ } ++ ++ m_glContext = glXCreateContext(m_Display, &visInfo, glContext, True); ++ ++ if (!glXMakeCurrent(m_Display, m_glPixmap, m_glContext)) ++ { ++ CLog::Log(LOGINFO, "VDPAU::COutput::CreateGlxContext - Could not make Pixmap current"); ++ return false; ++ } ++ ++ CLog::Log(LOGNOTICE, "VDPAU::COutput::CreateGlxContext - created context"); ++ return true; ++} ++ ++bool COutput::DestroyGlxContext() ++{ ++ if (m_glContext) ++ { ++ glXMakeCurrent(m_Display, None, NULL); ++ glXDestroyContext(m_Display, m_glContext); ++ } ++ m_glContext = 0; ++ ++ if (m_glPixmap) ++ glXDestroyPixmap(m_Display, m_glPixmap); ++ m_glPixmap = 0; ++ ++ if (m_pixmap) ++ XFreePixmap(m_Display, m_pixmap); ++ m_pixmap = 0; ++ ++ return true; ++} ++ ++ + #endif +diff -Naur xbmc-11.0.1/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.h xbmc-11.0.1.patch/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.h +--- xbmc-11.0.1/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.h 2012-03-21 23:57:34.000000000 +0100 ++++ xbmc-11.0.1.patch/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.h 2012-05-13 22:08:47.038194709 +0200 +@@ -1,4 +1,3 @@ +- + #pragma once + /* + * Copyright (C) 2005-2009 Team XBMC +@@ -21,6 +20,24 @@ + * + */ + ++/** ++ * design goals: ++ * - improve performance ++ * max out hw resources: e.g. make 1080p60 play on ION2 ++ * allow advanced de-interlacing on ION ++ * ++ * - add vdpau/opengl interop ++ * ++ * - remove tight dependency to render thread ++ * prior design needed to hijack render thread in order to do ++ * gl interop functions. In particular this was a problem for ++ * init and clear down. Introduction of GL_NV_vdpau_interop ++ * increased the need to be independent from render thread ++ * ++ * - move to an actor based design in order to reduce the number ++ * of locks needed. ++ */ ++ + #include "DllAvUtil.h" + #include "DVDVideoCodec.h" + #include "DVDVideoCodecFFmpeg.h" +@@ -37,118 +54,31 @@ + #include "settings/VideoSettings.h" + #include "guilib/DispResource.h" + #include "threads/Event.h" +-namespace Surface { class CSurface; } +- +-#define NUM_OUTPUT_SURFACES 4 +-#define NUM_VIDEO_SURFACES_MPEG2 10 // (1 frame being decoded, 2 reference) +-#define NUM_VIDEO_SURFACES_H264 32 // (1 frame being decoded, up to 16 references) +-#define NUM_VIDEO_SURFACES_VC1 10 // (same as MPEG-2) +-#define NUM_OUTPUT_SURFACES_FOR_FULLHD 2 +-#define FULLHD_WIDTH 1920 +- +-class CVDPAU +- : public CDVDVideoCodecFFmpeg::IHardwareDecoder +- , public IDispResource +-{ +-public: +- +- struct pictureAge +- { +- int b_age; +- int ip_age[2]; +- }; +- +- struct Desc +- { +- const char *name; +- uint32_t id; +- uint32_t aux; /* optional extra parameter... */ +- }; ++#include "threads/Thread.h" ++#include "utils/ActorProtocol.h" + +- CVDPAU(); +- virtual ~CVDPAU(); +- +- virtual bool Open (AVCodecContext* avctx, const enum PixelFormat, unsigned int surfaces = 0); +- virtual int Decode (AVCodecContext* avctx, AVFrame* frame); +- virtual bool GetPicture(AVCodecContext* avctx, AVFrame* frame, DVDVideoPicture* picture); +- virtual void Reset(); +- virtual void Close(); +- +- virtual int Check(AVCodecContext* avctx); +- +- virtual const std::string Name() { return "vdpau"; } +- +- bool MakePixmap(int width, int height); +- bool MakePixmapGL(); +- +- void ReleasePixmap(); +- void BindPixmap(); +- +- PFNGLXBINDTEXIMAGEEXTPROC glXBindTexImageEXT; +- PFNGLXRELEASETEXIMAGEEXTPROC glXReleaseTexImageEXT; +- GLXPixmap m_glPixmap; +- Pixmap m_Pixmap; ++using namespace Actor; + +- static void FFReleaseBuffer(AVCodecContext *avctx, AVFrame *pic); +- static void FFDrawSlice(struct AVCodecContext *s, +- const AVFrame *src, int offset[4], +- int y, int type, int height); +- static int FFGetBuffer(AVCodecContext *avctx, AVFrame *pic); + +- void Present(); +- bool ConfigVDPAU(AVCodecContext *avctx, int ref_frames); +- void SpewHardwareAvailable(); +- void InitCSCMatrix(int Height); +- bool CheckStatus(VdpStatus vdp_st, int line); +- bool IsSurfaceValid(vdpau_render_state *render); +- +- void CheckFeatures(); +- void SetColor(); +- void SetNoiseReduction(); +- void SetSharpness(); +- void SetDeinterlacing(); +- void SetHWUpscaling(); ++#define FULLHD_WIDTH 1920 ++#define MAX_PIC_Q_LENGTH 20 //for non-interop_yuv this controls the max length of the decoded pic to render completion Q + +- pictureAge picAge; +- vdpau_render_state *past[2], *current, *future; +- int tmpDeintMode, tmpDeintGUI, tmpDeint; +- float tmpNoiseReduction, tmpSharpness; +- float tmpBrightness, tmpContrast; +- int OutWidth, OutHeight; +- bool upScale; +- std::queue m_DVDVideoPics; +- +- static inline void ClearUsedForRender(vdpau_render_state **st) +- { +- if (*st) { +- (*st)->state &= ~FF_VDPAU_STATE_USED_FOR_RENDER; +- *st = NULL; +- } +- } ++namespace VDPAU ++{ + +- VdpProcamp m_Procamp; +- VdpCSCMatrix m_CSCMatrix; +- VdpDevice HasDevice() { return vdp_device != VDP_INVALID_HANDLE; }; +- VdpChromaType vdp_chroma_type; ++/** ++ * VDPAU interface to driver ++ */ + ++struct VDPAU_procs ++{ ++ VdpGetProcAddress * vdp_get_proc_address; ++ VdpDeviceDestroy * vdp_device_destroy; + +- // protected: +- void InitVDPAUProcs(); +- void FiniVDPAUProcs(); +- void FiniVDPAUOutput(); +- bool ConfigOutputMethod(AVCodecContext *avctx, AVFrame *pFrame); +- bool FiniOutputMethod(); +- +- VdpDevice vdp_device; +- VdpGetProcAddress * vdp_get_proc_address; +- VdpPresentationQueueTarget vdp_flip_target; +- VdpPresentationQueue vdp_flip_queue; +- VdpDeviceDestroy * vdp_device_destroy; +- +- VdpVideoSurfaceCreate * vdp_video_surface_create; +- VdpVideoSurfaceDestroy * vdp_video_surface_destroy; +- VdpVideoSurfacePutBitsYCbCr * vdp_video_surface_put_bits_y_cb_cr; +- VdpVideoSurfaceGetBitsYCbCr * vdp_video_surface_get_bits_y_cb_cr; ++ VdpVideoSurfaceCreate * vdp_video_surface_create; ++ VdpVideoSurfaceDestroy * vdp_video_surface_destroy; ++ VdpVideoSurfacePutBitsYCbCr * vdp_video_surface_put_bits_y_cb_cr; ++ VdpVideoSurfaceGetBitsYCbCr * vdp_video_surface_get_bits_y_cb_cr; + + VdpOutputSurfacePutBitsYCbCr * vdp_output_surface_put_bits_y_cb_cr; + VdpOutputSurfacePutBitsNative * vdp_output_surface_put_bits_native; +@@ -158,15 +88,15 @@ + VdpOutputSurfaceRenderOutputSurface * vdp_output_surface_render_output_surface; + VdpOutputSurfacePutBitsIndexed * vdp_output_surface_put_bits_indexed; + +- VdpVideoMixerCreate * vdp_video_mixer_create; +- VdpVideoMixerSetFeatureEnables * vdp_video_mixer_set_feature_enables; +- VdpVideoMixerQueryParameterSupport * vdp_video_mixer_query_parameter_support; +- VdpVideoMixerQueryFeatureSupport * vdp_video_mixer_query_feature_support; +- VdpVideoMixerDestroy * vdp_video_mixer_destroy; +- VdpVideoMixerRender * vdp_video_mixer_render; +- VdpVideoMixerSetAttributeValues * vdp_video_mixer_set_attribute_values; ++ VdpVideoMixerCreate * vdp_video_mixer_create; ++ VdpVideoMixerSetFeatureEnables * vdp_video_mixer_set_feature_enables; ++ VdpVideoMixerQueryParameterSupport * vdp_video_mixer_query_parameter_support; ++ VdpVideoMixerQueryFeatureSupport * vdp_video_mixer_query_feature_support; ++ VdpVideoMixerDestroy * vdp_video_mixer_destroy; ++ VdpVideoMixerRender * vdp_video_mixer_render; ++ VdpVideoMixerSetAttributeValues * vdp_video_mixer_set_attribute_values; + +- VdpGenerateCSCMatrix * vdp_generate_csc_matrix; ++ VdpGenerateCSCMatrix * vdp_generate_csc_matrix; + + VdpPresentationQueueTargetDestroy * vdp_presentation_queue_target_destroy; + VdpPresentationQueueCreate * vdp_presentation_queue_create; +@@ -179,64 +109,467 @@ + + VdpGetErrorString * vdp_get_error_string; + +- VdpDecoderCreate * vdp_decoder_create; +- VdpDecoderDestroy * vdp_decoder_destroy; +- VdpDecoderRender * vdp_decoder_render; +- VdpDecoderQueryCapabilities * vdp_decoder_query_caps; ++ VdpDecoderCreate * vdp_decoder_create; ++ VdpDecoderDestroy * vdp_decoder_destroy; ++ VdpDecoderRender * vdp_decoder_render; ++ VdpDecoderQueryCapabilities * vdp_decoder_query_caps; + + VdpPreemptionCallbackRegister * vdp_preemption_callback_register; + +- VdpOutputSurface outputSurfaces[NUM_OUTPUT_SURFACES]; +- VdpOutputSurface outputSurface; +- VdpOutputSurface presentSurface; +- +- VdpDecoder decoder; +- VdpVideoMixer videoMixer; +- VdpRect outRect; +- VdpRect outRectVid; ++}; + +- static void* dl_handle; +- VdpStatus (*dl_vdp_device_create_x11)(Display* display, int screen, VdpDevice* device, VdpGetProcAddress **get_proc_address); +- VdpStatus (*dl_vdp_get_proc_address)(VdpDevice device, VdpFuncId function_id, void** function_pointer); +- VdpStatus (*dl_vdp_preemption_callback_register)(VdpDevice device, VdpPreemptionCallback callback, void* context); ++//----------------------------------------------------------------------------- ++// VDPAU data structs ++//----------------------------------------------------------------------------- + +- int surfaceNum; +- int presentSurfaceNum; +- int totalAvailableOutputSurfaces; +- uint32_t vid_width, vid_height; +- int surface_width, surface_height; +- uint32_t max_references; +- Display* m_Display; +- bool vdpauConfigured; +- uint32_t *m_BlackBar; ++class CDecoder; ++ ++/** ++ * Buffer statistics used to control number of frames in queue ++ */ ++ ++class CVdpauBufferStats ++{ ++public: ++ uint16_t decodedPics; ++ uint16_t processedPics; ++ uint16_t renderPics; ++ uint64_t latency; // time decoder has waited for a frame, ideally there is no latency ++ int playSpeed; ++ bool canSkipDeint; ++ int processCmd; ++ ++ void IncDecoded() { CSingleLock l(m_sec); decodedPics++;} ++ void DecDecoded() { CSingleLock l(m_sec); decodedPics--;} ++ void IncProcessed() { CSingleLock l(m_sec); processedPics++;} ++ void DecProcessed() { CSingleLock l(m_sec); processedPics--;} ++ void IncRender() { CSingleLock l(m_sec); renderPics++;} ++ void DecRender() { CSingleLock l(m_sec); renderPics--;} ++ void Reset() { CSingleLock l(m_sec); decodedPics=0; processedPics=0;renderPics=0;latency=0;} ++ void Get(uint16_t &decoded, uint16_t &processed, uint16_t &render) {CSingleLock l(m_sec); decoded = decodedPics, processed=processedPics, render=renderPics;} ++ void SetParams(uint64_t time, int speed) { CSingleLock l(m_sec); latency = time; playSpeed = speed; } ++ void GetParams(uint64_t &lat, int &speed) { CSingleLock l(m_sec); lat = latency; speed = playSpeed; } ++ void SetCmd(int cmd) { CSingleLock l(m_sec); processCmd = cmd; } ++ void GetCmd(int &cmd) { CSingleLock l(m_sec); cmd = processCmd; processCmd = 0; } ++ void SetCanSkipDeint(bool canSkip) { CSingleLock l(m_sec); canSkipDeint = canSkip; } ++ bool CanSkipDeint() { CSingleLock l(m_sec); if (canSkipDeint) return true; else return false;} ++private: ++ CCriticalSection m_sec; ++}; ++ ++/** ++ * CVdpauConfig holds all configuration parameters needed by vdpau ++ * The structure is sent to the internal classes CMixer and COutput ++ * for init. ++ */ ++ ++struct CVdpauConfig ++{ ++ int surfaceWidth; ++ int surfaceHeight; ++ int vidWidth; ++ int vidHeight; ++ int outWidth; ++ int outHeight; ++ VDPAU_procs vdpProcs; ++ VdpDevice vdpDevice; ++ VdpDecoder vdpDecoder; ++ VdpChromaType vdpChromaType; ++ CVdpauBufferStats *stats; ++ CDecoder *vdpau; ++ int featureCount; ++ int upscale; ++ VdpVideoMixerFeature vdpFeatures[10]; ++ std::vector *videoSurfaces; ++ CCriticalSection *videoSurfaceSec; ++ bool usePixmaps; ++ int numRenderBuffers; ++ uint32_t maxReferences; ++ bool useInteropYuv; ++}; ++ ++/** ++ * Holds a decoded frame ++ * Input to COutput for further processing ++ */ ++struct CVdpauDecodedPicture ++{ ++ DVDVideoPicture DVDPic; ++ vdpau_render_state *render; ++}; ++ ++/** ++ * Frame after having been processed by vdpau mixer ++ */ ++struct CVdpauProcessedPicture ++{ ++ DVDVideoPicture DVDPic; ++ vdpau_render_state *render; ++ VdpOutputSurface outputSurface; ++}; + ++/** ++ * Ready to render textures ++ * Sent from COutput back to CDecoder ++ * Objects are referenced by DVDVideoPicture and are sent ++ * to renderer ++ */ ++class CVdpauRenderPicture ++{ ++ friend class CDecoder; ++ friend class COutput; ++public: ++ DVDVideoPicture DVDPic; ++ int texWidth, texHeight; ++ CRect crop; ++ GLuint texture[4]; ++ uint32_t sourceIdx; ++ bool valid; ++ CDecoder *vdpau; ++ CVdpauRenderPicture* Acquire(); ++ long Release(); ++private: ++ void ReturnUnused(); ++ int refCount; ++ CCriticalSection *renderPicSection; ++}; + ++//----------------------------------------------------------------------------- ++// Mixer ++//----------------------------------------------------------------------------- ++ ++class CMixerControlProtocol : public Protocol ++{ ++public: ++ CMixerControlProtocol(std::string name, CEvent* inEvent, CEvent *outEvent) : Protocol(name, inEvent, outEvent) {}; ++ enum OutSignal ++ { ++ INIT = 0, ++ FLUSH, ++ TIMEOUT, ++ }; ++ enum InSignal ++ { ++ ACC, ++ ERROR, ++ }; ++}; ++ ++class CMixerDataProtocol : public Protocol ++{ ++public: ++ CMixerDataProtocol(std::string name, CEvent* inEvent, CEvent *outEvent) : Protocol(name, inEvent, outEvent) {}; ++ enum OutSignal ++ { ++ FRAME, ++ BUFFER, ++ }; ++ enum InSignal ++ { ++ PICTURE, ++ }; ++}; ++ ++/** ++ * Embeds the vdpau video mixer ++ * Embedded by COutput class, gets decoded frames from COutput, processes ++ * them in mixer ands sends processed frames back to COutput ++ */ ++class CMixer : private CThread ++{ ++public: ++ CMixer(CEvent *inMsgEvent); ++ virtual ~CMixer(); ++ void Start(); ++ void Dispose(); ++ CMixerControlProtocol m_controlPort; ++ CMixerDataProtocol m_dataPort; ++protected: ++ void OnStartup(); ++ void OnExit(); ++ void Process(); ++ void StateMachine(int signal, Protocol *port, Message *msg); ++ void Init(); ++ void Uninit(); ++ void Flush(); ++ void CreateVdpauMixer(); ++ void ProcessPicture(); ++ void InitCycle(); ++ void FiniCycle(); ++ void CheckFeatures(); ++ void SetPostProcFeatures(bool postProcEnabled); ++ void PostProcOff(); ++ void InitCSCMatrix(int Width); ++ bool GenerateStudioCSCMatrix(VdpColorStandard colorStandard, VdpCSCMatrix &studioCSCMatrix); ++ void SetColor(); ++ void SetNoiseReduction(); ++ void SetSharpness(); ++ void SetDeintSkipChroma(); ++ void SetDeinterlacing(); ++ void SetHWUpscaling(); ++ void DisableHQScaling(); ++ EINTERLACEMETHOD GetDeinterlacingMethod(bool log = false); ++ bool CheckStatus(VdpStatus vdp_st, int line); ++ CEvent m_outMsgEvent; ++ CEvent *m_inMsgEvent; ++ int m_state; ++ bool m_bStateMachineSelfTrigger; ++ ++ // extended state variables for state machine ++ int m_extTimeout; ++ bool m_vdpError; ++ CVdpauConfig m_config; ++ VdpVideoMixer m_videoMixer; ++ VdpProcamp m_Procamp; ++ VdpCSCMatrix m_CSCMatrix; ++ bool m_PostProc; ++ float m_Brightness; ++ float m_Contrast; ++ float m_NoiseReduction; ++ float m_Sharpness; ++ int m_DeintMode; ++ int m_Deint; ++ int m_Upscale; ++ uint32_t *m_BlackBar; + VdpVideoMixerPictureStructure m_mixerfield; +- int m_mixerstep; ++ int m_mixerstep; ++ int m_mixersteps; ++ CVdpauProcessedPicture m_processPicture; ++ std::queue m_outputSurfaces; ++ std::queue m_decodedPics; ++ std::deque m_mixerInput; ++}; ++ ++//----------------------------------------------------------------------------- ++// Output ++//----------------------------------------------------------------------------- ++ ++/** ++ * Buffer pool holds allocated vdpau and gl resources ++ * Embedded in COutput ++ */ ++struct VdpauBufferPool ++{ ++ struct Pixmaps ++ { ++ unsigned short id; ++ bool used; ++ DVDVideoPicture DVDPic; ++ GLuint texture; ++ Pixmap pixmap; ++ GLXPixmap glPixmap; ++ VdpPresentationQueueTarget vdp_flip_target; ++ VdpPresentationQueue vdp_flip_queue; ++ VdpOutputSurface surface; ++ }; ++ struct GLVideoSurface ++ { ++ GLuint texture[4]; ++#ifdef GL_NV_vdpau_interop ++ GLvdpauSurfaceNV glVdpauSurface; ++#endif ++ vdpau_render_state *sourceVuv; ++ VdpOutputSurface sourceRgb; ++ }; ++ unsigned short numOutputSurfaces; ++ std::vector pixmaps; ++ std::vector outputSurfaces; ++ std::deque notVisiblePixmaps; ++ std::vector allRenderPics; ++ std::map glVideoSurfaceMap; ++ std::map glOutputSurfaceMap; ++ std::queue processedPics; ++ std::deque usedRenderPics; ++ std::deque freeRenderPics; ++ CCriticalSection renderPicSec; ++}; ++ ++class COutputControlProtocol : public Protocol ++{ ++public: ++ COutputControlProtocol(std::string name, CEvent* inEvent, CEvent *outEvent) : Protocol(name, inEvent, outEvent) {}; ++ enum OutSignal ++ { ++ INIT, ++ FLUSH, ++ PRECLEANUP, ++ TIMEOUT, ++ }; ++ enum InSignal ++ { ++ ACC, ++ ERROR, ++ STATS, ++ }; ++}; ++ ++class COutputDataProtocol : public Protocol ++{ ++public: ++ COutputDataProtocol(std::string name, CEvent* inEvent, CEvent *outEvent) : Protocol(name, inEvent, outEvent) {}; ++ enum OutSignal ++ { ++ NEWFRAME = 0, ++ RETURNPIC, ++ }; ++ enum InSignal ++ { ++ PICTURE, ++ }; ++}; ++ ++/** ++ * COutput is embedded in CDecoder and embeds CMixer ++ * The class has its own OpenGl context which is shared with render thread ++ * COuput generated ready to render textures and passes them back to ++ * CDecoder ++ */ ++class COutput : private CThread ++{ ++public: ++ COutput(CEvent *inMsgEvent); ++ virtual ~COutput(); ++ void Start(); ++ void Dispose(); ++ COutputControlProtocol m_controlPort; ++ COutputDataProtocol m_dataPort; ++protected: ++ void OnStartup(); ++ void OnExit(); ++ void Process(); ++ void StateMachine(int signal, Protocol *port, Message *msg); ++ bool HasWork(); ++ CVdpauRenderPicture *ProcessMixerPicture(); ++ void ProcessReturnPicture(CVdpauRenderPicture *pic); ++ int FindFreePixmap(); ++ bool Init(); ++ bool Uninit(); ++ void Flush(); ++ bool CreateGlxContext(); ++ bool DestroyGlxContext(); ++ bool EnsureBufferPool(); ++ void ReleaseBufferPool(); ++ void InitMixer(); ++ bool GLInit(); ++ void GLMapSurfaces(); ++ void GLUnmapSurfaces(); ++ void GLBindPixmaps(); ++ void GLUnbindPixmaps(); ++ bool MakePixmap(VdpauBufferPool::Pixmaps &pixmap); ++ bool MakePixmapGL(VdpauBufferPool::Pixmaps &pixmap); ++ bool CheckStatus(VdpStatus vdp_st, int line); ++ CEvent m_outMsgEvent; ++ CEvent *m_inMsgEvent; ++ int m_state; ++ bool m_bStateMachineSelfTrigger; ++ ++ // extended state variables for state machine ++ int m_extTimeout; ++ bool m_vdpError; ++ CVdpauConfig m_config; ++ VdpauBufferPool m_bufferPool; ++ CMixer m_mixer; ++ Display *m_Display; ++ Window m_Window; ++ GLXContext m_glContext; ++ GLXWindow m_glWindow; ++ Pixmap m_pixmap; ++ GLXPixmap m_glPixmap; ++ ++ // gl functions ++ PFNGLXBINDTEXIMAGEEXTPROC glXBindTexImageEXT; ++ PFNGLXRELEASETEXIMAGEEXTPROC glXReleaseTexImageEXT; ++#ifdef GL_NV_vdpau_interop ++ PFNGLVDPAUINITNVPROC glVDPAUInitNV; ++ PFNGLVDPAUFININVPROC glVDPAUFiniNV; ++ PFNGLVDPAUREGISTEROUTPUTSURFACENVPROC glVDPAURegisterOutputSurfaceNV; ++ PFNGLVDPAUREGISTERVIDEOSURFACENVPROC glVDPAURegisterVideoSurfaceNV; ++ PFNGLVDPAUISSURFACENVPROC glVDPAUIsSurfaceNV; ++ PFNGLVDPAUUNREGISTERSURFACENVPROC glVDPAUUnregisterSurfaceNV; ++ PFNGLVDPAUSURFACEACCESSNVPROC glVDPAUSurfaceAccessNV; ++ PFNGLVDPAUMAPSURFACESNVPROC glVDPAUMapSurfacesNV; ++ PFNGLVDPAUUNMAPSURFACESNVPROC glVDPAUUnmapSurfacesNV; ++ PFNGLVDPAUGETSURFACEIVNVPROC glVDPAUGetSurfaceivNV; ++#endif ++}; ++ ++//----------------------------------------------------------------------------- ++// VDPAU decoder ++//----------------------------------------------------------------------------- ++ ++/** ++ * VDPAU main class ++ */ ++class CDecoder ++ : public CDVDVideoCodecFFmpeg::IHardwareDecoder ++ , public IDispResource ++{ ++ friend class CVdpauRenderPicture; ++ ++public: ++ ++ struct PictureAge ++ { ++ int b_age; ++ int ip_age[2]; ++ }; ++ ++ struct Desc ++ { ++ const char *name; ++ uint32_t id; ++ uint32_t aux; /* optional extra parameter... */ ++ }; ++ ++ CDecoder(); ++ virtual ~CDecoder(); ++ ++ virtual bool Open (AVCodecContext* avctx, const enum PixelFormat, unsigned int surfaces = 0); ++ virtual int Decode (AVCodecContext* avctx, AVFrame* frame) {return Decode(avctx, frame, false, false);}; ++ virtual int Decode (AVCodecContext* avctx, AVFrame* frame, bool bSoftDrain = false, bool bHardDrain = false); ++ virtual bool GetPicture(AVCodecContext* avctx, AVFrame* frame, DVDVideoPicture* picture); ++ virtual void Reset(); ++ virtual void Close(); ++ virtual long Release(); ++ virtual bool CanSkipDeint(); ++ virtual void SetSpeed(int speed); ++ ++ virtual int Check(AVCodecContext* avctx); ++ virtual const std::string Name() { return "vdpau"; } + + bool Supports(VdpVideoMixerFeature feature); + bool Supports(EINTERLACEMETHOD method); + EINTERLACEMETHOD AutoInterlaceMethod(); ++ static bool IsVDPAUFormat(PixelFormat fmt); + +- VdpVideoMixerFeature m_features[10]; +- int m_feature_count; ++ static void FFReleaseBuffer(AVCodecContext *avctx, AVFrame *pic); ++ static void FFDrawSlice(struct AVCodecContext *s, ++ const AVFrame *src, int offset[4], ++ int y, int type, int height); ++ static int FFGetBuffer(AVCodecContext *avctx, AVFrame *pic); ++ ++ virtual void OnLostDevice(); ++ virtual void OnResetDevice(); ++ ++protected: ++ void SetWidthHeight(int width, int height); ++ bool ConfigVDPAU(AVCodecContext *avctx, int ref_frames); ++ void SpewHardwareAvailable(); ++ bool CheckStatus(VdpStatus vdp_st, int line); ++ bool IsSurfaceValid(vdpau_render_state *render); ++ void InitVDPAUProcs(); ++ void FiniVDPAUProcs(); ++ void FiniVDPAUOutput(); ++ void ReturnRenderPicture(CVdpauRenderPicture *renderPic); ++ long ReleasePicReference(); + +- static bool IsVDPAUFormat(PixelFormat fmt); + static void ReadFormatOf( PixelFormat fmt + , VdpDecoderProfile &decoder_profile + , VdpChromaType &chroma_type); + +- std::vector m_videoSurfaces; +- DllAvUtil m_dllAvUtil; +- +- enum VDPAUOutputMethod +- { +- OUTPUT_NONE, +- OUTPUT_PIXMAP, +- OUTPUT_GL_INTEROP_RGB, +- OUTPUT_GL_INTEROP_YUV +- }; +- VDPAUOutputMethod m_vdpauOutputMethod; ++ VdpStatus (*dl_vdp_device_create_x11)(Display* display, int screen, VdpDevice* device, VdpGetProcAddress **get_proc_address); ++ VdpStatus (*dl_vdp_get_proc_address)(VdpDevice device, VdpFuncId function_id, void** function_pointer); ++ VdpStatus (*dl_vdp_preemption_callback_register)(VdpDevice device, VdpPreemptionCallback callback, void* context); + + // OnLostDevice triggers transition from all states to LOST + // internal errors trigger transition from OPEN to RESET +@@ -247,9 +580,27 @@ + , VDPAU_LOST + , VDPAU_ERROR + } m_DisplayState; +- CSharedSection m_DecoderSection; +- CSharedSection m_DisplaySection; ++ CCriticalSection m_DecoderSection; + CEvent m_DisplayEvent; +- virtual void OnLostDevice(); +- virtual void OnResetDevice(); ++ ++ static void* dl_handle; ++ DllAvUtil m_dllAvUtil; ++ Display* m_Display; ++ ThreadIdentifier m_decoderThread; ++ bool m_vdpauConfigured; ++ CVdpauConfig m_vdpauConfig; ++ std::vector m_videoSurfaces; ++ CCriticalSection m_videoSurfaceSec; ++ PictureAge m_picAge; ++ ++ COutput m_vdpauOutput; ++ CVdpauBufferStats m_bufferStats; ++ CEvent m_inMsgEvent; ++ CVdpauRenderPicture *m_presentPicture; ++ ++ int m_speed; ++ int m_codecControl; + }; ++ ++} ++ +diff -Naur xbmc-11.0.1/xbmc/cores/dvdplayer/DVDCodecs/Video/XVBA.cpp xbmc-11.0.1.patch/xbmc/cores/dvdplayer/DVDCodecs/Video/XVBA.cpp +--- xbmc-11.0.1/xbmc/cores/dvdplayer/DVDCodecs/Video/XVBA.cpp 1970-01-01 01:00:00.000000000 +0100 ++++ xbmc-11.0.1.patch/xbmc/cores/dvdplayer/DVDCodecs/Video/XVBA.cpp 2012-05-13 22:08:47.063195207 +0200 +@@ -0,0 +1,2382 @@ ++/* ++ * Copyright (C) 2005-2011 Team XBMC ++ * http://www.xbmc.org ++ * ++ * 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 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 XBMC; see the file COPYING. If not, write to ++ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. ++ * http://www.gnu.org/copyleft/gpl.html ++ * ++ */ ++ ++#include "system.h" ++#ifdef HAVE_LIBXVBA ++#include ++#include ++#include "XVBA.h" ++#include "windowing/WindowingFactory.h" ++#include "guilib/GraphicContext.h" ++#include "settings/GUISettings.h" ++#include "settings/Settings.h" ++#include "utils/TimeUtils.h" ++#include "cores/dvdplayer/DVDClock.h" ++ ++using namespace XVBA; ++ ++// XVBA interface ++ ++#define XVBA_LIBRARY "libXvBAW.so.1" ++ ++typedef Bool (*XVBAQueryExtensionProc) (Display *dpy, int *vers); ++typedef Status (*XVBACreateContextProc) (void *input, void *output); ++typedef Status (*XVBADestroyContextProc) (void *context); ++typedef Bool (*XVBAGetSessionInfoProc) (void *input, void *output); ++typedef Status (*XVBACreateSurfaceProc) (void *input, void *output); ++typedef Status (*XVBACreateGLSharedSurfaceProc)(void *input, void *output); ++typedef Status (*XVBADestroySurfaceProc) (void *surface); ++typedef Status (*XVBACreateDecodeBuffersProc) (void *input, void *output); ++typedef Status (*XVBADestroyDecodeBuffersProc) (void *input); ++typedef Status (*XVBAGetCapDecodeProc) (void *input, void *output); ++typedef Status (*XVBACreateDecodeProc) (void *input, void *output); ++typedef Status (*XVBADestroyDecodeProc) (void *session); ++typedef Status (*XVBAStartDecodePictureProc) (void *input); ++typedef Status (*XVBADecodePictureProc) (void *input); ++typedef Status (*XVBAEndDecodePictureProc) (void *input); ++typedef Status (*XVBASyncSurfaceProc) (void *input, void *output); ++typedef Status (*XVBAGetSurfaceProc) (void *input); ++typedef Status (*XVBATransferSurfaceProc) (void *input); ++ ++static struct ++{ ++ XVBAQueryExtensionProc QueryExtension; ++ XVBACreateContextProc CreateContext; ++ XVBADestroyContextProc DestroyContext; ++ XVBAGetSessionInfoProc GetSessionInfo; ++ XVBACreateSurfaceProc CreateSurface; ++ XVBACreateGLSharedSurfaceProc CreateGLSharedSurface; ++ XVBADestroySurfaceProc DestroySurface; ++ XVBACreateDecodeBuffersProc CreateDecodeBuffers; ++ XVBADestroyDecodeBuffersProc DestroyDecodeBuffers; ++ XVBAGetCapDecodeProc GetCapDecode; ++ XVBACreateDecodeProc CreateDecode; ++ XVBADestroyDecodeProc DestroyDecode; ++ XVBAStartDecodePictureProc StartDecodePicture; ++ XVBADecodePictureProc DecodePicture; ++ XVBAEndDecodePictureProc EndDecodePicture; ++ XVBASyncSurfaceProc SyncSurface; ++ XVBAGetSurfaceProc GetSurface; ++ XVBATransferSurfaceProc TransferSurface; ++}g_XVBA_vtable; ++ ++//----------------------------------------------------------------------------- ++//----------------------------------------------------------------------------- ++ ++CXVBAContext *CXVBAContext::m_context = 0; ++CCriticalSection CXVBAContext::m_section; ++Display *CXVBAContext::m_display = 0; ++void *CXVBAContext::m_dlHandle = 0; ++ ++CXVBAContext::CXVBAContext() ++{ ++ m_context = 0; ++// m_dlHandle = 0; ++ m_xvbaContext = 0; ++ m_refCount = 0; ++} ++ ++void CXVBAContext::Release() ++{ ++ CSingleLock lock(m_section); ++ ++ m_refCount--; ++ if (m_refCount <= 0) ++ { ++ Close(); ++ delete this; ++ m_context = 0; ++ } ++} ++ ++void CXVBAContext::Close() ++{ ++ CLog::Log(LOGNOTICE, "XVBA::Close - closing decoder context"); ++ ++ DestroyContext(); ++// if (m_dlHandle) ++// { ++// dlclose(m_dlHandle); ++// m_dlHandle = 0; ++// } ++} ++ ++bool CXVBAContext::EnsureContext(CXVBAContext **ctx) ++{ ++ CSingleLock lock(m_section); ++ ++ if (m_context) ++ { ++ m_context->m_refCount++; ++ *ctx = m_context; ++ return true; ++ } ++ ++ m_context = new CXVBAContext(); ++ *ctx = m_context; ++ { ++ CSingleLock gLock(g_graphicsContext); ++ if (!m_context->LoadSymbols() || !m_context->CreateContext()) ++ { ++ delete m_context; ++ m_context = 0; ++ return false; ++ } ++ } ++ ++ m_context->m_refCount++; ++ ++ *ctx = m_context; ++ return true; ++} ++ ++bool CXVBAContext::LoadSymbols() ++{ ++ if (!m_dlHandle) ++ { ++ m_dlHandle = dlopen(XVBA_LIBRARY, RTLD_LAZY); ++ if (!m_dlHandle) ++ { ++ const char* error = dlerror(); ++ if (!error) ++ error = "dlerror() returned NULL"; ++ ++ CLog::Log(LOGERROR,"XVBA::LoadSymbols: Unable to get handle to lib: %s", error); ++ return false; ++ } ++ } ++ else ++ return true; ++ ++#define INIT_PROC(PREFIX, PROC) do { \ ++ g_##PREFIX##_vtable.PROC = (PREFIX##PROC##Proc) \ ++ dlsym(m_dlHandle, #PREFIX #PROC); \ ++ } while (0) ++ ++#define INIT_PROC_CHECK(PREFIX, PROC) do { \ ++ dlerror(); \ ++ INIT_PROC(PREFIX, PROC); \ ++ if (dlerror()) { \ ++ dlclose(m_dlHandle); \ ++ m_dlHandle = NULL; \ ++ return false; \ ++ } \ ++ } while (0) ++ ++#define XVBA_INIT_PROC(PROC) INIT_PROC_CHECK(XVBA, PROC) ++ ++ XVBA_INIT_PROC(QueryExtension); ++ XVBA_INIT_PROC(CreateContext); ++ XVBA_INIT_PROC(DestroyContext); ++ XVBA_INIT_PROC(GetSessionInfo); ++ XVBA_INIT_PROC(CreateSurface); ++ XVBA_INIT_PROC(CreateGLSharedSurface); ++ XVBA_INIT_PROC(DestroySurface); ++ XVBA_INIT_PROC(CreateDecodeBuffers); ++ XVBA_INIT_PROC(DestroyDecodeBuffers); ++ XVBA_INIT_PROC(GetCapDecode); ++ XVBA_INIT_PROC(CreateDecode); ++ XVBA_INIT_PROC(DestroyDecode); ++ XVBA_INIT_PROC(StartDecodePicture); ++ XVBA_INIT_PROC(DecodePicture); ++ XVBA_INIT_PROC(EndDecodePicture); ++ XVBA_INIT_PROC(SyncSurface); ++ XVBA_INIT_PROC(GetSurface); ++ XVBA_INIT_PROC(TransferSurface); ++ ++#undef XVBA_INIT_PROC ++#undef INIT_PROC ++ ++ return true; ++} ++ ++bool CXVBAContext::CreateContext() ++{ ++ if (m_xvbaContext) ++ return true; ++ ++ CLog::Log(LOGNOTICE,"XVBA::CreateContext - creating decoder context"); ++ ++ Drawable window; ++ { CSingleLock lock(g_graphicsContext); ++ if (!m_display) ++ m_display = XOpenDisplay(NULL); ++ window = 0; ++ } ++ ++ int version; ++ if (!g_XVBA_vtable.QueryExtension(m_display, &version)) ++ return false; ++ CLog::Log(LOGNOTICE,"XVBA::CreateContext - opening xvba version: %i", version); ++ ++ // create XVBA Context ++ XVBA_Create_Context_Input contextInput; ++ XVBA_Create_Context_Output contextOutput; ++ contextInput.size = sizeof(contextInput); ++ contextInput.display = m_display; ++ contextInput.draw = window; ++ contextOutput.size = sizeof(contextOutput); ++ if(Success != g_XVBA_vtable.CreateContext(&contextInput, &contextOutput)) ++ { ++ CLog::Log(LOGERROR,"XVBA::CreateContext - failed to create context"); ++ return false; ++ } ++ m_xvbaContext = contextOutput.context; ++ ++ return true; ++} ++ ++void CXVBAContext::DestroyContext() ++{ ++ if (!m_xvbaContext) ++ return; ++ ++ g_XVBA_vtable.DestroyContext(m_xvbaContext); ++ m_xvbaContext = 0; ++// XCloseDisplay(m_display); ++} ++ ++void *CXVBAContext::GetContext() ++{ ++ return m_xvbaContext; ++} ++ ++//----------------------------------------------------------------------------- ++//----------------------------------------------------------------------------- ++ ++static unsigned int decoderId = 0; ++ ++CDecoder::CDecoder() : m_xvbaOutput(&m_inMsgEvent) ++{ ++ m_xvbaConfig.context = 0; ++ m_xvbaConfig.xvbaSession = 0; ++ m_xvbaConfig.videoSurfaces = &m_videoSurfaces; ++ m_xvbaConfig.videoSurfaceSec = &m_videoSurfaceSec; ++ m_xvbaConfig.apiSec = &m_apiSec; ++ ++ m_displayState = XVBA_OPEN; ++} ++ ++CDecoder::~CDecoder() ++{ ++ Close(); ++} ++ ++typedef struct { ++ unsigned int size; ++ unsigned int num_of_decodecaps; ++ XVBADecodeCap decode_caps_list[]; ++} XVBA_GetCapDecode_Output_Base; ++ ++void CDecoder::OnLostDevice() ++{ ++ CLog::Log(LOGNOTICE,"XVBA::OnLostDevice event"); ++ ++ CSingleLock lock(m_decoderSection); ++ DestroySession(); ++ if (m_xvbaConfig.context) ++ m_xvbaConfig.context->Release(); ++ m_xvbaConfig.context = 0; ++ ++ m_displayState = XVBA_LOST; ++ m_displayEvent.Reset(); ++} ++ ++void CDecoder::OnResetDevice() ++{ ++ CLog::Log(LOGNOTICE,"XVBA::OnResetDevice event"); ++ ++ CSingleLock lock(m_decoderSection); ++ if (m_displayState == XVBA_LOST) ++ { ++ m_displayState = XVBA_RESET; ++ lock.Leave(); ++ m_displayEvent.Set(); ++ } ++} ++ ++bool CDecoder::Open(AVCodecContext* avctx, const enum PixelFormat fmt, unsigned int surfaces) ++{ ++ std::string Vendor = g_Windowing.GetRenderVendor(); ++ std::transform(Vendor.begin(), Vendor.end(), Vendor.begin(), ::tolower); ++ if (Vendor.compare(0, 3, "ati") != 0) ++ { ++ return false; ++ } ++ ++ m_decoderId = decoderId++; ++ ++ CLog::Log(LOGNOTICE,"(XVBA::Open) opening xvba decoder, id: %d", m_decoderId); ++ ++ if(avctx->coded_width == 0 ++ || avctx->coded_height == 0) ++ { ++ CLog::Log(LOGWARNING,"(XVBA) no width/height available, can't init"); ++ return false; ++ } ++ ++ if (!m_dllAvUtil.Load()) ++ return false; ++ ++ if (!CXVBAContext::EnsureContext(&m_xvbaConfig.context)) ++ return false; ++ ++ // xvba get session info ++ XVBA_GetSessionInfo_Input sessionInput; ++ XVBA_GetSessionInfo_Output sessionOutput; ++ sessionInput.size = sizeof(sessionInput); ++ sessionInput.context = m_xvbaConfig.context->GetContext(); ++ sessionOutput.size = sizeof(sessionOutput); ++ if (Success != g_XVBA_vtable.GetSessionInfo(&sessionInput, &sessionOutput)) ++ { ++ CLog::Log(LOGERROR,"(XVBA) can't get session info"); ++ return false; ++ } ++ if (sessionOutput.getcapdecode_output_size == 0) ++ { ++ CLog::Log(LOGERROR,"(XVBA) session decode not supported"); ++ return false; ++ } ++ ++ // get decoder capabilities ++ XVBA_GetCapDecode_Input capInput; ++ XVBA_GetCapDecode_Output *capOutput; ++ capInput.size = sizeof(capInput); ++ capInput.context = m_xvbaConfig.context->GetContext(); ++ capOutput = (XVBA_GetCapDecode_Output *)calloc(sessionOutput.getcapdecode_output_size, 1); ++ capOutput->size = sessionOutput.getcapdecode_output_size; ++ if (Success != g_XVBA_vtable.GetCapDecode(&capInput, capOutput)) ++ { ++ CLog::Log(LOGERROR,"(XVBA) can't get decode capabilities"); ++ return false; ++ } ++ ++ int match = -1; ++ if (avctx->codec_id == CODEC_ID_H264) ++ { ++ // search for profile high ++ for (unsigned int i = 0; i < capOutput->num_of_decodecaps; ++i) ++ { ++ if (capOutput->decode_caps_list[i].capability_id == XVBA_H264 && ++ capOutput->decode_caps_list[i].flags == XVBA_H264_HIGH) ++ { ++ match = (int) i; ++ break; ++ } ++ } ++ if (match < 0) ++ { ++ CLog::Log(LOGNOTICE, "(XVBA::Open) - profile XVBA_H264_HIGH not found"); ++ } ++ } ++ else if (avctx->codec_id == CODEC_ID_VC1) ++ { ++ // search for profile advanced ++ for (unsigned int i = 0; i < capOutput->num_of_decodecaps; ++i) ++ { ++ if (capOutput->decode_caps_list[i].capability_id == XVBA_VC1 && ++ capOutput->decode_caps_list[i].flags == XVBA_VC1_ADVANCED) ++ { ++ match = (int) i; ++ break; ++ } ++ } ++ if (match < 0) ++ { ++ CLog::Log(LOGNOTICE, "(XVBA::Open) - profile XVBA_VC1_ADVANCED not found"); ++ } ++ } ++ else if (avctx->codec_id == CODEC_ID_MPEG2VIDEO) ++ { ++ // search for profile high ++ for (unsigned int i = 0; i < capOutput->num_of_decodecaps; ++i) ++ { ++ if (capOutput->decode_caps_list[i].capability_id == XVBA_MPEG2_VLD) ++ { ++ // XXX: uncomment when implemented ++ // match = (int) i; ++ // break; ++ } ++ } ++ if (match < 0) ++ { ++ CLog::Log(LOGNOTICE, "(XVBA::Open) - profile XVBA_MPEG2_VLD not found"); ++ } ++ } ++ else if (avctx->codec_id == CODEC_ID_WMV3) ++ { ++ // search for profile high ++ for (unsigned int i = 0; i < capOutput->num_of_decodecaps; ++i) ++ { ++ if (capOutput->decode_caps_list[i].capability_id == XVBA_VC1 && ++ capOutput->decode_caps_list[i].flags == XVBA_VC1_MAIN) ++ { ++ match = (int) i; ++ break; ++ } ++ } ++ if (match < 0) ++ { ++ CLog::Log(LOGNOTICE, "(XVBA::Open) - profile XVBA_VC1_MAIN not found"); ++ } ++ } ++ ++ if (match < 0) ++ { ++ free(capOutput); ++ return false; ++ } ++ ++ CLog::Log(LOGNOTICE,"(XVBA) using decoder capability id: %i flags: %i", ++ capOutput->decode_caps_list[match].capability_id, ++ capOutput->decode_caps_list[match].flags); ++ CLog::Log(LOGNOTICE,"(XVBA) using surface type: %x", ++ capOutput->decode_caps_list[match].surface_type); ++ ++ m_xvbaConfig.decoderCap = capOutput->decode_caps_list[match]; ++ ++ free(capOutput); ++ ++ // set some varables ++ m_xvbaConfig.xvbaSession = 0; ++ m_xvbaBufferPool.data_buffer = 0; ++ m_xvbaBufferPool.iq_matrix_buffer = 0; ++ m_xvbaBufferPool.picture_descriptor_buffer = 0; ++ picAge.b_age = picAge.ip_age[0] = picAge.ip_age[1] = 256*256*256*64; ++ m_presentPicture = 0; ++ m_xvbaConfig.numRenderBuffers = surfaces; ++ m_decoderThread = CThread::GetCurrentThreadId(); ++ m_speed = DVD_PLAYSPEED_NORMAL; ++ ++ if (1) //g_guiSettings.GetBool("videoplayer.usexvbasharedsurface")) ++ m_xvbaConfig.useSharedSurfaces = true; ++ else ++ m_xvbaConfig.useSharedSurfaces = false; ++ ++ m_displayState = XVBA_OPEN; ++ ++ // setup ffmpeg ++ avctx->thread_count = 1; ++ avctx->get_buffer = CDecoder::FFGetBuffer; ++ avctx->release_buffer = CDecoder::FFReleaseBuffer; ++ avctx->draw_horiz_band = CDecoder::FFDrawSlice; ++ avctx->slice_flags = SLICE_FLAG_CODED_ORDER|SLICE_FLAG_ALLOW_FIELD; ++ ++ g_Windowing.Register(this); ++ return true; ++} ++ ++void CDecoder::Close() ++{ ++ CLog::Log(LOGNOTICE, "XVBA::Close - closing decoder, id: %d", m_decoderId); ++ ++ if (!m_xvbaConfig.context) ++ return; ++ ++ DestroySession(); ++ if (m_xvbaConfig.context) ++ m_xvbaConfig.context->Release(); ++ m_xvbaConfig.context = 0; ++ ++ while (!m_videoSurfaces.empty()) ++ { ++ xvba_render_state *render = m_videoSurfaces.back(); ++ if(render->buffers_alllocated > 0) ++ m_dllAvUtil.av_free(render->buffers); ++ m_videoSurfaces.pop_back(); ++ free(render); ++ } ++ ++ g_Windowing.Unregister(this); ++ m_dllAvUtil.Unload(); ++} ++ ++long CDecoder::Release() ++{ ++ // check if we should do some pre-cleanup here ++ // a second decoder might need resources ++ if (m_xvbaConfig.xvbaSession) ++ { ++ CSingleLock lock(m_decoderSection); ++ CLog::Log(LOGNOTICE,"XVBA::Release pre-cleanup"); ++ ++ Message *reply; ++ if (m_xvbaOutput.m_controlPort.SendOutMessageSync(COutputControlProtocol::PRECLEANUP, ++ &reply, ++ 2000)) ++ { ++ bool success = reply->signal == COutputControlProtocol::ACC ? true : false; ++ reply->Release(); ++ if (!success) ++ { ++ CLog::Log(LOGERROR, "XVBA::%s - pre-cleanup returned error", __FUNCTION__); ++ m_displayState = XVBA_ERROR; ++ } ++ } ++ else ++ { ++ CLog::Log(LOGERROR, "XVBA::%s - pre-cleanup timed out", __FUNCTION__); ++ m_displayState = XVBA_ERROR; ++ } ++ ++ for(unsigned int i = 0; i < m_videoSurfaces.size(); ++i) ++ { ++ xvba_render_state *render = m_videoSurfaces[i]; ++ if (render->surface && !(render->state & FF_XVBA_STATE_USED_FOR_RENDER)) ++ { ++ g_XVBA_vtable.DestroySurface(render->surface); ++ render->surface = 0; ++ render->picture_descriptor = 0; ++ render->iq_matrix = 0; ++ } ++ } ++ } ++ IHardwareDecoder::Release(); ++} ++ ++long CDecoder::ReleasePicReference() ++{ ++ return IHardwareDecoder::Release(); ++} ++ ++bool CDecoder::Supports(EINTERLACEMETHOD method) ++{ ++ if(method == VS_INTERLACEMETHOD_AUTO) ++ return true; ++ ++ if (1) //g_guiSettings.GetBool("videoplayer.usexvbasharedsurface")) ++ { ++ if (method == VS_INTERLACEMETHOD_XVBA) ++ return true; ++ } ++ ++ return false; ++} ++ ++void CDecoder::ResetState() ++{ ++ picAge.b_age = picAge.ip_age[0] = picAge.ip_age[1] = 256*256*256*64; ++ ++ m_displayState = XVBA_OPEN; ++} ++ ++int CDecoder::Check(AVCodecContext* avctx) ++{ ++ EDisplayState state; ++ ++ { CSingleLock lock(m_decoderSection); ++ state = m_displayState; ++ } ++ ++ if (state == XVBA_LOST) ++ { ++ CLog::Log(LOGNOTICE,"XVBA::Check waiting for display reset event"); ++ if (!m_displayEvent.WaitMSec(2000)) ++ { ++ CLog::Log(LOGERROR, "XVBA::Check - device didn't reset in reasonable time"); ++ state = XVBA_RESET;; ++ } ++ else ++ { CSingleLock lock(m_decoderSection); ++ state = m_displayState; ++ } ++ } ++ if (state == XVBA_RESET || state == XVBA_ERROR) ++ { ++ CLog::Log(LOGNOTICE,"XVBA::Check - Attempting recovery"); ++ ++ CSingleLock gLock(g_graphicsContext); ++ CSingleLock lock(m_decoderSection); ++ ++ DestroySession(); ++ ResetState(); ++ CXVBAContext::EnsureContext(&m_xvbaConfig.context); ++ ++ if (state == XVBA_RESET) ++ return VC_FLUSHED; ++ else ++ return VC_ERROR; ++ } ++ return 0; ++} ++ ++void CDecoder::SetError(const char* function, const char* msg, int line) ++{ ++ CLog::Log(LOGERROR, "XVBA::%s - %s, line %d", function, msg, line); ++ CSingleLock lock(m_decoderSection); ++ m_displayState = XVBA_ERROR; ++} ++ ++bool CDecoder::CreateSession(AVCodecContext* avctx) ++{ ++ m_xvbaConfig.surfaceWidth = (avctx->coded_width+15) & ~15; ++ m_xvbaConfig.surfaceHeight = (avctx->coded_height+15) & ~15; ++ ++ m_xvbaConfig.vidWidth = avctx->width; ++ m_xvbaConfig.vidHeight = avctx->height; ++ ++ XVBA_Create_Decode_Session_Input sessionInput; ++ XVBA_Create_Decode_Session_Output sessionOutput; ++ ++ sessionInput.size = sizeof(sessionInput); ++ sessionInput.width = m_xvbaConfig.surfaceWidth; ++ sessionInput.height = m_xvbaConfig.surfaceHeight; ++ sessionInput.context = m_xvbaConfig.context->GetContext(); ++ sessionInput.decode_cap = &m_xvbaConfig.decoderCap; ++ sessionOutput.size = sizeof(sessionOutput); ++ ++ if (Success != g_XVBA_vtable.CreateDecode(&sessionInput, &sessionOutput)) ++ { ++ SetError(__FUNCTION__, "failed to create decoder session", __LINE__); ++ CLog::Log(LOGERROR, "Decoder failed with following stats: m_surfaceWidth %u, m_surfaceHeight %u," ++ " m_vidWidth %u, m_vidHeight %u, coded_width %d, coded_height %d", ++ m_xvbaConfig.surfaceWidth, ++ m_xvbaConfig.surfaceHeight, ++ m_xvbaConfig.vidWidth, ++ m_xvbaConfig.vidHeight, ++ avctx->coded_width, ++ avctx->coded_height); ++ return false; ++ } ++ m_xvbaConfig.xvbaSession = sessionOutput.session; ++ ++ // create decode buffers ++ XVBA_Create_DecodeBuff_Input bufferInput; ++ XVBA_Create_DecodeBuff_Output bufferOutput; ++ ++ bufferInput.size = sizeof(bufferInput); ++ bufferInput.session = m_xvbaConfig.xvbaSession; ++ bufferInput.buffer_type = XVBA_PICTURE_DESCRIPTION_BUFFER; ++ bufferInput.num_of_buffers = 1; ++ bufferOutput.size = sizeof(bufferOutput); ++ if (Success != g_XVBA_vtable.CreateDecodeBuffers(&bufferInput, &bufferOutput) ++ || bufferOutput.num_of_buffers_in_list != 1) ++ { ++ SetError(__FUNCTION__, "failed to create picture buffer", __LINE__); ++ return false; ++ } ++ m_xvbaBufferPool.picture_descriptor_buffer = bufferOutput.buffer_list; ++ ++ // data buffer ++ bufferInput.buffer_type = XVBA_DATA_BUFFER; ++ if (Success != g_XVBA_vtable.CreateDecodeBuffers(&bufferInput, &bufferOutput) ++ || bufferOutput.num_of_buffers_in_list != 1) ++ { ++ SetError(__FUNCTION__, "failed to create data buffer", __LINE__); ++ return false; ++ } ++ m_xvbaBufferPool.data_buffer = bufferOutput.buffer_list; ++ ++ // QO Buffer ++ bufferInput.buffer_type = XVBA_QM_BUFFER; ++ if (Success != g_XVBA_vtable.CreateDecodeBuffers(&bufferInput, &bufferOutput) ++ || bufferOutput.num_of_buffers_in_list != 1) ++ { ++ SetError(__FUNCTION__, "failed to create qm buffer", __LINE__); ++ return false; ++ } ++ m_xvbaBufferPool.iq_matrix_buffer = bufferOutput.buffer_list; ++ ++ ++ // initialize output ++ CSingleLock lock(g_graphicsContext); ++ m_xvbaConfig.stats = &m_bufferStats; ++ m_bufferStats.Reset(); ++ m_xvbaOutput.Start(); ++ Message *reply; ++ if (m_xvbaOutput.m_controlPort.SendOutMessageSync(COutputControlProtocol::INIT, ++ &reply, ++ 2000, ++ &m_xvbaConfig, ++ sizeof(m_xvbaConfig))) ++ { ++ bool success = reply->signal == COutputControlProtocol::ACC ? true : false; ++ reply->Release(); ++ if (!success) ++ { ++ CLog::Log(LOGERROR, "XVBA::%s - vdpau output returned error", __FUNCTION__); ++ m_xvbaOutput.Dispose(); ++ return false; ++ } ++ } ++ else ++ { ++ CLog::Log(LOGERROR, "XVBA::%s - failed to init output", __FUNCTION__); ++ m_xvbaOutput.Dispose(); ++ return false; ++ } ++ m_inMsgEvent.Reset(); ++ ++ return true; ++} ++ ++void CDecoder::DestroySession() ++{ ++ m_xvbaOutput.Dispose(); ++ ++ XVBA_Destroy_Decode_Buffers_Input bufInput; ++ bufInput.size = sizeof(bufInput); ++ bufInput.num_of_buffers_in_list = 1; ++ ++ for (unsigned int i=0; isurface) ++ { ++ g_XVBA_vtable.DestroySurface(render->surface); ++ render->surface = 0; ++ render->picture_descriptor = 0; ++ render->iq_matrix = 0; ++ } ++ } ++ ++ if (m_xvbaConfig.xvbaSession) ++ g_XVBA_vtable.DestroyDecode(m_xvbaConfig.xvbaSession); ++ m_xvbaConfig.xvbaSession = 0; ++} ++ ++bool CDecoder::IsSurfaceValid(xvba_render_state *render) ++{ ++ // find render state in queue ++ bool found(false); ++ unsigned int i; ++ for(i = 0; i < m_videoSurfaces.size(); ++i) ++ { ++ if(m_videoSurfaces[i] == render) ++ { ++ found = true; ++ break; ++ } ++ } ++ if (!found) ++ { ++ CLog::Log(LOGERROR,"%s - video surface not found", __FUNCTION__); ++ return false; ++ } ++ if (m_videoSurfaces[i]->surface == 0) ++ { ++ m_videoSurfaces[i]->state = 0; ++ return false; ++ } ++ ++ return true; ++} ++ ++bool CDecoder::EnsureDataControlBuffers(unsigned int num) ++{ ++ if (m_xvbaBufferPool.data_control_buffers.size() >= num) ++ return true; ++ ++ unsigned int missing = num - m_xvbaBufferPool.data_control_buffers.size(); ++ ++ XVBA_Create_DecodeBuff_Input bufferInput; ++ XVBA_Create_DecodeBuff_Output bufferOutput; ++ bufferInput.size = sizeof(bufferInput); ++ bufferInput.session = m_xvbaConfig.xvbaSession; ++ bufferInput.buffer_type = XVBA_DATA_CTRL_BUFFER; ++ bufferInput.num_of_buffers = 1; ++ bufferOutput.size = sizeof(bufferOutput); ++ ++ for (unsigned int i=0; iopaque; ++ CDecoder* xvba = (CDecoder*)ctx->GetHardware(); ++ unsigned int i; ++ ++ CSingleLock lock(xvba->m_decoderSection); ++ ++ xvba_render_state * render = NULL; ++ render = (xvba_render_state*)pic->data[0]; ++ if(!render) ++ { ++ CLog::Log(LOGERROR, "XVBA::FFReleaseBuffer - invalid context handle provided"); ++ return; ++ } ++ ++ for(i=0; i<4; i++) ++ pic->data[i]= NULL; ++ ++ // find render state in queue ++ if (!xvba->IsSurfaceValid(render)) ++ { ++ CLog::Log(LOGDEBUG, "XVBA::FFReleaseBuffer - ignoring invalid buffer"); ++ return; ++ } ++ ++ render->state &= ~FF_XVBA_STATE_USED_FOR_REFERENCE; ++} ++ ++void CDecoder::FFDrawSlice(struct AVCodecContext *avctx, ++ const AVFrame *src, int offset[4], ++ int y, int type, int height) ++{ ++ CDVDVideoCodecFFmpeg* ctx = (CDVDVideoCodecFFmpeg*)avctx->opaque; ++ CDecoder* xvba = (CDecoder*)ctx->GetHardware(); ++ ++ CSingleLock lock(xvba->m_decoderSection); ++ ++ if(xvba->m_displayState != XVBA_OPEN) ++ return; ++ ++ if(src->linesize[0] || src->linesize[1] || src->linesize[2] ++ || offset[0] || offset[1] || offset[2]) ++ { ++ CLog::Log(LOGERROR, "XVBA::FFDrawSlice - invalid linesizes or offsets provided"); ++ return; ++ } ++ ++ xvba_render_state * render; ++ ++ render = (xvba_render_state*)src->data[0]; ++ if(!render) ++ { ++ CLog::Log(LOGERROR, "XVBA::FFDrawSlice - invalid context handle provided"); ++ return; ++ } ++ ++ // ffmpeg vc-1 decoder does not flush, make sure the data buffer is still valid ++ if (!xvba->IsSurfaceValid(render)) ++ { ++ CLog::Log(LOGWARNING, "XVBA::FFDrawSlice - ignoring invalid buffer"); ++ return; ++ } ++ ++ // decoding ++ XVBA_Decode_Picture_Start_Input startInput; ++ startInput.size = sizeof(startInput); ++ startInput.session = xvba->m_xvbaConfig.xvbaSession; ++ startInput.target_surface = render->surface; ++ { CSingleLock lock(xvba->m_apiSec); ++ if (Success != g_XVBA_vtable.StartDecodePicture(&startInput)) ++ { ++ xvba->SetError(__FUNCTION__, "failed to start decoding", __LINE__); ++ return; ++ } ++ } ++ ++ XVBA_Decode_Picture_Input picInput; ++ picInput.size = sizeof(picInput); ++ picInput.session = xvba->m_xvbaConfig.xvbaSession; ++ XVBABufferDescriptor *list[2]; ++ picInput.buffer_list = list; ++ list[0] = xvba->m_xvbaBufferPool.picture_descriptor_buffer; ++ picInput.num_of_buffers_in_list = 1; ++ if (avctx->codec_id == CODEC_ID_H264) ++ { ++ list[1] = xvba->m_xvbaBufferPool.iq_matrix_buffer; ++ picInput.num_of_buffers_in_list = 2; ++ } ++ ++ { CSingleLock lock(xvba->m_apiSec); ++ if (Success != g_XVBA_vtable.DecodePicture(&picInput)) ++ { ++ xvba->SetError(__FUNCTION__, "failed to decode picture 1", __LINE__); ++ return; ++ } ++ } ++ ++ if (!xvba->EnsureDataControlBuffers(render->num_slices)) ++ return; ++ ++ XVBADataCtrl *dataControl; ++ int location = 0; ++ xvba->m_xvbaBufferPool.data_buffer->data_size_in_buffer = 0; ++ for (unsigned int j = 0; j < render->num_slices; ++j) ++ { ++ int startCodeSize = 0; ++ uint8_t startCode[] = {0x00,0x00,0x01}; ++ if (avctx->codec_id == CODEC_ID_H264) ++ { ++ startCodeSize = 3; ++ memcpy((uint8_t*)xvba->m_xvbaBufferPool.data_buffer->bufferXVBA+location, ++ startCode, 3); ++ } ++ else if (avctx->codec_id == CODEC_ID_VC1 && ++ (memcmp(render->buffers[j].buffer, startCode, 3) != 0)) ++ { ++ startCodeSize = 4; ++ uint8_t sdf = 0x0d; ++ memcpy((uint8_t*)xvba->m_xvbaBufferPool.data_buffer->bufferXVBA+location, ++ startCode, 3); ++ memcpy((uint8_t*)xvba->m_xvbaBufferPool.data_buffer->bufferXVBA+location+3, ++ &sdf, 1); ++ } ++ // check for potential buffer overwrite ++ unsigned int bytesToCopy = render->buffers[j].size; ++ unsigned int freeBufferSize = xvba->m_xvbaBufferPool.data_buffer->buffer_size - ++ xvba->m_xvbaBufferPool.data_buffer->data_size_in_buffer; ++ if (bytesToCopy >= freeBufferSize) ++ { ++ xvba->SetError(__FUNCTION__, "bitstream buffer too large, maybe corrupted packet", __LINE__); ++ return; ++ } ++ memcpy((uint8_t*)xvba->m_xvbaBufferPool.data_buffer->bufferXVBA+location+startCodeSize, ++ render->buffers[j].buffer, ++ render->buffers[j].size); ++ dataControl = (XVBADataCtrl*)xvba->m_xvbaBufferPool.data_control_buffers[j]->bufferXVBA; ++ dataControl->SliceDataLocation = location; ++ dataControl->SliceBytesInBuffer = render->buffers[j].size+startCodeSize; ++ dataControl->SliceBitsInBuffer = dataControl->SliceBytesInBuffer * 8; ++ xvba->m_xvbaBufferPool.data_buffer->data_size_in_buffer += dataControl->SliceBytesInBuffer; ++ location += dataControl->SliceBytesInBuffer; ++ } ++ ++ int bufSize = xvba->m_xvbaBufferPool.data_buffer->data_size_in_buffer; ++ int padding = bufSize % 128; ++ if (padding) ++ { ++ padding = 128 - padding; ++ xvba->m_xvbaBufferPool.data_buffer->data_size_in_buffer += padding; ++ memset((uint8_t*)xvba->m_xvbaBufferPool.data_buffer->bufferXVBA+bufSize,0,padding); ++ } ++ ++ picInput.num_of_buffers_in_list = 2; ++ for (unsigned int i = 0; i < render->num_slices; ++i) ++ { ++ list[0] = xvba->m_xvbaBufferPool.data_buffer; ++ list[0]->data_offset = 0; ++ list[1] = xvba->m_xvbaBufferPool.data_control_buffers[i]; ++ list[1]->data_size_in_buffer = sizeof(*dataControl); ++ { CSingleLock lock(xvba->m_apiSec); ++ if (Success != g_XVBA_vtable.DecodePicture(&picInput)) ++ { ++ xvba->SetError(__FUNCTION__, "failed to decode picture 2", __LINE__); ++ return; ++ } ++ } ++ } ++ XVBA_Decode_Picture_End_Input endInput; ++ endInput.size = sizeof(endInput); ++ endInput.session = xvba->m_xvbaConfig.xvbaSession; ++ { CSingleLock lock(xvba->m_apiSec); ++ if (Success != g_XVBA_vtable.EndDecodePicture(&endInput)) ++ { ++ xvba->SetError(__FUNCTION__, "failed to decode picture 3", __LINE__); ++ return; ++ } ++ } ++ ++ // decode sync and error ++ XVBA_Surface_Sync_Input syncInput; ++ XVBA_Surface_Sync_Output syncOutput; ++ syncInput.size = sizeof(syncInput); ++ syncInput.session = xvba->m_xvbaConfig.xvbaSession; ++ syncInput.surface = render->surface; ++ syncInput.query_status = XVBA_GET_SURFACE_STATUS; ++ syncOutput.size = sizeof(syncOutput); ++ int64_t start = CurrentHostCounter(); ++ while (1) ++ { ++ { CSingleLock lock(xvba->m_apiSec); ++ if (Success != g_XVBA_vtable.SyncSurface(&syncInput, &syncOutput)) ++ { ++ xvba->SetError(__FUNCTION__, "failed sync surface 1", __LINE__); ++ return; ++ } ++ } ++ if (!(syncOutput.status_flags & XVBA_STILL_PENDING)) ++ break; ++ if (CurrentHostCounter() - start > CurrentHostFrequency()) ++ { ++ xvba->SetError(__FUNCTION__, "timed out waiting for surface", __LINE__); ++ break; ++ } ++ usleep(100); ++ } ++ render->state |= FF_XVBA_STATE_DECODED; ++} ++ ++int CDecoder::FFGetBuffer(AVCodecContext *avctx, AVFrame *pic) ++{ ++ CDVDVideoCodecFFmpeg* ctx = (CDVDVideoCodecFFmpeg*)avctx->opaque; ++ CDecoder* xvba = (CDecoder*)ctx->GetHardware(); ++ struct pictureAge* pA = &xvba->picAge; ++ ++ pic->data[0] = ++ pic->data[1] = ++ pic->data[2] = ++ pic->data[3] = 0; ++ ++ pic->linesize[0] = ++ pic->linesize[1] = ++ pic->linesize[2] = ++ pic->linesize[3] = 0; ++ ++ CSingleLock lock(xvba->m_decoderSection); ++ ++ if(xvba->m_displayState != XVBA_OPEN) ++ return -1; ++ ++ if (xvba->m_xvbaConfig.xvbaSession == 0) ++ { ++ if (!xvba->CreateSession(avctx)) ++ return -1; ++ } ++ ++ xvba_render_state * render = NULL; ++ // find unused surface ++ { CSingleLock lock(xvba->m_videoSurfaceSec); ++ for(unsigned int i = 0; i < xvba->m_videoSurfaces.size(); ++i) ++ { ++ if(!(xvba->m_videoSurfaces[i]->state & (FF_XVBA_STATE_USED_FOR_REFERENCE | FF_XVBA_STATE_USED_FOR_RENDER))) ++ { ++ render = xvba->m_videoSurfaces[i]; ++ render->state = 0; ++ break; ++ } ++ } ++ } ++ ++ // create a new render state ++ if (render == NULL) ++ { ++ render = (xvba_render_state*)calloc(sizeof(xvba_render_state), 1); ++ if (render == NULL) ++ { ++ CLog::Log(LOGERROR, "XVBA::FFGetBuffer - calloc failed"); ++ return -1; ++ } ++ render->surface = 0; ++ render->buffers_alllocated = 0; ++ CSingleLock lock(xvba->m_videoSurfaceSec); ++ xvba->m_videoSurfaces.push_back(render); ++ } ++ ++ // create a new surface ++ if (render->surface == 0) ++ { ++ XVBA_Create_Surface_Input surfaceInput; ++ XVBA_Create_Surface_Output surfaceOutput; ++ surfaceInput.size = sizeof(surfaceInput); ++ surfaceInput.surface_type = xvba->m_xvbaConfig.decoderCap.surface_type; ++ surfaceInput.width = xvba->m_xvbaConfig.surfaceWidth; ++ surfaceInput.height = xvba->m_xvbaConfig.surfaceHeight; ++ surfaceInput.session = xvba->m_xvbaConfig.xvbaSession; ++ surfaceOutput.size = sizeof(surfaceOutput); ++ { CSingleLock lock(xvba->m_apiSec); ++ if (Success != g_XVBA_vtable.CreateSurface(&surfaceInput, &surfaceOutput)) ++ { ++ xvba->SetError(__FUNCTION__, "failed to create video surface", __LINE__); ++ return -1; ++ } ++ } ++ render->surface = surfaceOutput.surface; ++ render->picture_descriptor = (XVBAPictureDescriptor *)xvba->m_xvbaBufferPool.picture_descriptor_buffer->bufferXVBA; ++ render->iq_matrix = (XVBAQuantMatrixAvc *)xvba->m_xvbaBufferPool.iq_matrix_buffer->bufferXVBA; ++ CLog::Log(LOGDEBUG, "XVBA::FFGetBuffer - created video surface"); ++ } ++ ++ if (render == NULL) ++ return -1; ++ ++ pic->data[0] = (uint8_t*)render; ++ ++ if(pic->reference) ++ { ++ pic->age = pA->ip_age[0]; ++ pA->ip_age[0]= pA->ip_age[1]+1; ++ pA->ip_age[1]= 1; ++ pA->b_age++; ++ } ++ else ++ { ++ pic->age = pA->b_age; ++ pA->ip_age[0]++; ++ pA->ip_age[1]++; ++ pA->b_age = 1; ++ } ++ pic->type= FF_BUFFER_TYPE_USER; ++ ++ render->state |= FF_XVBA_STATE_USED_FOR_REFERENCE; ++ render->state &= ~FF_XVBA_STATE_DECODED; ++ pic->reordered_opaque= avctx->reordered_opaque; ++ ++ return 0; ++} ++ ++int CDecoder::Decode(AVCodecContext* avctx, AVFrame* frame) ++{ ++ int result = Check(avctx); ++ if (result) ++ return result; ++ ++ CSingleLock lock(m_decoderSection); ++ ++ if(frame) ++ { // we have a new frame from decoder ++ ++ xvba_render_state * render = (xvba_render_state*)frame->data[0]; ++ if(!render) ++ { ++ CLog::Log(LOGERROR, "XVBA::Decode - no render buffer"); ++ return VC_ERROR; ++ } ++ ++ // ffmpeg vc-1 decoder does not flush, make sure the data buffer is still valid ++ if (!IsSurfaceValid(render)) ++ { ++ CLog::Log(LOGWARNING, "XVBA::Decode - ignoring invalid buffer"); ++ return VC_BUFFER; ++ } ++ if (!(render->state & FF_XVBA_STATE_DECODED)) ++ { ++ CLog::Log(LOGDEBUG, "XVBA::Decode - ffmpeg failed"); ++ return VC_BUFFER; ++ } ++ ++ CSingleLock lock(m_videoSurfaceSec); ++ render->state |= FF_XVBA_STATE_USED_FOR_RENDER; ++ lock.Leave(); ++ ++ // send frame to output for processing ++ CXvbaDecodedPicture pic; ++ memset(&pic.DVDPic, 0, sizeof(pic.DVDPic)); ++ ((CDVDVideoCodecFFmpeg*)avctx->opaque)->GetPictureCommon(&pic.DVDPic); ++ pic.render = render; ++ m_bufferStats.IncDecoded(); ++ m_xvbaOutput.m_dataPort.SendOutMessage(COutputDataProtocol::NEWFRAME, &pic, sizeof(pic)); ++ ++ m_codecControl = pic.DVDPic.iFlags & (DVP_FLAG_DRAIN | DVP_FLAG_SKIP_PROC); ++ if (m_codecControl & DVP_FLAG_SKIP_PROC) ++ { ++ m_bufferStats.SetCmd(DVP_FLAG_SKIP_PROC); ++ } ++ } ++ ++ int retval = 0; ++ uint16_t decoded, processed, render; ++ Message *msg; ++ while (m_xvbaOutput.m_controlPort.ReceiveInMessage(&msg)) ++ { ++ if (msg->signal == COutputControlProtocol::ERROR) ++ { ++ m_displayState = XVBA_ERROR; ++ retval |= VC_ERROR; ++ } ++ msg->Release(); ++ } ++ ++ m_bufferStats.Get(decoded, processed, render); ++ ++ uint64_t startTime = CurrentHostCounter(); ++ while (!retval) ++ { ++ if (m_xvbaOutput.m_dataPort.ReceiveInMessage(&msg)) ++ { ++ if (msg->signal == COutputDataProtocol::PICTURE) ++ { ++ if (m_presentPicture) ++ { ++ m_presentPicture->ReturnUnused(); ++ m_presentPicture = 0; ++ } ++ ++ m_presentPicture = *(CXvbaRenderPicture**)msg->data; ++ m_presentPicture->xvba = this; ++ m_bufferStats.DecRender(); ++ m_bufferStats.Get(decoded, processed, render); ++ retval |= VC_PICTURE; ++ } ++ msg->Release(); ++ } ++ else if (m_xvbaOutput.m_controlPort.ReceiveInMessage(&msg)) ++ { ++ if (msg->signal == COutputControlProtocol::STATS) ++ { ++ m_bufferStats.Get(decoded, processed, render); ++ } ++ else ++ { ++ m_displayState = XVBA_ERROR; ++ retval |= VC_ERROR; ++ } ++ msg->Release(); ++ } ++ ++ if ((m_codecControl & DVP_FLAG_DRAIN)) ++ { ++ if (decoded + processed + render < 2) ++ { ++ retval |= VC_BUFFER; ++ } ++ } ++ else ++ { ++ if (decoded + processed + render < 4) ++ { ++ retval |= VC_BUFFER; ++ } ++ } ++ ++ if (!retval && !m_inMsgEvent.WaitMSec(2000)) ++ break; ++ } ++ uint64_t diff = CurrentHostCounter() - startTime; ++ if (retval & VC_PICTURE) ++ { ++ m_bufferStats.SetParams(diff, m_speed); ++ if (diff*1000/CurrentHostFrequency() > 50) ++ CLog::Log(LOGDEBUG,"XVBA::Decode long wait: %d", (int)((diff*1000)/CurrentHostFrequency())); ++ } ++ ++ if (!retval) ++ { ++ CLog::Log(LOGERROR, "XVBA::%s - timed out waiting for output message", __FUNCTION__); ++ m_displayState = XVBA_ERROR; ++ retval |= VC_ERROR; ++ } ++ ++ return retval; ++ ++} ++ ++bool CDecoder::GetPicture(AVCodecContext* avctx, AVFrame* frame, DVDVideoPicture* picture) ++{ ++ CSingleLock lock(m_decoderSection); ++ ++ if (m_displayState != XVBA_OPEN) ++ return false; ++ ++ *picture = m_presentPicture->DVDPic; ++ picture->xvba = m_presentPicture; ++ ++ return true; ++} ++ ++void CDecoder::ReturnRenderPicture(CXvbaRenderPicture *renderPic) ++{ ++ m_xvbaOutput.m_dataPort.SendOutMessage(COutputDataProtocol::RETURNPIC, &renderPic, sizeof(renderPic)); ++} ++ ++ ++//void CDecoder::CopyYV12(int index, uint8_t *dest) ++//{ ++// CSharedLock lock(m_decoderSection); ++// ++// { CSharedLock dLock(m_displaySection); ++// if(m_displayState != XVBA_OPEN) ++// return; ++// } ++// ++// if (!m_flipBuffer[index].outPic) ++// { ++// CLog::Log(LOGWARNING, "XVBA::Present: present picture is NULL"); ++// return; ++// } ++// ++// XVBA_GetSurface_Target target; ++// target.size = sizeof(target); ++// target.surfaceType = XVBA_YV12; ++// target.flag = XVBA_FRAME; ++// ++// XVBA_Get_Surface_Input input; ++// input.size = sizeof(input); ++// input.session = m_xvbaSession; ++// input.src_surface = m_flipBuffer[index].outPic->render->surface; ++// input.target_buffer = dest; ++// input.target_pitch = m_surfaceWidth; ++// input.target_width = m_surfaceWidth; ++// input.target_height = m_surfaceHeight; ++// input.target_parameter = target; ++// { CSingleLock lock(m_apiSec); ++// if (Success != g_XVBA_vtable.GetSurface(&input)) ++// { ++// CLog::Log(LOGERROR,"(XVBA::CopyYV12) failed to get surface"); ++// } ++// } ++//} ++ ++void CDecoder::Reset() ++{ ++ CSingleLock lock(m_decoderSection); ++ ++ if (!m_xvbaConfig.xvbaSession) ++ return; ++ ++ Message *reply; ++ if (m_xvbaOutput.m_controlPort.SendOutMessageSync(COutputControlProtocol::FLUSH, ++ &reply, ++ 2000)) ++ { ++ bool success = reply->signal == COutputControlProtocol::ACC ? true : false; ++ reply->Release(); ++ if (!success) ++ { ++ CLog::Log(LOGERROR, "XVBA::%s - flush returned error", __FUNCTION__); ++ m_displayState = XVBA_ERROR; ++ } ++ else ++ m_bufferStats.Reset(); ++ } ++ else ++ { ++ CLog::Log(LOGERROR, "XVBA::%s - flush timed out", __FUNCTION__); ++ m_displayState = XVBA_ERROR; ++ } ++} ++ ++bool CDecoder::CanSkipDeint() ++{ ++ return m_bufferStats.CanSkipDeint(); ++} ++ ++void CDecoder::SetSpeed(int speed) ++{ ++ m_speed = speed; ++} ++ ++//----------------------------------------------------------------------------- ++// RenderPicture ++//----------------------------------------------------------------------------- ++ ++CXvbaRenderPicture* CXvbaRenderPicture::Acquire() ++{ ++ CSingleLock lock(*renderPicSection); ++ ++ if (refCount == 0) ++ xvba->Acquire(); ++ ++ refCount++; ++ return this; ++} ++ ++long CXvbaRenderPicture::Release() ++{ ++ CSingleLock lock(*renderPicSection); ++ ++ refCount--; ++ if (refCount > 0) ++ return refCount; ++ ++ lock.Leave(); ++ xvba->ReturnRenderPicture(this); ++ xvba->ReleasePicReference(); ++ ++ return refCount; ++} ++ ++void CXvbaRenderPicture::Transfer() ++{ ++ CSingleLock lock(*renderPicSection); ++ ++ if (valid) ++ xvbaOutput->TransferSurface(sourceIdx); ++} ++ ++void CXvbaRenderPicture::ReturnUnused() ++{ ++ { CSingleLock lock(*renderPicSection); ++ if (refCount > 0) ++ return; ++ } ++ if (xvba) ++ xvba->ReturnRenderPicture(this); ++} ++ ++//----------------------------------------------------------------------------- ++// Output ++//----------------------------------------------------------------------------- ++COutput::COutput(CEvent *inMsgEvent) : ++ CThread("XVBA Output Thread"), ++ m_controlPort("OutputControlPort", inMsgEvent, &m_outMsgEvent), ++ m_dataPort("OutputDataPort", inMsgEvent, &m_outMsgEvent) ++{ ++ m_inMsgEvent = inMsgEvent; ++ ++ CXvbaRenderPicture pic; ++ pic.renderPicSection = &m_bufferPool.renderPicSec; ++ pic.refCount = 0; ++ for (unsigned int i = 0; i < NUM_RENDER_PICS; i++) ++ { ++ m_bufferPool.allRenderPics.push_back(pic); ++ } ++ for (unsigned int i = 0; i < m_bufferPool.allRenderPics.size(); ++i) ++ { ++ m_bufferPool.freeRenderPics.push_back(&m_bufferPool.allRenderPics[i]); ++ } ++} ++ ++void COutput::Start() ++{ ++ Create(); ++} ++ ++COutput::~COutput() ++{ ++ Dispose(); ++ ++ m_bufferPool.freeRenderPics.clear(); ++ m_bufferPool.usedRenderPics.clear(); ++ m_bufferPool.allRenderPics.clear(); ++} ++ ++void COutput::Dispose() ++{ ++ CSingleLock lock(g_graphicsContext); ++ m_bStop = true; ++ m_outMsgEvent.Set(); ++ StopThread(); ++ m_controlPort.Purge(); ++ m_dataPort.Purge(); ++} ++ ++void COutput::OnStartup() ++{ ++ CLog::Log(LOGNOTICE, "COutput::OnStartup: Output Thread created"); ++} ++ ++void COutput::OnExit() ++{ ++ CLog::Log(LOGNOTICE, "COutput::OnExit: Output Thread terminated"); ++} ++ ++enum OUTPUT_STATES ++{ ++ O_TOP = 0, // 0 ++ O_TOP_ERROR, // 1 ++ O_TOP_UNCONFIGURED, // 2 ++ O_TOP_CONFIGURED, // 3 ++ O_TOP_CONFIGURED_WAIT_RES1, // 4 ++ O_TOP_CONFIGURED_WAIT_DEC, // 5 ++ O_TOP_CONFIGURED_STEP1, // 6 ++ O_TOP_CONFIGURED_WAIT_RES2, // 7 ++ O_TOP_CONFIGURED_STEP2, // 8 ++}; ++ ++int OUTPUT_parentStates[] = { ++ -1, ++ 0, //TOP_ERROR ++ 0, //TOP_UNCONFIGURED ++ 0, //TOP_CONFIGURED ++ 3, //TOP_CONFIGURED_WAIT_RES1 ++ 3, //TOP_CONFIGURED_WAIT_DEC ++ 3, //TOP_CONFIGURED_STEP1 ++ 3, //TOP_CONFIGURED_WAIT_RES2 ++ 3, //TOP_CONFIGURED_STEP2 ++}; ++ ++void COutput::StateMachine(int signal, Protocol *port, Message *msg) ++{ ++ for (int state = m_state; ; state = OUTPUT_parentStates[state]) ++ { ++ switch (state) ++ { ++ case O_TOP: // TOP ++ if (port == &m_controlPort) ++ { ++ switch (signal) ++ { ++ case COutputControlProtocol::FLUSH: ++ msg->Reply(COutputControlProtocol::ACC); ++ return; ++ case COutputControlProtocol::PRECLEANUP: ++ msg->Reply(COutputControlProtocol::ACC); ++ return; ++ default: ++ break; ++ } ++ } ++ else if (port == &m_dataPort) ++ { ++ switch (signal) ++ { ++ case COutputDataProtocol::RETURNPIC: ++ CXvbaRenderPicture *pic; ++ pic = *((CXvbaRenderPicture**)msg->data); ++ ProcessReturnPicture(pic); ++ return; ++ default: ++ break; ++ } ++ } ++ { ++ std::string portName = port == NULL ? "timer" : port->portName; ++ CLog::Log(LOGWARNING, "COutput::%s - signal: %d form port: %s not handled for state: %d", __FUNCTION__, signal, portName.c_str(), m_state); ++ } ++ return; ++ ++ case O_TOP_ERROR: ++ m_extTimeout = 1000; ++ break; ++ ++ case O_TOP_UNCONFIGURED: ++ if (port == &m_controlPort) ++ { ++ switch (signal) ++ { ++ case COutputControlProtocol::INIT: ++ CXvbaConfig *data; ++ data = (CXvbaConfig*)msg->data; ++ if (data) ++ { ++ m_config = *data; ++ } ++ Init(); ++ EnsureBufferPool(); ++ if (!m_xvbaError) ++ { ++ m_state = O_TOP_CONFIGURED_WAIT_RES1; ++ msg->Reply(COutputControlProtocol::ACC); ++ } ++ else ++ { ++ m_state = O_TOP_ERROR; ++ msg->Reply(COutputControlProtocol::ERROR); ++ } ++ return; ++ default: ++ break; ++ } ++ } ++ break; ++ ++ case O_TOP_CONFIGURED: ++ if (port == &m_controlPort) ++ { ++ switch (signal) ++ { ++ case COutputControlProtocol::FLUSH: ++ m_state = O_TOP_CONFIGURED_WAIT_RES1; ++ Flush(); ++ msg->Reply(COutputControlProtocol::ACC); ++ return; ++ case COutputControlProtocol::PRECLEANUP: ++ m_state = O_TOP_CONFIGURED_WAIT_RES1; ++ Flush(); ++ PreReleaseBufferPool(); ++ msg->Reply(COutputControlProtocol::ACC); ++ return; ++ default: ++ break; ++ } ++ } ++ else if (port == &m_dataPort) ++ { ++ switch (signal) ++ { ++ case COutputDataProtocol::NEWFRAME: ++ CXvbaDecodedPicture *frame; ++ frame = (CXvbaDecodedPicture*)msg->data; ++ if (frame) ++ { ++ m_decodedPics.push(*frame); ++ m_extTimeout = 0; ++ } ++ return; ++ case COutputDataProtocol::RETURNPIC: ++ CXvbaRenderPicture *pic; ++ pic = *((CXvbaRenderPicture**)msg->data); ++ ProcessReturnPicture(pic); ++ m_controlPort.SendInMessage(COutputControlProtocol::STATS); ++ m_extTimeout = 0; ++ return; ++ default: ++ break; ++ } ++ } ++ break; ++ ++ case O_TOP_CONFIGURED_WAIT_RES1: ++ if (port == NULL) // timeout ++ { ++ switch (signal) ++ { ++ case COutputControlProtocol::TIMEOUT: ++ if (!m_decodedPics.empty() && FindFreeSurface() >= 0 && !m_bufferPool.freeRenderPics.empty()) ++ { ++ m_state = O_TOP_CONFIGURED_WAIT_DEC; ++ m_bStateMachineSelfTrigger = true; ++ } ++ else ++ { ++ if (m_extTimeout != 0) ++ { ++ uint16_t decoded, processed, render; ++ m_config.stats->Get(decoded, processed, render); ++// CLog::Log(LOGDEBUG, "CVDPAU::COutput - timeout idle: decoded: %d, proc: %d, render: %d", decoded, processed, render); ++ } ++ m_extTimeout = 100; ++ } ++ return; ++ default: ++ break; ++ } ++ } ++ break; ++ ++ case O_TOP_CONFIGURED_WAIT_DEC: ++ if (port == NULL) // timeout ++ { ++ switch (signal) ++ { ++ case COutputControlProtocol::TIMEOUT: ++ if (IsDecodingFinished()) ++ { ++ m_state = O_TOP_CONFIGURED_STEP1; ++ m_bStateMachineSelfTrigger = true; ++ } ++ else ++ { ++ m_extTimeout = 1; ++ } ++ return; ++ default: ++ break; ++ } ++ } ++ break; ++ ++ case O_TOP_CONFIGURED_STEP1: ++ if (port == NULL) // timeout ++ { ++ switch (signal) ++ { ++ case COutputControlProtocol::TIMEOUT: ++ m_processPicture = m_decodedPics.front(); ++ m_decodedPics.pop(); ++ InitCycle(); ++ CXvbaRenderPicture *pic; ++ pic = ProcessPicture(); ++ if (pic) ++ { ++ m_config.stats->IncRender(); ++ m_dataPort.SendInMessage(COutputDataProtocol::PICTURE, &pic, sizeof(pic)); ++ } ++ if (m_xvbaError) ++ { ++ m_state = O_TOP_ERROR; ++ return; ++ } ++ if (m_deinterlacing && !m_deintSkip) ++ { ++ m_state = O_TOP_CONFIGURED_WAIT_RES2; ++ m_extTimeout = 0; ++ } ++ else ++ { ++ FiniCycle(); ++ m_state = O_TOP_CONFIGURED_WAIT_RES1; ++ m_extTimeout = 0; ++ } ++ return; ++ default: ++ break; ++ } ++ } ++ break; ++ ++ case O_TOP_CONFIGURED_WAIT_RES2: ++ if (port == NULL) // timeout ++ { ++ switch (signal) ++ { ++ case COutputControlProtocol::TIMEOUT: ++ if (FindFreeSurface() >= 0 && !m_bufferPool.freeRenderPics.empty()) ++ { ++ m_state = O_TOP_CONFIGURED_STEP2; ++ m_bStateMachineSelfTrigger = true; ++ } ++ else ++ { ++ if (m_extTimeout != 0) ++ { ++ uint16_t decoded, processed, render; ++ m_config.stats->Get(decoded, processed, render); ++ CLog::Log(LOGDEBUG, "CVDPAU::COutput - timeout idle: decoded: %d, proc: %d, render: %d", decoded, processed, render); ++ } ++ m_extTimeout = 100; ++ } ++ return; ++ default: ++ break; ++ } ++ } ++ break; ++ ++ case O_TOP_CONFIGURED_STEP2: ++ if (port == NULL) // timeout ++ { ++ switch (signal) ++ { ++ case COutputControlProtocol::TIMEOUT: ++ CXvbaRenderPicture *pic; ++ m_deintStep = 1; ++ pic = ProcessPicture(); ++ if (pic) ++ { ++ m_config.stats->IncRender(); ++ m_dataPort.SendInMessage(COutputDataProtocol::PICTURE, &pic, sizeof(pic)); ++ } ++ if (m_xvbaError) ++ { ++ m_state = O_TOP_ERROR; ++ return; ++ } ++ FiniCycle(); ++ m_state = O_TOP_CONFIGURED_WAIT_RES1; ++ m_extTimeout = 0; ++ return; ++ default: ++ break; ++ } ++ } ++ break; ++ ++ default: // we are in no state, should not happen ++ CLog::Log(LOGERROR, "COutput::%s - no valid state: %d", __FUNCTION__, m_state); ++ return; ++ } ++ } // for ++} ++ ++void COutput::Process() ++{ ++ Message *msg; ++ Protocol *port; ++ bool gotMsg; ++ ++ m_state = O_TOP_UNCONFIGURED; ++ m_extTimeout = 1000; ++ m_bStateMachineSelfTrigger = false; ++ ++ while (!m_bStop) ++ { ++ gotMsg = false; ++ ++ if (m_bStateMachineSelfTrigger) ++ { ++ m_bStateMachineSelfTrigger = false; ++ // self trigger state machine ++ StateMachine(msg->signal, port, msg); ++ if (!m_bStateMachineSelfTrigger) ++ { ++ msg->Release(); ++ msg = NULL; ++ } ++ continue; ++ } ++ // check control port ++ else if (m_controlPort.ReceiveOutMessage(&msg)) ++ { ++ gotMsg = true; ++ port = &m_controlPort; ++ } ++ // check data port ++ else if (m_dataPort.ReceiveOutMessage(&msg)) ++ { ++ gotMsg = true; ++ port = &m_dataPort; ++ } ++ if (gotMsg) ++ { ++ StateMachine(msg->signal, port, msg); ++ if (!m_bStateMachineSelfTrigger) ++ { ++ msg->Release(); ++ msg = NULL; ++ } ++ continue; ++ } ++ ++ // wait for message ++ else if (m_outMsgEvent.WaitMSec(m_extTimeout)) ++ { ++ continue; ++ } ++ // time out ++ else ++ { ++ msg = m_controlPort.GetMessage(); ++ msg->signal = COutputControlProtocol::TIMEOUT; ++ port = 0; ++ // signal timeout to state machine ++ StateMachine(msg->signal, port, msg); ++ if (!m_bStateMachineSelfTrigger) ++ { ++ msg->Release(); ++ msg = NULL; ++ } ++ } ++ } ++ Flush(); ++ Uninit(); ++} ++ ++bool COutput::Init() ++{ ++ if (!CreateGlxContext()) ++ return false; ++ ++ m_xvbaError = false; ++ m_processPicture.render = 0; ++ ++ return true; ++} ++ ++bool COutput::Uninit() ++{ ++ ReleaseBufferPool(); ++ DestroyGlxContext(); ++ return true; ++} ++ ++void COutput::Flush() ++{ ++ while (!m_decodedPics.empty()) ++ { ++ CXvbaDecodedPicture pic = m_decodedPics.front(); ++ m_decodedPics.pop(); ++ CSingleLock lock(*m_config.videoSurfaceSec); ++ if (pic.render) ++ pic.render->state &= ~(FF_XVBA_STATE_USED_FOR_RENDER | FF_XVBA_STATE_DECODED); ++ } ++ ++ if (m_processPicture.render) ++ { ++ CSingleLock lock(*m_config.videoSurfaceSec); ++ m_processPicture.render->state &= ~(FF_XVBA_STATE_USED_FOR_RENDER | FF_XVBA_STATE_DECODED); ++ m_processPicture.render = 0; ++ } ++ ++ Message *msg; ++ while (m_dataPort.ReceiveOutMessage(&msg)) ++ { ++ if (msg->signal == COutputDataProtocol::NEWFRAME) ++ { ++ CXvbaDecodedPicture pic = *(CXvbaDecodedPicture*)msg->data; ++ CSingleLock lock(*m_config.videoSurfaceSec); ++ if (pic.render) ++ pic.render->state &= ~(FF_XVBA_STATE_USED_FOR_RENDER | FF_XVBA_STATE_DECODED); ++ } ++ else if (msg->signal == COutputDataProtocol::RETURNPIC) ++ { ++ CXvbaRenderPicture *pic; ++ pic = *((CXvbaRenderPicture**)msg->data); ++ ProcessReturnPicture(pic); ++ } ++ msg->Release(); ++ } ++ ++ while (m_dataPort.ReceiveInMessage(&msg)) ++ { ++ if (msg->signal == COutputDataProtocol::PICTURE) ++ { ++ CXvbaRenderPicture *pic; ++ pic = *((CXvbaRenderPicture**)msg->data); ++ ProcessReturnPicture(pic); ++ } ++ } ++} ++ ++bool COutput::IsDecodingFinished() ++{ ++ return true; ++ ++ // check for decoding to be finished ++ CXvbaDecodedPicture decodedPic = m_decodedPics.front(); ++ ++ XVBA_Surface_Sync_Input syncInput; ++ XVBA_Surface_Sync_Output syncOutput; ++ syncInput.size = sizeof(syncInput); ++ syncInput.session = m_config.xvbaSession; ++ syncInput.surface = decodedPic.render->surface; ++ syncInput.query_status = XVBA_GET_SURFACE_STATUS; ++ syncOutput.size = sizeof(syncOutput); ++ { CSingleLock lock(*(m_config.apiSec)); ++ if (Success != g_XVBA_vtable.SyncSurface(&syncInput, &syncOutput)) ++ { ++ CLog::Log(LOGERROR,"XVBA - failed sync surface"); ++ m_xvbaError = true; ++ return false; ++ } ++ } ++ if (!(syncOutput.status_flags & XVBA_STILL_PENDING)) ++ return true; ++ ++ return false; ++} ++ ++void COutput::TransferSurface(uint32_t source) ++{ ++ XvbaBufferPool::GLVideoSurface *glSurface = &m_bufferPool.glSurfaces[source]; ++ ++ if (glSurface->transferred) ++ return; ++ ++ glSurface->transferred = true; ++ ++ // transfer surface ++ XVBA_Transfer_Surface_Input transInput; ++ transInput.size = sizeof(transInput); ++ transInput.session = m_config.xvbaSession; ++ transInput.src_surface = glSurface->render->surface; ++ transInput.target_surface = glSurface->glSurface; ++ transInput.flag = glSurface->field; ++ { CSingleLock lock(*(m_config.apiSec)); ++ if (Success != g_XVBA_vtable.TransferSurface(&transInput)) ++ { ++ CLog::Log(LOGERROR,"(XVBA) failed to transfer surface"); ++ m_xvbaError = true; ++ return; ++ } ++ } ++} ++ ++CXvbaRenderPicture* COutput::ProcessPicture() ++{ ++ CXvbaRenderPicture *retPic = 0; ++ ++ if (m_deintStep == 1) ++ { ++ if(m_field == XVBA_TOP_FIELD) ++ m_field = XVBA_BOTTOM_FIELD; ++ else ++ m_field = XVBA_TOP_FIELD; ++ } ++ ++ // find unused shared surface ++ unsigned int idx = FindFreeSurface(); ++ XvbaBufferPool::GLVideoSurface *glSurface = &m_bufferPool.glSurfaces[idx]; ++ glSurface->used = true; ++ glSurface->field = m_field; ++ glSurface->render = m_processPicture.render; ++ glSurface->transferred = false; ++ ++ int cmd = 0; ++ m_config.stats->GetCmd(cmd); ++ ++// if (!(cmd & DVP_FLAG_SKIP_PROC)) ++// { ++ // transfer surface ++ XVBA_Transfer_Surface_Input transInput; ++ transInput.size = sizeof(transInput); ++ transInput.session = m_config.xvbaSession; ++ transInput.src_surface = m_processPicture.render->surface; ++ transInput.target_surface = glSurface->glSurface; ++ transInput.flag = m_field; ++ { CSingleLock lock(*(m_config.apiSec)); ++ if (Success != g_XVBA_vtable.TransferSurface(&transInput)) ++ { ++ CLog::Log(LOGERROR,"(XVBA) failed to transfer surface"); ++ m_xvbaError = true; ++ return retPic; ++ } ++ } ++ ++ // make sure that transfer is completed ++// uint64_t maxTimeout = 1000000000LL; ++// GLsync ReadyFence = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0); ++// glClientWaitSync(ReadyFence, GL_SYNC_FLUSH_COMMANDS_BIT, maxTimeout); ++// glDeleteSync(ReadyFence); ++// glFinish();GL_SYNC_FLUSH_COMMANDS_BIT ++// } ++// else ++// { ++// CLog::Log(LOGDEBUG,"XVBA::ProcessPicture - skipped transfer surface"); ++// m_processPicture.DVDPic.iFlags |= DVP_FLAG_DROPPED; ++// } ++ ++ // prepare render pic ++ retPic = m_bufferPool.freeRenderPics.front(); ++ m_bufferPool.freeRenderPics.pop_front(); ++ m_bufferPool.usedRenderPics.push_back(retPic); ++ retPic->sourceIdx = glSurface->id; ++ retPic->DVDPic = m_processPicture.DVDPic; ++ retPic->valid = true; ++ retPic->texture = glSurface->texture; ++ retPic->crop = CRect(0,0,0,0); ++ retPic->texWidth = m_config.surfaceWidth; ++ retPic->texHeight = m_config.surfaceHeight; ++ retPic->xvbaOutput = this; ++ ++ // set repeat pic for de-interlacing ++ if (m_deinterlacing) ++ { ++ if (m_deintStep == 1) ++ { ++ retPic->DVDPic.pts = DVD_NOPTS_VALUE; ++ retPic->DVDPic.dts = DVD_NOPTS_VALUE; ++ } ++ retPic->DVDPic.iRepeatPicture = 0.0; ++ } ++ ++ return retPic; ++} ++ ++void COutput::ProcessReturnPicture(CXvbaRenderPicture *pic) ++{ ++ std::deque::iterator it; ++ it = std::find(m_bufferPool.usedRenderPics.begin(), m_bufferPool.usedRenderPics.end(), pic); ++ if (it == m_bufferPool.usedRenderPics.end()) ++ { ++ CLog::Log(LOGWARNING, "COutput::ProcessReturnPicture - pic not found"); ++ return; ++ } ++ m_bufferPool.usedRenderPics.erase(it); ++ m_bufferPool.freeRenderPics.push_back(pic); ++ if (!pic->valid) ++ { ++ CLog::Log(LOGDEBUG, "COutput::%s - return of invalid render pic", __FUNCTION__); ++ return; ++ } ++ ++ if (m_config.useSharedSurfaces) ++ { ++ xvba_render_state *render = m_bufferPool.glSurfaces[pic->sourceIdx].render; ++ if (render) ++ { ++ // check if video surface if referenced by other glSurfaces ++ bool referenced(false); ++ for (unsigned int i=0; isourceIdx) ++ continue; ++ if (m_bufferPool.glSurfaces[i].render == render) ++ { ++ referenced = true; ++ break; ++ } ++ } ++ if (m_processPicture.render == render) ++ referenced = true; ++ ++ // release video surface ++ if (!referenced) ++ { ++ CSingleLock lock(*m_config.videoSurfaceSec); ++ render->state &= ~(FF_XVBA_STATE_USED_FOR_RENDER | FF_XVBA_STATE_DECODED); ++ } ++ ++ // unreference video surface ++ m_bufferPool.glSurfaces[pic->sourceIdx].render = 0; ++ } ++ m_bufferPool.glSurfaces[pic->sourceIdx].used = false; ++ return; ++ } ++} ++ ++int COutput::FindFreeSurface() ++{ ++ // find free shared surface ++ unsigned int i; ++ for (i = 0; i < m_bufferPool.glSurfaces.size(); ++i) ++ { ++ if (!m_bufferPool.glSurfaces[i].used) ++ break; ++ } ++ if (i == m_bufferPool.glSurfaces.size()) ++ return -1; ++ else ++ return i; ++} ++ ++void COutput::InitCycle() ++{ ++ uint64_t latency; ++ int speed; ++ m_config.stats->GetParams(latency, speed); ++ latency = (latency*1000)/CurrentHostFrequency(); ++ ++ m_config.stats->SetCanSkipDeint(false); ++ ++ EDEINTERLACEMODE mode = g_settings.m_currentVideoSettings.m_DeinterlaceMode; ++ EINTERLACEMETHOD method = g_settings.m_currentVideoSettings.m_InterlaceMethod; ++ bool interlaced = m_processPicture.DVDPic.iFlags & DVP_FLAG_INTERLACED; ++ ++ if (mode == VS_DEINTERLACEMODE_FORCE || ++ (mode == VS_DEINTERLACEMODE_AUTO && interlaced)) ++ { ++ if((method == VS_INTERLACEMETHOD_AUTO && interlaced) ++ || method == VS_INTERLACEMETHOD_XVBA) ++ { ++ m_deinterlacing = true; ++ m_deintSkip = false; ++ m_config.stats->SetCanSkipDeint(true); ++ ++ if (m_processPicture.DVDPic.iFlags & DVP_FLAG_DROPDEINT) ++ { ++ m_deintSkip = true; ++ } ++ ++ // do only half deinterlacing ++ if (speed != DVD_PLAYSPEED_NORMAL || !g_graphicsContext.IsFullScreenVideo()) ++ { ++ m_config.stats->SetCanSkipDeint(false); ++ m_deintSkip = true; ++ } ++ ++ if(m_processPicture.DVDPic.iFlags & DVP_FLAG_TOP_FIELD_FIRST) ++ m_field = XVBA_TOP_FIELD; ++ else ++ m_field = XVBA_BOTTOM_FIELD; ++ } ++ } ++ else ++ { ++ m_deinterlacing = false; ++ m_field = XVBA_FRAME; ++ } ++ ++ m_processPicture.DVDPic.format = DVDVideoPicture::FMT_XVBA; ++ m_processPicture.DVDPic.iFlags &= ~(DVP_FLAG_TOP_FIELD_FIRST | ++ DVP_FLAG_REPEAT_TOP_FIELD | ++ DVP_FLAG_INTERLACED); ++ m_processPicture.DVDPic.iWidth = m_config.vidWidth; ++ m_processPicture.DVDPic.iHeight = m_config.vidHeight; ++ ++ m_deintStep = 0; ++} ++ ++void COutput::FiniCycle() ++{ ++// { CSingleLock lock(*m_config.videoSurfaceSec); ++// m_processPicture.render->state &= ~FF_XVBA_STATE_USED_FOR_RENDER; ++// } ++ m_processPicture.render = 0; ++ m_config.stats->DecDecoded(); ++} ++ ++bool COutput::EnsureBufferPool() ++{ ++ if (m_config.useSharedSurfaces && m_bufferPool.glSurfaces.empty()) ++ { ++ GLenum textureTarget; ++ if (!glewIsSupported("GL_ARB_texture_non_power_of_two") && glewIsSupported("GL_ARB_texture_rectangle")) ++ { ++ textureTarget = GL_TEXTURE_RECTANGLE_ARB; ++ } ++ else ++ textureTarget = GL_TEXTURE_2D; ++ ++ // create shared surfaces ++ XvbaBufferPool::GLVideoSurface surface; ++ for (unsigned int i = 0; i < NUM_RENDER_PICS; ++i) ++ { ++ glEnable(textureTarget); ++ glGenTextures(1, &surface.texture); ++ glBindTexture(textureTarget, surface.texture); ++ glTexParameteri(textureTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR); ++ glTexParameteri(textureTarget, GL_TEXTURE_MAG_FILTER, GL_LINEAR); ++ glTexParameteri(textureTarget, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); ++ glTexParameteri(textureTarget, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); ++ glPixelStorei(GL_UNPACK_ALIGNMENT, 4); ++ glTexImage2D(textureTarget, 0, GL_RGBA, m_config.surfaceWidth, m_config.surfaceHeight, 0, GL_BGRA, GL_UNSIGNED_BYTE, NULL); ++ ++ XVBA_Create_GLShared_Surface_Input surfInput; ++ XVBA_Create_GLShared_Surface_Output surfOutput; ++ surfInput.size = sizeof(surfInput); ++ surfInput.session = m_config.xvbaSession; ++ surfInput.gltexture = surface.texture; ++ surfInput.glcontext = m_glContext; ++ surfOutput.size = sizeof(surfOutput); ++ surfOutput.surface = 0; ++ if (Success != g_XVBA_vtable.CreateGLSharedSurface(&surfInput, &surfOutput)) ++ { ++ CLog::Log(LOGERROR,"(XVBA) failed to create shared surface"); ++ m_xvbaError = true; ++ break; ++ } ++ CLog::Log(LOGDEBUG, "XVBA::GetTexture - created shared surface"); ++ ++ surface.glSurface = surfOutput.surface; ++ surface.id = i; ++ surface.used = false; ++ surface.render = 0; ++ m_bufferPool.glSurfaces.push_back(surface); ++ } ++ glDisable(textureTarget); ++ } ++ ++ return true; ++} ++ ++void COutput::ReleaseBufferPool() ++{ ++ CSingleLock lock(m_bufferPool.renderPicSec); ++ ++ if (m_config.useSharedSurfaces) ++ { ++ for (unsigned int i = 0; i < m_bufferPool.glSurfaces.size(); ++i) ++ { ++ if (!m_bufferPool.glSurfaces[i].glSurface) ++ continue; ++ g_XVBA_vtable.DestroySurface(m_bufferPool.glSurfaces[i].glSurface); ++ glDeleteTextures(1, &m_bufferPool.glSurfaces[i].texture); ++ } ++ m_bufferPool.glSurfaces.clear(); ++ } ++ // invalidate all used render pictures ++ for (unsigned int i = 0; i < m_bufferPool.usedRenderPics.size(); ++i) ++ { ++ m_bufferPool.usedRenderPics[i]->valid = false; ++ unsigned int idx = m_bufferPool.usedRenderPics[i]->sourceIdx; ++ if (m_bufferPool.glSurfaces[idx].render) ++ { ++ { CSingleLock lock(*m_config.videoSurfaceSec); ++ m_bufferPool.glSurfaces[idx].render->state &= ~(FF_XVBA_STATE_USED_FOR_RENDER | FF_XVBA_STATE_DECODED); ++ m_bufferPool.glSurfaces[idx].render = 0; ++ } ++ } ++ } ++} ++ ++void COutput::PreReleaseBufferPool() ++{ ++ CSingleLock lock(m_bufferPool.renderPicSec); ++ ++ if (m_config.useSharedSurfaces) ++ { ++ for (unsigned int i = 0; i < m_bufferPool.glSurfaces.size(); ++i) ++ { ++ if (!m_bufferPool.glSurfaces[i].used) ++ { ++ g_XVBA_vtable.DestroySurface(m_bufferPool.glSurfaces[i].glSurface); ++ glDeleteTextures(1, &m_bufferPool.glSurfaces[i].texture); ++ m_bufferPool.glSurfaces[i].glSurface = 0; ++ m_bufferPool.glSurfaces[i].used = true; ++ } ++ } ++ } ++} ++ ++bool COutput::CreateGlxContext() ++{ ++ GLXContext glContext; ++ Window window; ++ ++ m_Display = g_Windowing.GetDisplay(); ++ glContext = g_Windowing.GetGlxContext(); ++ m_Window = g_Windowing.GetWmWindow(); ++ ++ // Get our window attribs. ++ XWindowAttributes wndattribs; ++ XGetWindowAttributes(m_Display, m_Window, &wndattribs); ++ ++ // Get visual Info ++ XVisualInfo visInfo; ++ visInfo.visualid = wndattribs.visual->visualid; ++ int nvisuals = 0; ++ XVisualInfo* visuals = XGetVisualInfo(m_Display, VisualIDMask, &visInfo, &nvisuals); ++ if (nvisuals != 1) ++ { ++ CLog::Log(LOGERROR, "XVBA::COutput::CreateGlxContext - could not find visual"); ++ return false; ++ } ++ visInfo = visuals[0]; ++ XFree(visuals); ++ ++ m_pixmap = XCreatePixmap(m_Display, ++ DefaultRootWindow(m_Display), ++ 192, ++ 108, ++ visInfo.depth); ++ if (!m_pixmap) ++ { ++ CLog::Log(LOGERROR, "XVBA::COutput::CreateGlxContext - Unable to create XPixmap"); ++ return false; ++ } ++ ++ // create gl pixmap ++ m_glPixmap = glXCreateGLXPixmap(m_Display, &visInfo, m_pixmap); ++ ++ if (!m_glPixmap) ++ { ++ CLog::Log(LOGINFO, "XVBA::COutput::CreateGlxContext - Could not create glPixmap"); ++ return false; ++ } ++ ++ m_glContext = glXCreateContext(m_Display, &visInfo, glContext, True); ++ ++ if (!glXMakeCurrent(m_Display, m_glPixmap, m_glContext)) ++ { ++ CLog::Log(LOGINFO, "XVBA::COutput::CreateGlxContext - Could not make Pixmap current"); ++ return false; ++ } ++ ++ CLog::Log(LOGNOTICE, "XVBA::COutput::CreateGlxContext - created context"); ++ return true; ++} ++ ++bool COutput::DestroyGlxContext() ++{ ++ if (m_glContext) ++ { ++ glXMakeCurrent(m_Display, None, NULL); ++ glXDestroyContext(m_Display, m_glContext); ++ } ++ m_glContext = 0; ++ ++ if (m_glPixmap) ++ glXDestroyPixmap(m_Display, m_glPixmap); ++ m_glPixmap = 0; ++ ++ if (m_pixmap) ++ XFreePixmap(m_Display, m_pixmap); ++ m_pixmap = 0; ++ ++ return true; ++} ++ ++#endif +diff -Naur xbmc-11.0.1/xbmc/cores/dvdplayer/DVDCodecs/Video/XVBA.h xbmc-11.0.1.patch/xbmc/cores/dvdplayer/DVDCodecs/Video/XVBA.h +--- xbmc-11.0.1/xbmc/cores/dvdplayer/DVDCodecs/Video/XVBA.h 1970-01-01 01:00:00.000000000 +0100 ++++ xbmc-11.0.1.patch/xbmc/cores/dvdplayer/DVDCodecs/Video/XVBA.h 2012-05-13 22:08:47.053195007 +0200 +@@ -0,0 +1,386 @@ ++/* ++ * Copyright (C) 2005-2011 Team XBMC ++ * http://www.xbmc.org ++ * ++ * 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 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 XBMC; see the file COPYING. If not, write to ++ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. ++ * http://www.gnu.org/copyleft/gpl.html ++ * ++ */ ++#pragma once ++ ++#include "X11/Xlib.h" ++#include "amd/amdxvba.h" ++#include "DllAvCodec.h" ++#include "DVDCodecs/Video/DVDVideoCodecFFmpeg.h" ++#include "threads/Thread.h" ++#include "threads/CriticalSection.h" ++#include "threads/SharedSection.h" ++#include "threads/Event.h" ++#include "guilib/DispResource.h" ++#include "guilib/Geometry.h" ++#include "libavcodec/xvba.h" ++#include "utils/ActorProtocol.h" ++#include "settings/VideoSettings.h" ++#include ++#include ++#include ++#include ++ ++using namespace Actor; ++ ++ ++namespace XVBA ++{ ++ ++//----------------------------------------------------------------------------- ++// XVBA data structs ++//----------------------------------------------------------------------------- ++ ++class CDecoder; ++class CXVBAContext; ++class COutput; ++ ++#define NUM_RENDER_PICS 9 ++ ++/** ++ * Buffer statistics used to control number of frames in queue ++ */ ++ ++class CXvbaBufferStats ++{ ++public: ++ uint16_t decodedPics; ++ uint16_t processedPics; ++ uint16_t renderPics; ++ uint64_t latency; // time decoder has waited for a frame, ideally there is no latency ++ int playSpeed; ++ bool canSkipDeint; ++ int processCmd; ++ ++ void IncDecoded() { CSingleLock l(m_sec); decodedPics++;} ++ void DecDecoded() { CSingleLock l(m_sec); decodedPics--;} ++ void IncProcessed() { CSingleLock l(m_sec); processedPics++;} ++ void DecProcessed() { CSingleLock l(m_sec); processedPics--;} ++ void IncRender() { CSingleLock l(m_sec); renderPics++;} ++ void DecRender() { CSingleLock l(m_sec); renderPics--;} ++ void Reset() { CSingleLock l(m_sec); decodedPics=0; processedPics=0;renderPics=0;latency=0;} ++ void Get(uint16_t &decoded, uint16_t &processed, uint16_t &render) {CSingleLock l(m_sec); decoded = decodedPics, processed=processedPics, render=renderPics;} ++ void SetParams(uint64_t time, int speed) { CSingleLock l(m_sec); latency = time; playSpeed = speed; } ++ void GetParams(uint64_t &lat, int &speed) { CSingleLock l(m_sec); lat = latency; speed = playSpeed; } ++ void SetCmd(int cmd) { CSingleLock l(m_sec); processCmd = cmd; } ++ void GetCmd(int &cmd) { CSingleLock l(m_sec); cmd = processCmd; processCmd = 0; } ++ void SetCanSkipDeint(bool canSkip) { CSingleLock l(m_sec); canSkipDeint = canSkip; } ++ bool CanSkipDeint() { CSingleLock l(m_sec); if (canSkipDeint) return true; else return false;} ++private: ++ CCriticalSection m_sec; ++}; ++ ++/** ++ * CXvbaConfig holds all configuration parameters needed by vdpau ++ * The structure is sent to the internal classes CMixer and COutput ++ * for init. ++ */ ++ ++struct CXvbaConfig ++{ ++ int surfaceWidth; ++ int surfaceHeight; ++ int vidWidth; ++ int vidHeight; ++ int outWidth; ++ int outHeight; ++ bool useSharedSurfaces; ++ ++ CXVBAContext *context; ++ XVBADecodeCap decoderCap; ++ void *xvbaSession; ++ std::vector *videoSurfaces; ++ CCriticalSection *videoSurfaceSec; ++ CCriticalSection *apiSec; ++ ++ CXvbaBufferStats *stats; ++ int numRenderBuffers; ++ uint32_t maxReferences; ++}; ++ ++/** ++ * Holds a decoded frame ++ * Input to COutput for further processing ++ */ ++struct CXvbaDecodedPicture ++{ ++ DVDVideoPicture DVDPic; ++ xvba_render_state *render; ++}; ++ ++/** ++ * Ready to render textures ++ * Sent from COutput back to CDecoder ++ * Objects are referenced by DVDVideoPicture and are sent ++ * to renderer ++ */ ++class CXvbaRenderPicture ++{ ++ friend class CDecoder; ++ friend class COutput; ++public: ++ DVDVideoPicture DVDPic; ++ int texWidth, texHeight; ++ CRect crop; ++ GLuint texture; ++ uint32_t sourceIdx; ++ bool valid; ++ CDecoder *xvba; ++ CXvbaRenderPicture* Acquire(); ++ long Release(); ++ void Transfer(); ++private: ++ void ReturnUnused(); ++ int refCount; ++ CCriticalSection *renderPicSection; ++ COutput *xvbaOutput; ++}; ++ ++//----------------------------------------------------------------------------- ++// Output ++//----------------------------------------------------------------------------- ++ ++/** ++ * Buffer pool holds allocated xvba and gl resources ++ * Embedded in COutput ++ */ ++struct XvbaBufferPool ++{ ++ struct GLVideoSurface ++ { ++ unsigned int id; ++ bool used; ++ bool transferred; ++ GLuint texture; ++ void *glSurface; ++ xvba_render_state *render; ++ XVBA_SURFACE_FLAG field; ++ }; ++ std::vector glSurfaces; ++ std::vector allRenderPics; ++ std::deque usedRenderPics; ++ std::deque freeRenderPics; ++ CCriticalSection renderPicSec; ++}; ++ ++class COutputControlProtocol : public Protocol ++{ ++public: ++ COutputControlProtocol(std::string name, CEvent* inEvent, CEvent *outEvent) : Protocol(name, inEvent, outEvent) {}; ++ enum OutSignal ++ { ++ INIT, ++ FLUSH, ++ PRECLEANUP, ++ TIMEOUT, ++ }; ++ enum InSignal ++ { ++ ACC, ++ ERROR, ++ STATS, ++ }; ++}; ++ ++class COutputDataProtocol : public Protocol ++{ ++public: ++ COutputDataProtocol(std::string name, CEvent* inEvent, CEvent *outEvent) : Protocol(name, inEvent, outEvent) {}; ++ enum OutSignal ++ { ++ NEWFRAME = 0, ++ RETURNPIC, ++ }; ++ enum InSignal ++ { ++ PICTURE, ++ }; ++}; ++ ++/** ++ * COutput is embedded in CDecoder and embeds CMixer ++ * The class has its own OpenGl context which is shared with render thread ++ * COuput generated ready to render textures and passes them back to ++ * CDecoder ++ */ ++class COutput : private CThread ++{ ++public: ++ COutput(CEvent *inMsgEvent); ++ virtual ~COutput(); ++ void Start(); ++ void Dispose(); ++ void TransferSurface(uint32_t source); ++ COutputControlProtocol m_controlPort; ++ COutputDataProtocol m_dataPort; ++protected: ++ void OnStartup(); ++ void OnExit(); ++ void Process(); ++ void StateMachine(int signal, Protocol *port, Message *msg); ++ bool HasWork(); ++ bool IsDecodingFinished(); ++ CXvbaRenderPicture* ProcessPicture(); ++ void ProcessReturnPicture(CXvbaRenderPicture *pic); ++ int FindFreeSurface(); ++ void InitCycle(); ++ void FiniCycle(); ++ bool Init(); ++ bool Uninit(); ++ void Flush(); ++ bool CreateGlxContext(); ++ bool DestroyGlxContext(); ++ bool EnsureBufferPool(); ++ void ReleaseBufferPool(); ++ void PreReleaseBufferPool(); ++ CEvent m_outMsgEvent; ++ CEvent *m_inMsgEvent; ++ int m_state; ++ bool m_bStateMachineSelfTrigger; ++ ++ // extended state variables for state machine ++ int m_extTimeout; ++ bool m_xvbaError; ++ CXvbaConfig m_config; ++ XvbaBufferPool m_bufferPool; ++ Display *m_Display; ++ Window m_Window; ++ GLXContext m_glContext; ++ GLXWindow m_glWindow; ++ Pixmap m_pixmap; ++ GLXPixmap m_glPixmap; ++ std::queue m_decodedPics; ++ CXvbaDecodedPicture m_processPicture; ++ XVBA_SURFACE_FLAG m_field; ++ bool m_deinterlacing; ++ int m_deintStep; ++ bool m_deintSkip; ++}; ++ ++//----------------------------------------------------------------------------- ++// XVBA decoder ++//----------------------------------------------------------------------------- ++ ++class CXVBAContext ++{ ++public: ++ static bool EnsureContext(CXVBAContext **ctx); ++ void *GetContext(); ++ void Release(); ++private: ++ CXVBAContext(); ++ void Close(); ++ bool LoadSymbols(); ++ bool CreateContext(); ++ void DestroyContext(); ++ static CXVBAContext *m_context; ++ static CCriticalSection m_section; ++ static Display *m_display; ++ int m_refCount; ++ static void *m_dlHandle; ++ void *m_xvbaContext; ++}; ++ ++class CDecoder : public CDVDVideoCodecFFmpeg::IHardwareDecoder, ++ public IDispResource ++{ ++ friend class CXvbaRenderPicture; ++ ++public: ++ ++ struct pictureAge ++ { ++ int b_age; ++ int ip_age[2]; ++ }; ++ ++ enum EDisplayState ++ { XVBA_OPEN ++ , XVBA_RESET ++ , XVBA_LOST ++ , XVBA_ERROR ++ }; ++ ++ CDecoder(); ++ virtual ~CDecoder(); ++ virtual void OnLostDevice(); ++ virtual void OnResetDevice(); ++ ++ virtual bool Open(AVCodecContext* avctx, const enum PixelFormat fmt, unsigned int surfaces = 0); ++ virtual int Decode (AVCodecContext* avctx, AVFrame* frame); ++ virtual bool GetPicture(AVCodecContext* avctx, AVFrame* frame, DVDVideoPicture* picture); ++ virtual void Reset(); ++ virtual void Close(); ++ virtual int Check(AVCodecContext* avctx); ++ virtual long Release(); ++ virtual const std::string Name() { return "xvba"; } ++ virtual bool CanSkipDeint(); ++ virtual void SetSpeed(int speed); ++ ++ bool Supports(EINTERLACEMETHOD method); ++ long ReleasePicReference(); ++ ++protected: ++ bool CreateSession(AVCodecContext* avctx); ++ void DestroySession(); ++ bool EnsureDataControlBuffers(unsigned int num); ++ void ResetState(); ++ void SetError(const char* function, const char* msg, int line); ++ bool IsSurfaceValid(xvba_render_state *render); ++ void ReturnRenderPicture(CXvbaRenderPicture *renderPic); ++ ++ // callbacks for ffmpeg ++ static void FFReleaseBuffer(AVCodecContext *avctx, AVFrame *pic); ++ static void FFDrawSlice(struct AVCodecContext *avctx, ++ const AVFrame *src, int offset[4], ++ int y, int type, int height); ++ static int FFGetBuffer(AVCodecContext *avctx, AVFrame *pic); ++ ++ DllAvUtil m_dllAvUtil; ++ CCriticalSection m_decoderSection; ++ CEvent m_displayEvent; ++ EDisplayState m_displayState; ++ CXvbaConfig m_xvbaConfig; ++ std::vector m_videoSurfaces; ++ CCriticalSection m_apiSec, m_videoSurfaceSec; ++ ThreadIdentifier m_decoderThread; ++ ++ unsigned int m_decoderId; ++ struct XVBABufferPool ++ { ++ XVBABufferDescriptor *picture_descriptor_buffer; ++ XVBABufferDescriptor *iq_matrix_buffer; ++ XVBABufferDescriptor *data_buffer; ++ std::vector data_control_buffers; ++ }; ++ XVBABufferPool m_xvbaBufferPool; ++ ++ pictureAge picAge; ++ ++ COutput m_xvbaOutput; ++ CXvbaBufferStats m_bufferStats; ++ CEvent m_inMsgEvent; ++ CXvbaRenderPicture *m_presentPicture; ++ ++ int m_speed; ++ int m_codecControl; ++}; ++ ++} +diff -Naur xbmc-11.0.1/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.cpp xbmc-11.0.1.patch/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.cpp +--- xbmc-11.0.1/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.cpp 2012-03-21 23:57:34.000000000 +0100 ++++ xbmc-11.0.1.patch/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.cpp 2012-05-13 22:08:46.782189631 +0200 +@@ -19,7 +19,6 @@ + * + */ + +-#include "threads/SystemClock.h" + #include "system.h" + #ifndef __STDC_CONSTANT_MACROS + #define __STDC_CONSTANT_MACROS +@@ -43,6 +42,7 @@ + #include "filesystem/Directory.h" + #include "utils/log.h" + #include "threads/Thread.h" ++#include "threads/SystemClock.h" + #include "utils/TimeUtils.h" + + void CDemuxStreamAudioFFmpeg::GetStreamInfo(std::string& strInfo) +@@ -153,16 +153,12 @@ + ++it; + } + +-#ifdef _MSC_VER +-static __declspec(thread) CDVDDemuxFFmpeg* g_demuxer = 0; +-#else +-static TLS g_tls; +-#define g_demuxer (*((CDVDDemuxFFmpeg**)g_tls.Get())) +-#endif ++static XbmcThreads::ThreadLocal g_demuxer; + + static int interrupt_cb(void) + { +- if(g_demuxer && g_demuxer->Aborted()) ++ CDVDDemuxFFmpeg* demuxer = g_demuxer.get(); ++ if(demuxer && demuxer->Aborted()) + return 1; + return 0; + } +@@ -234,7 +230,7 @@ + std::string strFile; + m_iCurrentPts = DVD_NOPTS_VALUE; + m_speed = DVD_PLAYSPEED_NORMAL; +- g_demuxer = this; ++ g_demuxer.set(this); + m_program = UINT_MAX; + + if (!pInput) return false; +@@ -506,7 +502,7 @@ + + void CDVDDemuxFFmpeg::Dispose() + { +- g_demuxer = this; ++ g_demuxer.set(this); + + if (m_pFormatContext) + { +@@ -555,7 +551,7 @@ + + void CDVDDemuxFFmpeg::Flush() + { +- g_demuxer = this; ++ g_demuxer.set(this); + + // naughty usage of an internal ffmpeg function + if (m_pFormatContext) +@@ -571,7 +567,7 @@ + + void CDVDDemuxFFmpeg::SetSpeed(int iSpeed) + { +- g_demuxer = this; ++ g_demuxer.set(this); + + if(!m_pFormatContext) + return; +@@ -633,7 +629,7 @@ + + DemuxPacket* CDVDDemuxFFmpeg::Read() + { +- g_demuxer = this; ++ g_demuxer.set(this); + + AVPacket pkt; + DemuxPacket* pPacket = NULL; +@@ -832,7 +828,7 @@ + + bool CDVDDemuxFFmpeg::SeekTime(int time, bool backwords, double *startpts) + { +- g_demuxer = this; ++ g_demuxer.set(this); + + if(time < 0) + time = 0; +@@ -892,7 +888,7 @@ + + bool CDVDDemuxFFmpeg::SeekByte(__int64 pos) + { +- g_demuxer = this; ++ g_demuxer.set(this); + + CSingleLock lock(m_critSection); + int ret = m_dllAvFormat.av_seek_frame(m_pFormatContext, -1, pos, AVSEEK_FLAG_BYTE); +diff -Naur xbmc-11.0.1/xbmc/cores/dvdplayer/DVDPerformanceCounter.cpp xbmc-11.0.1.patch/xbmc/cores/dvdplayer/DVDPerformanceCounter.cpp +--- xbmc-11.0.1/xbmc/cores/dvdplayer/DVDPerformanceCounter.cpp 2012-03-21 23:57:34.000000000 +0100 ++++ xbmc-11.0.1.patch/xbmc/cores/dvdplayer/DVDPerformanceCounter.cpp 2012-05-13 22:08:46.782189631 +0200 +@@ -21,6 +21,7 @@ + + #include "DVDPerformanceCounter.h" + #include "DVDMessageQueue.h" ++#include "utils/TimeUtils.h" + + #include "dvd_config.h" + +@@ -68,22 +69,16 @@ + + inline __int64 get_thread_cpu_usage(ProcessPerformance* p) + { +- if (p->hThread) ++ if (p->thread) + { +- FILETIME dummy; +- FILETIME current_time_thread; +- FILETIME current_time_system; + ULARGE_INTEGER old_time_thread; + ULARGE_INTEGER old_time_system; + + old_time_thread.QuadPart = p->timer_thread.QuadPart; + old_time_system.QuadPart = p->timer_system.QuadPart; + +- GetThreadTimes(p->hThread, &dummy, &dummy, ¤t_time_thread, &dummy); +- GetSystemTimeAsFileTime(¤t_time_system); +- +- FILETIME_TO_ULARGE_INTEGER(p->timer_thread, current_time_thread); +- FILETIME_TO_ULARGE_INTEGER(p->timer_system, current_time_system); ++ p->timer_thread.QuadPart = p->thread->GetAbsoluteUsage(); ++ p->timer_system.QuadPart = CurrentHostCounter(); + + __int64 threadTime = (p->timer_thread.QuadPart - old_time_thread.QuadPart); + __int64 systemTime = (p->timer_system.QuadPart - old_time_system.QuadPart); +diff -Naur xbmc-11.0.1/xbmc/cores/dvdplayer/DVDPerformanceCounter.h xbmc-11.0.1.patch/xbmc/cores/dvdplayer/DVDPerformanceCounter.h +--- xbmc-11.0.1/xbmc/cores/dvdplayer/DVDPerformanceCounter.h 2012-03-21 23:57:34.000000000 +0100 ++++ xbmc-11.0.1.patch/xbmc/cores/dvdplayer/DVDPerformanceCounter.h 2012-05-13 22:08:46.783189651 +0200 +@@ -24,7 +24,7 @@ + #define FILETIME_TO_ULARGE_INTEGER(ularge, filetime) { ularge.u.HighPart = filetime.dwHighDateTime; ularge.u.LowPart = filetime.dwLowDateTime; } + + #include "system.h" +- ++#include "threads/Thread.h" + #include "threads/SingleLock.h" + + class CDVDMessageQueue; +@@ -33,7 +33,7 @@ + { + ULARGE_INTEGER timer_thread; + ULARGE_INTEGER timer_system; +- HANDLE hThread; ++ CThread* thread; + } ProcessPerformance; + + class CDVDPerformanceCounter +@@ -45,20 +45,20 @@ + bool Initialize(); + void DeInitialize(); + +- void EnableAudioQueue(CDVDMessageQueue* pQueue) { CSingleLock lock(m_critSection); m_pAudioQueue = pQueue; } +- void DisableAudioQueue() { CSingleLock lock(m_critSection); m_pAudioQueue = NULL; } ++ void EnableAudioQueue(CDVDMessageQueue* pQueue) { CSingleLock lock(m_critSection); m_pAudioQueue = pQueue; } ++ void DisableAudioQueue() { CSingleLock lock(m_critSection); m_pAudioQueue = NULL; } + +- void EnableVideoQueue(CDVDMessageQueue* pQueue) { CSingleLock lock(m_critSection); m_pVideoQueue = pQueue; } +- void DisableVideoQueue() { CSingleLock lock(m_critSection); m_pVideoQueue = NULL; } ++ void EnableVideoQueue(CDVDMessageQueue* pQueue) { CSingleLock lock(m_critSection); m_pVideoQueue = pQueue; } ++ void DisableVideoQueue() { CSingleLock lock(m_critSection); m_pVideoQueue = NULL; } + +- void EnableVideoDecodePerformance(HANDLE hThread) { CSingleLock lock(m_critSection); m_videoDecodePerformance.hThread = hThread; } +- void DisableVideoDecodePerformance() { CSingleLock lock(m_critSection); m_videoDecodePerformance.hThread = NULL; } ++ void EnableVideoDecodePerformance(CThread *thread) { CSingleLock lock(m_critSection); m_videoDecodePerformance.thread = thread; } ++ void DisableVideoDecodePerformance() { CSingleLock lock(m_critSection); m_videoDecodePerformance.thread = NULL; } + +- void EnableAudioDecodePerformance(HANDLE hThread) { CSingleLock lock(m_critSection); m_audioDecodePerformance.hThread = hThread; } +- void DisableAudioDecodePerformance() { CSingleLock lock(m_critSection); m_audioDecodePerformance.hThread = NULL; } ++ void EnableAudioDecodePerformance(CThread *thread) { CSingleLock lock(m_critSection); m_audioDecodePerformance.thread = thread; } ++ void DisableAudioDecodePerformance() { CSingleLock lock(m_critSection); m_audioDecodePerformance.thread = NULL; } + +- void EnableMainPerformance(HANDLE hThread) { CSingleLock lock(m_critSection); m_mainPerformance.hThread = hThread; } +- void DisableMainPerformance() { CSingleLock lock(m_critSection); m_mainPerformance.hThread = NULL; } ++ void EnableMainPerformance(CThread *thread) { CSingleLock lock(m_critSection); m_mainPerformance.thread = thread; } ++ void DisableMainPerformance() { CSingleLock lock(m_critSection); m_mainPerformance.thread = NULL; } + + CDVDMessageQueue* m_pAudioQueue; + CDVDMessageQueue* m_pVideoQueue; +diff -Naur xbmc-11.0.1/xbmc/cores/dvdplayer/DVDPlayerAudio.cpp xbmc-11.0.1.patch/xbmc/cores/dvdplayer/DVDPlayerAudio.cpp +--- xbmc-11.0.1/xbmc/cores/dvdplayer/DVDPlayerAudio.cpp 2012-03-21 23:57:34.000000000 +0100 ++++ xbmc-11.0.1.patch/xbmc/cores/dvdplayer/DVDPlayerAudio.cpp 2012-05-13 22:08:46.786189710 +0200 +@@ -518,7 +518,7 @@ + m_decode.msg = NULL; + m_decode.Release(); + +- g_dvdPerformanceCounter.EnableAudioDecodePerformance(ThreadHandle()); ++ g_dvdPerformanceCounter.EnableAudioDecodePerformance(this); + + #ifdef _WIN32 + CoInitializeEx(NULL, COINIT_MULTITHREADED); +diff -Naur xbmc-11.0.1/xbmc/cores/dvdplayer/DVDPlayer.cpp xbmc-11.0.1.patch/xbmc/cores/dvdplayer/DVDPlayer.cpp +--- xbmc-11.0.1/xbmc/cores/dvdplayer/DVDPlayer.cpp 2012-03-21 23:57:34.000000000 +0100 ++++ xbmc-11.0.1.patch/xbmc/cores/dvdplayer/DVDPlayer.cpp 2012-05-13 22:08:46.897191913 +0200 +@@ -341,7 +341,7 @@ + + // if playing a file close it first + // this has to be changed so we won't have to close it. +- if(ThreadHandle()) ++ if(IsRunning()) + CloseFile(); + + m_bAbortRequest = false; +@@ -358,7 +358,7 @@ + m_ready.Reset(); + + #if defined(HAS_VIDEO_PLAYBACK) +- g_renderManager.PreInit(); ++ g_renderManager.PreInit(&m_clock); + #endif + + Create(); +@@ -432,9 +432,8 @@ + + m_messenger.Init(); + +- g_dvdPerformanceCounter.EnableMainPerformance(ThreadHandle()); +- + CUtil::ClearTempFonts(); ++ g_dvdPerformanceCounter.EnableMainPerformance(this); + } + + bool CDVDPlayer::OpenInputStream() +@@ -1457,7 +1456,7 @@ + + } + else if (m_CurrentVideo.id >= 0 +- && m_CurrentVideo.inited == true ++ && (m_CurrentVideo.inited == true || GetPlaySpeed() < 0) + && m_SpeedState.lastpts != m_dvdPlayerVideo.GetCurrentPts() + && m_SpeedState.lasttime != GetTime()) + { +@@ -2127,6 +2126,11 @@ + if (speed != DVD_PLAYSPEED_PAUSE && m_playSpeed != DVD_PLAYSPEED_PAUSE && speed != m_playSpeed) + m_callback.OnPlayBackSpeedChanged(speed / DVD_PLAYSPEED_NORMAL); + ++ if (m_playSpeed < 0 && speed >= 0) ++ { ++ m_messenger.Put(new CDVDMsgPlayerSeek(GetTime(), true, true, true)); ++ } ++ + // if playspeed is different then DVD_PLAYSPEED_NORMAL or DVD_PLAYSPEED_PAUSE + // audioplayer, stops outputing audio to audiorendere, but still tries to + // sleep an correct amount for each packet +@@ -2143,6 +2147,7 @@ + // until our buffers are somewhat filled + if(m_pDemuxer) + m_pDemuxer->SetSpeed(speed); ++ + } + else if (pMsg->IsType(CDVDMsg::PLAYER_CHANNEL_NEXT) || + pMsg->IsType(CDVDMsg::PLAYER_CHANNEL_PREV) || +@@ -2716,7 +2721,7 @@ + m_dvdPlayerAudio.SendMessage(new CDVDMsg(CDVDMsg::PLAYER_STARTED), 1); + + /* audio normally won't consume full cpu, so let it have prio */ +- m_dvdPlayerAudio.SetPriority(GetThreadPriority(*this)+1); ++ m_dvdPlayerAudio.SetPriority(GetPriority()+1); + + return true; + } +@@ -2781,11 +2786,11 @@ + // the CoreAudio audio device handler thread. We do the same for + // the DVDPlayerVideo thread so it can run to sleep without getting + // swapped out by a busy OS. +- m_dvdPlayerVideo.SetPrioritySched_RR(); ++ m_dvdPlayerVideo.SetPriority(GetSchedRRPriority()); + #else + /* use same priority for video thread as demuxing thread, as */ + /* otherwise demuxer will starve if video consumes the full cpu */ +- m_dvdPlayerVideo.SetPriority(GetThreadPriority(*this)); ++ m_dvdPlayerVideo.SetPriority(GetPriority()); + #endif + return true; + +diff -Naur xbmc-11.0.1/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp xbmc-11.0.1.patch/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp +--- xbmc-11.0.1/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp 2012-03-21 23:57:34.000000000 +0100 ++++ xbmc-11.0.1.patch/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp 2012-05-13 22:08:47.040194749 +0200 +@@ -189,7 +189,7 @@ + return false; + } + +- if(g_guiSettings.GetBool("videoplayer.usedisplayasclock") && g_VideoReferenceClock.ThreadHandle() == NULL) ++ if(g_guiSettings.GetBool("videoplayer.usedisplayasclock") && !g_VideoReferenceClock.IsRunning()) + { + g_VideoReferenceClock.Create(); + //we have to wait for the clock to start otherwise alsa can cause trouble +@@ -247,6 +247,7 @@ + m_stalled = m_messageQueue.GetPacketCount(CDVDMsg::DEMUXER_PACKET) == 0; + m_started = false; + m_codecname = m_pVideoCodec->GetName(); ++ g_renderManager.EnableBuffering(false); + } + + void CDVDPlayerVideo::CloseStream(bool bWaitForBuffers) +@@ -291,7 +292,7 @@ + m_iCurrentPts = DVD_NOPTS_VALUE; + m_FlipTimeStamp = m_pClock->GetAbsoluteClock(); + +- g_dvdPerformanceCounter.EnableVideoDecodePerformance(ThreadHandle()); ++ g_dvdPerformanceCounter.EnableVideoDecodePerformance(this); + } + + void CDVDPlayerVideo::Process() +@@ -311,8 +312,10 @@ + + int iDropped = 0; //frames dropped in a row + bool bRequestDrop = false; ++ int iDropDirective; + + m_videoStats.Start(); ++ m_droppingStats.Reset(); + + while (!m_bStop) + { +@@ -414,18 +417,24 @@ + if(m_pVideoCodec) + m_pVideoCodec->Reset(); + m_packets.clear(); ++ picture.iFlags &= ~DVP_FLAG_ALLOCATED; + m_started = false; ++ m_droppingStats.Reset(); ++ g_renderManager.EnableBuffering(false); + } + else if (pMsg->IsType(CDVDMsg::GENERAL_FLUSH)) // private message sent by (CDVDPlayerVideo::Flush()) + { + if(m_pVideoCodec) + m_pVideoCodec->Reset(); + m_packets.clear(); ++ picture.iFlags &= ~DVP_FLAG_ALLOCATED; + + m_pullupCorrection.Flush(); + //we need to recalculate the framerate + //TODO: this needs to be set on a streamchange instead + ResetFrameRateCalc(); ++ m_droppingStats.Reset(); ++ g_renderManager.EnableBuffering(false); + + m_stalled = true; + m_started = false; +@@ -443,6 +452,10 @@ + m_speed = static_cast(pMsg)->m_value; + if(m_speed == DVD_PLAYSPEED_PAUSE) + m_iNrOfPicturesNotToSkip = 0; ++ m_droppingStats.Reset(); ++// g_renderManager.EnableBuffering(m_speed == DVD_PLAYSPEED_NORMAL); ++ if (m_pVideoCodec) ++ m_pVideoCodec->SetSpeed(m_speed); + } + else if (pMsg->IsType(CDVDMsg::PLAYER_STARTED)) + { +@@ -477,6 +490,29 @@ + m_iNrOfPicturesNotToSkip = 1; + } + ++ bRequestDrop = false; ++ iDropDirective = CalcDropRequirement(pts); ++ if (iDropDirective & EOS_VERYLATE) ++ { ++ if (m_bAllowDrop) ++ { ++ m_pullupCorrection.Flush(); ++ bRequestDrop = true; ++ } ++ } ++ int codecControl = 0; ++ if (iDropDirective & EOS_BUFFER_LEVEL) ++ { ++ if (iDropDirective & EOS_BUFFER_LEVEL) ++ codecControl |= DVP_FLAG_DRAIN; ++ } ++ m_pVideoCodec->SetCodecControl(codecControl); ++ if (iDropDirective & EOS_DROPPED) ++ { ++ m_iDroppedFrames++; ++ iDropped++; ++ } ++ + #ifdef PROFILE + bRequestDrop = false; + #else +@@ -486,6 +522,7 @@ + bRequestDrop = false; + m_iDroppedRequest = 0; + m_iLateFrames = 0; ++ m_droppingStats.m_requestOutputDrop = false; + } + #endif + +@@ -524,7 +561,7 @@ + if(m_pVideoCodec->GetConvergeCount() > 0) + { + m_packets.push_back(DVDMessageListItem(pMsg, 0)); +- if(m_packets.size() > m_pVideoCodec->GetConvergeCount() ++ if(m_packets.size() > m_pVideoCodec->GetConvergeCount() + || m_packets.size() * frametime > DVD_SEC_TO_TIME(10)) + m_packets.pop_front(); + } +@@ -534,11 +571,13 @@ + // picture from a demux packet, this should be reasonable + // for libavformat as a demuxer as it normally packetizes + // pictures when they come from demuxer +- if(bRequestDrop && !bPacketDrop && (iDecoderState & VC_BUFFER) && !(iDecoderState & VC_PICTURE)) +- { +- m_iDroppedFrames++; +- iDropped++; +- } ++// if(bRequestDrop && !bPacketDrop && (iDecoderState & VC_BUFFER) && !(iDecoderState & VC_PICTURE)) ++// { ++// m_iDroppedFrames++; ++// iDropped++; ++// } ++ ++ bRequestDrop = false; + + // loop while no error + while (!m_bStop) +@@ -561,6 +600,8 @@ + + m_pVideoCodec->Reset(); + m_packets.clear(); ++ picture.iFlags &= ~DVP_FLAG_ALLOCATED; ++ g_renderManager.DiscardBuffer(); + break; + } + +@@ -670,11 +711,15 @@ + CDVDCodecUtils::FreePicture(pTempYUVPackedPicture); + #endif + ++ if (!m_bFpsInvalid) ++ frametime = (double)DVD_TIME_BASE/m_fFrameRate; ++ + if(m_started == false) + { + m_codecname = m_pVideoCodec->GetName(); + m_started = true; + m_messageParent.Put(new CDVDMsgInt(CDVDMsg::PLAYER_STARTED, DVDPLAYER_VIDEO)); ++ g_renderManager.EnableBuffering(true); + } + + // guess next frame pts. iDuration is always valid +@@ -1037,6 +1082,10 @@ + flags |= CONF_FLAGS_FORMAT_VDPAU; + formatstr = "VDPAU"; + break; ++ case DVDVideoPicture::FMT_VDPAU_420: ++ flags |= CONF_FLAGS_FORMAT_VDPAU_420; ++ formatstr = "VDPAU_420"; ++ break; + case DVDVideoPicture::FMT_DXVA: + flags |= CONF_FLAGS_FORMAT_DXVA; + formatstr = "DXVA"; +@@ -1052,6 +1101,10 @@ + flags |= CONF_FLAGS_FORMAT_CVBREF; + formatstr = "BGRA"; + break; ++ case DVDVideoPicture::FMT_XVBA: ++ flags |= CONF_FLAGS_FORMAT_XVBA; ++ formatstr = "XVBA"; ++ break; + } + + if(m_bAllowFullscreen) +@@ -1160,50 +1213,63 @@ + m_FlipTimeStamp += max(0.0, iSleepTime); + m_FlipTimeStamp += iFrameDuration; + +- if (iSleepTime <= 0 && m_speed) +- m_iLateFrames++; +- else +- m_iLateFrames = 0; ++// if (iSleepTime <= 0 && m_speed) ++// m_iLateFrames++; ++// else ++// m_iLateFrames = 0; ++// ++// // ask decoder to drop frames next round, as we are very late ++// if(m_iLateFrames > 10) ++// { ++// if (!(pPicture->iFlags & DVP_FLAG_NOSKIP)) ++// { ++// //if we're calculating the framerate, ++// //don't drop frames until we've calculated a stable framerate ++// if (m_bAllowDrop || m_speed != DVD_PLAYSPEED_NORMAL) ++// { ++// result |= EOS_VERYLATE; ++// m_pullupCorrection.Flush(); //dropped frames mess up the pattern, so just flush it ++// } ++// ++// //if we requested 5 drops in a row and we're still late, drop on output ++// //this keeps a/v sync if the decoder can't drop, or we're still calculating the framerate ++// if (m_iDroppedRequest > 5) ++// { ++// m_iDroppedRequest--; //decrease so we only drop half the frames ++// return result | EOS_DROPPED; ++// } ++// m_iDroppedRequest++; ++// } ++// } ++// else ++// { ++// m_iDroppedRequest = 0; ++// } ++ ++ if ((m_droppingStats.m_requestOutputDrop && !(pPicture->iFlags & DVP_FLAG_NOSKIP)) ++ || (pPicture->iFlags & DVP_FLAG_DROPPED)) ++ { ++ m_droppingStats.AddOutputDropGain(pts, 1/m_fFrameRate); ++ m_droppingStats.m_requestOutputDrop = false; ++ CLog::Log(LOGDEBUG,"%s - dropped in output", __FUNCTION__); ++ return result | EOS_DROPPED; ++ } + +- // ask decoder to drop frames next round, as we are very late +- if(m_iLateFrames > 10) ++ if( m_speed < 0 ) + { +- if (!(pPicture->iFlags & DVP_FLAG_NOSKIP)) ++ double decoderPts = m_droppingStats.m_lastDecoderPts; ++ double renderPts = m_droppingStats.m_lastRenderPts; ++ if (pts > renderPts) + { +- //if we're calculating the framerate, +- //don't drop frames until we've calculated a stable framerate +- if (m_bAllowDrop || m_speed != DVD_PLAYSPEED_NORMAL) ++ if (decoderPts >= renderPts) + { +- result |= EOS_VERYLATE; +- m_pullupCorrection.Flush(); //dropped frames mess up the pattern, so just flush it ++ Sleep(200); + } +- +- //if we requested 5 drops in a row and we're still late, drop on output +- //this keeps a/v sync if the decoder can't drop, or we're still calculating the framerate +- if (m_iDroppedRequest > 5) +- { +- m_iDroppedRequest--; //decrease so we only drop half the frames +- return result | EOS_DROPPED; +- } +- m_iDroppedRequest++; +- } +- } +- else +- { +- m_iDroppedRequest = 0; +- } +- +- if( m_speed < 0 ) +- { +- if( iClockSleep < -DVD_MSEC_TO_TIME(200) +- && !(pPicture->iFlags & DVP_FLAG_NOSKIP) ) + return result | EOS_DROPPED; ++ } + } + +- if( (pPicture->iFlags & DVP_FLAG_DROPPED) ) +- return result | EOS_DROPPED; +- +- if( m_speed != DVD_PLAYSPEED_NORMAL && limited ) ++ if( m_speed != DVD_PLAYSPEED_NORMAL && m_speed >= 0 && limited ) + { + // calculate frame dropping pattern to render at this speed + // we do that by deciding if this or next frame is closest +@@ -1239,6 +1305,16 @@ + mDisplayField = FS_BOT; + } + ++ int buffer = g_renderManager.WaitForBuffer(m_bStop); ++ while (buffer < 0 && !CThread::m_bStop && ++ CDVDClock::GetAbsoluteClock(false) < iCurrentClock + iSleepTime + DVD_MSEC_TO_TIME(500) ) ++ { ++ Sleep(1); ++ buffer = g_renderManager.WaitForBuffer(m_bStop); ++ } ++ if (buffer < 0) ++ return EOS_DROPPED; ++ + ProcessOverlays(pPicture, pts); + AutoCrop(pPicture); + +@@ -1255,7 +1331,7 @@ + if (index < 0) + return EOS_DROPPED; + +- g_renderManager.FlipPage(CThread::m_bStop, (iCurrentClock + iSleepTime) / DVD_TIME_BASE, -1, mDisplayField); ++ g_renderManager.FlipPage(CThread::m_bStop, pts, -1, mDisplayField, m_speed); + + return result; + #else +@@ -1269,7 +1345,8 @@ + if ((pPicture->format == DVDVideoPicture::FMT_YUV420P) || + (pPicture->format == DVDVideoPicture::FMT_NV12) || + (pPicture->format == DVDVideoPicture::FMT_YUY2) || +- (pPicture->format == DVDVideoPicture::FMT_UYVY)) ++ (pPicture->format == DVDVideoPicture::FMT_UYVY) || ++ (pPicture->format == DVDVideoPicture::FMT_VDPAU_420)) + { + RECT crop; + +@@ -1498,7 +1575,7 @@ + double frameduration = m_pullupCorrection.GetFrameDuration(); + + if (frameduration == DVD_NOPTS_VALUE || +- (g_advancedSettings.m_videoFpsDetect == 1 && m_pullupCorrection.GetPatternLength() > 1)) ++ (g_advancedSettings.m_videoFpsDetect == 1 && (m_pullupCorrection.GetPatternLength() > 1 && !m_bFpsInvalid))) + { + //reset the stored framerates if no good framerate was detected + m_fStableFrameRate = 0.0; +@@ -1554,3 +1631,142 @@ + m_iFrameRateCount = 0; + } + } ++ ++int CDVDPlayerVideo::CalcDropRequirement(double pts) ++{ ++ int result = 0; ++ double iSleepTime; ++ double iDecoderPts, iRenderPts; ++ double iInterval; ++ int interlaced; ++ double iGain; ++ double iLateness; ++ bool bNewFrame; ++ int iSkippedDeint = 0; ++ int iBufferLevel; ++ ++ // get decoder stats ++ if (!m_pVideoCodec->GetPts(iDecoderPts, iSkippedDeint, interlaced)) ++ iDecoderPts = pts; ++ ++ // get render stats ++ g_renderManager.GetStats(iSleepTime, iRenderPts, iBufferLevel); ++ ++ if (iBufferLevel < 2) ++ { ++ result |= EOS_BUFFER_LEVEL; ++ if (iBufferLevel < 1) ++ CLog::Log(LOGDEBUG,"--------------------- hurry: %d", iBufferLevel); ++ } ++ ++ bNewFrame = iDecoderPts != m_droppingStats.m_lastDecoderPts; ++ ++ if (interlaced) ++ iInterval = 2/m_fFrameRate*(double)DVD_TIME_BASE; ++ else ++ iInterval = 1/m_fFrameRate*(double)DVD_TIME_BASE; ++ ++ // add any gains regardless of being late ++ if (m_droppingStats.m_lastDecoderPts > 0 ++ && bNewFrame ++ && m_bAllowDrop ++ && m_droppingStats.m_dropRequests > 0) ++ { ++ iGain = (iDecoderPts - m_droppingStats.m_lastDecoderPts - iInterval)/(double)DVD_TIME_BASE; ++ if (iSkippedDeint) ++ { ++ CDroppingStats::CGain gain; ++ gain.gain = 1/m_fFrameRate; ++ gain.pts = iDecoderPts; ++ m_droppingStats.m_gain.push_back(gain); ++ m_droppingStats.m_totalGain += gain.gain; ++ result |= EOS_DROPPED; ++ m_droppingStats.m_dropRequests = 0; ++ CLog::Log(LOGDEBUG,"CDVDPlayerVideo::CalcDropRequirement - dropped de-interlacing cycle, Sleeptime: %f, Bufferlevel: %d", iSleepTime, iBufferLevel); ++ } ++ else if (iGain > 1/m_fFrameRate) ++ { ++ CDroppingStats::CGain gain; ++ gain.gain = iGain; ++ gain.pts = iDecoderPts; ++ m_droppingStats.m_gain.push_back(gain); ++ m_droppingStats.m_totalGain += iGain; ++ result |= EOS_DROPPED; ++ m_droppingStats.m_dropRequests = 0; ++ CLog::Log(LOGDEBUG,"CDVDPlayerVideo::CalcDropRequirement - dropped in decoder, Sleeptime: %f, Bufferlevel: %d, Gain: %f", iSleepTime, iBufferLevel, iGain); ++ } ++ ++ } ++ m_droppingStats.m_lastDecoderPts = iDecoderPts; ++ ++ // subtract gains ++ while (!m_droppingStats.m_gain.empty() && ++ iRenderPts >= m_droppingStats.m_gain.front().pts) ++ { ++ m_droppingStats.m_totalGain -= m_droppingStats.m_gain.front().gain; ++ m_droppingStats.m_gain.pop_front(); ++ } ++ ++// if (iSleepTime < 0) ++// { ++// CLog::Log(LOGNOTICE,"----- sleep: %f, gain :%f", ++// iSleepTime, m_droppingStats.m_totalGain); ++// } ++ ++ // calculate lateness ++ iLateness = iSleepTime + m_droppingStats.m_totalGain; ++ if (iLateness < 0 && m_speed) ++ { ++ if (bNewFrame) ++ m_droppingStats.m_lateFrames++; ++ ++ // if lateness is smaller than frametime, we observe this state ++ // for 10 cycles ++ if (m_droppingStats.m_lateFrames > 10 || iLateness < -2/m_fFrameRate) ++ { ++ // is frame allowed to skip ++ if (m_iNrOfPicturesNotToSkip <= 0) ++ { ++ result |= EOS_VERYLATE; ++ ++ // drop in output ++ if (m_droppingStats.m_dropRequests > 7 && g_graphicsContext.IsFullScreenVideo()) ++ { ++ m_droppingStats.m_dropRequests--; //decrease so we only drop half the frames ++ m_droppingStats.m_requestOutputDrop = true; ++ CLog::Log(LOGNOTICE,"-------- drop output"); ++ } ++ else if (bNewFrame) ++ m_droppingStats.m_dropRequests++; ++ } ++ } ++ } ++ else ++ { ++ m_droppingStats.m_dropRequests = 0; ++ m_droppingStats.m_lateFrames = 0; ++ m_droppingStats.m_requestOutputDrop = false; ++ } ++ m_droppingStats.m_lastRenderPts = iRenderPts; ++ return result; ++} ++ ++void CDroppingStats::Reset() ++{ ++ m_gain.clear(); ++ m_totalGain = 0; ++ m_lastDecoderPts = 0; ++ m_lastRenderPts = 0; ++ m_lateFrames = 0; ++ m_dropRequests = 0; ++ m_requestOutputDrop = false; ++} ++ ++void CDroppingStats::AddOutputDropGain(double pts, double frametime) ++{ ++ CDroppingStats::CGain gain; ++ gain.gain = frametime; ++ gain.pts = pts; ++ m_gain.push_back(gain); ++ m_totalGain += frametime; ++} +diff -Naur xbmc-11.0.1/xbmc/cores/dvdplayer/DVDPlayerVideo.h xbmc-11.0.1.patch/xbmc/cores/dvdplayer/DVDPlayerVideo.h +--- xbmc-11.0.1/xbmc/cores/dvdplayer/DVDPlayerVideo.h 2012-03-21 23:57:34.000000000 +0100 ++++ xbmc-11.0.1.patch/xbmc/cores/dvdplayer/DVDPlayerVideo.h 2012-05-13 22:08:47.047194890 +0200 +@@ -38,6 +38,26 @@ + + #define VIDEO_PICTURE_QUEUE_SIZE 1 + ++class CDroppingStats ++{ ++public: ++ void Reset(); ++ void AddOutputDropGain(double pts, double frametime); ++ struct CGain ++ { ++ double gain; ++ double pts; ++ }; ++ std::deque m_gain; ++ double m_totalGain; ++ double m_lastDecoderPts; ++ double m_lastRenderPts; ++ unsigned int m_lateFrames; ++ unsigned int m_dropRequests; ++ bool m_requestOutputDrop; ++}; ++ ++ + class CDVDPlayerVideo : public CThread + { + public: +@@ -111,6 +131,7 @@ + #define EOS_ABORT 1 + #define EOS_DROPPED 2 + #define EOS_VERYLATE 4 ++#define EOS_BUFFER_LEVEL 8 + + void AutoCrop(DVDVideoPicture* pPicture); + void AutoCrop(DVDVideoPicture *pPicture, RECT &crop); +@@ -130,9 +151,11 @@ + int m_iLateFrames; + int m_iDroppedFrames; + int m_iDroppedRequest; ++ double m_iLastSleepTime; + + void ResetFrameRateCalc(); + void CalcFrameRate(); ++ int CalcDropRequirement(double pts); + + double m_fFrameRate; //framerate of the video currently playing + bool m_bCalcFrameRate; //if we should calculate the framerate from the timestamps +@@ -193,5 +216,7 @@ + CPullupCorrection m_pullupCorrection; + + std::list m_packets; ++ ++ CDroppingStats m_droppingStats; + }; + +diff -Naur xbmc-11.0.1/xbmc/cores/paplayer/PAPlayer.cpp xbmc-11.0.1.patch/xbmc/cores/paplayer/PAPlayer.cpp +--- xbmc-11.0.1/xbmc/cores/paplayer/PAPlayer.cpp 2012-03-21 23:57:34.000000000 +0100 ++++ xbmc-11.0.1.patch/xbmc/cores/paplayer/PAPlayer.cpp 2012-05-13 22:08:46.787189730 +0200 +@@ -52,7 +52,7 @@ + // Supporting all open audio codec standards. + // First one being nullsoft's nsv audio decoder format + +-PAPlayer::PAPlayer(IPlayerCallback& callback) : IPlayer(callback) ++PAPlayer::PAPlayer(IPlayerCallback& callback) : CThread("PAPlayer"), IPlayer(callback) + { + m_bIsPlaying = false; + m_bPaused = false; +@@ -168,7 +168,7 @@ + + *m_currentFile = file; + +- if (ThreadHandle() == NULL) ++ if (!IsRunning()) + Create(); + + m_startEvent.Set(); +diff -Naur xbmc-11.0.1/xbmc/cores/VideoRenderers/LinuxRendererGL.cpp xbmc-11.0.1.patch/xbmc/cores/VideoRenderers/LinuxRendererGL.cpp +--- xbmc-11.0.1/xbmc/cores/VideoRenderers/LinuxRendererGL.cpp 2012-03-21 23:57:35.000000000 +0100 ++++ xbmc-11.0.1.patch/xbmc/cores/VideoRenderers/LinuxRendererGL.cpp 2012-05-13 22:08:47.060195147 +0200 +@@ -61,6 +61,9 @@ + VA_MICRO_VERSION == 0 && VA_SDS_VERSION < 5))) + + #endif ++#ifdef HAVE_LIBXVBA ++#include "cores/dvdplayer/DVDCodecs/Video/XVBA.h" ++#endif + + #ifdef HAS_GLX + #include +@@ -121,6 +124,9 @@ + #ifdef HAVE_LIBVDPAU + vdpau = NULL; + #endif ++#ifdef HAVE_LIBXVBA ++ xvba = NULL; ++#endif + } + + CLinuxRendererGL::YUVBUFFER::~YUVBUFFER() +@@ -224,7 +230,7 @@ + + void CLinuxRendererGL::ManageTextures() + { +- m_NumYV12Buffers = 2; ++// m_NumYV12Buffers = NUM_BUFFERS; + //m_iYV12RenderBuffer = 0; + return; + } +@@ -241,6 +247,11 @@ + else + CLog::Log(LOGNOTICE,"Using GL_TEXTURE_2D"); + ++ // function pointer for texture might change in ++ // call to LoadShaders ++ for (int i = 0 ; i < m_NumYV12Buffers ; i++) ++ (this->*m_textureDelete)(i); ++ + // create the yuv textures + LoadShaders(); + +@@ -567,6 +578,18 @@ + + glFinish(); + m_bValidated = false; ++ m_iYV12RenderBuffer = 0; ++} ++ ++void CLinuxRendererGL::ReleaseBuffer(int idx) ++{ ++ YUVBUFFER &buf = m_buffers[idx]; ++#ifdef HAVE_LIBVDPAU ++ SAFE_RELEASE(buf.vdpau); ++#endif ++#ifdef HAVE_LIBXVBA ++ SAFE_RELEASE(buf.xvba); ++#endif + } + + void CLinuxRendererGL::Update(bool bPauseDrawing) +@@ -640,6 +663,18 @@ + + glDisable(GL_POLYGON_STIPPLE); + } ++ else if( CONF_FLAGS_FORMAT_MASK(m_iFlags) == CONF_FLAGS_FORMAT_VDPAU_420 ++ && !(flags & (RENDER_FLAG_TOP | RENDER_FLAG_BOT))) ++ { ++ glDisable(GL_BLEND); ++ glColor4f(1.0f, 1.0f, 1.0f, 1.0f); ++ Render(flags | RENDER_FLAG_TOP, index); ++ ++ glEnable(GL_BLEND); ++ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); ++ glColor4f(1.0f, 1.0f, 1.0f, 128 / 255.0f); ++ Render(flags | RENDER_FLAG_BOT , index); ++ } + else + Render(flags, index); + +@@ -718,11 +753,6 @@ + + m_buffers[m_iYV12RenderBuffer].flipindex = ++m_flipindex; + +-#ifdef HAVE_LIBVDPAU +- if((m_renderMethod & RENDER_VDPAU) && m_buffers[m_iYV12RenderBuffer].vdpau) +- m_buffers[m_iYV12RenderBuffer].vdpau->Present(); +-#endif +- + return; + } + +@@ -737,7 +767,6 @@ + m_resolution = RES_DESKTOP; + + m_iYV12RenderBuffer = 0; +- m_NumYV12Buffers = 2; + + // setup the background colour + m_clearColour = (float)(g_advancedSettings.m_videoBlackBarColour & 0xff) / 0xff; +@@ -817,7 +846,7 @@ + case VS_SCALINGMETHOD_LINEAR: + SetTextureFilter(m_scalingMethod == VS_SCALINGMETHOD_NEAREST ? GL_NEAREST : GL_LINEAR); + m_renderQuality = RQ_SINGLEPASS; +- if (((m_renderMethod & RENDER_VDPAU) || (m_renderMethod & RENDER_VAAPI)) && m_nonLinStretch) ++ if (((m_renderMethod & RENDER_VDPAU) || (m_renderMethod & RENDER_VAAPI) || (m_renderMethod & RENDER_XVBA)) && m_nonLinStretch) + { + m_pVideoFilterShader = new StretchFilterShader(); + if (!m_pVideoFilterShader->CompileAndLink()) +@@ -898,6 +927,11 @@ + CLog::Log(LOGNOTICE, "GL: Using VAAPI render method"); + m_renderMethod = RENDER_VAAPI; + } ++ else if (CONF_FLAGS_FORMAT_MASK(m_iFlags) == CONF_FLAGS_FORMAT_XVBA) ++ { ++ CLog::Log(LOGNOTICE, "GL: Using XVBA render method"); ++ m_renderMethod = RENDER_XVBA; ++ } + else + { + int requestedMethod = g_guiSettings.GetInt("videoplayer.rendermethod"); +@@ -1026,12 +1060,24 @@ + m_textureCreate = &CLinuxRendererGL::CreateVDPAUTexture; + m_textureDelete = &CLinuxRendererGL::DeleteVDPAUTexture; + } ++ else if (CONF_FLAGS_FORMAT_MASK(m_iFlags) == CONF_FLAGS_FORMAT_VDPAU_420) ++ { ++ m_textureUpload = &CLinuxRendererGL::UploadVDPAUTexture420; ++ m_textureCreate = &CLinuxRendererGL::CreateVDPAUTexture420; ++ m_textureDelete = &CLinuxRendererGL::DeleteVDPAUTexture420; ++ } + else if (CONF_FLAGS_FORMAT_MASK(m_iFlags) == CONF_FLAGS_FORMAT_VAAPI) + { + m_textureUpload = &CLinuxRendererGL::UploadVAAPITexture; + m_textureCreate = &CLinuxRendererGL::CreateVAAPITexture; + m_textureDelete = &CLinuxRendererGL::DeleteVAAPITexture; + } ++ else if (CONF_FLAGS_FORMAT_MASK(m_iFlags) == CONF_FLAGS_FORMAT_XVBA) ++ { ++ m_textureUpload = &CLinuxRendererGL::UploadXVBATexture; ++ m_textureCreate = &CLinuxRendererGL::CreateXVBATexture; ++ m_textureDelete = &CLinuxRendererGL::DeleteXVBATexture; ++ } + else + { + // setup default YV12 texture handlers +@@ -1132,6 +1178,13 @@ + RenderVAAPI(renderBuffer, m_currentField); + } + #endif ++#ifdef HAVE_LIBXVBA ++ else if (m_renderMethod & RENDER_XVBA) ++ { ++ UpdateVideoFilter(); ++ RenderXVBA(renderBuffer, m_currentField); ++ } ++#endif + else + { + RenderSoftware(renderBuffer, m_currentField); +@@ -1434,17 +1487,12 @@ + void CLinuxRendererGL::RenderVDPAU(int index, int field) + { + #ifdef HAVE_LIBVDPAU +- YUVPLANE &plane = m_buffers[index].fields[field][0]; +- CVDPAU *vdpau = m_buffers[m_iYV12RenderBuffer].vdpau; +- +- if (!vdpau) +- return; ++ YUVPLANE &plane = m_buffers[index].fields[0][1]; + + glEnable(m_textureTarget); + glActiveTextureARB(GL_TEXTURE0); +- glBindTexture(m_textureTarget, plane.id); + +- vdpau->BindPixmap(); ++ glBindTexture(m_textureTarget, plane.id); + + // Try some clamping or wrapping + glTexParameteri(m_textureTarget, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); +@@ -1502,8 +1550,6 @@ + if (m_pVideoFilterShader) + m_pVideoFilterShader->Disable(); + +- vdpau->ReleasePixmap(); +- + glBindTexture (m_textureTarget, 0); + glDisable(m_textureTarget); + #endif +@@ -1598,6 +1644,77 @@ + #endif + } + ++void CLinuxRendererGL::RenderXVBA(int index, int field) ++{ ++#ifdef HAVE_LIBXVBA ++ YUVPLANE &plane = m_buffers[index].fields[0][1]; ++ ++ glEnable(m_textureTarget); ++ glActiveTextureARB(GL_TEXTURE0); ++ ++ glBindTexture(m_textureTarget, plane.id); ++ ++ // Try some clamping or wrapping ++ glTexParameteri(m_textureTarget, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); ++ glTexParameteri(m_textureTarget, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); ++ ++ if (m_pVideoFilterShader) ++ { ++ GLint filter; ++ if (!m_pVideoFilterShader->GetTextureFilter(filter)) ++ filter = m_scalingMethod == VS_SCALINGMETHOD_NEAREST ? GL_NEAREST : GL_LINEAR; ++ ++ glTexParameteri(m_textureTarget, GL_TEXTURE_MAG_FILTER, filter); ++ glTexParameteri(m_textureTarget, GL_TEXTURE_MIN_FILTER, filter); ++ m_pVideoFilterShader->SetSourceTexture(0); ++ m_pVideoFilterShader->SetWidth(m_sourceWidth); ++ m_pVideoFilterShader->SetHeight(m_sourceHeight); ++ ++ //disable non-linear stretch when a dvd menu is shown, parts of the menu are rendered through the overlay renderer ++ //having non-linear stretch on breaks the alignment ++ if (g_application.m_pPlayer && g_application.m_pPlayer->IsInMenu()) ++ m_pVideoFilterShader->SetNonLinStretch(1.0); ++ else ++ m_pVideoFilterShader->SetNonLinStretch(pow(g_settings.m_fPixelRatio, g_advancedSettings.m_videoNonLinStretchRatio)); ++ ++ m_pVideoFilterShader->Enable(); ++ } ++ else ++ { ++ GLint filter = m_scalingMethod == VS_SCALINGMETHOD_NEAREST ? GL_NEAREST : GL_LINEAR; ++ glTexParameteri(m_textureTarget, GL_TEXTURE_MAG_FILTER, filter); ++ glTexParameteri(m_textureTarget, GL_TEXTURE_MIN_FILTER, filter); ++ } ++ ++ glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); ++ VerifyGLState(); ++ ++ glBegin(GL_QUADS); ++ if (m_textureTarget==GL_TEXTURE_2D) ++ { ++ glTexCoord2f(plane.rect.x1, plane.rect.y1); glVertex2f(m_destRect.x1, m_destRect.y1); ++ glTexCoord2f(plane.rect.x2, plane.rect.y1); glVertex2f(m_destRect.x2, m_destRect.y1); ++ glTexCoord2f(plane.rect.x2, plane.rect.y2); glVertex2f(m_destRect.x2, m_destRect.y2); ++ glTexCoord2f(plane.rect.x1, plane.rect.y2); glVertex2f(m_destRect.x1, m_destRect.y2); ++ } ++ else ++ { ++ glTexCoord2f(m_destRect.x1, m_destRect.y1); glVertex4f(m_destRect.x1, m_destRect.y1, 0.0f, 0.0f); ++ glTexCoord2f(m_destRect.x2, m_destRect.y1); glVertex4f(m_destRect.x2, m_destRect.y1, 1.0f, 0.0f); ++ glTexCoord2f(m_destRect.x2, m_destRect.y2); glVertex4f(m_destRect.x2, m_destRect.y2, 1.0f, 1.0f); ++ glTexCoord2f(m_destRect.x1, m_destRect.y2); glVertex4f(m_destRect.x1, m_destRect.y2, 0.0f, 1.0f); ++ } ++ glEnd(); ++ VerifyGLState(); ++ ++ if (m_pVideoFilterShader) ++ m_pVideoFilterShader->Disable(); ++ ++ glBindTexture (m_textureTarget, 0); ++ glDisable(m_textureTarget); ++#endif ++} ++ + void CLinuxRendererGL::RenderSoftware(int index, int field) + { + YUVPLANES &planes = m_buffers[index].fields[field]; +@@ -2162,12 +2279,14 @@ + { + #ifdef HAVE_LIBVDPAU + YUVPLANE &plane = m_buffers[index].fields[0][0]; ++ YUVFIELDS &fields = m_buffers[index].fields; + + SAFE_RELEASE(m_buffers[index].vdpau); + + if(plane.id && glIsTexture(plane.id)) + glDeleteTextures(1, &plane.id); + plane.id = 0; ++ fields[0][1].id = 0; + #endif + } + +@@ -2201,8 +2320,156 @@ + void CLinuxRendererGL::UploadVDPAUTexture(int index) + { + #ifdef HAVE_LIBVDPAU ++ VDPAU::CVdpauRenderPicture *vdpau = m_buffers[index].vdpau; ++ ++ unsigned int flipindex = m_buffers[index].flipindex; ++ YUVFIELDS &fields = m_buffers[index].fields; ++ YUVPLANE &plane = fields[0][0]; ++ ++ if (!vdpau) ++ { ++ fields[0][1].id = plane.id; ++ m_eventTexturesDone[index]->Set(); ++ CLog::Log(LOGWARNING,"--------- no vdpau texture, index: %d", index); ++ return; ++ } ++ ++// CLog::Log(LOGNOTICE,"-------- rendered output surf: %d", vdpau->sourceIdx); ++// CLog::Log(LOGNOTICE,"-------- pts: %f", vdpau->DVDPic.pts); ++ fields[0][1].id = vdpau->texture[0]; ++ ++ m_eventTexturesDone[index]->Set(); ++#endif ++} ++ ++void CLinuxRendererGL::DeleteVDPAUTexture420(int index) ++{ ++#ifdef HAVE_LIBVDPAU ++ YUVPLANE &plane = m_buffers[index].fields[0][0]; ++ YUVFIELDS &fields = m_buffers[index].fields; ++ ++ SAFE_RELEASE(m_buffers[index].vdpau); ++ ++ if(plane.id && glIsTexture(plane.id)) ++ glDeleteTextures(1, &plane.id); ++ plane.id = 0; ++ fields[1][0].id = 0; ++ fields[1][1].id = 0; ++ fields[2][0].id = 0; ++ fields[2][1].id = 0; ++ ++#endif ++} ++ ++bool CLinuxRendererGL::CreateVDPAUTexture420(int index) ++{ ++#ifdef HAVE_LIBVDPAU ++ YV12Image &im = m_buffers[index].image; ++ YUVFIELDS &fields = m_buffers[index].fields; ++ YUVPLANE &plane = fields[0][0]; ++ GLuint *pbo = m_buffers[index].pbo; ++ ++ DeleteVDPAUTexture420(index); ++ ++ memset(&im , 0, sizeof(im)); ++ memset(&fields, 0, sizeof(fields)); ++ ++ im.cshift_x = 1; ++ im.cshift_y = 1; ++ ++ im.plane[0] = NULL; ++ im.plane[1] = NULL; ++ im.plane[2] = NULL; ++ ++ for(int p = 0;p<3;p++) ++ { ++ pbo[p] = None; ++ } ++ ++ glEnable(m_textureTarget); ++ glGenTextures(1, &plane.id); ++ glDisable(m_textureTarget); ++ ++ m_eventTexturesDone[index]->Set(); ++#endif ++ return true; ++} ++ ++void CLinuxRendererGL::UploadVDPAUTexture420(int index) ++{ ++#ifdef HAVE_LIBVDPAU ++ VDPAU::CVdpauRenderPicture *vdpau = m_buffers[index].vdpau; ++ YV12Image &im = m_buffers[index].image; ++ ++ unsigned int flipindex = m_buffers[index].flipindex; ++ YUVFIELDS &fields = m_buffers[index].fields; ++ YUVPLANE &plane = fields[0][0]; ++ ++ if (!vdpau) ++ { ++ fields[1][0].id = plane.id; ++ fields[1][1].id = plane.id; ++ fields[2][0].id = plane.id; ++ fields[2][1].id = plane.id; ++ m_eventTexturesDone[index]->Set(); ++ return; ++ } ++ ++ im.height = vdpau->texHeight; ++ im.width = vdpau->texWidth; ++ ++ // YUV ++ for (int f = FIELD_FULL; f<=FIELD_BOT ; f++) ++ { ++ int fieldshift = (f==FIELD_FULL) ? 0 : 1; ++ YUVPLANES &planes = fields[f]; ++ ++ planes[0].texwidth = im.width; ++ planes[0].texheight = im.height >> fieldshift; ++ ++ planes[1].texwidth = planes[0].texwidth >> im.cshift_x; ++ planes[1].texheight = planes[0].texheight >> im.cshift_y; ++ planes[2].texwidth = planes[1].texwidth; ++ planes[2].texheight = planes[1].texheight; ++ ++ for (int p = 0; p < 3; p++) ++ { ++ planes[p].pixpertex_x = 1; ++ planes[p].pixpertex_y = 1; ++ } ++ } ++ // crop ++// m_sourceRect.x1 += vdpau->crop.x1; ++// m_sourceRect.x2 -= vdpau->crop.x2; ++// m_sourceRect.y1 += vdpau->crop.y1; ++// m_sourceRect.y2 -= vdpau->crop.y2; ++ ++ // set textures ++ fields[1][0].id = vdpau->texture[0]; ++ fields[1][1].id = vdpau->texture[2]; ++ fields[2][0].id = vdpau->texture[1]; ++ fields[2][1].id = vdpau->texture[3]; ++ ++ glEnable(m_textureTarget); ++ for (int f = 1; f < 3; f++) ++ { ++ for (int p=0;p<2;p++) ++ { ++ glBindTexture(m_textureTarget,fields[f][p].id); ++ glTexParameteri(m_textureTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR); ++ glTexParameteri(m_textureTarget, GL_TEXTURE_MAG_FILTER, GL_LINEAR); ++ glTexParameteri(m_textureTarget, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); ++ glTexParameteri(m_textureTarget, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); ++ ++ glBindTexture(m_textureTarget,0); ++ VerifyGLState(); ++ } ++ fields[f][2].id = fields[f][1].id; ++ } ++ CalculateTextureSourceRects(index, 3); ++ glDisable(m_textureTarget); ++ + m_eventTexturesDone[index]->Set(); +- glPixelStorei(GL_UNPACK_ALIGNMENT,1); //what's this for? + #endif + } + +@@ -2352,6 +2619,93 @@ + #endif + } + ++void CLinuxRendererGL::DeleteXVBATexture(int index) ++{ ++#ifdef HAVE_LIBXVBA ++ YUVPLANE &plane = m_buffers[index].fields[0][0]; ++ YUVFIELDS &fields = m_buffers[index].fields; ++ ++ SAFE_RELEASE(m_buffers[index].xvba); ++ ++ if(plane.id && glIsTexture(plane.id)) ++ glDeleteTextures(1, &plane.id); ++ plane.id = 0; ++ fields[0][1].id = 0; ++#endif ++} ++ ++bool CLinuxRendererGL::CreateXVBATexture(int index) ++{ ++#ifdef HAVE_LIBXVBA ++ YV12Image &im = m_buffers[index].image; ++ YUVFIELDS &fields = m_buffers[index].fields; ++ YUVPLANE &plane = fields[0][0]; ++ ++ DeleteXVBATexture(index); ++ ++ memset(&im , 0, sizeof(im)); ++ memset(&fields, 0, sizeof(fields)); ++ ++ glGenTextures(1, &plane.id); ++ ++ m_eventTexturesDone[index]->Set(); ++#endif ++ return true; ++} ++ ++void CLinuxRendererGL::UploadXVBATexture(int index) ++{ ++#ifdef HAVE_LIBXVBA ++ XVBA::CXvbaRenderPicture *xvba = m_buffers[index].xvba; ++ YV12Image &im = m_buffers[index].image; ++ ++ YUVFIELDS &fields = m_buffers[index].fields; ++ YUVPLANE &plane = fields[0][1]; ++ ++ if (!xvba) ++ { ++ fields[0][1].id = fields[0][0].id; ++ m_eventTexturesDone[index]->Set(); ++ CLog::Log(LOGWARNING,"CLinuxRendererGL::UploadXVBATexture no xvba texture, index: %d", index); ++ return; ++ } ++// xvba->Transfer(); ++ ++ fields[0][1].id = xvba->texture; ++ ++ im.height = xvba->texHeight; ++ im.width = xvba->texWidth; ++ ++ plane.texwidth = xvba->texWidth; ++ plane.texheight = xvba->texHeight; ++ plane.pixpertex_x = 1; ++ plane.pixpertex_y = 1; ++ ++ plane.rect = m_sourceRect; ++ plane.width = im.width; ++ plane.height = im.height; ++ ++ plane.height /= plane.pixpertex_y; ++ plane.rect.y1 /= plane.pixpertex_y; ++ plane.rect.y2 /= plane.pixpertex_y; ++ plane.width /= plane.pixpertex_x; ++ plane.rect.x1 /= plane.pixpertex_x; ++ plane.rect.x2 /= plane.pixpertex_x; ++ ++ if (m_textureTarget == GL_TEXTURE_2D) ++ { ++ plane.height /= plane.texheight; ++ plane.rect.y1 /= plane.texheight; ++ plane.rect.y2 /= plane.texheight; ++ plane.width /= plane.texwidth; ++ plane.rect.x1 /= plane.texwidth; ++ plane.rect.x2 /= plane.texwidth; ++ } ++ ++ m_eventTexturesDone[index]->Set(); ++#endif ++} ++ + void CLinuxRendererGL::UploadYUV422PackedTexture(int source) + { + YUVBUFFER& buf = m_buffers[source]; +@@ -2935,6 +3289,9 @@ + if (m_renderMethod & RENDER_VAAPI) + return false; + ++ if (m_renderMethod & RENDER_XVBA) ++ return false; ++ + return (m_renderMethod & RENDER_GLSL) + || (m_renderMethod & RENDER_ARB) + || ((m_renderMethod & RENDER_SW) && glewIsSupported("GL_ARB_imaging") == GL_TRUE); +@@ -2948,6 +3305,9 @@ + if (m_renderMethod & RENDER_VAAPI) + return false; + ++ if (m_renderMethod & RENDER_XVBA) ++ return false; ++ + return (m_renderMethod & RENDER_GLSL) + || (m_renderMethod & RENDER_ARB) + || ((m_renderMethod & RENDER_SW) && glewIsSupported("GL_ARB_imaging") == GL_TRUE); +@@ -2971,7 +3331,8 @@ + if (feature == RENDERFEATURE_NONLINSTRETCH) + { + if (((m_renderMethod & RENDER_GLSL) && !(m_renderMethod & RENDER_POT)) || +- (m_renderMethod & RENDER_VDPAU) || (m_renderMethod & RENDER_VAAPI)) ++ (m_renderMethod & RENDER_VDPAU) || (m_renderMethod & RENDER_VAAPI) || ++ (m_renderMethod & RENDER_XVBA)) + return true; + } + +@@ -2998,12 +3359,13 @@ + if(method == VS_INTERLACEMETHOD_AUTO) + return true; + +- if(m_renderMethod & RENDER_VDPAU) ++ if(m_renderMethod & RENDER_VDPAU || ++ CONF_FLAGS_FORMAT_MASK(m_iFlags) == CONF_FLAGS_FORMAT_VDPAU_420) + { + #ifdef HAVE_LIBVDPAU +- CVDPAU *vdpau = m_buffers[m_iYV12RenderBuffer].vdpau; +- if(vdpau) +- return vdpau->Supports(method); ++ VDPAU::CVdpauRenderPicture *vdpauPic = m_buffers[m_iYV12RenderBuffer].vdpau; ++ if(vdpauPic && vdpauPic->vdpau) ++ return vdpauPic->vdpau->Supports(method); + #endif + return false; + } +@@ -3027,6 +3389,16 @@ + return false; + } + ++ if(m_renderMethod & RENDER_XVBA) ++ { ++#ifdef HAVE_LIBXVBA ++ XVBA::CXvbaRenderPicture *xvba = m_buffers[m_iYV12RenderBuffer].xvba; ++ if(xvba) ++ return xvba->xvba->Supports(method); ++#endif ++ return false; ++ } ++ + #ifdef TARGET_DARWIN + // YADIF too slow for HD but we have no methods to fall back + // to something that works so just turn it off. +@@ -3069,7 +3441,7 @@ + || method == VS_SCALINGMETHOD_LANCZOS3) + { + if ((glewIsSupported("GL_EXT_framebuffer_object") && (m_renderMethod & RENDER_GLSL)) || +- (m_renderMethod & RENDER_VDPAU) || (m_renderMethod & RENDER_VAAPI)) ++ (m_renderMethod & RENDER_VDPAU) || (m_renderMethod & RENDER_VAAPI) || (m_renderMethod & RENDER_XVBA)) + { + // spline36 and lanczos3 are only allowed through advancedsettings.xml + if(method != VS_SCALINGMETHOD_SPLINE36 +@@ -3088,9 +3460,9 @@ + if(m_renderMethod & RENDER_VDPAU) + { + #ifdef HAVE_LIBVDPAU +- CVDPAU *vdpau = m_buffers[m_iYV12RenderBuffer].vdpau; +- if(vdpau) +- return vdpau->AutoInterlaceMethod(); ++ VDPAU::CVdpauRenderPicture *vdpauPic = m_buffers[m_iYV12RenderBuffer].vdpau; ++ if(vdpauPic && vdpauPic->vdpau) ++ return vdpauPic->vdpau->AutoInterlaceMethod(); + #endif + return VS_INTERLACEMETHOD_NONE; + } +@@ -3136,20 +3508,31 @@ + } + + #ifdef HAVE_LIBVDPAU +-void CLinuxRendererGL::AddProcessor(CVDPAU* vdpau) ++void CLinuxRendererGL::AddProcessor(VDPAU::CVdpauRenderPicture *vdpau, int index) + { +- YUVBUFFER &buf = m_buffers[NextYV12Texture()]; ++ YUVBUFFER &buf = m_buffers[index]; ++ VDPAU::CVdpauRenderPicture *pic = vdpau->Acquire(); + SAFE_RELEASE(buf.vdpau); +- buf.vdpau = (CVDPAU*)vdpau->Acquire(); ++ buf.vdpau = pic; + } + #endif + + #ifdef HAVE_LIBVA +-void CLinuxRendererGL::AddProcessor(VAAPI::CHolder& holder) ++void CLinuxRendererGL::AddProcessor(VAAPI::CHolder& holder, int index) + { +- YUVBUFFER &buf = m_buffers[NextYV12Texture()]; ++ YUVBUFFER &buf = m_buffers[index]; + buf.vaapi.surface = holder.surface; + } + #endif + ++#ifdef HAVE_LIBXVBA ++void CLinuxRendererGL::AddProcessor(XVBA::CXvbaRenderPicture* xvba, int index) ++{ ++ YUVBUFFER &buf = m_buffers[index]; ++ XVBA::CXvbaRenderPicture *pic = xvba->Acquire(); ++ SAFE_RELEASE(buf.xvba); ++ buf.xvba = pic; ++} ++#endif ++ + #endif +diff -Naur xbmc-11.0.1/xbmc/cores/VideoRenderers/LinuxRendererGL.h xbmc-11.0.1.patch/xbmc/cores/VideoRenderers/LinuxRendererGL.h +--- xbmc-11.0.1/xbmc/cores/VideoRenderers/LinuxRendererGL.h 2012-03-21 23:57:34.000000000 +0100 ++++ xbmc-11.0.1.patch/xbmc/cores/VideoRenderers/LinuxRendererGL.h 2012-05-13 22:08:46.947192904 +0200 +@@ -35,13 +35,14 @@ + + class CRenderCapture; + +-class CVDPAU; + class CBaseTexture; + namespace Shaders { class BaseYUV2RGBShader; } + namespace Shaders { class BaseVideoFilterShader; } + namespace VAAPI { struct CHolder; } ++namespace VDPAU { class CVdpauRenderPicture; } ++namespace XVBA { class CXvbaRenderPicture; } + +-#define NUM_BUFFERS 3 ++#define NUM_BUFFERS 10 + + + #undef ALIGN +@@ -94,6 +95,7 @@ + RENDER_VDPAU=0x08, + RENDER_POT=0x10, + RENDER_VAAPI=0x20, ++ RENDER_XVBA=0x40, + }; + + enum RenderQuality +@@ -141,14 +143,19 @@ + virtual void UnInit(); + virtual void Reset(); /* resets renderer after seek for example */ + virtual void Flush(); ++ virtual void ReleaseBuffer(int idx); ++ virtual void SetProcessorSize(int numBuffers) { m_NumYV12Buffers = numBuffers; } ++ virtual unsigned int GetProcessorSize() { return m_NumYV12Buffers; } + + #ifdef HAVE_LIBVDPAU +- virtual void AddProcessor(CVDPAU* vdpau); ++ virtual void AddProcessor(VDPAU::CVdpauRenderPicture* vdpau, int index); + #endif + #ifdef HAVE_LIBVA +- virtual void AddProcessor(VAAPI::CHolder& holder); ++ virtual void AddProcessor(VAAPI::CHolder& holder, int index); ++#endif ++#ifdef HAVE_LIBXVBA ++ virtual void AddProcessor(XVBA::CXvbaRenderPicture* xvba, int index); + #endif +- + virtual void RenderUpdate(bool clear, DWORD flags = 0, DWORD alpha = 255); + + // Feature support +@@ -190,6 +197,10 @@ + void DeleteVDPAUTexture(int index); + bool CreateVDPAUTexture(int index); + ++ void UploadVDPAUTexture420(int index); ++ void DeleteVDPAUTexture420(int index); ++ bool CreateVDPAUTexture420(int index); ++ + void UploadVAAPITexture(int index); + void DeleteVAAPITexture(int index); + bool CreateVAAPITexture(int index); +@@ -198,6 +209,10 @@ + void DeleteYUV422PackedTexture(int index); + bool CreateYUV422PackedTexture(int index); + ++ void UploadXVBATexture(int index); ++ void DeleteXVBATexture(int index); ++ bool CreateXVBATexture(int index); ++ + void UploadRGBTexture(int index); + void ToRGBFrame(YV12Image* im, unsigned flipIndexPlane, unsigned flipIndexBuf); + void ToRGBFields(YV12Image* im, unsigned flipIndexPlaneTop, unsigned flipIndexPlaneBot, unsigned flipIndexBuf); +@@ -210,7 +225,9 @@ + void RenderSinglePass(int renderBuffer, int field); // single pass glsl renderer + void RenderSoftware(int renderBuffer, int field); // single pass s/w yuv2rgb renderer + void RenderVDPAU(int renderBuffer, int field); // render using vdpau hardware ++ void RenderVDPAUYV12(int renderBuffer, int field); // render using vdpau hardware + void RenderVAAPI(int renderBuffer, int field); // render using vdpau hardware ++ void RenderXVBA(int renderBuffer, int field); // render using xvba hardware + + CFrameBufferObject m_fbo; + +@@ -265,11 +282,14 @@ + GLuint pbo[MAX_PLANES]; + + #ifdef HAVE_LIBVDPAU +- CVDPAU* vdpau; ++ VDPAU::CVdpauRenderPicture *vdpau; + #endif + #ifdef HAVE_LIBVA + VAAPI::CHolder& vaapi; + #endif ++#ifdef HAVE_LIBXVBA ++ XVBA::CXvbaRenderPicture *xvba; ++#endif + }; + + typedef YUVBUFFER YUVBUFFERS[NUM_BUFFERS]; +diff -Naur xbmc-11.0.1/xbmc/cores/VideoRenderers/OverlayRenderer.cpp xbmc-11.0.1.patch/xbmc/cores/VideoRenderers/OverlayRenderer.cpp +--- xbmc-11.0.1/xbmc/cores/VideoRenderers/OverlayRenderer.cpp 2012-03-21 23:57:35.000000000 +0100 ++++ xbmc-11.0.1.patch/xbmc/cores/VideoRenderers/OverlayRenderer.cpp 2012-05-13 22:08:46.744188878 +0200 +@@ -89,7 +89,7 @@ + CRenderer::CRenderer() + { + m_render = 0; +- m_decode = (m_render + 1) % 2; ++// m_decode = (m_render + 1) % 2; + } + + CRenderer::~CRenderer() +@@ -154,9 +154,10 @@ + { + CSingleLock lock(m_section); + +- for(int i = 0; i < 2; i++) ++ for(int i = 0; i < m_iNumBuffers; i++) + Release(m_buffers[i]); + ++ m_render = 0; + Release(m_cleanup); + } + +@@ -164,10 +165,23 @@ + { + CSingleLock lock(m_section); + +- m_render = m_decode; +- m_decode =(m_decode + 1) % 2; ++// m_render = m_decode; ++ m_render = (m_render + 1) % m_iNumBuffers; ++ ++// Release(m_buffers[m_decode]); ++} ++ ++void CRenderer::SetBuffer(int idx) ++{ ++ CSingleLock lock(m_section); ++ Release(m_buffers[idx]); ++ m_decode = idx; ++} + +- Release(m_buffers[m_decode]); ++void CRenderer::ReleaseBuffer(int idx) ++{ ++ CSingleLock lock(m_section); ++ Release(m_buffers[idx]); + } + + void CRenderer::Render() +diff -Naur xbmc-11.0.1/xbmc/cores/VideoRenderers/OverlayRenderer.h xbmc-11.0.1.patch/xbmc/cores/VideoRenderers/OverlayRenderer.h +--- xbmc-11.0.1/xbmc/cores/VideoRenderers/OverlayRenderer.h 2012-03-21 23:57:34.000000000 +0100 ++++ xbmc-11.0.1.patch/xbmc/cores/VideoRenderers/OverlayRenderer.h 2012-05-13 22:08:46.745188897 +0200 +@@ -99,6 +99,9 @@ + void Flip(); + void Render(); + void Flush(); ++ void SetNumBuffers(int numBuffers) { m_iNumBuffers = numBuffers; } ++ void SetBuffer(int idx); ++ void ReleaseBuffer(int idx); + + protected: + +@@ -124,7 +127,8 @@ + void Release(SElementV& list); + + CCriticalSection m_section; +- SElementV m_buffers[2]; ++ SElementV m_buffers[10]; ++ int m_iNumBuffers; + int m_decode; + int m_render; + +diff -Naur xbmc-11.0.1/xbmc/cores/VideoRenderers/RenderFlags.h xbmc-11.0.1.patch/xbmc/cores/VideoRenderers/RenderFlags.h +--- xbmc-11.0.1/xbmc/cores/VideoRenderers/RenderFlags.h 2012-03-21 23:57:34.000000000 +0100 ++++ xbmc-11.0.1.patch/xbmc/cores/VideoRenderers/RenderFlags.h 2012-05-13 22:08:46.948192924 +0200 +@@ -76,8 +76,10 @@ + #define CONF_FLAGS_FORMAT_YUY2 0x008000 + #define CONF_FLAGS_FORMAT_DXVA 0x010000 + #define CONF_FLAGS_FORMAT_VDPAU 0x020000 ++#define CONF_FLAGS_FORMAT_VDPAU_420 0x22000 + #define CONF_FLAGS_FORMAT_VAAPI 0x030000 + #define CONF_FLAGS_FORMAT_OMXEGL 0x040000 + #define CONF_FLAGS_FORMAT_CVBREF 0x080000 + #define CONF_FLAGS_FORMAT_BYPASS 0x100000 ++#define CONF_FLAGS_FORMAT_XVBA 0x200000 + #endif +diff -Naur xbmc-11.0.1/xbmc/cores/VideoRenderers/RenderManager.cpp xbmc-11.0.1.patch/xbmc/cores/VideoRenderers/RenderManager.cpp +--- xbmc-11.0.1/xbmc/cores/VideoRenderers/RenderManager.cpp 2012-03-21 23:57:34.000000000 +0100 ++++ xbmc-11.0.1.patch/xbmc/cores/VideoRenderers/RenderManager.cpp 2012-05-13 22:08:47.061195167 +0200 +@@ -26,6 +26,7 @@ + #include "utils/MathUtils.h" + #include "threads/SingleLock.h" + #include "utils/log.h" ++#include "utils/TimeUtils.h" + + #include "Application.h" + #include "settings/Settings.h" +@@ -53,6 +54,8 @@ + #include "../dvdplayer/DVDCodecs/Video/DVDVideoCodec.h" + #include "../dvdplayer/DVDCodecs/DVDCodecUtils.h" + ++#include "windowing/WindowingFactory.h" ++ + #define MAXPRESENTDELAY 0.500 + + /* at any point we want an exclusive lock on rendermanager */ +@@ -246,6 +249,7 @@ + m_bReconfigured = true; + m_presentstep = PRESENT_IDLE; + m_presentevent.Set(); ++// ResetRenderBuffer(); + } + + return result; +@@ -277,8 +281,12 @@ + if (!m_pRenderer) + return; + ++ if (m_presentstep == PRESENT_IDLE) ++ PrepareNextRender(); ++ + if(m_presentstep == PRESENT_FLIP) + { ++ FlipRenderBuffer(); + m_overlays.Flip(); + m_pRenderer->FlipPage(m_presentsource); + m_presentstep = PRESENT_FRAME; +@@ -286,6 +294,8 @@ + } + } + ++// CLog::Log(LOGNOTICE,"------ current: %d", m_iCurrentRenderBuffer); ++ + if (g_advancedSettings.m_videoDisableBackgroundDeinterlace) + { + CSharedLock lock(m_sharedSection); +@@ -297,7 +307,7 @@ + m_presentevent.Set(); + } + +-unsigned int CXBMCRenderManager::PreInit() ++unsigned int CXBMCRenderManager::PreInit(CDVDClock *pClock) + { + CRetakeLock lock(m_sharedSection); + +@@ -305,6 +315,7 @@ + m_presenterr = 0.0; + m_errorindex = 0; + memset(m_errorbuff, 0, sizeof(m_errorbuff)); ++ m_pClock = pClock; + + m_bIsStarted = false; + m_bPauseDrawing = false; +@@ -323,6 +334,17 @@ + + UpdateDisplayLatency(); + ++ m_swapCount = 1; ++// std::string Vendor = g_Windowing.GetRenderVendor(); ++// std::transform(Vendor.begin(), Vendor.end(), Vendor.begin(), ::tolower); ++// if (Vendor.compare(0, 3, "ati") == 0) ++// { ++// m_swapCount = 2; ++// } ++ ResetRenderBuffer(); ++ m_bUseBuffering = false; ++ m_overlays.SetNumBuffers(m_iNumRenderBuffers); ++ m_pRenderer->SetProcessorSize(m_iNumRenderBuffers); + return m_pRenderer->PreInit(); + } + +@@ -351,7 +373,9 @@ + + CRetakeLock lock(m_sharedSection); + m_pRenderer->Flush(); ++ m_overlays.Flush(); + m_flushEvent.Set(); ++ ResetRenderBuffer(); + } + else + { +@@ -512,25 +536,21 @@ + m_captures.erase(it); + } + +-void CXBMCRenderManager::FlipPage(volatile bool& bStop, double timestamp /* = 0LL*/, int source /*= -1*/, EFIELDSYNC sync /*= FS_NONE*/) ++void CXBMCRenderManager::FlipPage(volatile bool& bStop, double timestamp /* = 0LL*/, int source /*= -1*/, EFIELDSYNC sync /*= FS_NONE*/, int speed /*= 0*/) + { +- if(timestamp - GetPresentTime() > MAXPRESENTDELAY) +- timestamp = GetPresentTime() + MAXPRESENTDELAY; +- +- /* can't flip, untill timestamp */ +- if(!g_graphicsContext.IsFullScreenVideo()) +- WaitPresentTime(timestamp); +- +- /* make sure any queued frame was fully presented */ +- double timeout = m_presenttime + 1.0; +- while(m_presentstep != PRESENT_IDLE && !bStop) ++ if (!m_bUseBuffering) + { +- if(!m_presentevent.WaitMSec(100) && GetPresentTime() > timeout && !bStop) ++ /* make sure any queued frame was fully presented */ ++ double timeout = m_presenttime + 1.0; ++ while(m_presentstep != PRESENT_IDLE && !bStop) + { +- CLog::Log(LOGWARNING, "CRenderManager::FlipPage - timeout waiting for previous frame"); +- return; ++ if(!m_presentevent.WaitMSec(100) && GetPresentTime() > timeout && !bStop) ++ { ++ CLog::Log(LOGWARNING, "CRenderManager::FlipPage - timeout waiting for previous frame"); ++ return; ++ } + } +- }; ++ } + + if(bStop) + return; +@@ -538,58 +558,67 @@ + { CRetakeLock lock(m_sharedSection); + if(!m_pRenderer) return; + +- m_presenttime = timestamp; +- m_presentfield = sync; +- m_presentstep = PRESENT_FLIP; +- m_presentsource = source; ++ double presenttime = timestamp; ++ EFIELDSYNC presentfield = sync; ++ EPRESENTMETHOD presentmethod; ++ + EDEINTERLACEMODE deinterlacemode = g_settings.m_currentVideoSettings.m_DeinterlaceMode; + EINTERLACEMETHOD interlacemethod = AutoInterlaceMethodInternal(g_settings.m_currentVideoSettings.m_InterlaceMethod); + + bool invert = false; + + if (deinterlacemode == VS_DEINTERLACEMODE_OFF) +- m_presentmethod = PRESENT_METHOD_SINGLE; ++ presentmethod = PRESENT_METHOD_SINGLE; + else + { +- if (deinterlacemode == VS_DEINTERLACEMODE_AUTO && m_presentfield == FS_NONE) +- m_presentmethod = PRESENT_METHOD_SINGLE; ++ if (deinterlacemode == VS_DEINTERLACEMODE_AUTO && presentfield == FS_NONE) ++ presentmethod = PRESENT_METHOD_SINGLE; + else + { +- if (interlacemethod == VS_INTERLACEMETHOD_RENDER_BLEND) m_presentmethod = PRESENT_METHOD_BLEND; +- else if (interlacemethod == VS_INTERLACEMETHOD_RENDER_WEAVE) m_presentmethod = PRESENT_METHOD_WEAVE; +- else if (interlacemethod == VS_INTERLACEMETHOD_RENDER_WEAVE_INVERTED) { m_presentmethod = PRESENT_METHOD_WEAVE ; invert = true; } +- else if (interlacemethod == VS_INTERLACEMETHOD_RENDER_BOB) m_presentmethod = PRESENT_METHOD_BOB; +- else if (interlacemethod == VS_INTERLACEMETHOD_RENDER_BOB_INVERTED) { m_presentmethod = PRESENT_METHOD_BOB; invert = true; } +- else if (interlacemethod == VS_INTERLACEMETHOD_DXVA_BOB) m_presentmethod = PRESENT_METHOD_BOB; +- else if (interlacemethod == VS_INTERLACEMETHOD_DXVA_BEST) m_presentmethod = PRESENT_METHOD_BOB; +- else m_presentmethod = PRESENT_METHOD_SINGLE; ++ if (interlacemethod == VS_INTERLACEMETHOD_RENDER_BLEND) presentmethod = PRESENT_METHOD_BLEND; ++ else if (interlacemethod == VS_INTERLACEMETHOD_RENDER_WEAVE) presentmethod = PRESENT_METHOD_WEAVE; ++ else if (interlacemethod == VS_INTERLACEMETHOD_RENDER_WEAVE_INVERTED) { presentmethod = PRESENT_METHOD_WEAVE ; invert = true; } ++ else if (interlacemethod == VS_INTERLACEMETHOD_RENDER_BOB) presentmethod = PRESENT_METHOD_BOB; ++ else if (interlacemethod == VS_INTERLACEMETHOD_RENDER_BOB_INVERTED) { presentmethod = PRESENT_METHOD_BOB; invert = true; } ++ else if (interlacemethod == VS_INTERLACEMETHOD_DXVA_BOB) presentmethod = PRESENT_METHOD_BOB; ++ else if (interlacemethod == VS_INTERLACEMETHOD_DXVA_BEST) presentmethod = PRESENT_METHOD_BOB; ++ else presentmethod = PRESENT_METHOD_SINGLE; + + /* default to odd field if we want to deinterlace and don't know better */ +- if (deinterlacemode == VS_DEINTERLACEMODE_FORCE && m_presentfield == FS_NONE) +- m_presentfield = FS_TOP; ++ if (deinterlacemode == VS_DEINTERLACEMODE_FORCE && presentfield == FS_NONE) ++ presentfield = FS_TOP; + + /* invert present field */ + if(invert) + { +- if( m_presentfield == FS_BOT ) +- m_presentfield = FS_TOP; ++ if( presentfield == FS_BOT ) ++ presentfield = FS_TOP; + else +- m_presentfield = FS_BOT; ++ presentfield = FS_BOT; + } + } + } + ++ FlipFreeBuffer(); ++ m_renderBuffers[m_iOutputRenderBuffer].pts = timestamp; ++ m_renderBuffers[m_iOutputRenderBuffer].presentfield = presentfield; ++ m_renderBuffers[m_iOutputRenderBuffer].presentmethod = presentmethod; ++ m_speed = speed; + } + + g_application.NewFrame(); +- /* wait untill render thread have flipped buffers */ +- timeout = m_presenttime + 1.0; +- while(m_presentstep == PRESENT_FLIP && !bStop) ++ ++ if (!m_bUseBuffering) + { +- if(!m_presentevent.WaitMSec(100) && GetPresentTime() > timeout && !bStop) ++ /* wait untill render thread have flipped buffers */ ++ double timeout = m_presenttime + 1.0; ++ while(m_presentstep == PRESENT_FLIP && !bStop) + { +- CLog::Log(LOGWARNING, "CRenderManager::FlipPage - timeout waiting for flip to complete"); +- return; ++ if(!m_presentevent.WaitMSec(100) && GetPresentTime() > timeout && !bStop) ++ { ++ CLog::Log(LOGWARNING, "CRenderManager::FlipPage - timeout waiting for flip to complete"); ++ return; ++ } + } + } + } +@@ -631,8 +660,12 @@ + if (!m_pRenderer) + return; + ++ if (m_presentstep == PRESENT_IDLE) ++ PrepareNextRender(); ++ + if(m_presentstep == PRESENT_FLIP) + { ++ FlipRenderBuffer(); + m_overlays.Flip(); + m_pRenderer->FlipPage(m_presentsource); + m_presentstep = PRESENT_FRAME; +@@ -647,6 +680,8 @@ + WaitPresentTime(m_presenttime); + + m_presentevent.Set(); ++ ++ m_rendertime = CurrentHostCounter(); + } + + /* simple present method */ +@@ -753,7 +788,7 @@ + return 1; + + YV12Image image; +- int index = m_pRenderer->GetImage(&image); ++ int index = m_pRenderer->GetImage(&image, (m_iOutputRenderBuffer + 1) % m_iNumRenderBuffers); + + if(index < 0) + return index; +@@ -776,8 +811,9 @@ + CDVDCodecUtils::CopyDXVA2Picture(&image, &pic); + } + #ifdef HAVE_LIBVDPAU +- else if(pic.format == DVDVideoPicture::FMT_VDPAU) +- m_pRenderer->AddProcessor(pic.vdpau); ++ else if(pic.format == DVDVideoPicture::FMT_VDPAU ++ || pic.format == DVDVideoPicture::FMT_VDPAU_420) ++ m_pRenderer->AddProcessor(pic.vdpau, index); + #endif + #ifdef HAVE_LIBOPENMAX + else if(pic.format == DVDVideoPicture::FMT_OMXEGL) +@@ -789,7 +825,11 @@ + #endif + #ifdef HAVE_LIBVA + else if(pic.format == DVDVideoPicture::FMT_VAAPI) +- m_pRenderer->AddProcessor(*pic.vaapi); ++ m_pRenderer->AddProcessor(*pic.vaapi, index); ++#endif ++#ifdef HAVE_LIBXVBA ++ else if(pic.format == DVDVideoPicture::FMT_XVBA) ++ m_pRenderer->AddProcessor(pic.xvba, index); + #endif + m_pRenderer->ReleaseImage(index, false); + +@@ -809,3 +849,212 @@ + + return mInt; + } ++ ++int CXBMCRenderManager::WaitForBuffer(volatile bool& bStop) ++{ ++ CSharedLock lock(m_sharedSection); ++ if (!m_pRenderer) ++ return -1; ++ ++ //wait up to a second as this is our slowest allowed output rate ++ double timeout = GetPresentTime() + 0.1; ++ while(!HasFreeBuffer() && !bStop) ++ { ++ lock.Leave(); ++ m_flipEvent.WaitMSec(50); ++ if(GetPresentTime() > timeout && !bStop) ++ { ++ CLog::Log(LOGWARNING, "CRenderManager::WaitForBuffer - timeout waiting for buffer"); ++ return -1; ++ } ++ lock.Enter(); ++ } ++ lock.Leave(); ++ ++ { CRetakeLock lock(m_sharedSection); ++ m_overlays.SetBuffer((m_iOutputRenderBuffer + 1) % m_iNumRenderBuffers); ++ } ++ ++ if (bStop) ++ return -1; ++ ++ return 1; ++} ++ ++int CXBMCRenderManager::GetNextRenderBufferIndex() ++{ ++ if (m_iOutputRenderBuffer == m_iCurrentRenderBuffer) ++ return -1; ++ return (m_iCurrentRenderBuffer + 1) % m_iNumRenderBuffers; ++} ++ ++void CXBMCRenderManager::FlipRenderBuffer() ++{ ++ m_iCurrentRenderBuffer = GetNextRenderBufferIndex(); ++// CLog::Log(LOGNOTICE,"-------- flip render: %d", m_iCurrentRenderBuffer); ++} ++ ++int CXBMCRenderManager::FlipFreeBuffer() ++{ ++ // See "Render Buffer State Description" in header for information. ++ if (HasFreeBuffer()) ++ { ++ m_bAllRenderBuffersDisplayed = false; ++ m_iOutputRenderBuffer = (m_iOutputRenderBuffer + 1) % m_iNumRenderBuffers; ++ return m_iOutputRenderBuffer; ++ } ++} ++ ++bool CXBMCRenderManager::HasFreeBuffer() ++{ ++ if (!m_bUseBuffering) ++ { ++ if (m_iOutputRenderBuffer != m_iCurrentRenderBuffer) ++ return false; ++ else ++ return true; ++ } ++ ++ int outputPlusSwap = (m_iOutputRenderBuffer + m_swapCount) % m_iNumRenderBuffers; ++ if ((m_iOutputRenderBuffer == m_iDisplayedRenderBuffer && !m_bAllRenderBuffersDisplayed) ++ || outputPlusSwap == m_iCurrentRenderBuffer) ++ return false; ++ else ++ return true; ++} ++ ++void CXBMCRenderManager::ResetRenderBuffer() ++{ ++ m_iNumRenderBuffers = 5; ++ m_iCurrentRenderBuffer = 0; ++ m_iFlipRequestRenderBuffer = 0; ++ m_iOutputRenderBuffer = 0; ++ m_iDisplayedRenderBuffer = 0; ++ m_bAllRenderBuffersDisplayed = true; ++ m_sleeptime = 1.0; ++ m_presentPts = DVD_NOPTS_VALUE; ++// m_bUseBuffering = true; ++ m_speed = 0; ++} ++ ++void CXBMCRenderManager::PrepareNextRender() ++{ ++ int idx = GetNextRenderBufferIndex(); ++ if (idx < 0) ++ { ++ if (m_speed >= DVD_PLAYSPEED_NORMAL && g_graphicsContext.IsFullScreenVideo()) ++ CLog::Log(LOGNOTICE,"----------- no buffer, out: %d, current: %d, display: %d", ++ m_iOutputRenderBuffer, m_iCurrentRenderBuffer, m_iDisplayedRenderBuffer); ++ return; ++ } ++ ++ double iClockSleep, iPlayingClock, iCurrentClock; ++ iPlayingClock = m_pClock->GetClock(iCurrentClock, false); ++ iClockSleep = m_renderBuffers[idx].pts - iPlayingClock; ++ ++ if (m_speed) ++ iClockSleep = iClockSleep * DVD_PLAYSPEED_NORMAL / m_speed; ++ ++ double presenttime = (iCurrentClock + iClockSleep) / DVD_TIME_BASE; ++ double clocktime = iCurrentClock / DVD_TIME_BASE; ++ if(presenttime - clocktime > MAXPRESENTDELAY) ++ presenttime = clocktime + MAXPRESENTDELAY; ++ ++ m_sleeptime = presenttime - clocktime; ++ ++// double interval; ++// if (g_VideoReferenceClock.GetRefreshRate(&interval) > 0) ++// { ++// if (m_swaptime > interval * 0.7) ++// { ++// presenttime += interval; ++// CLog::Log(LOGDEBUG,"------------ very long swaptime"); ++// } ++// } ++ ++ if (g_graphicsContext.IsFullScreenVideo() || presenttime <= clocktime+0.01) ++ { ++ m_presentPts = m_renderBuffers[idx].pts; ++ m_presenttime = presenttime; ++ m_presentmethod = m_renderBuffers[idx].presentmethod; ++ m_presentfield = m_renderBuffers[idx].presentfield; ++ m_presentstep = PRESENT_FLIP; ++ m_presentsource = idx; ++ } ++} ++ ++void CXBMCRenderManager::EnableBuffering(bool enable) ++{ ++ CRetakeLock lock(m_sharedSection); ++ m_bUseBuffering = enable; ++ if (!m_bUseBuffering) ++ m_iOutputRenderBuffer = m_iCurrentRenderBuffer; ++ ++ CLog::Log(LOGDEBUG, "CXBMCRenderManager::EnableBuffering - %d", m_bUseBuffering); ++} ++ ++void CXBMCRenderManager::DiscardBuffer() ++{ ++ CRetakeLock lock(m_sharedSection); ++ m_iOutputRenderBuffer = m_iCurrentRenderBuffer; ++} ++ ++void CXBMCRenderManager::NotifyDisplayFlip() ++{ ++ CRetakeLock lock(m_sharedSection); ++ if (!m_pRenderer) ++ return; ++ ++// if (g_graphicsContext.IsFullScreenVideo()) ++// { ++// uint64_t diff = CurrentHostCounter() - m_rendertime; ++// m_swaptime = ((double)(diff))/CurrentHostFrequency(); ++// int waittime = (int)((diff*1000LL)/CurrentHostFrequency()); ++// if (waittime > 15) ++// { ++// CLog::Log(LOGNOTICE,"------------------ wait swap buffers: %f, sleep: %f", m_swaptime, m_sleeptime); ++// } ++// } ++ ++ int last = m_iDisplayedRenderBuffer; ++ m_iDisplayedRenderBuffer = (m_iCurrentRenderBuffer + m_iNumRenderBuffers - m_swapCount) % m_iNumRenderBuffers; ++ m_iFlipRequestRenderBuffer = m_iCurrentRenderBuffer; ++ ++// // we have caught up with output so all buffers are re-usable ++// if (last != m_iDisplayedRenderBuffer ++// && m_iDisplayedRenderBuffer == m_iOutputRenderBuffer) ++// { ++// CLog::Log(LOGNOTICE,"-------------- all displayed"); ++// m_bAllRenderBuffersDisplayed = true; ++// } ++ ++ if (last != m_iDisplayedRenderBuffer ++ && m_iDisplayedRenderBuffer != m_iCurrentRenderBuffer) ++ { ++ m_pRenderer->ReleaseBuffer(m_iDisplayedRenderBuffer); ++ m_overlays.ReleaseBuffer(m_iDisplayedRenderBuffer); ++ } ++ ++ lock.Leave(); ++ m_flipEvent.Set(); ++} ++ ++bool CXBMCRenderManager::GetStats(double &sleeptime, double &pts, int &bufferLevel) ++{ ++ CSharedLock lock(m_sharedSection); ++ sleeptime = m_sleeptime; ++ pts = m_presentPts; ++ bufferLevel = (m_iOutputRenderBuffer - m_iCurrentRenderBuffer + m_iNumRenderBuffers) % m_iNumRenderBuffers; ++ return true; ++} ++ ++bool CXBMCRenderManager::HasFrame() ++{ ++ CSharedLock lock(m_sharedSection); ++ if (m_presentstep == PRESENT_IDLE && ++ GetNextRenderBufferIndex() < 0 && ++ m_speed > 0) ++ return false; ++ else ++ return true; ++} +diff -Naur xbmc-11.0.1/xbmc/cores/VideoRenderers/RenderManager.h xbmc-11.0.1.patch/xbmc/cores/VideoRenderers/RenderManager.h +--- xbmc-11.0.1/xbmc/cores/VideoRenderers/RenderManager.h 2012-03-21 23:57:34.000000000 +0100 ++++ xbmc-11.0.1.patch/xbmc/cores/VideoRenderers/RenderManager.h 2012-05-13 22:08:47.016194272 +0200 +@@ -39,10 +39,11 @@ + #include "OverlayRenderer.h" + + class CRenderCapture; ++class CDVDClock; + + namespace DXVA { class CProcessor; } + namespace VAAPI { class CSurfaceHolder; } +-class CVDPAU; ++namespace VDPAU { struct CVdpauRenderPicture; } + struct DVDVideoPicture; + + #define ERRORBUFFSIZE 30 +@@ -73,8 +74,8 @@ + + int AddVideoPicture(DVDVideoPicture& picture); + +- void FlipPage(volatile bool& bStop, double timestamp = 0.0, int source = -1, EFIELDSYNC sync = FS_NONE); +- unsigned int PreInit(); ++ void FlipPage(volatile bool& bStop, double timestamp = 0.0, int source = -1, EFIELDSYNC sync = FS_NONE, int speed = 0); ++ unsigned int PreInit(CDVDClock *pClock); + void UnInit(); + bool Flush(); + +@@ -182,6 +183,13 @@ + + CSharedSection& GetSection() { return m_sharedSection; }; + ++ int WaitForBuffer(volatile bool& bStop); ++ void NotifyDisplayFlip(); ++ bool GetStats(double &sleeptime, double &pts, int &bufferLevel); ++ bool HasFrame(); ++ void EnableBuffering(bool enable); ++ void DiscardBuffer(); ++ + protected: + void Render(bool clear, DWORD flags, DWORD alpha); + +@@ -190,6 +198,13 @@ + void PresentBob(bool clear, DWORD flags, DWORD alpha); + void PresentBlend(bool clear, DWORD flags, DWORD alpha); + ++ int GetNextRenderBufferIndex(); ++ void FlipRenderBuffer(); ++ int FlipFreeBuffer(); ++ bool HasFreeBuffer(); ++ void ResetRenderBuffer(); ++ void PrepareNextRender(); ++ + EINTERLACEMETHOD AutoInterlaceMethodInternal(EINTERLACEMETHOD mInt); + + bool m_bPauseDrawing; // true if we should pause rendering +@@ -220,6 +235,43 @@ + double m_displayLatency; + void UpdateDisplayLatency(); + ++ // Render Buffer State Description: ++ // ++ // Output: is the buffer about to or having its texture prepared for render (ie from output thread). ++ // Cannot go past the "Displayed" buffer (otherwise we will probably overwrite buffers not yet ++ // displayed or even rendered). ++ // Current: is the current buffer being or having been submitted for render to back buffer. ++ // Cannot go past "Output" buffer (else it would be rendering old output). ++ // FlipRequest: is the render buffer that has last been submitted for render AND importantly has had ++ // swap-buffer flip subsequently invoked (thus flip to front buffer is requested for vblank ++ // subsequent to render completion). ++ // Displayed: is the buffer that is now considered to be safely copied from back buffer to front buffer ++ // (we assume that after two swap-buffer flips for the same "Current" render buffer that that ++ // buffer will be safe, but otherwise we consider that only the previous-to-"Current" is guaranteed). ++ // Last: is the last buffer successfully submitted for render to back buffer (purpose: to rollback to in ++ // unexpected case where a texture render fails). ++ ++ int m_iCurrentRenderBuffer; ++ int m_iNumRenderBuffers; ++// int m_iLastRenderBuffer; ++ int m_iFlipRequestRenderBuffer; ++ int m_iOutputRenderBuffer; ++ int m_iDisplayedRenderBuffer; ++ bool m_bAllRenderBuffersDisplayed; ++ bool m_bUseBuffering; ++ int m_speed; ++ CEvent m_flipEvent; ++ ++ struct ++ { ++ double pts; ++ EFIELDSYNC presentfield; ++ EPRESENTMETHOD presentmethod; ++ }m_renderBuffers[5]; ++ ++ double m_sleeptime; ++ double m_presentPts; ++ + double m_presenttime; + double m_presentcorr; + double m_presenterr; +@@ -231,7 +283,10 @@ + int m_presentsource; + CEvent m_presentevent; + CEvent m_flushEvent; +- ++ CDVDClock *m_pClock; ++ uint64_t m_rendertime; ++ double m_swaptime; ++ unsigned int m_swapCount; + + OVERLAY::CRenderer m_overlays; + +diff -Naur xbmc-11.0.1/xbmc/cores/VideoRenderers/VideoShaders/YUV2RGBShader.cpp xbmc-11.0.1.patch/xbmc/cores/VideoRenderers/VideoShaders/YUV2RGBShader.cpp +--- xbmc-11.0.1/xbmc/cores/VideoRenderers/VideoShaders/YUV2RGBShader.cpp 2012-03-21 23:57:34.000000000 +0100 ++++ xbmc-11.0.1.patch/xbmc/cores/VideoRenderers/VideoShaders/YUV2RGBShader.cpp 2012-05-13 22:01:28.569494075 +0200 +@@ -186,6 +186,8 @@ + m_defines += "#define XBMC_YUY2\n"; + else if (CONF_FLAGS_FORMAT_MASK(flags) == CONF_FLAGS_FORMAT_UYVY) + m_defines += "#define XBMC_UYVY\n"; ++ else if (CONF_FLAGS_FORMAT_MASK(flags) == CONF_FLAGS_FORMAT_VDPAU_420) ++ m_defines += "#define XBMC_VDPAU_NV12\n"; + + VertexShader()->LoadSource("yuv2rgb_vertex.glsl", m_defines); + #elif HAS_GLES == 2 +diff -Naur xbmc-11.0.1/xbmc/dialogs/GUIDialogCache.cpp xbmc-11.0.1.patch/xbmc/dialogs/GUIDialogCache.cpp +--- xbmc-11.0.1/xbmc/dialogs/GUIDialogCache.cpp 2012-03-21 23:57:33.000000000 +0100 ++++ xbmc-11.0.1.patch/xbmc/dialogs/GUIDialogCache.cpp 2012-05-13 22:08:46.789189770 +0200 +@@ -29,7 +29,7 @@ + #include "threads/SingleLock.h" + #include "utils/TimeUtils.h" + +-CGUIDialogCache::CGUIDialogCache(DWORD dwDelay, const CStdString& strHeader, const CStdString& strMsg) ++CGUIDialogCache::CGUIDialogCache(DWORD dwDelay, const CStdString& strHeader, const CStdString& strMsg) : CThread("CGUIDialogCache") + { + m_pDlg = (CGUIDialogProgress*)g_windowManager.GetWindow(WINDOW_DIALOG_PROGRESS); + +diff -Naur xbmc-11.0.1/xbmc/filesystem/FileCache.cpp xbmc-11.0.1.patch/xbmc/filesystem/FileCache.cpp +--- xbmc-11.0.1/xbmc/filesystem/FileCache.cpp 2012-03-21 23:57:33.000000000 +0100 ++++ xbmc-11.0.1.patch/xbmc/filesystem/FileCache.cpp 2012-05-13 22:08:46.789189770 +0200 +@@ -79,7 +79,7 @@ + }; + + +-CFileCache::CFileCache() ++CFileCache::CFileCache() : CThread("CFileCache") + { + m_bDeleteCache = true; + m_nSeekResult = 0; +@@ -95,7 +95,7 @@ + m_cacheFull = false; + } + +-CFileCache::CFileCache(CCacheStrategy *pCache, bool bDeleteCache) ++CFileCache::CFileCache(CCacheStrategy *pCache, bool bDeleteCache) : CThread("CFileCache") + { + m_pCache = pCache; + m_bDeleteCache = bDeleteCache; +diff -Naur xbmc-11.0.1/xbmc/filesystem/FilePipe.cpp xbmc-11.0.1.patch/xbmc/filesystem/FilePipe.cpp +--- xbmc-11.0.1/xbmc/filesystem/FilePipe.cpp 2012-03-21 23:57:33.000000000 +0100 ++++ xbmc-11.0.1.patch/xbmc/filesystem/FilePipe.cpp 2012-05-13 22:08:46.790189789 +0200 +@@ -24,6 +24,8 @@ + #include "PipesManager.h" + #include "utils/StringUtils.h" + ++#define INFINITE 0xFFFFFFFF ++ + using namespace XFILE; + + CFilePipe::CFilePipe() : m_pos(0), m_length(-1), m_pipe(NULL) +diff -Naur xbmc-11.0.1/xbmc/filesystem/FileRar.cpp xbmc-11.0.1.patch/xbmc/filesystem/FileRar.cpp +--- xbmc-11.0.1/xbmc/filesystem/FileRar.cpp 2012-03-21 23:57:33.000000000 +0100 ++++ xbmc-11.0.1.patch/xbmc/filesystem/FileRar.cpp 2012-05-13 22:08:46.790189789 +0200 +@@ -43,7 +43,7 @@ + #define SEEKTIMOUT 30000 + + #ifdef HAS_FILESYSTEM_RAR +-CFileRarExtractThread::CFileRarExtractThread() : hRunning(true), hQuit(true) ++CFileRarExtractThread::CFileRarExtractThread() : CThread("CFileRarExtractThread"), hRunning(true), hQuit(true) + { + m_pArc = NULL; + m_pCmd = NULL; +diff -Naur xbmc-11.0.1/xbmc/filesystem/HTSPDirectory.cpp xbmc-11.0.1.patch/xbmc/filesystem/HTSPDirectory.cpp +--- xbmc-11.0.1/xbmc/filesystem/HTSPDirectory.cpp 2012-03-21 23:57:33.000000000 +0100 ++++ xbmc-11.0.1.patch/xbmc/filesystem/HTSPDirectory.cpp 2012-05-13 22:08:46.791189809 +0200 +@@ -76,7 +76,7 @@ + static CCriticalSection g_section; + + +-CHTSPDirectorySession::CHTSPDirectorySession() ++CHTSPDirectorySession::CHTSPDirectorySession() : CThread("CHTSPDirectorySession") + { + } + +diff -Naur xbmc-11.0.1/xbmc/filesystem/LastFMDirectory.cpp xbmc-11.0.1.patch/xbmc/filesystem/LastFMDirectory.cpp +--- xbmc-11.0.1/xbmc/filesystem/LastFMDirectory.cpp 2012-03-21 23:57:33.000000000 +0100 ++++ xbmc-11.0.1.patch/xbmc/filesystem/LastFMDirectory.cpp 2012-05-13 22:08:46.792189829 +0200 +@@ -69,7 +69,7 @@ + m_dlgProgress->Progress(); + } + +- CThread thread(this); ++ CThread thread(this, "CLastFMDirectory"); + m_strSource = url; + m_strDestination = "special://temp/lastfm.xml"; + thread.Create(); +diff -Naur xbmc-11.0.1/xbmc/filesystem/MythSession.cpp xbmc-11.0.1.patch/xbmc/filesystem/MythSession.cpp +--- xbmc-11.0.1/xbmc/filesystem/MythSession.cpp 2012-03-21 23:57:33.000000000 +0100 ++++ xbmc-11.0.1.patch/xbmc/filesystem/MythSession.cpp 2012-05-13 22:08:46.792189829 +0200 +@@ -359,7 +359,7 @@ + return; + } + +-CMythSession::CMythSession(const CURL& url) ++CMythSession::CMythSession(const CURL& url) : CThread("CMythSession") + { + m_control = NULL; + m_event = NULL; +diff -Naur xbmc-11.0.1/xbmc/filesystem/PipesManager.cpp xbmc-11.0.1.patch/xbmc/filesystem/PipesManager.cpp +--- xbmc-11.0.1/xbmc/filesystem/PipesManager.cpp 2012-03-21 23:57:33.000000000 +0100 ++++ xbmc-11.0.1.patch/xbmc/filesystem/PipesManager.cpp 2012-05-13 22:08:46.793189848 +0200 +@@ -23,6 +23,8 @@ + #include "threads/SingleLock.h" + #include "Application.h" + ++#define INFINITE 0xFFFFFFFF ++ + #ifndef min + #define min(a,b) ((a) < (b) ? (a) : (b)) + #endif +diff -Naur xbmc-11.0.1/xbmc/filesystem/RarManager.h xbmc-11.0.1.patch/xbmc/filesystem/RarManager.h +--- xbmc-11.0.1/xbmc/filesystem/RarManager.h 2012-03-21 23:57:33.000000000 +0100 ++++ xbmc-11.0.1.patch/xbmc/filesystem/RarManager.h 2012-05-13 22:08:46.793189848 +0200 +@@ -71,7 +71,7 @@ + CRarManager(); + ~CRarManager(); + bool CacheRarredFile(CStdString& strPathInCache, const CStdString& strRarPath, +- const CStdString& strPathInRar, BYTE bOptions = EXFILE_AUTODELETE, ++ const CStdString& strPathInRar, uint8_t bOptions = EXFILE_AUTODELETE, + const CStdString& strDir =RAR_DEFAULT_CACHE, const int64_t iSize=-1); + bool GetPathInCache(CStdString& strPathInCache, const CStdString& strRarPath, + const CStdString& strPathInRar = ""); +diff -Naur xbmc-11.0.1/xbmc/filesystem/SAPDirectory.cpp xbmc-11.0.1.patch/xbmc/filesystem/SAPDirectory.cpp +--- xbmc-11.0.1/xbmc/filesystem/SAPDirectory.cpp 2012-03-21 23:57:33.000000000 +0100 ++++ xbmc-11.0.1.patch/xbmc/filesystem/SAPDirectory.cpp 2012-05-13 22:08:46.794189867 +0200 +@@ -272,7 +272,7 @@ + using namespace SDP; + + +-CSAPSessions::CSAPSessions() ++CSAPSessions::CSAPSessions() : CThread("CSAPSessions") + { + m_socket = INVALID_SOCKET; + } +@@ -486,7 +486,7 @@ + + CSingleLock lock(g_sapsessions.m_section); + +- if(g_sapsessions.ThreadHandle() == NULL) ++ if(!g_sapsessions.IsRunning()) + g_sapsessions.Create(); + + // check if we can find this session in our cache +diff -Naur xbmc-11.0.1/xbmc/interfaces/python/xbmcmodule/GUIPythonWindow.cpp xbmc-11.0.1.patch/xbmc/interfaces/python/xbmcmodule/GUIPythonWindow.cpp +--- xbmc-11.0.1/xbmc/interfaces/python/xbmcmodule/GUIPythonWindow.cpp 2012-03-21 23:57:33.000000000 +0100 ++++ xbmc-11.0.1.patch/xbmc/interfaces/python/xbmcmodule/GUIPythonWindow.cpp 2012-05-13 22:08:46.796189907 +0200 +@@ -181,9 +181,9 @@ + m_threadState = state; + } + +-void CGUIPythonWindow::WaitForActionEvent(unsigned int timeout) ++void CGUIPythonWindow::WaitForActionEvent() + { +- g_pythonParser.WaitForEvent(m_actionEvent, timeout); ++ g_pythonParser.WaitForEvent(m_actionEvent); + m_actionEvent.Reset(); + } + +diff -Naur xbmc-11.0.1/xbmc/interfaces/python/xbmcmodule/GUIPythonWindow.h xbmc-11.0.1.patch/xbmc/interfaces/python/xbmcmodule/GUIPythonWindow.h +--- xbmc-11.0.1/xbmc/interfaces/python/xbmcmodule/GUIPythonWindow.h 2012-03-21 23:57:33.000000000 +0100 ++++ xbmc-11.0.1.patch/xbmc/interfaces/python/xbmcmodule/GUIPythonWindow.h 2012-05-13 22:08:46.796189907 +0200 +@@ -51,7 +51,7 @@ + virtual bool OnAction(const CAction &action); + virtual bool OnBack(int actionID); + void SetCallbackWindow(void* state, void *object); +- void WaitForActionEvent(unsigned int timeout); ++ void WaitForActionEvent(); + void PulseActionEvent(); + void SetDestroyAfterDeinit(bool destroy = true); + protected: +diff -Naur xbmc-11.0.1/xbmc/interfaces/python/xbmcmodule/GUIPythonWindowXML.cpp xbmc-11.0.1.patch/xbmc/interfaces/python/xbmcmodule/GUIPythonWindowXML.cpp +--- xbmc-11.0.1/xbmc/interfaces/python/xbmcmodule/GUIPythonWindowXML.cpp 2012-03-21 23:57:33.000000000 +0100 ++++ xbmc-11.0.1.patch/xbmc/interfaces/python/xbmcmodule/GUIPythonWindowXML.cpp 2012-05-13 22:08:46.797189927 +0200 +@@ -279,9 +279,9 @@ + UpdateButtons(); + } + +-void CGUIPythonWindowXML::WaitForActionEvent(unsigned int timeout) ++void CGUIPythonWindowXML::WaitForActionEvent() + { +- g_pythonParser.WaitForEvent(m_actionEvent, timeout); ++ g_pythonParser.WaitForEvent(m_actionEvent); + m_actionEvent.Reset(); + } + +diff -Naur xbmc-11.0.1/xbmc/interfaces/python/xbmcmodule/GUIPythonWindowXML.h xbmc-11.0.1.patch/xbmc/interfaces/python/xbmcmodule/GUIPythonWindowXML.h +--- xbmc-11.0.1/xbmc/interfaces/python/xbmcmodule/GUIPythonWindowXML.h 2012-03-21 23:57:33.000000000 +0100 ++++ xbmc-11.0.1.patch/xbmc/interfaces/python/xbmcmodule/GUIPythonWindowXML.h 2012-05-13 22:08:46.798189947 +0200 +@@ -40,7 +40,7 @@ + virtual void AllocResources(bool forceLoad = false); + virtual void FreeResources(bool forceUnLoad = false); + void Process(unsigned int currentTime, CDirtyRegionList ®ions); +- void WaitForActionEvent(unsigned int timeout); ++ void WaitForActionEvent(); + void PulseActionEvent(); + void AddItem(CFileItemPtr fileItem,int itemPosition); + void RemoveItem(int itemPosition); +diff -Naur xbmc-11.0.1/xbmc/interfaces/python/xbmcmodule/window.cpp xbmc-11.0.1.patch/xbmc/interfaces/python/xbmcmodule/window.cpp +--- xbmc-11.0.1/xbmc/interfaces/python/xbmcmodule/window.cpp 2012-03-21 23:57:33.000000000 +0100 ++++ xbmc-11.0.1.patch/xbmc/interfaces/python/xbmcmodule/window.cpp 2012-05-13 22:08:46.798189947 +0200 +@@ -540,11 +540,11 @@ + + CPyThreadState pyState; + if (WindowXML_Check(self)) +- ((CGUIPythonWindowXML*)self->pWindow)->WaitForActionEvent(INFINITE); ++ ((CGUIPythonWindowXML*)self->pWindow)->WaitForActionEvent(); + else if (WindowXMLDialog_Check(self)) +- ((CGUIPythonWindowXMLDialog*)self->pWindow)->WaitForActionEvent(INFINITE); ++ ((CGUIPythonWindowXMLDialog*)self->pWindow)->WaitForActionEvent(); + else +- ((CGUIPythonWindow*)self->pWindow)->WaitForActionEvent(INFINITE); ++ ((CGUIPythonWindow*)self->pWindow)->WaitForActionEvent(); + } + } + Py_INCREF(Py_None); +diff -Naur xbmc-11.0.1/xbmc/interfaces/python/XBPython.cpp xbmc-11.0.1.patch/xbmc/interfaces/python/XBPython.cpp +--- xbmc-11.0.1/xbmc/interfaces/python/XBPython.cpp 2012-03-21 23:57:33.000000000 +0100 ++++ xbmc-11.0.1.patch/xbmc/interfaces/python/XBPython.cpp 2012-05-13 22:08:46.795189887 +0200 +@@ -676,11 +676,11 @@ + m_globalEvent.Set(); + } + +-void XBPython::WaitForEvent(CEvent& hEvent, unsigned int timeout) ++void XBPython::WaitForEvent(CEvent& hEvent) + { + // wait for either this event our our global event + XbmcThreads::CEventGroup eventGroup(&hEvent, &m_globalEvent, NULL); +- eventGroup.wait(timeout); ++ eventGroup.wait(); + m_globalEvent.Reset(); + } + +diff -Naur xbmc-11.0.1/xbmc/interfaces/python/XBPython.h xbmc-11.0.1.patch/xbmc/interfaces/python/XBPython.h +--- xbmc-11.0.1/xbmc/interfaces/python/XBPython.h 2012-03-21 23:57:33.000000000 +0100 ++++ xbmc-11.0.1.patch/xbmc/interfaces/python/XBPython.h 2012-05-13 22:08:46.795189887 +0200 +@@ -61,7 +61,7 @@ + void Process(); + + void PulseGlobalEvent(); +- void WaitForEvent(CEvent& hEvent, unsigned int timeout); ++ void WaitForEvent(CEvent& hEvent); + + int ScriptsSize(); + int GetPythonScriptId(int scriptPosition); +diff -Naur xbmc-11.0.1/xbmc/linux/Makefile.in xbmc-11.0.1.patch/xbmc/linux/Makefile.in +--- xbmc-11.0.1/xbmc/linux/Makefile.in 2012-03-21 23:57:32.000000000 +0100 ++++ xbmc-11.0.1.patch/xbmc/linux/Makefile.in 2012-05-13 22:08:46.799189967 +0200 +@@ -10,14 +10,11 @@ + LinuxResourceCounter.cpp \ + LinuxTimezone.cpp \ + PosixMountProvider.cpp \ +- XEventUtils.cpp \ + XFileUtils.cpp \ + XHandle.cpp \ + XLCDproc.cpp \ + XMemUtils.cpp \ +- XSyncUtils.cpp \ + XTimeUtils.cpp \ +- XThreadUtils.cpp \ + + LIB=linux.a + +diff -Naur xbmc-11.0.1/xbmc/linux/PlatformDefs.h xbmc-11.0.1.patch/xbmc/linux/PlatformDefs.h +--- xbmc-11.0.1/xbmc/linux/PlatformDefs.h 2012-03-21 23:57:32.000000000 +0100 ++++ xbmc-11.0.1.patch/xbmc/linux/PlatformDefs.h 2012-05-13 22:08:46.800189987 +0200 +@@ -182,8 +182,6 @@ + #define EXCEPTION_EXECUTE_HANDLER ... + //NOTE: dont try to define __except because it breaks g++ (already uses it). + +-typedef pthread_t ThreadIdentifier; +- + struct CXHandle; // forward declaration + typedef CXHandle* HANDLE; + +diff -Naur xbmc-11.0.1/xbmc/linux/PlatformInclude.h xbmc-11.0.1.patch/xbmc/linux/PlatformInclude.h +--- xbmc-11.0.1/xbmc/linux/PlatformInclude.h 2012-03-21 23:57:32.000000000 +0100 ++++ xbmc-11.0.1.patch/xbmc/linux/PlatformInclude.h 2012-05-13 22:08:46.800189987 +0200 +@@ -25,10 +25,7 @@ + #include "PlatformDefs.h" + #include "XHandlePublic.h" + #include "XFileUtils.h" +-#include "XSyncUtils.h" +-#include "XEventUtils.h" + #include "XTimeUtils.h" +-#include "XThreadUtils.h" + #include "XMemUtils.h" + #include "ConvUtils.h" + +diff -Naur xbmc-11.0.1/xbmc/linux/XEventUtils.cpp xbmc-11.0.1.patch/xbmc/linux/XEventUtils.cpp +--- xbmc-11.0.1/xbmc/linux/XEventUtils.cpp 2012-03-21 23:57:32.000000000 +0100 ++++ xbmc-11.0.1.patch/xbmc/linux/XEventUtils.cpp 1970-01-01 01:00:00.000000000 +0100 +@@ -1,144 +0,0 @@ +-/* +- * Copyright (C) 2005-2008 Team XBMC +- * http://www.xbmc.org +- * +- * 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 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 XBMC; see the file COPYING. If not, write to +- * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. +- * http://www.gnu.org/copyleft/gpl.html +- * +- */ +- +-#include "system.h" +-#include "PlatformDefs.h" +-#include "XEventUtils.h" +-#include "XHandle.h" +-#include "utils/log.h" +-#include "threads/SingleLock.h" +- +-using namespace std; +- +-HANDLE WINAPI CreateEvent(void *pDummySec, bool bManualReset, bool bInitialState, char *szDummyName) +-{ +- CXHandle *pHandle = new CXHandle(CXHandle::HND_EVENT); +- pHandle->m_bManualEvent = bManualReset; +- pHandle->m_hCond = new XbmcThreads::ConditionVariable(); +- pHandle->m_hMutex = new CCriticalSection(); +- pHandle->m_bEventSet = false; +- +- if (bInitialState) +- SetEvent(pHandle); +- +- return pHandle; +-} +- +-// +-// The state of a manual-reset event object remains signaled until it is set explicitly to the nonsignaled +-// state by the ResetEvent function. Any number of waiting threads, or threads that subsequently begin wait +-// operations for the specified event object by calling one of the wait functions, can be released while the +-// object's state is signaled. +-// +-// The state of an auto-reset event object remains signaled until a single waiting thread is released, at +-// which time the system automatically sets the state to nonsignaled. If no threads are waiting, the event +-// object's state remains signaled. +-// +-bool WINAPI SetEvent(HANDLE hEvent) +-{ +- if (hEvent == NULL || hEvent->m_hCond == NULL || hEvent->m_hMutex == NULL) +- return false; +- +- CSingleLock lock(*(hEvent->m_hMutex)); +- hEvent->m_bEventSet = true; +- +- // we must guarantee that these handle's won't be deleted, until we are done +- list events = hEvent->m_hParents; +- for(list::iterator it = events.begin();it != events.end();it++) +- DuplicateHandle(GetCurrentProcess(), *it, GetCurrentProcess(), NULL, 0, FALSE, DUPLICATE_SAME_ACCESS); +- +- lock.Leave(); +- +- for(list::iterator it = events.begin();it != events.end();it++) +- { +- SetEvent(*it); +- CloseHandle(*it); +- } +- +- DuplicateHandle(GetCurrentProcess(), hEvent, GetCurrentProcess(), NULL, 0, FALSE, DUPLICATE_SAME_ACCESS); +- +- if (hEvent->m_bManualEvent == true) +- hEvent->m_hCond->notifyAll(); +- else +- hEvent->m_hCond->notify(); +- +- CloseHandle(hEvent); +- +- return true; +-} +- +-bool WINAPI ResetEvent(HANDLE hEvent) +-{ +- if (hEvent == NULL || hEvent->m_hCond == NULL || hEvent->m_hMutex == NULL) +- return false; +- +- CSingleLock lock(*(hEvent->m_hMutex)); +- hEvent->m_bEventSet = false; +- +- return true; +-} +- +-bool WINAPI PulseEvent(HANDLE hEvent) +-{ +- if (hEvent == NULL || hEvent->m_hCond == NULL || hEvent->m_hMutex == NULL) +- return false; +- +- CSingleLock lock(*(hEvent->m_hMutex)); +- // we must guarantee that these handle's won't be deleted, until we are done +- list events = hEvent->m_hParents; +- for(list::iterator it = events.begin();it != events.end();it++) +- DuplicateHandle(GetCurrentProcess(), *it, GetCurrentProcess(), NULL, 0, FALSE, DUPLICATE_SAME_ACCESS); +- +- if(events.size()) +- { +- CLog::Log(LOGWARNING,"PulseEvent - ineffecient multiwait detected"); +- hEvent->m_bEventSet = true; +- } +- +- lock.Leave(); +- +- for(list::iterator it = events.begin();it != events.end();it++) +- { +- SetEvent(*it); +- CloseHandle(*it); +- +- if (hEvent->m_bManualEvent == false) +- break; +- } +- +- // for multiwaits, we must yield some time to get the multiwaits to notice it was signaled +- if(events.size()) +- Sleep(10); +- +- // we should always unset the event on pulse +- { +- CSingleLock lock2(*(hEvent->m_hMutex)); +- hEvent->m_bEventSet = false; +- } +- +- if (hEvent->m_bManualEvent == true) +- hEvent->m_hCond->notifyAll(); +- else +- hEvent->m_hCond->notify(); +- +- return true; +-} +- +diff -Naur xbmc-11.0.1/xbmc/linux/XEventUtils.h xbmc-11.0.1.patch/xbmc/linux/XEventUtils.h +--- xbmc-11.0.1/xbmc/linux/XEventUtils.h 2012-03-21 23:57:32.000000000 +0100 ++++ xbmc-11.0.1.patch/xbmc/linux/XEventUtils.h 1970-01-01 01:00:00.000000000 +0100 +@@ -1,38 +0,0 @@ +-#ifndef __X_EVENT_UTIL_H__ +-#define __X_EVENT_UTIL_H__ +- +-/* +- * Copyright (C) 2005-2008 Team XBMC +- * http://www.xbmc.org +- * +- * 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 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 XBMC; see the file COPYING. If not, write to +- * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. +- * http://www.gnu.org/copyleft/gpl.html +- * +- */ +- +-#include "XHandlePublic.h" +- +-#ifdef _LINUX +- +-HANDLE WINAPI CreateEvent(void *pDummySec, bool bManualReset, bool bInitialState, char *szDummyName); +-bool WINAPI SetEvent(HANDLE hEvent); +-bool WINAPI ResetEvent(HANDLE hEvent); +-bool WINAPI PulseEvent(HANDLE hEvent); +- +-#endif +- +- +-#endif +- +diff -Naur xbmc-11.0.1/xbmc/linux/XHandle.cpp xbmc-11.0.1.patch/xbmc/linux/XHandle.cpp +--- xbmc-11.0.1/xbmc/linux/XHandle.cpp 2012-03-21 23:57:32.000000000 +0100 ++++ xbmc-11.0.1.patch/xbmc/linux/XHandle.cpp 2012-05-13 22:08:46.805190085 +0200 +@@ -20,12 +20,15 @@ + */ + + #include "XHandle.h" +-#include "XThreadUtils.h" + #include "utils/log.h" + #include "threads/SingleLock.h" + + int CXHandle::m_objectTracker[10] = {0}; + ++HANDLE WINAPI GetCurrentProcess(void) { ++ return (HANDLE)-1; // -1 a special value - pseudo handle ++} ++ + CXHandle::CXHandle() + { + Init(); +@@ -47,11 +50,6 @@ + + Init(); + +- if (m_threadValid) +- { +- CLog::Log(LOGERROR, "%s - thread handle copied instead of passed!", __FUNCTION__); +- } +- + if (src.m_hMutex) + m_hMutex = new CCriticalSection(); + +@@ -80,7 +78,7 @@ + CLog::Log(LOGERROR,"%s, destroying handle with ref count %d", __FUNCTION__, m_nRefCount); + assert(false); + } +- ++ + if (m_hMutex) { + delete m_hMutex; + } +@@ -93,10 +91,6 @@ + delete m_hCond; + } + +- if (m_threadValid) { +- pthread_join(m_hThread, NULL); +- } +- + if ( fd != 0 ) { + close(fd); + } +@@ -107,11 +101,9 @@ + { + fd=0; + m_hMutex=NULL; +- m_threadValid=false; + m_hCond=NULL; + m_type = HND_NULL; + RecursionCount=0; +- OwningThread=0; + m_bManualEvent=FALSE; + m_bEventSet=FALSE; + m_nFindFileIterator=0 ; +diff -Naur xbmc-11.0.1/xbmc/linux/XHandle.h xbmc-11.0.1.patch/xbmc/linux/XHandle.h +--- xbmc-11.0.1/xbmc/linux/XHandle.h 2012-03-21 23:57:32.000000000 +0100 ++++ xbmc-11.0.1.patch/xbmc/linux/XHandle.h 2012-05-13 22:08:46.805190085 +0200 +@@ -25,7 +25,6 @@ + #ifndef _WIN32 + + #include +-#include + + #include "PlatformDefs.h" + #include "XHandlePublic.h" +@@ -36,7 +35,7 @@ + struct CXHandle { + + public: +- typedef enum { HND_NULL = 0, HND_FILE, HND_EVENT, HND_MUTEX, HND_THREAD, HND_FIND_FILE } HandleType; ++ typedef enum { HND_NULL = 0, HND_FILE, HND_EVENT, HND_MUTEX, HND_FIND_FILE } HandleType; + + CXHandle(); + CXHandle(HandleType nType); +@@ -47,8 +46,6 @@ + inline HandleType GetType() { return m_type; } + void ChangeType(HandleType newType); + +- ThreadIdentifier m_hThread; +- bool m_threadValid; + XbmcThreads::ConditionVariable *m_hCond; + std::list m_hParents; + +@@ -62,7 +59,6 @@ + // simulate mutex and critical section + CCriticalSection *m_hMutex; + int RecursionCount; // for mutex - for compatibility with WIN32 critical section +- pthread_t OwningThread; + int fd; + bool m_bManualEvent; + time_t m_tmCreation; +diff -Naur xbmc-11.0.1/xbmc/linux/XMemUtils.cpp xbmc-11.0.1.patch/xbmc/linux/XMemUtils.cpp +--- xbmc-11.0.1/xbmc/linux/XMemUtils.cpp 2012-03-21 23:57:32.000000000 +0100 ++++ xbmc-11.0.1.patch/xbmc/linux/XMemUtils.cpp 2012-05-13 22:08:46.806190105 +0200 +@@ -25,6 +25,10 @@ + + #include "XMemUtils.h" + ++#ifdef __APPLE__ ++#include ++#endif ++ + #undef ALIGN + #define ALIGN(value, alignment) (((value)+(alignment-1))&~(alignment-1)) + +@@ -49,4 +53,130 @@ + free(pFull); + } + ++#ifndef _WIN32 ++ ++#if defined(_LINUX) && !defined(__APPLE__) && !defined(__FreeBSD__) ++static FILE* procMeminfoFP = NULL; ++#endif ++ ++void GlobalMemoryStatusEx(LPMEMORYSTATUSEX lpBuffer) ++{ ++ if (!lpBuffer) ++ return; ++ ++ memset(lpBuffer, 0, sizeof(MEMORYSTATUSEX)); ++ ++#ifdef __APPLE__ ++ uint64_t physmem; ++ size_t len = sizeof physmem; ++ int mib[2] = { CTL_HW, HW_MEMSIZE }; ++ size_t miblen = sizeof(mib) / sizeof(mib[0]); ++ ++ // Total physical memory. ++ if (sysctl(mib, miblen, &physmem, &len, NULL, 0) == 0 && len == sizeof (physmem)) ++ lpBuffer->ullTotalPhys = physmem; ++ ++ // Virtual memory. ++ mib[0] = CTL_VM; mib[1] = VM_SWAPUSAGE; ++ struct xsw_usage swap; ++ len = sizeof(struct xsw_usage); ++ if (sysctl(mib, miblen, &swap, &len, NULL, 0) == 0) ++ { ++ lpBuffer->ullAvailPageFile = swap.xsu_avail; ++ lpBuffer->ullTotalVirtual = lpBuffer->ullTotalPhys + swap.xsu_total; ++ } ++ ++ // In use. ++ mach_port_t stat_port = mach_host_self(); ++ vm_statistics_data_t vm_stat; ++ mach_msg_type_number_t count = sizeof(vm_stat) / sizeof(natural_t); ++ if (host_statistics(stat_port, HOST_VM_INFO, (host_info_t)&vm_stat, &count) == 0) ++ { ++ // Find page size. ++ int pageSize; ++ mib[0] = CTL_HW; mib[1] = HW_PAGESIZE; ++ len = sizeof(int); ++ if (sysctl(mib, miblen, &pageSize, &len, NULL, 0) == 0) ++ { ++ uint64_t used = (vm_stat.active_count + vm_stat.inactive_count + vm_stat.wire_count) * pageSize; ++ ++ lpBuffer->ullAvailPhys = lpBuffer->ullTotalPhys - used; ++ lpBuffer->ullAvailVirtual = lpBuffer->ullAvailPhys; // FIXME. ++ } ++ } ++#elif defined(__FreeBSD__) ++ /* sysctl hw.physmem */ ++ size_t physmem = 0, mem_free = 0, pagesize = 0, swap_free = 0; ++ size_t mem_avail = 0, mem_inactive = 0, mem_cache = 0, len = 0; ++ ++ /* physmem */ ++ len = sizeof(physmem); ++ if (sysctlbyname("hw.physmem", &physmem, &len, NULL, 0) == 0) { ++ lpBuffer->ullTotalPhys = physmem; ++ lpBuffer->ullTotalVirtual = physmem; ++ } ++ /* pagesize */ ++ len = sizeof(pagesize); ++ if (sysctlbyname("hw.pagesize", &pagesize, &len, NULL, 0) != 0) ++ pagesize = 4096; ++ /* mem_inactive */ ++ len = sizeof(mem_inactive); ++ if (sysctlbyname("vm.stats.vm.v_inactive_count", &mem_inactive, &len, NULL, 0) == 0) ++ mem_inactive *= pagesize; ++ /* mem_cache */ ++ len = sizeof(mem_cache); ++ if (sysctlbyname("vm.stats.vm.v_cache_count", &mem_cache, &len, NULL, 0) == 0) ++ mem_cache *= pagesize; ++ /* mem_free */ ++ len = sizeof(mem_free); ++ if (sysctlbyname("vm.stats.vm.v_free_count", &mem_free, &len, NULL, 0) == 0) ++ mem_free *= pagesize; ++ ++ /* mem_avail = mem_inactive + mem_cache + mem_free */ ++ lpBuffer->ullAvailPhys = mem_inactive + mem_cache + mem_free; ++ lpBuffer->ullAvailVirtual = mem_inactive + mem_cache + mem_free; ++ ++ if (sysctlbyname("vm.stats.vm.v_swappgsout", &swap_free, &len, NULL, 0) == 0) ++ lpBuffer->ullAvailPageFile = swap_free * pagesize; ++#else ++ struct sysinfo info; ++ char name[32]; ++ unsigned val; ++ if (!procMeminfoFP && (procMeminfoFP = fopen("/proc/meminfo", "r")) == NULL) ++ sysinfo(&info); ++ else ++ { ++ memset(&info, 0, sizeof(struct sysinfo)); ++ info.mem_unit = 4096; ++ while (fscanf(procMeminfoFP, "%31s %u%*[^\n]\n", name, &val) != EOF) ++ { ++ if (strncmp("MemTotal:", name, 9) == 0) ++ info.totalram = val/4; ++ else if (strncmp("MemFree:", name, 8) == 0) ++ info.freeram = val/4; ++ else if (strncmp("Buffers:", name, 8) == 0) ++ info.bufferram += val/4; ++ else if (strncmp("Cached:", name, 7) == 0) ++ info.bufferram += val/4; ++ else if (strncmp("SwapTotal:", name, 10) == 0) ++ info.totalswap = val/4; ++ else if (strncmp("SwapFree:", name, 9) == 0) ++ info.freeswap = val/4; ++ else if (strncmp("HighTotal:", name, 10) == 0) ++ info.totalhigh = val/4; ++ else if (strncmp("HighFree:", name, 9) == 0) ++ info.freehigh = val/4; ++ } ++ rewind(procMeminfoFP); ++ fflush(procMeminfoFP); ++ } ++ lpBuffer->ullAvailPageFile = (info.freeswap * info.mem_unit); ++ lpBuffer->ullAvailPhys = ((info.freeram + info.bufferram) * info.mem_unit); ++ lpBuffer->ullAvailVirtual = ((info.freeram + info.bufferram) * info.mem_unit); ++ lpBuffer->ullTotalPhys = (info.totalram * info.mem_unit); ++ lpBuffer->ullTotalVirtual = (info.totalram * info.mem_unit); ++#endif ++} ++ ++#endif + +diff -Naur xbmc-11.0.1/xbmc/linux/XMemUtils.h xbmc-11.0.1.patch/xbmc/linux/XMemUtils.h +--- xbmc-11.0.1/xbmc/linux/XMemUtils.h 2012-03-21 23:57:32.000000000 +0100 ++++ xbmc-11.0.1.patch/xbmc/linux/XMemUtils.h 2012-05-13 22:08:46.806190105 +0200 +@@ -22,10 +22,14 @@ + * + */ + ++#include "linux/PlatformDefs.h" ++ + // aligned memory allocation and free. memory returned will be aligned to "alignTo" bytes. + // this is a linux (actually platfom free) implementation of the win32 CRT methods _aligned_malloc and _aligned_free. + void *_aligned_malloc(size_t s, size_t alignTo); + void _aligned_free(void *p) ; + ++void GlobalMemoryStatusEx(LPMEMORYSTATUSEX lpBuffer); ++ + #endif + +diff -Naur xbmc-11.0.1/xbmc/linux/XSyncUtils.cpp xbmc-11.0.1.patch/xbmc/linux/XSyncUtils.cpp +--- xbmc-11.0.1/xbmc/linux/XSyncUtils.cpp 2012-03-21 23:57:32.000000000 +0100 ++++ xbmc-11.0.1.patch/xbmc/linux/XSyncUtils.cpp 1970-01-01 01:00:00.000000000 +0100 +@@ -1,169 +0,0 @@ +-/* +- * Copyright (C) 2005-2008 Team XBMC +- * http://www.xbmc.org +- * +- * 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 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 XBMC; see the file COPYING. If not, write to +- * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. +- * http://www.gnu.org/copyleft/gpl.html +- * +- */ +- +-#ifndef _WIN32 +- +- +-#include +-#include +-#include +-#include +-#include +-#ifdef __APPLE__ +-#include +-#endif +- +-#include "XSyncUtils.h" +-#include "XTimeUtils.h" +-#include "PlatformDefs.h" +-#include "XHandle.h" +-#include "XEventUtils.h" +- +-using namespace std; +-using namespace XbmcThreads; +- +-#include "../utils/log.h" +-#include "../utils/TimeUtils.h" +- +-#if defined(_LINUX) && !defined(__APPLE__) && !defined(__FreeBSD__) +-static FILE* procMeminfoFP = NULL; +-#endif +- +-void GlobalMemoryStatusEx(LPMEMORYSTATUSEX lpBuffer) +-{ +- if (!lpBuffer) +- return; +- +- memset(lpBuffer, 0, sizeof(MEMORYSTATUSEX)); +- +-#ifdef __APPLE__ +- uint64_t physmem; +- size_t len = sizeof physmem; +- int mib[2] = { CTL_HW, HW_MEMSIZE }; +- size_t miblen = sizeof(mib) / sizeof(mib[0]); +- +- // Total physical memory. +- if (sysctl(mib, miblen, &physmem, &len, NULL, 0) == 0 && len == sizeof (physmem)) +- lpBuffer->ullTotalPhys = physmem; +- +- // Virtual memory. +- mib[0] = CTL_VM; mib[1] = VM_SWAPUSAGE; +- struct xsw_usage swap; +- len = sizeof(struct xsw_usage); +- if (sysctl(mib, miblen, &swap, &len, NULL, 0) == 0) +- { +- lpBuffer->ullAvailPageFile = swap.xsu_avail; +- lpBuffer->ullTotalVirtual = lpBuffer->ullTotalPhys + swap.xsu_total; +- } +- +- // In use. +- mach_port_t stat_port = mach_host_self(); +- vm_statistics_data_t vm_stat; +- mach_msg_type_number_t count = sizeof(vm_stat) / sizeof(natural_t); +- if (host_statistics(stat_port, HOST_VM_INFO, (host_info_t)&vm_stat, &count) == 0) +- { +- // Find page size. +- int pageSize; +- mib[0] = CTL_HW; mib[1] = HW_PAGESIZE; +- len = sizeof(int); +- if (sysctl(mib, miblen, &pageSize, &len, NULL, 0) == 0) +- { +- uint64_t used = (vm_stat.active_count + vm_stat.inactive_count + vm_stat.wire_count) * pageSize; +- +- lpBuffer->ullAvailPhys = lpBuffer->ullTotalPhys - used; +- lpBuffer->ullAvailVirtual = lpBuffer->ullAvailPhys; // FIXME. +- } +- } +-#elif defined(__FreeBSD__) +- /* sysctl hw.physmem */ +- size_t physmem = 0, mem_free = 0, pagesize = 0, swap_free = 0; +- size_t mem_avail = 0, mem_inactive = 0, mem_cache = 0, len = 0; +- +- /* physmem */ +- len = sizeof(physmem); +- if (sysctlbyname("hw.physmem", &physmem, &len, NULL, 0) == 0) { +- lpBuffer->ullTotalPhys = physmem; +- lpBuffer->ullTotalVirtual = physmem; +- } +- /* pagesize */ +- len = sizeof(pagesize); +- if (sysctlbyname("hw.pagesize", &pagesize, &len, NULL, 0) != 0) +- pagesize = 4096; +- /* mem_inactive */ +- len = sizeof(mem_inactive); +- if (sysctlbyname("vm.stats.vm.v_inactive_count", &mem_inactive, &len, NULL, 0) == 0) +- mem_inactive *= pagesize; +- /* mem_cache */ +- len = sizeof(mem_cache); +- if (sysctlbyname("vm.stats.vm.v_cache_count", &mem_cache, &len, NULL, 0) == 0) +- mem_cache *= pagesize; +- /* mem_free */ +- len = sizeof(mem_free); +- if (sysctlbyname("vm.stats.vm.v_free_count", &mem_free, &len, NULL, 0) == 0) +- mem_free *= pagesize; +- +- /* mem_avail = mem_inactive + mem_cache + mem_free */ +- lpBuffer->ullAvailPhys = mem_inactive + mem_cache + mem_free; +- lpBuffer->ullAvailVirtual = mem_inactive + mem_cache + mem_free; +- +- if (sysctlbyname("vm.stats.vm.v_swappgsout", &swap_free, &len, NULL, 0) == 0) +- lpBuffer->ullAvailPageFile = swap_free * pagesize; +-#else +- struct sysinfo info; +- char name[32]; +- unsigned val; +- if (!procMeminfoFP && (procMeminfoFP = fopen("/proc/meminfo", "r")) == NULL) +- sysinfo(&info); +- else +- { +- memset(&info, 0, sizeof(struct sysinfo)); +- info.mem_unit = 4096; +- while (fscanf(procMeminfoFP, "%31s %u%*[^\n]\n", name, &val) != EOF) +- { +- if (strncmp("MemTotal:", name, 9) == 0) +- info.totalram = val/4; +- else if (strncmp("MemFree:", name, 8) == 0) +- info.freeram = val/4; +- else if (strncmp("Buffers:", name, 8) == 0) +- info.bufferram += val/4; +- else if (strncmp("Cached:", name, 7) == 0) +- info.bufferram += val/4; +- else if (strncmp("SwapTotal:", name, 10) == 0) +- info.totalswap = val/4; +- else if (strncmp("SwapFree:", name, 9) == 0) +- info.freeswap = val/4; +- else if (strncmp("HighTotal:", name, 10) == 0) +- info.totalhigh = val/4; +- else if (strncmp("HighFree:", name, 9) == 0) +- info.freehigh = val/4; +- } +- rewind(procMeminfoFP); +- fflush(procMeminfoFP); +- } +- lpBuffer->ullAvailPageFile = (info.freeswap * info.mem_unit); +- lpBuffer->ullAvailPhys = ((info.freeram + info.bufferram) * info.mem_unit); +- lpBuffer->ullAvailVirtual = ((info.freeram + info.bufferram) * info.mem_unit); +- lpBuffer->ullTotalPhys = (info.totalram * info.mem_unit); +- lpBuffer->ullTotalVirtual = (info.totalram * info.mem_unit); +-#endif +-} +- +-#endif +diff -Naur xbmc-11.0.1/xbmc/linux/XSyncUtils.h xbmc-11.0.1.patch/xbmc/linux/XSyncUtils.h +--- xbmc-11.0.1/xbmc/linux/XSyncUtils.h 2012-03-21 23:57:32.000000000 +0100 ++++ xbmc-11.0.1.patch/xbmc/linux/XSyncUtils.h 1970-01-01 01:00:00.000000000 +0100 +@@ -1,44 +0,0 @@ +-#ifndef __X_SYNC_UTILS_ +-#define __X_SYNC_UTILS_ +- +-/* +- * Copyright (C) 2005-2008 Team XBMC +- * http://www.xbmc.org +- * +- * 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 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 XBMC; see the file COPYING. If not, write to +- * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. +- * http://www.gnu.org/copyleft/gpl.html +- * +- */ +- +-#include "PlatformDefs.h" +-#include "XHandlePublic.h" +- +-#ifdef _LINUX +- +-#define STATUS_WAIT_0 ((DWORD )0x00000000L) +-#define WAIT_FAILED ((DWORD)0xFFFFFFFF) +-#define WAIT_OBJECT_0 ((STATUS_WAIT_0 ) + 0 ) +-#define WAIT_TIMEOUT 258L +-#define INFINITE 0xFFFFFFFF +-#define STATUS_ABANDONED_WAIT_0 0x00000080 +-#define WAIT_ABANDONED ((STATUS_ABANDONED_WAIT_0 ) + 0 ) +-#define WAIT_ABANDONED_0 ((STATUS_ABANDONED_WAIT_0 ) + 0 ) +- +-void GlobalMemoryStatusEx(LPMEMORYSTATUSEX lpBuffer); +- +-#endif +- +-#endif +- +diff -Naur xbmc-11.0.1/xbmc/linux/XThreadUtils.cpp xbmc-11.0.1.patch/xbmc/linux/XThreadUtils.cpp +--- xbmc-11.0.1/xbmc/linux/XThreadUtils.cpp 2012-03-21 23:57:32.000000000 +0100 ++++ xbmc-11.0.1.patch/xbmc/linux/XThreadUtils.cpp 1970-01-01 01:00:00.000000000 +0100 +@@ -1,210 +0,0 @@ +-/* +- * Copyright (C) 2005-2009 Team XBMC +- * http://www.xbmc.org +- * +- * 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 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 XBMC; see the file COPYING. If not, write to +- * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. +- * http://www.gnu.org/copyleft/gpl.html +- * +- */ +- +-#include "PlatformDefs.h" +-#include "XHandle.h" +-#include "XThreadUtils.h" +-#include "XTimeUtils.h" +-#include "XEventUtils.h" +-#include "system.h" +-#include "utils/log.h" +- +-#ifdef _LINUX +-#include +-#include +-#include +- +-HANDLE WINAPI CreateThread( +- LPSECURITY_ATTRIBUTES lpThreadAttributes, +- SIZE_T dwStackSize, +- LPTHREAD_START_ROUTINE lpStartAddress, +- LPVOID lpParameter, +- DWORD dwCreationFlags, +- LPDWORD lpThreadId +- ) { +- +- // a thread handle would actually contain an event +- // the event would mark if the thread is running or not. it will be used in the Wait functions. +- HANDLE h = CreateEvent(NULL, TRUE, FALSE, NULL); +- h->ChangeType(CXHandle::HND_THREAD); +-#ifdef __APPLE__ +- h->m_machThreadPort = MACH_PORT_NULL; +-#endif +- pthread_attr_t attr; +- pthread_attr_init(&attr); +- if (dwStackSize > PTHREAD_STACK_MIN) +- pthread_attr_setstacksize(&attr, dwStackSize); +- if (pthread_create(&(h->m_hThread), &attr, (void*(*)(void*))lpStartAddress, lpParameter) == 0) +- h->m_threadValid = true; +- else +- { +- CloseHandle(h); +- h = NULL; +- } +- pthread_attr_destroy(&attr); +- +- if (h && lpThreadId) +- // WARNING: This can truncate thread IDs on x86_64. +- *lpThreadId = (DWORD)h->m_hThread; +- return h; +-} +- +- +-#if 0 // Deprecated, use CThread::GetCurrentThreadId() instead +-DWORD WINAPI GetCurrentThreadId(void) { +- // WARNING: This can truncate thread IDs on x86_64. +- return (DWORD)pthread_self(); +-} +-#endif +- +-HANDLE WINAPI GetCurrentThread(void) { +- return (HANDLE)-1; // -1 a special value - pseudo handle +-} +- +-HANDLE WINAPI GetCurrentProcess(void) { +- return (HANDLE)-1; // -1 a special value - pseudo handle +-} +- +-HANDLE _beginthreadex( +- void *security, +- unsigned stack_size, +- int ( *start_address )( void * ), +- void *arglist, +- unsigned initflag, +- unsigned *thrdaddr +-) { +- +- HANDLE h = CreateThread(NULL, stack_size, start_address, arglist, initflag, (LPDWORD)thrdaddr); +- return h; +- +-} +- +-uintptr_t _beginthread( +- void( *start_address )( void * ), +- unsigned stack_size, +- void *arglist +-) { +- HANDLE h = CreateThread(NULL, stack_size, (LPTHREAD_START_ROUTINE)start_address, arglist, 0, NULL); +- return (uintptr_t)h; +-} +- +-BOOL WINAPI GetThreadTimes ( +- HANDLE hThread, +- LPFILETIME lpCreationTime, +- LPFILETIME lpExitTime, +- LPFILETIME lpKernelTime, +- LPFILETIME lpUserTime +-) { +- if (!hThread) +- return false; +- if (!hThread->m_threadValid) +- return false; +- +- if (hThread == (HANDLE)-1) { +- if (lpCreationTime) +- TimeTToFileTime(0,lpCreationTime); +- if (lpExitTime) +- TimeTToFileTime(time(NULL),lpExitTime); +- if (lpKernelTime) +- TimeTToFileTime(0,lpKernelTime); +- if (lpUserTime) +- TimeTToFileTime(0,lpUserTime); +- +- return true; +- } +- +- if (lpCreationTime) +- TimeTToFileTime(hThread->m_tmCreation,lpCreationTime); +- if (lpExitTime) +- TimeTToFileTime(time(NULL),lpExitTime); +- if (lpKernelTime) +- TimeTToFileTime(0,lpKernelTime); +- +-#ifdef __APPLE__ +- thread_info_data_t threadInfo; +- mach_msg_type_number_t threadInfoCount = THREAD_INFO_MAX; +- +- if (hThread->m_machThreadPort == MACH_PORT_NULL) +- hThread->m_machThreadPort = pthread_mach_thread_np(hThread->m_hThread); +- +- kern_return_t ret = thread_info(hThread->m_machThreadPort, THREAD_BASIC_INFO, (thread_info_t)threadInfo, &threadInfoCount); +- if (ret == KERN_SUCCESS) +- { +- thread_basic_info_t threadBasicInfo = (thread_basic_info_t)threadInfo; +- +- if (lpUserTime) +- { +- // User time. +- unsigned long long time = ((__int64)threadBasicInfo->user_time.seconds * 10000000L) + threadBasicInfo->user_time.microseconds*10L; +- lpUserTime->dwLowDateTime = (time & 0xFFFFFFFF); +- lpUserTime->dwHighDateTime = (time >> 32); +- } +- +- if (lpKernelTime) +- { +- // System time. +- unsigned long long time = ((__int64)threadBasicInfo->system_time.seconds * 10000000L) + threadBasicInfo->system_time.microseconds*10L; +- lpKernelTime->dwLowDateTime = (time & 0xFFFFFFFF); +- lpKernelTime->dwHighDateTime = (time >> 32); +- } +- } +- else +- { +- if (lpUserTime) +- lpUserTime->dwLowDateTime = lpUserTime->dwHighDateTime = 0; +- +- if (lpKernelTime) +- lpKernelTime->dwLowDateTime = lpKernelTime->dwHighDateTime = 0; +- } +-#elif _POSIX_THREAD_CPUTIME != -1 +- if(lpUserTime) +- { +- lpUserTime->dwLowDateTime = 0; +- lpUserTime->dwHighDateTime = 0; +- clockid_t clock; +- if (pthread_getcpuclockid(hThread->m_hThread, &clock) == 0) +- { +- struct timespec tp = {}; +- clock_gettime(clock, &tp); +- unsigned long long time = (unsigned long long)tp.tv_sec * 10000000 + (unsigned long long)tp.tv_nsec/100; +- lpUserTime->dwLowDateTime = (time & 0xFFFFFFFF); +- lpUserTime->dwHighDateTime = (time >> 32); +- } +- } +-#else +- if (lpUserTime) +- TimeTToFileTime(0,lpUserTime); +-#endif +- return true; +-} +- +-BOOL WINAPI SetThreadPriority(HANDLE hThread, int nPriority) +-{ +- return true; +-} +- +-int GetThreadPriority(HANDLE hThread) +-{ +- return 0; +-} +- +-#endif +- +diff -Naur xbmc-11.0.1/xbmc/music/infoscanner/MusicInfoScanner.cpp xbmc-11.0.1.patch/xbmc/music/infoscanner/MusicInfoScanner.cpp +--- xbmc-11.0.1/xbmc/music/infoscanner/MusicInfoScanner.cpp 2012-03-21 23:57:32.000000000 +0100 ++++ xbmc-11.0.1.patch/xbmc/music/infoscanner/MusicInfoScanner.cpp 2012-05-13 22:08:46.811190206 +0200 +@@ -57,7 +57,7 @@ + using namespace XFILE; + using namespace MUSIC_GRABBER; + +-CMusicInfoScanner::CMusicInfoScanner() ++CMusicInfoScanner::CMusicInfoScanner() : CThread("CMusicInfoScanner") + { + m_bRunning = false; + m_pObserver = NULL; +@@ -99,7 +99,7 @@ + + // Create the thread to count all files to be scanned + SetPriority( GetMinPriority() ); +- CThread fileCountReader(this); ++ CThread fileCountReader(this, "CMusicInfoScanner"); + if (m_pObserver) + fileCountReader.Create(); + +diff -Naur xbmc-11.0.1/xbmc/music/infoscanner/MusicInfoScraper.cpp xbmc-11.0.1.patch/xbmc/music/infoscanner/MusicInfoScraper.cpp +--- xbmc-11.0.1/xbmc/music/infoscanner/MusicInfoScraper.cpp 2012-03-21 23:57:32.000000000 +0100 ++++ xbmc-11.0.1.patch/xbmc/music/infoscanner/MusicInfoScraper.cpp 2012-05-13 22:08:46.812190226 +0200 +@@ -28,7 +28,7 @@ + using namespace ADDON; + using namespace std; + +-CMusicInfoScraper::CMusicInfoScraper(const ADDON::ScraperPtr &scraper) ++CMusicInfoScraper::CMusicInfoScraper(const ADDON::ScraperPtr &scraper) : CThread("CMusicInfoScraper") + { + m_bSucceeded=false; + m_bCanceled=false; +diff -Naur xbmc-11.0.1/xbmc/music/LastFmManager.cpp xbmc-11.0.1.patch/xbmc/music/LastFmManager.cpp +--- xbmc-11.0.1/xbmc/music/LastFmManager.cpp 2012-03-21 23:57:32.000000000 +0100 ++++ xbmc-11.0.1.patch/xbmc/music/LastFmManager.cpp 2012-05-13 22:08:46.810190186 +0200 +@@ -70,7 +70,7 @@ + + CLastFmManager* CLastFmManager::m_pInstance=NULL; + +-CLastFmManager::CLastFmManager() ++CLastFmManager::CLastFmManager() : CThread("CLastFmManager") + { + m_RadioTrackQueue = new CPlayList; + } +@@ -534,7 +534,7 @@ + if (iNrCachedTracks == 0) + { + //get more tracks +- if (ThreadHandle() != NULL) ++ if (IsRunning()) + { + m_hWorkerEvent.Set(); + } +@@ -633,7 +633,7 @@ + { + m_RadioSession = ""; + } +- if (m_ThreadHandle) ++ if (IsRunning()) + { + m_bStop = true; + m_hWorkerEvent.Set(); +diff -Naur xbmc-11.0.1/xbmc/network/AirPlayServer.cpp xbmc-11.0.1.patch/xbmc/network/AirPlayServer.cpp +--- xbmc-11.0.1/xbmc/network/AirPlayServer.cpp 2012-03-21 23:57:32.000000000 +0100 ++++ xbmc-11.0.1.patch/xbmc/network/AirPlayServer.cpp 2012-05-13 22:08:46.813190246 +0200 +@@ -184,7 +184,7 @@ + } + } + +-CAirPlayServer::CAirPlayServer(int port, bool nonlocal) ++CAirPlayServer::CAirPlayServer(int port, bool nonlocal) : CThread("AirPlayServer") + { + m_port = port; + m_nonlocal = nonlocal; +diff -Naur xbmc-11.0.1/xbmc/network/AirTunesServer.cpp xbmc-11.0.1.patch/xbmc/network/AirTunesServer.cpp +--- xbmc-11.0.1/xbmc/network/AirTunesServer.cpp 2012-03-21 23:57:32.000000000 +0100 ++++ xbmc-11.0.1.patch/xbmc/network/AirTunesServer.cpp 2012-05-13 22:08:46.871191395 +0200 +@@ -292,7 +292,7 @@ + } + } + +-CAirTunesServer::CAirTunesServer(int port, bool nonlocal) ++CAirTunesServer::CAirTunesServer(int port, bool nonlocal) : CThread("CAirTunesServer") + { + m_port = port; + m_pLibShairport = new DllLibShairport(); +diff -Naur xbmc-11.0.1/xbmc/network/libscrobbler/scrobbler.cpp xbmc-11.0.1.patch/xbmc/network/libscrobbler/scrobbler.cpp +--- xbmc-11.0.1/xbmc/network/libscrobbler/scrobbler.cpp 2012-03-21 23:57:32.000000000 +0100 ++++ xbmc-11.0.1.patch/xbmc/network/libscrobbler/scrobbler.cpp 2012-05-13 22:08:46.816190305 +0200 +@@ -46,7 +46,7 @@ + #define SCROBBLER_ACTION_NOWPLAYING 2 + + CScrobbler::CScrobbler(const CStdString &strHandshakeURL, const CStdString &strLogPrefix) +- : CThread() ++ : CThread("CScrobbler") + { + m_bBanned = false; + m_bBadAuth = false; +@@ -67,7 +67,7 @@ + ResetState(); + LoadCredentials(); + LoadJournal(); +- if (!ThreadHandle()) ++ if (!IsRunning()) + Create(); + } + +diff -Naur xbmc-11.0.1/xbmc/network/Network.h xbmc-11.0.1.patch/xbmc/network/Network.h +--- xbmc-11.0.1/xbmc/network/Network.h 2012-03-21 23:57:32.000000000 +0100 ++++ xbmc-11.0.1.patch/xbmc/network/Network.h 2012-05-13 22:08:46.813190246 +0200 +@@ -24,6 +24,7 @@ + + #include + #include "utils/StdString.h" ++#include "system.h" + + enum EncMode { ENC_NONE = 0, ENC_WEP = 1, ENC_WPA = 2, ENC_WPA2 = 3 }; + enum NetworkAssignment { NETWORK_DASH = 0, NETWORK_DHCP = 1, NETWORK_STATIC = 2, NETWORK_DISABLED = 3 }; +diff -Naur xbmc-11.0.1/xbmc/network/TCPServer.cpp xbmc-11.0.1.patch/xbmc/network/TCPServer.cpp +--- xbmc-11.0.1/xbmc/network/TCPServer.cpp 2012-03-21 23:57:32.000000000 +0100 ++++ xbmc-11.0.1.patch/xbmc/network/TCPServer.cpp 2012-05-13 22:08:46.814190266 +0200 +@@ -85,7 +85,7 @@ + } + } + +-CTCPServer::CTCPServer(int port, bool nonlocal) ++CTCPServer::CTCPServer(int port, bool nonlocal) : CThread("CTCPServer") + { + m_port = port; + m_nonlocal = nonlocal; +diff -Naur xbmc-11.0.1/xbmc/network/UdpClient.cpp xbmc-11.0.1.patch/xbmc/network/UdpClient.cpp +--- xbmc-11.0.1/xbmc/network/UdpClient.cpp 2012-03-21 23:57:32.000000000 +0100 ++++ xbmc-11.0.1.patch/xbmc/network/UdpClient.cpp 2012-05-13 22:08:46.814190266 +0200 +@@ -35,7 +35,7 @@ + + #define UDPCLIENT_DEBUG_LEVEL LOGDEBUG + +-CUdpClient::CUdpClient(void) : CThread() ++CUdpClient::CUdpClient(void) : CThread("CUdpClient") + {} + + CUdpClient::~CUdpClient(void) +diff -Naur xbmc-11.0.1/xbmc/network/UdpClient.h xbmc-11.0.1.patch/xbmc/network/UdpClient.h +--- xbmc-11.0.1/xbmc/network/UdpClient.h 2012-03-21 23:57:32.000000000 +0100 ++++ xbmc-11.0.1.patch/xbmc/network/UdpClient.h 2012-05-13 22:08:46.815190286 +0200 +@@ -25,6 +25,7 @@ + #include "threads/CriticalSection.h" + #include + #include ++#include "system.h" + + class CUdpClient : CThread + { +diff -Naur xbmc-11.0.1/xbmc/peripherals/Peripherals.cpp xbmc-11.0.1.patch/xbmc/peripherals/Peripherals.cpp +--- xbmc-11.0.1/xbmc/peripherals/Peripherals.cpp 2012-03-21 23:57:32.000000000 +0100 ++++ xbmc-11.0.1.patch/xbmc/peripherals/Peripherals.cpp 2012-05-13 22:08:46.940192765 +0200 +@@ -19,6 +19,7 @@ + * + */ + ++#include "system.h" + #include "Peripherals.h" + #include "bus/PeripheralBus.h" + #include "devices/PeripheralBluetooth.h" +diff -Naur xbmc-11.0.1/xbmc/pictures/GUIWindowSlideShow.cpp xbmc-11.0.1.patch/xbmc/pictures/GUIWindowSlideShow.cpp +--- xbmc-11.0.1/xbmc/pictures/GUIWindowSlideShow.cpp 2012-03-21 23:57:32.000000000 +0100 ++++ xbmc-11.0.1.patch/xbmc/pictures/GUIWindowSlideShow.cpp 2012-05-13 22:08:46.816190305 +0200 +@@ -67,7 +67,7 @@ + + static float zoomamount[10] = { 1.0f, 1.2f, 1.5f, 2.0f, 2.8f, 4.0f, 6.0f, 9.0f, 13.5f, 20.0f }; + +-CBackgroundPicLoader::CBackgroundPicLoader() ++CBackgroundPicLoader::CBackgroundPicLoader() : CThread("CBackgroundPicLoader") + { + m_pCallback = NULL; + m_isLoading = false; +diff -Naur xbmc-11.0.1/xbmc/rendering/dx/RenderSystemDX.cpp xbmc-11.0.1.patch/xbmc/rendering/dx/RenderSystemDX.cpp +--- xbmc-11.0.1/xbmc/rendering/dx/RenderSystemDX.cpp 2012-03-21 23:57:32.000000000 +0100 ++++ xbmc-11.0.1.patch/xbmc/rendering/dx/RenderSystemDX.cpp 2012-05-13 22:08:46.817190325 +0200 +@@ -569,7 +569,7 @@ + + //CVideoReferenceClock polls GetRasterStatus too, + //polling it from two threads at the same time is bad +- if (g_advancedSettings.m_sleepBeforeFlip > 0 && g_VideoReferenceClock.ThreadHandle() == NULL) ++ if (g_advancedSettings.m_sleepBeforeFlip > 0 && !g_VideoReferenceClock.IsRunning()) + { + //save current thread priority and set thread priority to THREAD_PRIORITY_TIME_CRITICAL + int priority = GetThreadPriority(GetCurrentThread()); +diff -Naur xbmc-11.0.1/xbmc/settings/AdvancedSettings.cpp xbmc-11.0.1.patch/xbmc/settings/AdvancedSettings.cpp +--- xbmc-11.0.1/xbmc/settings/AdvancedSettings.cpp 2012-03-21 23:57:32.000000000 +0100 ++++ xbmc-11.0.1.patch/xbmc/settings/AdvancedSettings.cpp 2012-05-13 22:08:47.021194373 +0200 +@@ -96,12 +96,18 @@ + m_videoAllowMpeg4VAAPI = false; + m_videoDisableBackgroundDeinterlace = false; + m_videoCaptureUseOcclusionQuery = -1; //-1 is auto detect ++ m_videoVDPAUdeintHD = -1; ++ m_videoVDPAUdeintSD = -1; ++ m_videoVDPAUtelecine = false; ++ m_videoVDPAUmaxHeight = -1; ++ m_videoVDPAUdeintSkipChromaHD = false; + m_DXVACheckCompatibility = false; + m_DXVACheckCompatibilityPresent = false; + m_DXVAForceProcessorRenderer = true; + m_DXVANoDeintProcForProgressive = false; + m_videoFpsDetect = 1; + m_videoDefaultLatency = 0.0; ++ m_vblankPolling = false; + + m_musicUseTimeSeeking = true; + m_musicTimeSeekForward = 10; +@@ -455,6 +461,11 @@ + XMLUtils::GetBoolean(pElement,"allowmpeg4vaapi",m_videoAllowMpeg4VAAPI); + XMLUtils::GetBoolean(pElement, "disablebackgrounddeinterlace", m_videoDisableBackgroundDeinterlace); + XMLUtils::GetInt(pElement, "useocclusionquery", m_videoCaptureUseOcclusionQuery, -1, 1); ++ XMLUtils::GetInt(pElement,"vdpauHDdeint",m_videoVDPAUdeintHD); ++ XMLUtils::GetInt(pElement,"vdpauSDdeint",m_videoVDPAUdeintSD); ++ XMLUtils::GetInt(pElement,"vdpauMaxHeight",m_videoVDPAUmaxHeight); ++ XMLUtils::GetBoolean(pElement,"vdpauInvTelecine",m_videoVDPAUtelecine); ++ XMLUtils::GetBoolean(pElement,"vdpauHDdeintSkipChroma",m_videoVDPAUdeintSkipChromaHD); + + TiXmlElement* pAdjustRefreshrate = pElement->FirstChildElement("adjustrefreshrate"); + if (pAdjustRefreshrate) +@@ -544,6 +555,8 @@ + //0 = disable fps detect, 1 = only detect on timestamps with uniform spacing, 2 detect on all timestamps + XMLUtils::GetInt(pElement, "fpsdetect", m_videoFpsDetect, 0, 2); + ++ XMLUtils::GetBoolean(pElement,"vblankpolling", m_vblankPolling); ++ + // Store global display latency settings + TiXmlElement* pVideoLatency = pElement->FirstChildElement("latency"); + if (pVideoLatency) +diff -Naur xbmc-11.0.1/xbmc/settings/AdvancedSettings.h xbmc-11.0.1.patch/xbmc/settings/AdvancedSettings.h +--- xbmc-11.0.1/xbmc/settings/AdvancedSettings.h 2012-03-21 23:57:32.000000000 +0100 ++++ xbmc-11.0.1.patch/xbmc/settings/AdvancedSettings.h 2012-05-13 22:08:47.022194393 +0200 +@@ -111,6 +111,11 @@ + int m_videoPercentSeekBackwardBig; + CStdString m_videoPPFFmpegDeint; + CStdString m_videoPPFFmpegPostProc; ++ int m_videoVDPAUdeintHD; ++ int m_videoVDPAUdeintSD; ++ bool m_videoVDPAUtelecine; ++ int m_videoVDPAUmaxHeight; ++ bool m_videoVDPAUdeintSkipChromaHD; + bool m_musicUseTimeSeeking; + int m_musicTimeSeekForward; + int m_musicTimeSeekBackward; +@@ -143,6 +148,7 @@ + bool m_DXVAForceProcessorRenderer; + bool m_DXVANoDeintProcForProgressive; + int m_videoFpsDetect; ++ bool m_vblankPolling; + + CStdString m_videoDefaultPlayer; + CStdString m_videoDefaultDVDPlayer; +diff -Naur xbmc-11.0.1/xbmc/settings/GUISettings.cpp xbmc-11.0.1.patch/xbmc/settings/GUISettings.cpp +--- xbmc-11.0.1/xbmc/settings/GUISettings.cpp 2012-03-21 23:57:32.000000000 +0100 ++++ xbmc-11.0.1.patch/xbmc/settings/GUISettings.cpp 2012-05-13 22:08:46.957193103 +0200 +@@ -583,10 +583,15 @@ + + #ifdef HAVE_LIBVDPAU + AddBool(vp, "videoplayer.usevdpau", 13425, true); ++ AddBool(vp, "videoplayer.usevdpauinteroprgb", 13433, true); ++ AddBool(vp, "videoplayer.usevdpauinteropyuv", 13434, true); + #endif + #ifdef HAVE_LIBVA + AddBool(vp, "videoplayer.usevaapi", 13426, true); + #endif ++#ifdef HAVE_LIBXVBA ++ AddBool(vp, "videoplayer.usexvba", 13435, true); ++#endif + #ifdef HAS_DX + AddBool(g_sysinfo.IsVistaOrHigher() ? vp: NULL, "videoplayer.usedxva2", 13427, g_sysinfo.IsVistaOrHigher() ? true : false); + #endif +diff -Naur xbmc-11.0.1/xbmc/settings/GUIWindowSettingsCategory.cpp xbmc-11.0.1.patch/xbmc/settings/GUIWindowSettingsCategory.cpp +--- xbmc-11.0.1/xbmc/settings/GUIWindowSettingsCategory.cpp 2012-03-21 23:57:32.000000000 +0100 ++++ xbmc-11.0.1.patch/xbmc/settings/GUIWindowSettingsCategory.cpp 2012-05-13 22:08:46.682187646 +0200 +@@ -549,6 +549,40 @@ + pControl->SetEnabled(true); + } + } ++ else if (strSetting.Equals("videoplayer.usevdpauinteropyuv")) ++ { ++ bool hasInterop = false; ++#ifdef GL_NV_vdpau_interop ++ hasInterop = true; ++#endif ++ CGUIControl *pControl = (CGUIControl *)GetControl(pSettingControl->GetID()); ++ if (pControl && hasInterop && glewIsSupported("GL_NV_vdpau_interop")) ++ { ++ pControl->SetEnabled(true); ++ } ++ else ++ { ++ pControl->SetEnabled(false); ++ g_guiSettings.SetBool("videoplayer.usevdpauinteropyuv",false); ++ } ++ } ++ else if (strSetting.Equals("videoplayer.usevdpauinteroprgb")) ++ { ++ bool hasInterop = false; ++#ifdef GL_NV_vdpau_interop ++ hasInterop = true; ++#endif ++ CGUIControl *pControl = (CGUIControl *)GetControl(pSettingControl->GetID()); ++ if (pControl && hasInterop && glewIsSupported("GL_NV_vdpau_interop")) ++ { ++ pControl->SetEnabled(true); ++ } ++ else ++ { ++ pControl->SetEnabled(false); ++ g_guiSettings.SetBool("videoplayer.usevdpauinteroprgb",false); ++ } ++ } + else + #endif + if (strSetting.Equals("videoscreen.resolution")) +diff -Naur xbmc-11.0.1/xbmc/settings/VideoSettings.h xbmc-11.0.1.patch/xbmc/settings/VideoSettings.h +--- xbmc-11.0.1/xbmc/settings/VideoSettings.h 2012-03-21 23:57:32.000000000 +0100 ++++ xbmc-11.0.1.patch/xbmc/settings/VideoSettings.h 2012-05-13 22:08:46.958193123 +0200 +@@ -67,6 +67,8 @@ + + VS_INTERLACEMETHOD_SW_BLEND = 20, + ++ VS_INTERLACEMETHOD_XVBA = 22, ++ + VS_INTERLACEMETHOD_MAX // do not use and keep as last enum value. + }; + +diff -Naur xbmc-11.0.1/xbmc/threads/platform/darwin/ThreadSchedImpl.cpp xbmc-11.0.1.patch/xbmc/threads/platform/darwin/ThreadSchedImpl.cpp +--- xbmc-11.0.1/xbmc/threads/platform/darwin/ThreadSchedImpl.cpp 1970-01-01 01:00:00.000000000 +0100 ++++ xbmc-11.0.1.patch/xbmc/threads/platform/darwin/ThreadSchedImpl.cpp 2012-05-13 22:08:46.821190405 +0200 +@@ -0,0 +1,47 @@ ++/* ++ * Copyright (C) 2005-2011 Team XBMC ++ * http://www.xbmc.org ++ * ++ * 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 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 XBMC; see the file COPYING. If not, write to ++ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. ++ * http://www.gnu.org/copyleft/gpl.html ++ * ++ */ ++ ++int CThread::GetSchedRRPriority(void) ++{ ++ return 96; ++} ++ ++bool CThread::SetPrioritySched_RR(int iPriority) ++{ ++ // Changing to SCHED_RR is safe under OSX, you don't need elevated privileges and the ++ // OSX scheduler will monitor SCHED_RR threads and drop to SCHED_OTHER if it detects ++ // the thread running away. OSX automatically does this with the CoreAudio audio ++ // device handler thread. ++ int32_t result; ++ thread_extended_policy_data_t theFixedPolicy; ++ ++ // make thread fixed, set to 'true' for a non-fixed thread ++ theFixedPolicy.timeshare = false; ++ result = thread_policy_set(pthread_mach_thread_np(ThreadId()), THREAD_EXTENDED_POLICY, ++ (thread_policy_t)&theFixedPolicy, THREAD_EXTENDED_POLICY_COUNT); ++ ++ int policy; ++ struct sched_param param; ++ result = pthread_getschedparam(ThreadId(), &policy, ¶m ); ++ // change from default SCHED_OTHER to SCHED_RR ++ policy = SCHED_RR; ++ result = pthread_setschedparam(ThreadId(), policy, ¶m ); ++} +diff -Naur xbmc-11.0.1/xbmc/threads/platform/linux/ThreadSchedImpl.cpp xbmc-11.0.1.patch/xbmc/threads/platform/linux/ThreadSchedImpl.cpp +--- xbmc-11.0.1/xbmc/threads/platform/linux/ThreadSchedImpl.cpp 1970-01-01 01:00:00.000000000 +0100 ++++ xbmc-11.0.1.patch/xbmc/threads/platform/linux/ThreadSchedImpl.cpp 2012-05-13 22:08:46.821190405 +0200 +@@ -0,0 +1,30 @@ ++/* ++ * Copyright (C) 2005-2011 Team XBMC ++ * http://www.xbmc.org ++ * ++ * 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 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 XBMC; see the file COPYING. If not, write to ++ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. ++ * http://www.gnu.org/copyleft/gpl.html ++ * ++ */ ++ ++int CThread::GetSchedRRPriority(void) ++{ ++ return GetNormalPriority(); ++} ++ ++bool CThread::SetPrioritySched_RR(int iPriority) ++{ ++ return false; ++} +diff -Naur xbmc-11.0.1/xbmc/threads/platform/pthreads/ThreadImpl.cpp xbmc-11.0.1.patch/xbmc/threads/platform/pthreads/ThreadImpl.cpp +--- xbmc-11.0.1/xbmc/threads/platform/pthreads/ThreadImpl.cpp 1970-01-01 01:00:00.000000000 +0100 ++++ xbmc-11.0.1.patch/xbmc/threads/platform/pthreads/ThreadImpl.cpp 2012-05-13 22:08:46.822190424 +0200 +@@ -0,0 +1,220 @@ ++/* ++ * Copyright (C) 2005-2011 Team XBMC ++ * http://www.xbmc.org ++ * ++ * 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 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 XBMC; see the file COPYING. If not, write to ++ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. ++ * http://www.gnu.org/copyleft/gpl.html ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++ ++void CThread::Create(bool bAutoDelete, unsigned stacksize) ++{ ++ if (m_ThreadId != 0) ++ { ++ CLog::Log(LOGERROR, "%s - fatal error creating thread- old thread id not null", __FUNCTION__); ++ exit(1); ++ } ++ m_iLastTime = XbmcThreads::SystemClockMillis() * 10000; ++ m_iLastUsage = 0; ++ m_fLastUsage = 0.0f; ++ m_bAutoDelete = bAutoDelete; ++ m_bStop = false; ++ m_StopEvent.Reset(); ++ m_TermEvent.Reset(); ++ m_StartEvent.Reset(); ++ ++ pthread_attr_t attr; ++ pthread_attr_init(&attr); ++ if (stacksize > PTHREAD_STACK_MIN) ++ pthread_attr_setstacksize(&attr, stacksize); ++ pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); ++ if (pthread_create(&m_ThreadId, &attr, (void*(*)(void*))staticThread, this) != 0) ++ { ++ CLog::Log(LOGNOTICE, "%s - fatal error creating thread",__FUNCTION__); ++ } ++ pthread_attr_destroy(&attr); ++} ++ ++void CThread::TermHandler() ++{ ++ ++} ++ ++void CThread::SetThreadInfo() ++{ ++ m_ThreadOpaque.LwpId = syscall(SYS_gettid); ++ ++ // start thread with nice level of appication ++ int appNice = getpriority(PRIO_PROCESS, getpid()); ++ if (setpriority(PRIO_PROCESS, m_ThreadOpaque.LwpId, appNice) != 0) ++ CLog::Log(LOGERROR, "%s: error %s", __FUNCTION__, strerror(errno)); ++} ++ ++ThreadIdentifier CThread::GetCurrentThreadId() ++{ ++ return pthread_self(); ++} ++ ++bool CThread::IsCurrentThread(const ThreadIdentifier tid) ++{ ++ return pthread_equal(pthread_self(), tid); ++} ++ ++int CThread::GetMinPriority(void) ++{ ++ // one level lower than application ++ return -1; ++} ++ ++int CThread::GetMaxPriority(void) ++{ ++ // one level higher than application ++ return 1; ++} ++ ++int CThread::GetNormalPriority(void) ++{ ++ // same level as application ++ return 0; ++} ++ ++bool CThread::SetPriority(const int iPriority) ++{ ++ bool bReturn = false; ++ ++ // wait until thread is running, it needs to get its lwp id ++ m_StartEvent.Wait(); ++ ++ CSingleLock lock(m_CriticalSection); ++ ++ // get min prio for SCHED_RR ++ int minRR = GetMaxPriority() + 1; ++ ++ if (!m_ThreadId) ++ bReturn = false; ++ else if (iPriority >= minRR) ++ bReturn = SetPrioritySched_RR(iPriority); ++ else ++ { ++ // get user max prio ++ struct rlimit limit; ++ int userMaxPrio; ++ if (getrlimit(RLIMIT_NICE, &limit) == 0) ++ { ++ userMaxPrio = limit.rlim_cur - 20; ++ } ++ else ++ userMaxPrio = 0; ++ ++ // keep priority in bounds ++ int prio = iPriority; ++ if (prio >= GetMaxPriority()) ++ prio = std::min(GetMaxPriority(), userMaxPrio); ++ if (prio < GetMinPriority()) ++ prio = GetMinPriority(); ++ ++ // nice level of application ++ int appNice = getpriority(PRIO_PROCESS, getpid()); ++ if (prio) ++ prio = prio > 0 ? appNice-1 : appNice+1; ++ ++ if (setpriority(PRIO_PROCESS, m_ThreadOpaque.LwpId, prio) == 0) ++ bReturn = true; ++ else ++ CLog::Log(LOGERROR, "%s: error %s", __FUNCTION__, strerror(errno)); ++ } ++ ++ return bReturn; ++} ++ ++int CThread::GetPriority() ++{ ++ int iReturn; ++ ++ // lwp id is valid after start signel has fired ++ m_StartEvent.Wait(); ++ ++ CSingleLock lock(m_CriticalSection); ++ ++ int appNice = getpriority(PRIO_PROCESS, getpid()); ++ int prio = getpriority(PRIO_PROCESS, m_ThreadOpaque.LwpId); ++ iReturn = appNice - prio; ++ ++ return iReturn; ++} ++ ++bool CThread::WaitForThreadExit(unsigned int milliseconds) ++{ ++ bool bReturn = m_TermEvent.WaitMSec(milliseconds); ++ ++ return bReturn; ++} ++ ++int64_t CThread::GetAbsoluteUsage() ++{ ++ CSingleLock lock(m_CriticalSection); ++ ++ if (!m_ThreadId) ++ return 0; ++ ++ clockid_t clock; ++ int64_t time = 0; ++ if (pthread_getcpuclockid(m_ThreadId, &clock) == 0) ++ { ++ struct timespec tp; ++ clock_gettime(clock, &tp); ++ time = (int64_t)tp.tv_sec * 10000000 + tp.tv_nsec/100; ++ } ++ return time; ++} ++ ++float CThread::GetRelativeUsage() ++{ ++ unsigned int iTime = XbmcThreads::SystemClockMillis(); ++ iTime *= 10000; // convert into 100ns tics ++ ++ // only update every 1 second ++ if( iTime < m_iLastTime + 1000*10000 ) return m_fLastUsage; ++ ++ int64_t iUsage = GetAbsoluteUsage(); ++ ++ if (m_iLastUsage > 0 && m_iLastTime > 0) ++ m_fLastUsage = (float)( iUsage - m_iLastUsage ) / (float)( iTime - m_iLastTime ); ++ ++ m_iLastUsage = iUsage; ++ m_iLastTime = iTime; ++ ++ return m_fLastUsage; ++} ++ ++int64_t CThread::GetCurrentThreadUsage() ++{ ++ pthread_t tid = pthread_self(); ++ clockid_t clock; ++ int64_t time = 0; ++ if (pthread_getcpuclockid(tid, &clock) == 0) ++ { ++ struct timespec tp; ++ clock_gettime(clock, &tp); ++ time = (int64_t)tp.tv_sec * 10000000 + tp.tv_nsec/100; ++ } ++ return time; ++} ++ +diff -Naur xbmc-11.0.1/xbmc/threads/platform/pthreads/ThreadImpl.h xbmc-11.0.1.patch/xbmc/threads/platform/pthreads/ThreadImpl.h +--- xbmc-11.0.1/xbmc/threads/platform/pthreads/ThreadImpl.h 1970-01-01 01:00:00.000000000 +0100 ++++ xbmc-11.0.1.patch/xbmc/threads/platform/pthreads/ThreadImpl.h 2012-05-13 22:08:46.822190424 +0200 +@@ -0,0 +1,39 @@ ++/* ++* Copyright (C) 2005-2011 Team XBMC ++* http://www.xbmc.org ++* ++* 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 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 XBMC; see the file COPYING. If not, write to ++* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. ++* http://www.gnu.org/copyleft/gpl.html ++* ++*/ ++ ++#pragma once ++ ++#include ++ ++struct threadOpaque ++{ ++ pid_t LwpId; ++}; ++ ++typedef pthread_t ThreadIdentifier; ++typedef threadOpaque ThreadOpaque; ++typedef int THREADFUNC; ++ ++namespace XbmcThreads ++{ ++ inline static void ThreadSleep(unsigned int millis) { usleep(millis*1000); } ++} ++ +diff -Naur xbmc-11.0.1/xbmc/threads/platform/ThreadImpl.cpp xbmc-11.0.1.patch/xbmc/threads/platform/ThreadImpl.cpp +--- xbmc-11.0.1/xbmc/threads/platform/ThreadImpl.cpp 1970-01-01 01:00:00.000000000 +0100 ++++ xbmc-11.0.1.patch/xbmc/threads/platform/ThreadImpl.cpp 2012-05-13 22:08:46.820190385 +0200 +@@ -0,0 +1,34 @@ ++/* ++ * Copyright (C) 2005-2011 Team XBMC ++ * http://www.xbmc.org ++ * ++ * 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 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 XBMC; see the file COPYING. If not, write to ++ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. ++ * http://www.gnu.org/copyleft/gpl.html ++ * ++ */ ++ ++#pragma once ++ ++#if (defined TARGET_POSIX) ++#include "threads/platform/pthreads/ThreadImpl.cpp" ++#if defined(TARGET_DARWIN_IOS) ++#include "threads/platform/darwin/ThreadSchedImpl.cpp" ++#else ++#include "threads/platform/linux/ThreadSchedImpl.cpp" ++#endif ++#elif (defined TARGET_WINDOWS) ++#include "threads/platform/win/ThreadImpl.cpp" ++#endif ++ +diff -Naur xbmc-11.0.1/xbmc/threads/platform/ThreadImpl.h xbmc-11.0.1.patch/xbmc/threads/platform/ThreadImpl.h +--- xbmc-11.0.1/xbmc/threads/platform/ThreadImpl.h 1970-01-01 01:00:00.000000000 +0100 ++++ xbmc-11.0.1.patch/xbmc/threads/platform/ThreadImpl.h 2012-05-13 22:08:46.820190385 +0200 +@@ -0,0 +1,28 @@ ++/* ++ * Copyright (C) 2005-2011 Team XBMC ++ * http://www.xbmc.org ++ * ++ * 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 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 XBMC; see the file COPYING. If not, write to ++ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. ++ * http://www.gnu.org/copyleft/gpl.html ++ * ++ */ ++ ++#pragma once ++ ++#if (defined TARGET_POSIX) ++#include "threads/platform/pthreads/ThreadImpl.h" ++#elif (defined TARGET_WINDOWS) ++#include "threads/platform/win/ThreadImpl.h" ++#endif +diff -Naur xbmc-11.0.1/xbmc/threads/platform/win/ThreadImpl.cpp xbmc-11.0.1.patch/xbmc/threads/platform/win/ThreadImpl.cpp +--- xbmc-11.0.1/xbmc/threads/platform/win/ThreadImpl.cpp 1970-01-01 01:00:00.000000000 +0100 ++++ xbmc-11.0.1.patch/xbmc/threads/platform/win/ThreadImpl.cpp 2012-05-13 22:08:46.823190444 +0200 +@@ -0,0 +1,207 @@ ++/* ++ * Copyright (C) 2005-2011 Team XBMC ++ * http://www.xbmc.org ++ * ++ * 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 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 XBMC; see the file COPYING. If not, write to ++ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. ++ * http://www.gnu.org/copyleft/gpl.html ++ * ++ */ ++ ++#include ++ ++ ++void CThread::Create(bool bAutoDelete, unsigned stacksize) ++{ ++ if (m_ThreadId != 0) ++ { ++ CLog::Log(LOGERROR, "%s - fatal error creating thread- old thread id not null", __FUNCTION__); ++ exit(1); ++ } ++ m_iLastTime = XbmcThreads::SystemClockMillis() * 10000; ++ m_iLastUsage = 0; ++ m_fLastUsage = 0.0f; ++ m_bAutoDelete = bAutoDelete; ++ m_bStop = false; ++ m_StopEvent.Reset(); ++ m_TermEvent.Reset(); ++ m_StartEvent.Reset(); ++ ++ m_ThreadOpaque.handle = CreateThread(NULL,stacksize, (LPTHREAD_START_ROUTINE)&staticThread, this, 0, &m_ThreadId); ++ if (m_ThreadOpaque.handle == NULL) ++ { ++ CLog::Log(LOGERROR, "%s - fatal error creating thread", __FUNCTION__); ++ } ++} ++ ++void CThread::TermHandler() ++{ ++ CloseHandle(m_ThreadOpaque.handle); ++ m_ThreadOpaque.handle = NULL; ++} ++ ++void CThread::SetThreadInfo() ++{ ++ const unsigned int MS_VC_EXCEPTION = 0x406d1388; ++ struct THREADNAME_INFO ++ { ++ DWORD dwType; // must be 0x1000 ++ LPCSTR szName; // pointer to name (in same addr space) ++ DWORD dwThreadID; // thread ID (-1 caller thread) ++ DWORD dwFlags; // reserved for future use, most be zero ++ } info; ++ ++ info.dwType = 0x1000; ++ info.szName = m_ThreadName.c_str(); ++ info.dwThreadID = m_ThreadId; ++ info.dwFlags = 0; ++ ++ try ++ { ++ RaiseException(MS_VC_EXCEPTION, 0, sizeof(info) / sizeof(ULONG_PTR), (ULONG_PTR *)&info); ++ } ++ catch(...) ++ { ++ } ++} ++ ++ThreadIdentifier CThread::GetCurrentThreadId() ++{ ++ return ::GetCurrentThreadId(); ++} ++ ++bool CThread::IsCurrentThread(const ThreadIdentifier tid) ++{ ++ return (::GetCurrentThreadId() == tid); ++} ++ ++int CThread::GetMinPriority(void) ++{ ++ return(THREAD_PRIORITY_IDLE); ++} ++ ++int CThread::GetMaxPriority(void) ++{ ++ return(THREAD_PRIORITY_HIGHEST); ++} ++ ++int CThread::GetNormalPriority(void) ++{ ++ return(THREAD_PRIORITY_NORMAL); ++} ++ ++int CThread::GetSchedRRPriority(void) ++{ ++ return GetNormalPriority(); ++} ++ ++bool CThread::SetPriority(const int iPriority) ++{ ++ bool bReturn = false; ++ ++ CSingleLock lock(m_CriticalSection); ++ if (m_ThreadOpaque.handle) ++ { ++ bReturn = SetThreadPriority(m_ThreadOpaque.handle, iPriority) == TRUE; ++ } ++ ++ return bReturn; ++} ++ ++int CThread::GetPriority() ++{ ++ CSingleLock lock(m_CriticalSection); ++ ++ int iReturn = THREAD_PRIORITY_NORMAL; ++ if (m_ThreadOpaque.handle) ++ { ++ iReturn = GetThreadPriority(m_ThreadOpaque.handle); ++ } ++ return iReturn; ++} ++ ++bool CThread::WaitForThreadExit(unsigned int milliseconds) ++{ ++ bool bReturn = true; ++ ++ CSingleLock lock(m_CriticalSection); ++ if (m_ThreadId && m_ThreadOpaque.handle != NULL) ++ { ++ // boost priority of thread we are waiting on to same as caller ++ int callee = GetThreadPriority(m_ThreadOpaque.handle); ++ int caller = GetThreadPriority(GetCurrentThread()); ++ if(caller > callee) ++ SetThreadPriority(m_ThreadOpaque.handle, caller); ++ ++ lock.Leave(); ++ bReturn = m_TermEvent.WaitMSec(milliseconds); ++ lock.Enter(); ++ ++ // restore thread priority if thread hasn't exited ++ if(caller > callee && m_ThreadOpaque.handle) ++ SetThreadPriority(m_ThreadOpaque.handle, callee); ++ } ++ return bReturn; ++} ++ ++int64_t CThread::GetAbsoluteUsage() ++{ ++ CSingleLock lock(m_CriticalSection); ++ ++ if (!m_ThreadOpaque.handle) ++ return 0; ++ ++ uint64_t time = 0; ++ FILETIME CreationTime, ExitTime, UserTime, KernelTime; ++ if( GetThreadTimes(m_ThreadOpaque.handle, &CreationTime, &ExitTime, &KernelTime, &UserTime ) ) ++ { ++ time = (((uint64_t)UserTime.dwHighDateTime) << 32) + ((uint64_t)UserTime.dwLowDateTime); ++ time += (((uint64_t)KernelTime.dwHighDateTime) << 32) + ((uint64_t)KernelTime.dwLowDateTime); ++ } ++ return time; ++} ++ ++float CThread::GetRelativeUsage() ++{ ++ unsigned int iTime = XbmcThreads::SystemClockMillis(); ++ iTime *= 10000; // convert into 100ns tics ++ ++ // only update every 1 second ++ if( iTime < m_iLastTime + 1000*10000 ) return m_fLastUsage; ++ ++ int64_t iUsage = GetAbsoluteUsage(); ++ ++ if (m_iLastUsage > 0 && m_iLastTime > 0) ++ m_fLastUsage = (float)( iUsage - m_iLastUsage ) / (float)( iTime - m_iLastTime ); ++ ++ m_iLastUsage = iUsage; ++ m_iLastTime = iTime; ++ ++ return m_fLastUsage; ++} ++ ++int64_t CThread::GetCurrentThreadUsage() ++{ ++ HANDLE h = GetCurrentThread(); ++ ++ uint64_t time = 0; ++ FILETIME CreationTime, ExitTime, UserTime, KernelTime; ++ if( GetThreadTimes(h, &CreationTime, &ExitTime, &KernelTime, &UserTime ) ) ++ { ++ time = (((uint64_t)UserTime.dwHighDateTime) << 32) + ((uint64_t)UserTime.dwLowDateTime); ++ time += (((uint64_t)KernelTime.dwHighDateTime) << 32) + ((uint64_t)KernelTime.dwLowDateTime); ++ } ++ return time; ++} ++ +diff -Naur xbmc-11.0.1/xbmc/threads/platform/win/ThreadImpl.h xbmc-11.0.1.patch/xbmc/threads/platform/win/ThreadImpl.h +--- xbmc-11.0.1/xbmc/threads/platform/win/ThreadImpl.h 1970-01-01 01:00:00.000000000 +0100 ++++ xbmc-11.0.1.patch/xbmc/threads/platform/win/ThreadImpl.h 2012-05-13 22:08:46.823190444 +0200 +@@ -0,0 +1,40 @@ ++/* ++* Copyright (C) 2005-2011 Team XBMC ++* http://www.xbmc.org ++* ++* 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 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 XBMC; see the file COPYING. If not, write to ++* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. ++* http://www.gnu.org/copyleft/gpl.html ++* ++*/ ++ ++#pragma once ++ ++#include ++ ++ ++struct threadOpaque ++{ ++ HANDLE handle; ++}; ++ ++typedef DWORD ThreadIdentifier; ++typedef threadOpaque ThreadOpaque; ++typedef DWORD THREADFUNC; ++ ++namespace XbmcThreads ++{ ++ inline static void ThreadSleep(unsigned int millis) { Sleep(millis); } ++} ++ +diff -Naur xbmc-11.0.1/xbmc/threads/Thread.cpp xbmc-11.0.1.patch/xbmc/threads/Thread.cpp +--- xbmc-11.0.1/xbmc/threads/Thread.cpp 2012-03-21 23:57:32.000000000 +0100 ++++ xbmc-11.0.1.patch/xbmc/threads/Thread.cpp 2012-05-13 22:08:46.872191415 +0200 +@@ -20,41 +20,27 @@ + + #include "threads/SystemClock.h" + #include "Thread.h" +-#ifndef _LINUX +-#include +-#include "utils/win32exception.h" +-#ifndef _MT +-#pragma message( "Please compile using multithreaded run-time libraries" ) +-#endif +-typedef unsigned (WINAPI *PBEGINTHREADEX_THREADFUNC)(LPVOID lpThreadParameter); +-#else +-#include "PlatformInclude.h" +-#include "XHandle.h" +-#include +-typedef int (*PBEGINTHREADEX_THREADFUNC)(LPVOID lpThreadParameter); +-#endif +- +-#if defined(__GNUC__) && !defined(__clang__) +-#include +-using namespace __cxxabiv1; +-#endif +- + #include "utils/log.h" + #include "utils/TimeUtils.h" + #include "threads/ThreadLocal.h" + ++#define __STDC_FORMAT_MACROS ++#include ++ + static XbmcThreads::ThreadLocal currentThread; + ++#include "threads/platform/ThreadImpl.cpp" ++ + ////////////////////////////////////////////////////////////////////// + // Construction/Destruction + ////////////////////////////////////////////////////////////////////// + +-CThread::CThread(const char* ThreadName) : m_StopEvent(true,true) ++CThread::CThread(const char* ThreadName) ++: m_StopEvent(true,true), m_TermEvent(true), m_StartEvent(true) + { + m_bStop = false; + + m_bAutoDelete = false; +- m_ThreadHandle = NULL; + m_ThreadId = 0; + m_iLastTime = 0; + m_iLastUsage = 0; +@@ -66,12 +52,12 @@ + m_ThreadName = ThreadName; + } + +-CThread::CThread(IRunnable* pRunnable, const char* ThreadName) : m_StopEvent(true,true) ++CThread::CThread(IRunnable* pRunnable, const char* ThreadName) ++: m_StopEvent(true,true), m_TermEvent(true), m_StartEvent(true) + { + m_bStop = false; + + m_bAutoDelete = false; +- m_ThreadHandle = NULL; + m_ThreadId = 0; + m_iLastTime = 0; + m_iLastUsage = 0; +@@ -85,171 +71,62 @@ + + CThread::~CThread() + { +- if (m_ThreadHandle != NULL) +- { +- CloseHandle(m_ThreadHandle); +- } +- m_ThreadHandle = NULL; +- ++ StopThread(); + } + +-#ifndef _WIN32 +-void CThread::term_handler (int signum) ++bool CThread::IsRunning() + { +- CLog::Log(LOGERROR,"thread 0x%lx (%lu) got signal %d. calling OnException and terminating thread abnormally.", (long unsigned int)pthread_self(), (long unsigned int)pthread_self(), signum); +- +- CThread* curThread = currentThread.get(); +- if (curThread) +- { +- curThread->m_bStop = TRUE; +- curThread->m_StopEvent.Set(); +- +- curThread->OnException(); +- if( curThread->IsAutoDelete() ) +- delete curThread; +- } +- +- pthread_exit(NULL); ++ return m_ThreadId ? true : false; + } + +-int CThread::staticThread(void* data) +-#else +-DWORD WINAPI CThread::staticThread(LPVOID* data) +-#endif ++THREADFUNC CThread::staticThread(void* data) + { + CThread* pThread = (CThread*)(data); ++ std::string name; ++ ThreadIdentifier id; ++ bool autodelete; ++ + if (!pThread) { + CLog::Log(LOGERROR,"%s, sanity failed. thread is NULL.",__FUNCTION__); + return 1; + } + +- if (pThread->m_ThreadName.empty()) +- pThread->m_ThreadName = pThread->GetTypeName(); +- pThread->SetDebugCallStackName(pThread->m_ThreadName.c_str()); ++ name = pThread->m_ThreadName; ++ id = pThread->m_ThreadId; ++ autodelete = pThread->m_bAutoDelete; + +- CLog::Log(LOGDEBUG,"Thread %s start, auto delete: %d", pThread->m_ThreadName.c_str(), pThread->IsAutoDelete()); ++ pThread->SetThreadInfo(); ++ ++ CLog::Log(LOGNOTICE,"Thread %s start, auto delete: %s", name.c_str(), (autodelete ? "true" : "false")); + + currentThread.set(pThread); +-#ifndef _LINUX +- /* install win32 exception translator */ +- win32_exception::install_handler(); +-#else +- struct sigaction action; +- action.sa_handler = term_handler; +- sigemptyset (&action.sa_mask); +- action.sa_flags = 0; +- //sigaction (SIGABRT, &action, NULL); +- //sigaction (SIGSEGV, &action, NULL); +-#endif ++ pThread->m_StartEvent.Set(); + ++ pThread->OnStartup(); ++ pThread->Process(); ++ pThread->OnExit(); + +- try +- { +- pThread->OnStartup(); +- } +-#ifndef _LINUX +- catch (const win32_exception &e) +- { +- e.writelog(__FUNCTION__); +- if( pThread->IsAutoDelete() ) +- { +- delete pThread; +- _endthreadex(123); +- return 0; +- } +- } +-#endif +- catch(...) +- { +- CLog::Log(LOGERROR, "%s - thread %s, Unhandled exception caught in thread startup, aborting. auto delete: %d", __FUNCTION__, pThread->m_ThreadName.c_str(), pThread->IsAutoDelete()); +- if( pThread->IsAutoDelete() ) +- { +- delete pThread; +-#ifndef _LINUX +- _endthreadex(123); +-#endif +- return 0; +- } +- } ++ // lock during termination ++ CSingleLock lock(pThread->m_CriticalSection); + +- try +- { +- pThread->Process(); +- } +-#ifndef _LINUX +- catch (const access_violation &e) +- { +- e.writelog(__FUNCTION__); +- } +- catch (const win32_exception &e) +- { +- e.writelog(__FUNCTION__); +- } +-#endif +- catch(...) +- { +- CLog::Log(LOGERROR, "%s - thread %s, Unhandled exception caught in thread process, attemping cleanup in OnExit", __FUNCTION__, pThread->m_ThreadName.c_str()); +- } ++ pThread->m_ThreadId = 0; ++ pThread->m_TermEvent.Set(); ++ pThread->TermHandler(); + +- try +- { +- pThread->OnExit(); +- } +-#ifndef _LINUX +- catch (const access_violation &e) +- { +- e.writelog(__FUNCTION__); +- } +- catch (const win32_exception &e) +- { +- e.writelog(__FUNCTION__); +- } +-#endif +- catch(...) +- { +- CLog::Log(LOGERROR, "%s - thread %s, Unhandled exception caught in thread exit", __FUNCTION__, pThread->m_ThreadName.c_str()); +- } ++ lock.Leave(); + +- if ( pThread->IsAutoDelete() ) ++ if (autodelete) + { +- CLog::Log(LOGDEBUG,"Thread %s %"PRIu64" terminating (autodelete)", pThread->m_ThreadName.c_str(), (uint64_t)CThread::GetCurrentThreadId()); ++ CLog::Log(LOGDEBUG,"Thread %s %"PRIu64" terminating (autodelete)", name.c_str(), (uint64_t)id); + delete pThread; + pThread = NULL; + } + else +- CLog::Log(LOGDEBUG,"Thread %s %"PRIu64" terminating", pThread->m_ThreadName.c_str(), (uint64_t)CThread::GetCurrentThreadId()); +- +-// DXMERGE - this looks like it might have used to have been useful for something... +-// g_graphicsContext.DeleteThreadContext(); ++ CLog::Log(LOGDEBUG,"Thread %s %"PRIu64" terminating", name.c_str(), (uint64_t)id); + +-#ifndef _LINUX +- _endthreadex(123); +-#endif + return 0; + } + +-void CThread::Create(bool bAutoDelete, unsigned stacksize) +-{ +- if (m_ThreadHandle != NULL) +- { +- throw 1; //ERROR should not b possible!!! +- } +- m_iLastTime = XbmcThreads::SystemClockMillis() * 10000; +- m_iLastUsage = 0; +- m_fLastUsage = 0.0f; +- m_bAutoDelete = bAutoDelete; +- m_bStop = false; +- m_StopEvent.Reset(); +- +- m_ThreadHandle = (HANDLE)_beginthreadex(NULL, stacksize, (PBEGINTHREADEX_THREADFUNC)staticThread, (void*)this, 0, &m_ThreadId); +- +-#ifdef _LINUX +- if (m_ThreadHandle && m_ThreadHandle->m_threadValid && m_bAutoDelete) +- // FIXME: WinAPI can truncate 64bit pthread ids +- pthread_detach(m_ThreadHandle->m_hThread); +-#endif +-} +- + bool CThread::IsAutoDelete() const + { + return m_bAutoDelete; +@@ -259,213 +136,17 @@ + { + m_bStop = true; + m_StopEvent.Set(); +- if (m_ThreadHandle && bWait) ++ CSingleLock lock(m_CriticalSection); ++ if (m_ThreadId && bWait) + { +- WaitForThreadExit(INFINITE); +- CloseHandle(m_ThreadHandle); +- m_ThreadHandle = NULL; ++ lock.Leave(); ++ WaitForThreadExit(0xFFFFFFFF); + } + } + + ThreadIdentifier CThread::ThreadId() const + { +-#ifdef _LINUX +- if (m_ThreadHandle && m_ThreadHandle->m_threadValid) +- return m_ThreadHandle->m_hThread; +- else +- return 0; +-#else + return m_ThreadId; +-#endif +-} +- +- +-CThread::operator HANDLE() +-{ +- return m_ThreadHandle; +-} +- +-CThread::operator HANDLE() const +-{ +- return m_ThreadHandle; +-} +- +-bool CThread::SetPriority(const int iPriority) +-// Set thread priority +-// Return true for success +-{ +- bool rtn = false; +- +- if (m_ThreadHandle) +- { +- rtn = SetThreadPriority( m_ThreadHandle, iPriority ) == TRUE; +- } +- +- return(rtn); +-} +- +-void CThread::SetPrioritySched_RR(void) +-{ +-#ifdef __APPLE__ +- // Changing to SCHED_RR is safe under OSX, you don't need elevated privileges and the +- // OSX scheduler will monitor SCHED_RR threads and drop to SCHED_OTHER if it detects +- // the thread running away. OSX automatically does this with the CoreAudio audio +- // device handler thread. +- int32_t result; +- thread_extended_policy_data_t theFixedPolicy; +- +- // make thread fixed, set to 'true' for a non-fixed thread +- theFixedPolicy.timeshare = false; +- result = thread_policy_set(pthread_mach_thread_np(ThreadId()), THREAD_EXTENDED_POLICY, +- (thread_policy_t)&theFixedPolicy, THREAD_EXTENDED_POLICY_COUNT); +- +- int policy; +- struct sched_param param; +- result = pthread_getschedparam(ThreadId(), &policy, ¶m ); +- // change from default SCHED_OTHER to SCHED_RR +- policy = SCHED_RR; +- result = pthread_setschedparam(ThreadId(), policy, ¶m ); +-#endif +-} +- +-int CThread::GetMinPriority(void) +-{ +-#if 0 +-//#if defined(__APPLE__) +- struct sched_param sched; +- int rtn, policy; +- +- rtn = pthread_getschedparam(ThreadId(), &policy, &sched); +- int min = sched_get_priority_min(policy); +- +- return(min); +-#else +- return(THREAD_PRIORITY_IDLE); +-#endif +-} +- +-int CThread::GetMaxPriority(void) +-{ +-#if 0 +-//#if defined(__APPLE__) +- struct sched_param sched; +- int rtn, policy; +- +- rtn = pthread_getschedparam(ThreadId(), &policy, &sched); +- int max = sched_get_priority_max(policy); +- +- return(max); +-#else +- return(THREAD_PRIORITY_HIGHEST); +-#endif +-} +- +-int CThread::GetNormalPriority(void) +-{ +-#if 0 +-//#if defined(__APPLE__) +- struct sched_param sched; +- int rtn, policy; +- +- rtn = pthread_getschedparam(ThreadId(), &policy, &sched); +- int min = sched_get_priority_min(policy); +- int max = sched_get_priority_max(policy); +- +- return( min + ((max-min) / 2) ); +-#else +- return(THREAD_PRIORITY_NORMAL); +-#endif +-} +- +- +-void CThread::SetDebugCallStackName( const char *name ) +-{ +-#ifdef _WIN32 +- const unsigned int MS_VC_EXCEPTION = 0x406d1388; +- struct THREADNAME_INFO +- { +- DWORD dwType; // must be 0x1000 +- LPCSTR szName; // pointer to name (in same addr space) +- DWORD dwThreadID; // thread ID (-1 caller thread) +- DWORD dwFlags; // reserved for future use, most be zero +- } info; +- +- info.dwType = 0x1000; +- info.szName = name; +- info.dwThreadID = m_ThreadId; +- info.dwFlags = 0; +- +- try +- { +- RaiseException(MS_VC_EXCEPTION, 0, sizeof(info) / sizeof(ULONG_PTR), (ULONG_PTR *)&info); +- } +- catch(...) +- { +- } +-#endif +-} +- +-// Get the thread name using the implementation dependant typeid() class +-// and attempt to clean it. +-std::string CThread::GetTypeName(void) +-{ +- std::string name = typeid(*this).name(); +- +-#if defined(_MSC_VER) +- // Visual Studio 2010 returns the name as "class CThread" etc +- if (name.substr(0, 6) == "class ") +- name = name.substr(6, name.length() - 6); +-#elif defined(__GNUC__) && !defined(__clang__) +- // gcc provides __cxa_demangle to demangle the name +- char* demangled = NULL; +- int status; +- +- demangled = __cxa_demangle(name.c_str(), NULL, 0, &status); +- if (status == 0) +- name = demangled; +- else +- CLog::Log(LOGDEBUG,"%s, __cxa_demangle(%s) failed with status %d", __FUNCTION__, name.c_str(), status); +- +- if (demangled) +- free(demangled); +-#endif +- +- return name; +-} +- +-bool CThread::WaitForThreadExit(unsigned int milliseconds) +-// Waits for thread to exit, timeout in given number of msec. +-// Returns true when thread ended +-{ +- if (!m_ThreadHandle) return true; +- +-#ifndef _LINUX +- // boost priority of thread we are waiting on to same as caller +- int callee = GetThreadPriority(m_ThreadHandle); +- int caller = GetThreadPriority(GetCurrentThread()); +- if(caller > callee) +- SetThreadPriority(m_ThreadHandle, caller); +- +- if (::WaitForSingleObject(m_ThreadHandle, milliseconds) != WAIT_TIMEOUT) +- return true; +- +- // restore thread priority if thread hasn't exited +- if(caller > callee) +- SetThreadPriority(m_ThreadHandle, callee); +-#else +- if (!(m_ThreadHandle->m_threadValid) || pthread_join(m_ThreadHandle->m_hThread, NULL) == 0) +- { +- m_ThreadHandle->m_threadValid = false; +- return true; +- } +-#endif +- +- return false; +-} +- +-HANDLE CThread::ThreadHandle() +-{ +- return m_ThreadHandle; + } + + void CThread::Process() +@@ -474,54 +155,14 @@ + m_pRunnable->Run(); + } + +-float CThread::GetRelativeUsage() +-{ +- unsigned __int64 iTime = XbmcThreads::SystemClockMillis(); +- iTime *= 10000; // convert into 100ns tics +- +- // only update every 1 second +- if( iTime < m_iLastTime + 1000*10000 ) return m_fLastUsage; +- +- FILETIME CreationTime, ExitTime, UserTime, KernelTime; +- if( GetThreadTimes( m_ThreadHandle, &CreationTime, &ExitTime, &KernelTime, &UserTime ) ) +- { +- unsigned __int64 iUsage = 0; +- iUsage += (((unsigned __int64)UserTime.dwHighDateTime) << 32) + ((unsigned __int64)UserTime.dwLowDateTime); +- iUsage += (((unsigned __int64)KernelTime.dwHighDateTime) << 32) + ((unsigned __int64)KernelTime.dwLowDateTime); +- +- if(m_iLastUsage > 0 && m_iLastTime > 0) +- m_fLastUsage = (float)( iUsage - m_iLastUsage ) / (float)( iTime - m_iLastTime ); +- +- m_iLastUsage = iUsage; +- m_iLastTime = iTime; +- +- return m_fLastUsage; +- } +- return 0.0f; +-} +- + bool CThread::IsCurrentThread() const + { + return IsCurrentThread(ThreadId()); + } + +- +-ThreadIdentifier CThread::GetCurrentThreadId() ++CThread* CThread::GetCurrentThread() + { +-#ifdef _LINUX +- return pthread_self(); +-#else +- return ::GetCurrentThreadId(); +-#endif +-} +- +-bool CThread::IsCurrentThread(const ThreadIdentifier tid) +-{ +-#ifdef _LINUX +- return pthread_equal(pthread_self(), tid); +-#else +- return (::GetCurrentThreadId() == tid); +-#endif ++ return currentThread.get(); + } + + void CThread::Sleep(unsigned int milliseconds) +@@ -529,7 +170,7 @@ + if(milliseconds > 10 && IsCurrentThread()) + m_StopEvent.WaitMSec(milliseconds); + else +- ::Sleep(milliseconds); ++ XbmcThreads::ThreadSleep(milliseconds); + } + + +diff -Naur xbmc-11.0.1/xbmc/threads/Thread.h xbmc-11.0.1.patch/xbmc/threads/Thread.h +--- xbmc-11.0.1/xbmc/threads/Thread.h 2012-03-21 23:57:32.000000000 +0100 ++++ xbmc-11.0.1.patch/xbmc/threads/Thread.h 2012-05-13 22:08:46.819190365 +0200 +@@ -23,19 +23,13 @@ + // + ////////////////////////////////////////////////////////////////////// + +-#if !defined(AFX_THREAD_H__ACFB7357_B961_4AC1_9FB2_779526219817__INCLUDED_) && !defined(AFX_THREAD_H__67621B15_8724_4B5D_9343_7667075C89F2__INCLUDED_) +-#define AFX_THREAD_H__ACFB7357_B961_4AC1_9FB2_779526219817__INCLUDED_ +- +-#if _MSC_VER > 1000 + #pragma once +-#endif // _MSC_VER > 1000 + + #include +-#include "system.h" // for HANDLE +-#ifdef _LINUX +-#include "PlatformInclude.h" +-#endif ++#include + #include "Event.h" ++#include "threads/ThreadImpl.h" ++#include "threads/ThreadLocal.h" + + class IRunnable + { +@@ -44,37 +38,36 @@ + virtual ~IRunnable() {} + }; + +-#ifdef CTHREAD +-#undef CTHREAD +-#endif +- + // minimum as mandated by XTL + #define THREAD_MINSTACKSIZE 0x10000 + + class CThread + { + public: +- CThread(const char* ThreadName = NULL); +- CThread(IRunnable* pRunnable, const char* ThreadName = NULL); ++ CThread(const char* ThreadName); ++ CThread(IRunnable* pRunnable, const char* ThreadName); + virtual ~CThread(); + void Create(bool bAutoDelete = false, unsigned stacksize = 0); + bool WaitForThreadExit(unsigned int milliseconds); + void Sleep(unsigned int milliseconds); + bool SetPriority(const int iPriority); +- void SetPrioritySched_RR(void); ++ int GetPriority(void); + int GetMinPriority(void); + int GetMaxPriority(void); + int GetNormalPriority(void); +- HANDLE ThreadHandle(); +- operator HANDLE(); +- operator HANDLE() const; ++ int GetSchedRRPriority(void); ++ bool SetPrioritySched_RR(int iPriority); + bool IsAutoDelete() const; + virtual void StopThread(bool bWait = true); + float GetRelativeUsage(); // returns the relative cpu usage of this thread since last call ++ int64_t GetAbsoluteUsage(); + bool IsCurrentThread() const; ++ bool IsRunning(); + + static bool IsCurrentThread(const ThreadIdentifier tid); + static ThreadIdentifier GetCurrentThreadId(); ++ static CThread* GetCurrentThread(); ++ static int64_t GetCurrentThreadUsage(); + protected: + virtual void OnStartup(){}; + virtual void OnExit(){}; +@@ -82,7 +75,6 @@ + virtual void Process(); + + volatile bool m_bStop; +- HANDLE m_ThreadHandle; + + enum WaitResponse { WAIT_INTERRUPTED = -1, WAIT_SIGNALED = 0, WAIT_TIMEDOUT = 1 }; + +@@ -108,36 +100,22 @@ + } + + private: +- /*! \brief set the threadname for the debugger/callstack, implementation dependent. +- */ +- void SetDebugCallStackName( const char *threadName ); +- std::string GetTypeName(void); +- +-private: ++ static THREADFUNC staticThread(void *data); + ThreadIdentifier ThreadId() const; ++ void SetThreadInfo(); ++ void TermHandler(); ++ ++ ThreadIdentifier m_ThreadId; ++ ThreadOpaque m_ThreadOpaque; + bool m_bAutoDelete; + CEvent m_StopEvent; +- unsigned m_ThreadId; // This value is unreliable on platforms using pthreads +- // Use m_ThreadHandle->m_hThread instead ++ CEvent m_TermEvent; ++ CEvent m_StartEvent; ++ CCriticalSection m_CriticalSection; + IRunnable* m_pRunnable; +- +- unsigned __int64 m_iLastUsage; +- unsigned __int64 m_iLastTime; ++ uint64_t m_iLastUsage; ++ uint64_t m_iLastTime; + float m_fLastUsage; + + std::string m_ThreadName; +- +-#ifdef _LINUX +- static void term_handler (int signum); +-#endif +- +-#ifndef _WIN32 +- static int staticThread(void* data); +-#else +- static DWORD WINAPI staticThread(LPVOID* data); +-#endif +- +-private: + }; +- +-#endif // !defined(AFX_THREAD_H__ACFB7357_B961_4AC1_9FB2_779526219817__INCLUDED_) +diff -Naur xbmc-11.0.1/xbmc/threads/ThreadImpl.h xbmc-11.0.1.patch/xbmc/threads/ThreadImpl.h +--- xbmc-11.0.1/xbmc/threads/ThreadImpl.h 1970-01-01 01:00:00.000000000 +0100 ++++ xbmc-11.0.1.patch/xbmc/threads/ThreadImpl.h 2012-05-13 22:08:46.819190365 +0200 +@@ -0,0 +1,25 @@ ++/* ++ * Copyright (C) 2005-2011 Team XBMC ++ * http://www.xbmc.org ++ * ++ * 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 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 XBMC; see the file COPYING. If not, write to ++ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. ++ * http://www.gnu.org/copyleft/gpl.html ++ * ++ */ ++ ++#pragma once ++ ++#include "threads/platform/ThreadImpl.h" ++ +diff -Naur xbmc-11.0.1/xbmc/utils/ActorProtocol.cpp xbmc-11.0.1.patch/xbmc/utils/ActorProtocol.cpp +--- xbmc-11.0.1/xbmc/utils/ActorProtocol.cpp 1970-01-01 01:00:00.000000000 +0100 ++++ xbmc-11.0.1.patch/xbmc/utils/ActorProtocol.cpp 2012-05-13 22:08:46.700188003 +0200 +@@ -0,0 +1,254 @@ ++/* ++ * Copyright (C) 2005-2011 Team XBMC ++ * http://www.xbmc.org ++ * ++ * 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 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 XBMC; see the file COPYING. If not, write to ++ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. ++ * http://www.gnu.org/copyleft/gpl.html ++ * ++ */ ++ ++#include "ActorProtocol.h" ++ ++using namespace Actor; ++ ++void Message::Release() ++{ ++ bool skip; ++ origin->Lock(); ++ skip = isSync ? !isSyncFini : false; ++ isSyncFini = true; ++ origin->Unlock(); ++ ++ if (skip) ++ return; ++ ++ // free data buffer ++ if (data != buffer) ++ delete [] data; ++ ++ // delete event in case of sync message ++ if (event) ++ delete event; ++ ++ origin->ReturnMessage(this); ++} ++ ++bool Message::Reply(int sig, void *data /* = NULL*/, int size /* = 0 */) ++{ ++ if (!isSync) ++ { ++ if (isOut) ++ return origin->SendInMessage(sig, data, size); ++ else ++ return origin->SendOutMessage(sig, data, size); ++ } ++ ++ origin->Lock(); ++ ++ if (!isSyncTimeout) ++ { ++ Message *msg = origin->GetMessage(); ++ msg->signal = sig; ++ msg->isOut = !isOut; ++ replyMessage = msg; ++ if (data) ++ { ++ if (size > MSG_INTERNAL_BUFFER_SIZE) ++ msg->data = new uint8_t[size]; ++ else ++ msg->data = msg->buffer; ++ memcpy(msg->data, data, size); ++ } ++ } ++ ++ origin->Unlock(); ++ ++ if (event) ++ event->Set(); ++ ++ return true; ++} ++ ++Protocol::~Protocol() ++{ ++ Message *msg; ++ Purge(); ++ while (!freeMessageQueue.empty()) ++ { ++ msg = freeMessageQueue.front(); ++ freeMessageQueue.pop(); ++ delete msg; ++ } ++} ++ ++Message *Protocol::GetMessage() ++{ ++ Message *msg; ++ ++ CSingleLock lock(criticalSection); ++ ++ if (!freeMessageQueue.empty()) ++ { ++ msg = freeMessageQueue.front(); ++ freeMessageQueue.pop(); ++ } ++ else ++ msg = new Message(); ++ ++ msg->isSync = false; ++ msg->isSyncFini = false; ++ msg->isSyncTimeout = false; ++ msg->event = NULL; ++ msg->data = NULL; ++ msg->payloadSize = 0; ++ msg->replyMessage = NULL; ++ msg->origin = this; ++ ++ return msg; ++} ++ ++void Protocol::ReturnMessage(Message *msg) ++{ ++ CSingleLock lock(criticalSection); ++ ++ freeMessageQueue.push(msg); ++} ++ ++bool Protocol::SendOutMessage(int signal, void *data /* = NULL */, int size /* = 0 */, Message *outMsg /* = NULL */) ++{ ++ Message *msg; ++ if (outMsg) ++ msg = outMsg; ++ else ++ msg = GetMessage(); ++ ++ msg->signal = signal; ++ msg->isOut = true; ++ ++ if (data) ++ { ++ if (size > MSG_INTERNAL_BUFFER_SIZE) ++ msg->data = new uint8_t[size]; ++ else ++ msg->data = msg->buffer; ++ memcpy(msg->data, data, size); ++ } ++ ++ { CSingleLock lock(criticalSection); ++ outMessages.push(msg); ++ } ++ containerOutEvent->Set(); ++ ++ return true; ++} ++ ++bool Protocol::SendInMessage(int signal, void *data /* = NULL */, int size /* = 0 */, Message *outMsg /* = NULL */) ++{ ++ Message *msg; ++ if (outMsg) ++ msg = outMsg; ++ else ++ msg = GetMessage(); ++ ++ msg->signal = signal; ++ msg->isOut = false; ++ ++ if (data) ++ { ++ if (size > MSG_INTERNAL_BUFFER_SIZE) ++ msg->data = new uint8_t[size]; ++ else ++ msg->data = msg->buffer; ++ memcpy(msg->data, data, size); ++ } ++ ++ { CSingleLock lock(criticalSection); ++ inMessages.push(msg); ++ } ++ containerInEvent->Set(); ++ ++ return true; ++} ++ ++ ++bool Protocol::SendOutMessageSync(int signal, Message **retMsg, int timeout, void *data /* = NULL */, int size /* = 0 */) ++{ ++ Message *msg = GetMessage(); ++ msg->isOut = true; ++ msg->isSync = true; ++ msg->event = new CEvent; ++ msg->event->Reset(); ++ SendOutMessage(signal, data, size, msg); ++ ++ if (!msg->event->WaitMSec(timeout)) ++ { ++ msg->origin->Lock(); ++ if (msg->replyMessage) ++ *retMsg = msg->replyMessage; ++ else ++ { ++ *retMsg = NULL; ++ msg->isSyncTimeout = true; ++ } ++ msg->origin->Unlock(); ++ } ++ else ++ *retMsg = msg->replyMessage; ++ ++ msg->Release(); ++ ++ if (*retMsg) ++ return true; ++ else ++ return false; ++} ++ ++bool Protocol::ReceiveOutMessage(Message **msg) ++{ ++ CSingleLock lock(criticalSection); ++ ++ if (outMessages.empty() || outDefered) ++ return false; ++ ++ *msg = outMessages.front(); ++ outMessages.pop(); ++ ++ return true; ++} ++ ++bool Protocol::ReceiveInMessage(Message **msg) ++{ ++ CSingleLock lock(criticalSection); ++ ++ if (inMessages.empty() || inDefered) ++ return false; ++ ++ *msg = inMessages.front(); ++ inMessages.pop(); ++ ++ return true; ++} ++ ++ ++void Protocol::Purge() ++{ ++ Message *msg; ++ ++ while (ReceiveInMessage(&msg)) ++ msg->Release(); ++ ++ while (ReceiveOutMessage(&msg)) ++ msg->Release(); ++} +diff -Naur xbmc-11.0.1/xbmc/utils/ActorProtocol.h xbmc-11.0.1.patch/xbmc/utils/ActorProtocol.h +--- xbmc-11.0.1/xbmc/utils/ActorProtocol.h 1970-01-01 01:00:00.000000000 +0100 ++++ xbmc-11.0.1.patch/xbmc/utils/ActorProtocol.h 2012-05-13 22:08:46.700188003 +0200 +@@ -0,0 +1,89 @@ ++ ++#pragma once ++ ++/* ++ * Copyright (C) 2005-2011 Team XBMC ++ * http://www.xbmc.org ++ * ++ * 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 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 XBMC; see the file COPYING. If not, write to ++ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. ++ * http://www.gnu.org/copyleft/gpl.html ++ * ++ */ ++ ++#include "threads/Thread.h" ++#include "utils/log.h" ++#include ++#include "memory.h" ++ ++#define MSG_INTERNAL_BUFFER_SIZE 32 ++ ++namespace Actor ++{ ++ ++class Protocol; ++ ++class Message ++{ ++ friend class Protocol; ++public: ++ int signal; ++ bool isSync; ++ bool isSyncFini; ++ bool isOut; ++ bool isSyncTimeout; ++ int payloadSize; ++ uint8_t buffer[MSG_INTERNAL_BUFFER_SIZE]; ++ uint8_t *data; ++ Message *replyMessage; ++ Protocol *origin; ++ CEvent *event; ++ ++ void Release(); ++ bool Reply(int sig, void *data = NULL, int size = 0); ++ ++private: ++ Message() {isSync = false; data = NULL; event = NULL; replyMessage = NULL;}; ++}; ++ ++class Protocol ++{ ++public: ++ Protocol(std::string name, CEvent* inEvent, CEvent *outEvent) ++ : inDefered(false), outDefered(false), portName(name) {containerInEvent = inEvent; containerOutEvent = outEvent;}; ++ virtual ~Protocol(); ++ Message *GetMessage(); ++ void ReturnMessage(Message *msg); ++ bool SendOutMessage(int signal, void *data = NULL, int size = 0, Message *outMsg = NULL); ++ bool SendInMessage(int signal, void *data = NULL, int size = 0, Message *outMsg = NULL); ++ bool SendOutMessageSync(int signal, Message **retMsg, int timeout, void *data = NULL, int size = 0); ++ bool ReceiveOutMessage(Message **msg); ++ bool ReceiveInMessage(Message **msg); ++ void Purge(); ++ void DeferIn(bool value) {inDefered = value;}; ++ void DeferOut(bool value) {outDefered = value;}; ++ void Lock() {criticalSection.lock();}; ++ void Unlock() {criticalSection.unlock();}; ++ std::string portName; ++ ++protected: ++ CEvent *containerInEvent, *containerOutEvent; ++ CCriticalSection criticalSection; ++ std::queue outMessages; ++ std::queue inMessages; ++ std::queue freeMessageQueue; ++ bool inDefered, outDefered; ++}; ++ ++} +diff -Naur xbmc-11.0.1/xbmc/utils/AlarmClock.cpp xbmc-11.0.1.patch/xbmc/utils/AlarmClock.cpp +--- xbmc-11.0.1/xbmc/utils/AlarmClock.cpp 2012-03-21 23:57:33.000000000 +0100 ++++ xbmc-11.0.1.patch/xbmc/utils/AlarmClock.cpp 2012-05-13 22:08:46.823190444 +0200 +@@ -28,7 +28,7 @@ + + using namespace std; + +-CAlarmClock::CAlarmClock() : m_bIsRunning(false) ++CAlarmClock::CAlarmClock() : CThread("CAlarmClock"), m_bIsRunning(false) + { + } + +diff -Naur xbmc-11.0.1/xbmc/utils/AsyncFileCopy.cpp xbmc-11.0.1.patch/xbmc/utils/AsyncFileCopy.cpp +--- xbmc-11.0.1/xbmc/utils/AsyncFileCopy.cpp 2012-03-21 23:57:33.000000000 +0100 ++++ xbmc-11.0.1.patch/xbmc/utils/AsyncFileCopy.cpp 2012-05-13 22:08:46.824190464 +0200 +@@ -26,7 +26,7 @@ + #include "log.h" + #include "utils/TimeUtils.h" + +-CAsyncFileCopy::CAsyncFileCopy() ++CAsyncFileCopy::CAsyncFileCopy() : CThread("CAsyncFileCopy") + { + m_cancelled = false; + m_succeeded = false; +diff -Naur xbmc-11.0.1/xbmc/utils/DownloadQueue.cpp xbmc-11.0.1.patch/xbmc/utils/DownloadQueue.cpp +--- xbmc-11.0.1/xbmc/utils/DownloadQueue.cpp 2012-03-21 23:57:33.000000000 +0100 ++++ xbmc-11.0.1.patch/xbmc/utils/DownloadQueue.cpp 2012-05-13 22:08:46.824190464 +0200 +@@ -32,7 +32,7 @@ + + WORD CDownloadQueue::m_wNextQueueId = 0; + +-CDownloadQueue::CDownloadQueue(void) : CThread() ++CDownloadQueue::CDownloadQueue(void) : CThread("CDownloadQueue") + { + m_bStop = false; + m_wQueueId = m_wNextQueueId++; +diff -Naur xbmc-11.0.1/xbmc/utils/DownloadQueue.h xbmc-11.0.1.patch/xbmc/utils/DownloadQueue.h +--- xbmc-11.0.1/xbmc/utils/DownloadQueue.h 2012-03-21 23:57:33.000000000 +0100 ++++ xbmc-11.0.1.patch/xbmc/utils/DownloadQueue.h 2012-05-13 22:08:46.825190483 +0200 +@@ -26,6 +26,8 @@ + #include "threads/CriticalSection.h" + #include "StdString.h" + ++#include "system.h" ++ + struct TICKET + { + TICKET(WORD aQueueId, DWORD aItemId) +diff -Naur xbmc-11.0.1/xbmc/utils/DownloadQueueManager.h xbmc-11.0.1.patch/xbmc/utils/DownloadQueueManager.h +--- xbmc-11.0.1/xbmc/utils/DownloadQueueManager.h 2012-03-21 23:57:33.000000000 +0100 ++++ xbmc-11.0.1.patch/xbmc/utils/DownloadQueueManager.h 2012-05-13 22:08:46.825190483 +0200 +@@ -22,6 +22,7 @@ + */ + + #include "DownloadQueue.h" ++#include "system.h" + + #define MAX_DOWNLOAD_QUEUES 3 + +diff -Naur xbmc-11.0.1/xbmc/utils/JobManager.cpp xbmc-11.0.1.patch/xbmc/utils/JobManager.cpp +--- xbmc-11.0.1/xbmc/utils/JobManager.cpp 2012-03-21 23:57:33.000000000 +0100 ++++ xbmc-11.0.1.patch/xbmc/utils/JobManager.cpp 2012-05-13 22:08:46.826190502 +0200 +@@ -24,6 +24,9 @@ + #include "threads/SingleLock.h" + #include "utils/log.h" + ++#include "system.h" ++ ++ + using namespace std; + + bool CJob::ShouldCancel(unsigned int progress, unsigned int total) const +diff -Naur xbmc-11.0.1/xbmc/utils/LCD.h xbmc-11.0.1.patch/xbmc/utils/LCD.h +--- xbmc-11.0.1/xbmc/utils/LCD.h 2012-03-21 23:57:33.000000000 +0100 ++++ xbmc-11.0.1.patch/xbmc/utils/LCD.h 2012-05-13 22:08:46.826190502 +0200 +@@ -68,8 +68,9 @@ + void LoadSkin(const CStdString &xmlFile); + void Reset(); + void Render(LCD_MODE mode); +- ILCD() : m_disableOnPlay(DISABLE_ON_PLAY_NONE), +- m_eCurrentCharset(CUSTOM_CHARSET_DEFAULT) {} ++ ILCD() : CThread("ILCD"), ++ m_disableOnPlay(DISABLE_ON_PLAY_NONE), ++ m_eCurrentCharset(CUSTOM_CHARSET_DEFAULT) {} + protected: + virtual void Process() = 0; + void StringToLCDCharSet(CStdString& strText); +diff -Naur xbmc-11.0.1/xbmc/utils/Makefile xbmc-11.0.1.patch/xbmc/utils/Makefile +--- xbmc-11.0.1/xbmc/utils/Makefile 2012-03-21 23:57:33.000000000 +0100 ++++ xbmc-11.0.1.patch/xbmc/utils/Makefile 2012-05-13 22:08:46.701188023 +0200 +@@ -57,6 +57,7 @@ + Weather.cpp \ + Win32Exception.cpp \ + XMLUtils.cpp \ ++ ActorProtocol.cpp \ + + LIB=utils.a + +diff -Naur xbmc-11.0.1/xbmc/utils/RssReader.cpp xbmc-11.0.1.patch/xbmc/utils/RssReader.cpp +--- xbmc-11.0.1/xbmc/utils/RssReader.cpp 2012-03-21 23:57:33.000000000 +0100 ++++ xbmc-11.0.1.patch/xbmc/utils/RssReader.cpp 2012-05-13 22:08:46.827190522 +0200 +@@ -44,7 +44,7 @@ + // Construction/Destruction + ////////////////////////////////////////////////////////////////////// + +-CRssReader::CRssReader() : CThread() ++CRssReader::CRssReader() : CThread("CRssReader") + { + m_pObserver = NULL; + m_spacesBetweenFeeds = 0; +diff -Naur xbmc-11.0.1/xbmc/utils/RssReader.h xbmc-11.0.1.patch/xbmc/utils/RssReader.h +--- xbmc-11.0.1/xbmc/utils/RssReader.h 2012-03-21 23:57:33.000000000 +0100 ++++ xbmc-11.0.1.patch/xbmc/utils/RssReader.h 2012-05-13 22:08:46.827190522 +0200 +@@ -39,6 +39,9 @@ + + #include "tinyXML/tinyxml.h" + ++#include "system.h" ++ ++ + #define RSS_COLOR_BODY 0 + #define RSS_COLOR_HEADLINE 1 + #define RSS_COLOR_CHANNEL 2 +diff -Naur xbmc-11.0.1/xbmc/utils/Splash.cpp xbmc-11.0.1.patch/xbmc/utils/Splash.cpp +--- xbmc-11.0.1/xbmc/utils/Splash.cpp 2012-03-21 23:57:33.000000000 +0100 ++++ xbmc-11.0.1.patch/xbmc/utils/Splash.cpp 2012-05-13 22:08:46.828190542 +0200 +@@ -31,7 +31,7 @@ + + using namespace XFILE; + +-CSplash::CSplash(const CStdString& imageName) ++CSplash::CSplash(const CStdString& imageName) : CThread("CSplash") + { + m_ImageName = imageName; + fade = 0.5; +@@ -139,5 +139,5 @@ + + bool CSplash::IsRunning() + { +- return (m_ThreadHandle != NULL); ++ return (IsRunning()); + } +diff -Naur xbmc-11.0.1/xbmc/utils/TuxBoxUtil.cpp xbmc-11.0.1.patch/xbmc/utils/TuxBoxUtil.cpp +--- xbmc-11.0.1/xbmc/utils/TuxBoxUtil.cpp 2012-03-21 23:57:33.000000000 +0100 ++++ xbmc-11.0.1.patch/xbmc/utils/TuxBoxUtil.cpp 2012-05-13 22:08:46.829190562 +0200 +@@ -48,7 +48,7 @@ + CTuxBoxUtil g_tuxbox; + CTuxBoxService g_tuxboxService; + +-CTuxBoxService::CTuxBoxService() ++CTuxBoxService::CTuxBoxService() : CThread("CTuxBoxService") + { + } + CTuxBoxService::~CTuxBoxService() +diff -Naur xbmc-11.0.1/xbmc/video/dialogs/GUIDialogVideoSettings.cpp xbmc-11.0.1.patch/xbmc/video/dialogs/GUIDialogVideoSettings.cpp +--- xbmc-11.0.1/xbmc/video/dialogs/GUIDialogVideoSettings.cpp 2012-03-21 23:57:32.000000000 +0100 ++++ xbmc-11.0.1.patch/xbmc/video/dialogs/GUIDialogVideoSettings.cpp 2012-05-13 22:18:16.222981047 +0200 +@@ -105,12 +105,12 @@ + entries.push_back(make_pair(VS_INTERLACEMETHOD_INVERSE_TELECINE , 16314)); + entries.push_back(make_pair(VS_INTERLACEMETHOD_VDPAU_TEMPORAL_SPATIAL , 16311)); + entries.push_back(make_pair(VS_INTERLACEMETHOD_VDPAU_TEMPORAL , 16310)); +- entries.push_back(make_pair(VS_INTERLACEMETHOD_VDPAU_BOB , 16021)); ++ entries.push_back(make_pair(VS_INTERLACEMETHOD_VDPAU_BOB , 16326)); + entries.push_back(make_pair(VS_INTERLACEMETHOD_VDPAU_TEMPORAL_SPATIAL_HALF, 16318)); + entries.push_back(make_pair(VS_INTERLACEMETHOD_VDPAU_TEMPORAL_HALF , 16317)); +- entries.push_back(make_pair(VS_INTERLACEMETHOD_VDPAU_INVERSE_TELECINE , 16314)); + entries.push_back(make_pair(VS_INTERLACEMETHOD_DXVA_BOB , 16320)); + entries.push_back(make_pair(VS_INTERLACEMETHOD_DXVA_BEST , 16321)); ++ entries.push_back(make_pair(VS_INTERLACEMETHOD_XVBA , 16327)); + + /* remove unsupported methods */ + for(vector >::iterator it = entries.begin(); it != entries.end();) +diff -Naur xbmc-11.0.1/xbmc/video/VideoInfoDownloader.cpp xbmc-11.0.1.patch/xbmc/video/VideoInfoDownloader.cpp +--- xbmc-11.0.1/xbmc/video/VideoInfoDownloader.cpp 2012-03-21 23:57:32.000000000 +0100 ++++ xbmc-11.0.1.patch/xbmc/video/VideoInfoDownloader.cpp 2012-05-13 22:08:46.829190562 +0200 +@@ -116,7 +116,7 @@ + m_state = FIND_MOVIE; + m_strMovie = strMovie; + m_found = 0; +- if (ThreadHandle()) ++ if (IsRunning()) + StopThread(); + Create(); + while (m_state != DO_NOTHING) +@@ -160,7 +160,7 @@ + { // threaded version + m_state = GET_DETAILS; + m_found = 0; +- if (ThreadHandle()) ++ if (IsRunning()) + StopThread(); + Create(); + while (!m_found) +@@ -195,7 +195,7 @@ + { // threaded version + m_state = GET_EPISODE_DETAILS; + m_found = 0; +- if (ThreadHandle()) ++ if (IsRunning()) + StopThread(); + Create(); + while (!m_found) +@@ -230,7 +230,7 @@ + { // threaded version + m_state = GET_EPISODE_LIST; + m_found = 0; +- if (ThreadHandle()) ++ if (IsRunning()) + StopThread(); + Create(); + while (!m_found) +diff -Naur xbmc-11.0.1/xbmc/video/VideoInfoDownloader.h xbmc-11.0.1.patch/xbmc/video/VideoInfoDownloader.h +--- xbmc-11.0.1/xbmc/video/VideoInfoDownloader.h 2012-03-21 23:57:32.000000000 +0100 ++++ xbmc-11.0.1.patch/xbmc/video/VideoInfoDownloader.h 2012-05-13 22:08:46.830190582 +0200 +@@ -42,7 +42,7 @@ + class CVideoInfoDownloader : public CThread + { + public: +- CVideoInfoDownloader(const ADDON::ScraperPtr &scraper) : m_info(scraper) {} ++ CVideoInfoDownloader(const ADDON::ScraperPtr &scraper) : CThread("CVideoInfoDownloader"), m_info(scraper) {} + virtual ~CVideoInfoDownloader() {} + + // threaded lookup functions +diff -Naur xbmc-11.0.1/xbmc/video/VideoInfoScanner.cpp xbmc-11.0.1.patch/xbmc/video/VideoInfoScanner.cpp +--- xbmc-11.0.1/xbmc/video/VideoInfoScanner.cpp 2012-03-21 23:57:32.000000000 +0100 ++++ xbmc-11.0.1.patch/xbmc/video/VideoInfoScanner.cpp 2012-05-13 22:08:46.831190602 +0200 +@@ -54,7 +54,7 @@ + namespace VIDEO + { + +- CVideoInfoScanner::CVideoInfoScanner() ++ CVideoInfoScanner::CVideoInfoScanner() : CThread("CVideoInfoScanner") + { + m_bRunning = false; + m_pObserver = NULL; +diff -Naur xbmc-11.0.1/xbmc/video/VideoReferenceClock.cpp xbmc-11.0.1.patch/xbmc/video/VideoReferenceClock.cpp +--- xbmc-11.0.1/xbmc/video/VideoReferenceClock.cpp 2012-03-21 23:57:32.000000000 +0100 ++++ xbmc-11.0.1.patch/xbmc/video/VideoReferenceClock.cpp 2012-05-13 22:08:47.011194174 +0200 +@@ -31,6 +31,7 @@ + #include + #include + #include "windowing/WindowingFactory.h" ++ #include "settings/AdvancedSettings.h" + #define NVSETTINGSCMD "nvidia-settings -nt -q RefreshRate3" + #elif defined(__APPLE__) && !defined(__arm__) + #include +@@ -107,7 +108,7 @@ + + #endif + +-CVideoReferenceClock::CVideoReferenceClock() ++CVideoReferenceClock::CVideoReferenceClock() : CThread("CVideoReferenceClock") + { + m_SystemFrequency = CurrentHostFrequency(); + m_ClockSpeed = 1.0; +@@ -118,7 +119,7 @@ + + #if defined(HAS_GLX) && defined(HAS_XRANDR) + m_Dpy = NULL; +- m_UseNvSettings = true; ++ m_UseNvSettings = false; + #endif + } + +@@ -270,12 +271,21 @@ + return false; + } + ++ m_bIsATI = false; ++ m_bPolling = false; ++ + CStdString Vendor = g_Windowing.GetRenderVendor(); + Vendor.ToLower(); + if (Vendor.compare(0, 3, "ati") == 0) + { + CLog::Log(LOGDEBUG, "CVideoReferenceClock: GL_VENDOR: %s, using ati workaround", Vendor.c_str()); + m_bIsATI = true; ++ m_bPolling = true; ++ } ++ if (g_advancedSettings.m_vblankPolling) ++ { ++ m_bPolling = true; ++ CLog::Log(LOGDEBUG, "CVideoReferenceClock: use polling"); + } + + m_vInfo = glXChooseVisual(m_Dpy, DefaultScreen(m_Dpy), singleBufferAttributes); +@@ -285,7 +295,7 @@ + return false; + } + +- if (!m_bIsATI) ++ if (!m_bPolling) + { + Swa.border_pixel = 0; + Swa.event_mask = StructureNotifyMask; +@@ -313,7 +323,7 @@ + return false; + } + +- if (!m_bIsATI) ++ if (!m_bPolling) + ReturnV = glXMakeCurrent(m_Dpy, m_Window, m_Context); + else + ReturnV = glXMakeCurrent(m_Dpy, m_glPixmap, m_Context); +@@ -324,7 +334,7 @@ + return false; + } + +- if (!m_bIsATI) ++ if (!m_bPolling) + { + m_glXWaitVideoSyncSGI = (int (*)(int, int, unsigned int*))glXGetProcAddress((const GLubyte*)"glXWaitVideoSyncSGI"); + if (!m_glXWaitVideoSyncSGI) +@@ -369,6 +379,9 @@ + UpdateRefreshrate(true); //forced refreshrate update + m_MissedVblanks = 0; + ++ if (m_bPolling) ++ SetPriority(1); ++ + return true; + } + +@@ -567,7 +580,7 @@ + while(!m_bStop) + { + //wait for the next vblank +- if (!m_bIsATI) ++ if (!m_bPolling) + { + ReturnV = m_glXWaitVideoSyncSGI(2, (VblankCount + 1) % 2, &VblankCount); + m_glXGetVideoSyncSGI(&VblankCount); //the vblank count returned by glXWaitVideoSyncSGI is not always correct +@@ -591,7 +604,7 @@ + sleepTime = std::max(int(300000LL/m_RefreshRate), sleepTime); + + unsigned int iterations = 0; +- while (VblankCount == PrevVblankCount && !m_bStop) ++ while (VblankCount == PrevVblankCount && iterations < 500 && !m_bStop) + { + usleep(sleepTime); + m_glXGetVideoSyncSGI(&VblankCount); +@@ -652,7 +665,7 @@ + } + + CLog::Log(LOGDEBUG, "CVideoReferenceClock: Attaching glX context"); +- if (!m_bIsATI) ++ if (!m_bPolling) + ReturnV = glXMakeCurrent(m_Dpy, m_Window, m_Context); + else + ReturnV = glXMakeCurrent(m_Dpy, m_glPixmap, m_Context); +@@ -1275,6 +1288,9 @@ + + if (m_UseVblank) //when true the vblank is used as clock source + { ++ if (Target < m_CurrTime) ++ Target = m_CurrTime + 0.5/m_RefreshRate; ++ + while (m_CurrTime < Target) + { + //calculate how long to sleep before we should have gotten a signal that a vblank happened +diff -Naur xbmc-11.0.1/xbmc/video/VideoReferenceClock.h xbmc-11.0.1.patch/xbmc/video/VideoReferenceClock.h +--- xbmc-11.0.1/xbmc/video/VideoReferenceClock.h 2012-03-21 23:57:32.000000000 +0100 ++++ xbmc-11.0.1.patch/xbmc/video/VideoReferenceClock.h 2012-05-13 22:08:46.917192309 +0200 +@@ -125,6 +125,7 @@ + + bool m_UseNvSettings; + bool m_bIsATI; ++ bool m_bPolling; + + #elif defined(_WIN32) && defined(HAS_DX) + bool SetupD3D(); +diff -Naur xbmc-11.0.1/xbmc/win32/PlatformDefs.h xbmc-11.0.1.patch/xbmc/win32/PlatformDefs.h +--- xbmc-11.0.1/xbmc/win32/PlatformDefs.h 2012-03-21 23:57:34.000000000 +0100 ++++ xbmc-11.0.1.patch/xbmc/win32/PlatformDefs.h 2012-05-13 22:08:46.870191375 +0200 +@@ -33,7 +33,6 @@ + typedef __int64 fpos64_t; + typedef __int64 __off64_t; + typedef long __off_t; +-typedef unsigned long ThreadIdentifier; + + #define ssize_t int + +diff -Naur xbmc-11.0.1/xbmc/win32/WindowHelper.cpp xbmc-11.0.1.patch/xbmc/win32/WindowHelper.cpp +--- xbmc-11.0.1/xbmc/win32/WindowHelper.cpp 2012-03-21 23:57:34.000000000 +0100 ++++ xbmc-11.0.1.patch/xbmc/win32/WindowHelper.cpp 2012-05-13 22:08:46.871191395 +0200 +@@ -28,7 +28,7 @@ + + CWHelper g_windowHelper; + +-CWHelper::CWHelper(void) ++CWHelper::CWHelper(void) : CThread("CWHelper") + { + m_hwnd = NULL; + m_hProcess = NULL; +diff -Naur xbmc-11.0.1/xbmc/windowing/X11/WinSystemX11.cpp xbmc-11.0.1.patch/xbmc/windowing/X11/WinSystemX11.cpp +--- xbmc-11.0.1/xbmc/windowing/X11/WinSystemX11.cpp 2012-03-21 23:57:33.000000000 +0100 ++++ xbmc-11.0.1.patch/xbmc/windowing/X11/WinSystemX11.cpp 2012-05-13 22:08:47.023194413 +0200 +@@ -35,6 +35,8 @@ + #include + #include "cores/VideoRenderers/RenderManager.h" + #include "utils/TimeUtils.h" ++#include "settings/AdvancedSettings.h" ++#include "settings/GUISettings.h" + + #if defined(HAS_XRANDR) + #include +@@ -52,6 +54,7 @@ + m_wmWindow = 0; + m_bWasFullScreenBeforeMinimize = false; + m_dpyLostTime = 0; ++ m_internalModeSwitch = false; + + XSetErrorHandler(XErrorHandler); + } +@@ -178,6 +181,45 @@ + return false; + } + ++void CWinSystemX11::RefreshWindow() ++{ ++ // save current mode if this is not an internal request ++ if (!m_internalModeSwitch) ++ { ++ CLog::Log(LOGNOTICE, "CWinSystemX11::RefreshWindow - external or initial xrandr event"); ++ m_xrandrOut = g_xrandr.GetCurrentOutput(); ++ m_xrandrMode = g_xrandr.GetCurrentMode(m_xrandrOut.name); ++ } ++ m_internalModeSwitch = false; ++ ++ g_xrandr.Query(true); ++ XOutput out = g_xrandr.GetCurrentOutput(); ++ XMode mode = g_xrandr.GetCurrentMode(out.name); ++ ++ RESOLUTION_INFO res; ++ unsigned int i; ++ bool found(false); ++ for (i = RES_DESKTOP; i < g_settings.m_ResInfo.size(); ++i) ++ { ++ if (g_settings.m_ResInfo[i].strId == mode.id) ++ { ++ found = true; ++ break; ++ } ++ } ++ ++ if (!found) ++ { ++ CLog::Log(LOGERROR, "CWinSystemX11::RefreshWindow - could not find resolution"); ++ return; ++ } ++ ++ g_graphicsContext.SetVideoResolution((RESOLUTION)i, true); ++ g_guiSettings.SetInt("window.width", mode.w); ++ g_guiSettings.SetInt("window.height", mode.h); ++ g_settings.Save(); ++} ++ + bool CWinSystemX11::SetFullScreen(bool fullScreen, RESOLUTION_INFO& res, bool blankOtherDisplays) + { + m_nWidth = res.iWidth; +@@ -193,13 +235,32 @@ + mode.hz = res.fRefreshRate; + mode.id = res.strId; + +- if(m_bFullScreen) ++ XOutput currout = g_xrandr.GetCurrentOutput(); ++ XMode currmode = g_xrandr.GetCurrentMode(currout.name); ++ ++ if (m_xrandrOut.name.empty()) ++ { ++ m_xrandrOut = currout; ++ m_xrandrMode = currmode; ++ } ++ ++ if(!m_bFullScreen) + { ++ // reset to mode we had before internal mode switch ++ out = m_xrandrOut; ++ mode = m_xrandrMode; ++ } ++ ++ // only call xrandr if mode changes ++ if (currout.name != out.name || currmode.w != mode.w || currmode.h != mode.h || ++ currmode.hz != mode.hz || currmode.id != mode.id) ++ { ++ CLog::Log(LOGNOTICE, "CWinSystemX11::SetFullScreen - calling xrandr"); + OnLostDevice(); ++ m_internalModeSwitch = true; + g_xrandr.SetMode(out, mode); + } +- else +- g_xrandr.RestoreState(); ++ + #endif + + int options = SDL_OPENGL; +@@ -493,6 +554,7 @@ + if (bGotEvent || bTimeout) + { + CLog::Log(LOGDEBUG, "%s - notify display reset event", __FUNCTION__); ++ RefreshWindow(); + + CSingleLock lock(m_resourceSection); + +diff -Naur xbmc-11.0.1/xbmc/windowing/X11/WinSystemX11.h xbmc-11.0.1.patch/xbmc/windowing/X11/WinSystemX11.h +--- xbmc-11.0.1/xbmc/windowing/X11/WinSystemX11.h 2012-03-21 23:57:33.000000000 +0100 ++++ xbmc-11.0.1.patch/xbmc/windowing/X11/WinSystemX11.h 2012-05-13 22:08:47.024194433 +0200 +@@ -27,6 +27,7 @@ + #include "utils/Stopwatch.h" + #include + #include "threads/CriticalSection.h" ++#include "XRandR.h" + + class IDispResource; + +@@ -60,6 +61,9 @@ + // Local to WinSystemX11 only + Display* GetDisplay() { return m_dpy; } + GLXWindow GetWindow() { return m_glWindow; } ++ GLXContext GetGlxContext() { return m_glContext; } ++ Window GetWmWindow() { return m_wmWindow; } ++ void RefreshWindow(); + + protected: + bool RefreshGlxContext(); +@@ -76,6 +80,9 @@ + CCriticalSection m_resourceSection; + std::vector m_resources; + uint64_t m_dpyLostTime; ++ XOutput m_xrandrOut; ++ XMode m_xrandrMode; ++ bool m_internalModeSwitch; + + private: + bool IsSuitableVisual(XVisualInfo *vInfo);