From 2689cd4218201ae9ea35238684757196a1900d2b Mon Sep 17 00:00:00 2001 From: vpeter4 Date: Thu, 21 Feb 2013 16:45:48 +0100 Subject: [PATCH 01/13] sundtek-mediatv: bump version added addon settings enable HW PID filter (enabled for RPi by default) enable IR receiver allow sharing local tuner over network use network tuners sundtek's binaries are downloaded on first run automatically download new version of the binaries if available added preload library to .profile (to run mediaclient, w_scan, ... from console) --- .../driver/{sundtek => sundtek-mediatv}/addon | 0 .../changelog.txt | 9 +-- .../config/sundtek.conf | 3 - .../config/sundtek.conf.full | 0 .../icon/icon.png | Bin .../driver/{sundtek => sundtek-mediatv}/meta | 4 +- .../settings-default.xml | 0 .../source/bin/sundtek.start | 2 +- .../source/bin/sundtek.stop | 2 +- .../source/bin/userspace-driver.sh | 57 ++++++++---------- .../source/default.py | 0 .../resources/language/English/strings.xml | 0 .../source/resources/settings.xml | 14 ++--- .../source/sleep.d/sundtek-mediatv.power} | 8 +-- .../sundtek/source/bin/device-attached.sh | 25 -------- 15 files changed, 43 insertions(+), 81 deletions(-) rename packages/addons/driver/{sundtek => sundtek-mediatv}/addon (100%) rename packages/addons/driver/{sundtek => sundtek-mediatv}/changelog.txt (89%) rename packages/addons/driver/{sundtek => sundtek-mediatv}/config/sundtek.conf (78%) rename packages/addons/driver/{sundtek => sundtek-mediatv}/config/sundtek.conf.full (100%) rename packages/addons/driver/{sundtek => sundtek-mediatv}/icon/icon.png (100%) rename packages/addons/driver/{sundtek => sundtek-mediatv}/meta (97%) rename packages/addons/driver/{sundtek => sundtek-mediatv}/settings-default.xml (100%) rename packages/addons/driver/{sundtek => sundtek-mediatv}/source/bin/sundtek.start (95%) rename packages/addons/driver/{sundtek => sundtek-mediatv}/source/bin/sundtek.stop (95%) rename packages/addons/driver/{sundtek => sundtek-mediatv}/source/bin/userspace-driver.sh (86%) rename packages/addons/driver/{sundtek => sundtek-mediatv}/source/default.py (100%) rename packages/addons/driver/{sundtek => sundtek-mediatv}/source/resources/language/English/strings.xml (100%) rename packages/addons/driver/{sundtek => sundtek-mediatv}/source/resources/settings.xml (72%) rename packages/addons/driver/{sundtek/source/sleep.d/sundtek.power => sundtek-mediatv/source/sleep.d/sundtek-mediatv.power} (91%) delete mode 100644 packages/addons/driver/sundtek/source/bin/device-attached.sh diff --git a/packages/addons/driver/sundtek/addon b/packages/addons/driver/sundtek-mediatv/addon similarity index 100% rename from packages/addons/driver/sundtek/addon rename to packages/addons/driver/sundtek-mediatv/addon diff --git a/packages/addons/driver/sundtek/changelog.txt b/packages/addons/driver/sundtek-mediatv/changelog.txt similarity index 89% rename from packages/addons/driver/sundtek/changelog.txt rename to packages/addons/driver/sundtek-mediatv/changelog.txt index be4e096e2a..f3f1d1e893 100644 --- a/packages/addons/driver/sundtek/changelog.txt +++ b/packages/addons/driver/sundtek-mediatv/changelog.txt @@ -1,14 +1,9 @@ -3.0.3 - new addon settings: +3.0.1 + added addon settings enable HW PID filter (enabled for RPi by default) enable IR receiver allow sharing local tuner over network use network tuners -3.0.2 - special version -3.0.1 - addon renamed to just sundtek - added addon settings sundtek's binaries are downloaded on first run automatically download new version of the binaries if available added preload library to .profile (to run mediaclient, w_scan, ... from console) diff --git a/packages/addons/driver/sundtek/config/sundtek.conf b/packages/addons/driver/sundtek-mediatv/config/sundtek.conf similarity index 78% rename from packages/addons/driver/sundtek/config/sundtek.conf rename to packages/addons/driver/sundtek-mediatv/config/sundtek.conf index 15a81288a6..5f9d4acadb 100644 --- a/packages/addons/driver/sundtek/config/sundtek.conf +++ b/packages/addons/driver/sundtek-mediatv/config/sundtek.conf @@ -1,9 +1,6 @@ # # sundtek.conf # -# Call attach/detach script when new device appears/disappears -# Do not change this line (OpenElec addon require this) ! -device_attach=/storage/.xbmc/addons/driver.dvb.sundtek/bin/device-attached.sh # enable HW PID filter (default on for RPi) use_hwpidfilter=off diff --git a/packages/addons/driver/sundtek/config/sundtek.conf.full b/packages/addons/driver/sundtek-mediatv/config/sundtek.conf.full similarity index 100% rename from packages/addons/driver/sundtek/config/sundtek.conf.full rename to packages/addons/driver/sundtek-mediatv/config/sundtek.conf.full diff --git a/packages/addons/driver/sundtek/icon/icon.png b/packages/addons/driver/sundtek-mediatv/icon/icon.png similarity index 100% rename from packages/addons/driver/sundtek/icon/icon.png rename to packages/addons/driver/sundtek-mediatv/icon/icon.png diff --git a/packages/addons/driver/sundtek/meta b/packages/addons/driver/sundtek-mediatv/meta similarity index 97% rename from packages/addons/driver/sundtek/meta rename to packages/addons/driver/sundtek-mediatv/meta index afeb13dab2..725a629276 100644 --- a/packages/addons/driver/sundtek/meta +++ b/packages/addons/driver/sundtek-mediatv/meta @@ -18,9 +18,9 @@ # http://www.gnu.org/copyleft/gpl.html ################################################################################ -PKG_NAME="sundtek" +PKG_NAME="sundtek-mediatv" PKG_VERSION="3.0" -PKG_REV="3" +PKG_REV="1" PKG_ARCH="any" PKG_LICENSE="nonfree" PKG_SITE="http://support.sundtek.com/" diff --git a/packages/addons/driver/sundtek/settings-default.xml b/packages/addons/driver/sundtek-mediatv/settings-default.xml similarity index 100% rename from packages/addons/driver/sundtek/settings-default.xml rename to packages/addons/driver/sundtek-mediatv/settings-default.xml diff --git a/packages/addons/driver/sundtek/source/bin/sundtek.start b/packages/addons/driver/sundtek-mediatv/source/bin/sundtek.start similarity index 95% rename from packages/addons/driver/sundtek/source/bin/sundtek.start rename to packages/addons/driver/sundtek-mediatv/source/bin/sundtek.start index eed33185de..232caa545d 100644 --- a/packages/addons/driver/sundtek/source/bin/sundtek.start +++ b/packages/addons/driver/sundtek-mediatv/source/bin/sundtek.start @@ -22,7 +22,7 @@ . /etc/profile -ADDON_DIR="$HOME/.xbmc/addons/driver.dvb.sundtek" +ADDON_DIR="$HOME/.xbmc/addons/driver.dvb.sundtek-mediatv" logger -t Sundtek "### Sundtek manual start ###" . $ADDON_DIR/bin/userspace-driver.sh diff --git a/packages/addons/driver/sundtek/source/bin/sundtek.stop b/packages/addons/driver/sundtek-mediatv/source/bin/sundtek.stop similarity index 95% rename from packages/addons/driver/sundtek/source/bin/sundtek.stop rename to packages/addons/driver/sundtek-mediatv/source/bin/sundtek.stop index be22e253f3..dff6338175 100644 --- a/packages/addons/driver/sundtek/source/bin/sundtek.stop +++ b/packages/addons/driver/sundtek-mediatv/source/bin/sundtek.stop @@ -22,7 +22,7 @@ . /etc/profile -ADDON_DIR="$HOME/.xbmc/addons/driver.dvb.sundtek" +ADDON_DIR="$HOME/.xbmc/addons/driver.dvb.sundtek-mediatv" export LD_PRELOAD=$ADDON_DIR/lib/libmediaclient.so diff --git a/packages/addons/driver/sundtek/source/bin/userspace-driver.sh b/packages/addons/driver/sundtek-mediatv/source/bin/userspace-driver.sh similarity index 86% rename from packages/addons/driver/sundtek/source/bin/userspace-driver.sh rename to packages/addons/driver/sundtek-mediatv/source/bin/userspace-driver.sh index 40b93317f9..3b50b046a5 100644 --- a/packages/addons/driver/sundtek/source/bin/userspace-driver.sh +++ b/packages/addons/driver/sundtek-mediatv/source/bin/userspace-driver.sh @@ -32,10 +32,9 @@ net_tuner_num_fix() { echo $num } -ADDON_DIR="$HOME/.xbmc/addons/driver.dvb.sundtek" -ADDON_HOME="$HOME/.xbmc/userdata/addon_data/driver.dvb.sundtek" +ADDON_DIR="$HOME/.xbmc/addons/driver.dvb.sundtek-mediatv" +ADDON_HOME="$HOME/.xbmc/userdata/addon_data/driver.dvb.sundtek-mediatv" ADDON_SETTINGS="$ADDON_HOME/settings.xml" -SUNDTEK_READY="/var/run/sundtek.ready" mkdir -p $ADDON_HOME @@ -45,9 +44,11 @@ else # in case of missing entries in addon home's sundtek.conf entry_set="$(grep use_hwpidfilter $ADDON_HOME/sundtek.conf 2>/dev/null)" if [ -z "$entry_set" ]; then - sed -i 's|\(^device_attach=.*\)|\1\n# enable listening on network\nenablenetwork=off|g' $ADDON_HOME/sundtek.conf - sed -i 's|\(^device_attach=.*\)|\1\n\n# enable HW PID filter\nuse_hwpidfilter=off\n|g' $ADDON_HOME/sundtek.conf + sed -i 's|^device_attach=.*|# device_attach not used anymore\n\n# enable HW PID filter\nuse_hwpidfilter=off\n\n# enable listening on network\nenablenetwork=off|g' $ADDON_HOME/sundtek.conf sed -i 's|^#first_adapter=.*|first_adapter=0|g' $ADDON_HOME/sundtek.conf + + sed -i 's|.*network tuner IP address (OpenELEC specific).*||g' $ADDON_HOME/sundtek.conf + sed -i 's|.*network_tuner_ip=.*||g' $ADDON_HOME/sundtek.conf fi fi @@ -74,6 +75,10 @@ if [ "$AUTO_UPDATE" = "true" -a -f $ADDON_DIR/bin/mediasrv ]; then fi if [ ! -f $ADDON_DIR/bin/mediasrv ]; then + # remove renamed addon if exist + rm -fr "$HOME/.xbmc/addons/driver.dvb.sundtek" + rm -fr "$HOME/userdata/addon_data/driver.dvb.sundtek" + logger -t Sundtek "### Downloading installer ###" cd $ADDON_DIR mkdir -p bin lib tmp @@ -90,7 +95,7 @@ if [ ! -f $ADDON_DIR/bin/mediasrv ]; then # enable HW PID filter on RPi by default sed -i 's|^use_hwpidfilter=.*|use_hwpidfilter=on|g' $ADDON_DIR/config/sundtek.conf sed -i 's|^use_hwpidfilter=.*|use_hwpidfilter=on|g' $ADDON_HOME/sundtek.conf - sed -i 's|.*id="ENABLE_HW_PID_FILTER" value=.*||' $ADDON_SETTINGS + sed -i 's|.*id="ENABLE_HW_PID_FILTER".*||' $ADDON_SETTINGS else logger -t Sundtek "### Unsupported architecture ###" cd .. @@ -124,15 +129,18 @@ if [ ! -f $ADDON_HOME/driver-version.txt ]; then cp $ADDON_DIR/driver-version.txt $ADDON_HOME/ fi -# enable to install same addon version again -rm -f /storage/.xbmc/addons/packages/driver.dvb.sundtek-* +# enable to install same addon package version again +rm -f /storage/.xbmc/addons/packages/driver.dvb.sundtek* # add alias for /opt/bin/mediaclient alias_set="$(grep libmediaclient.so /storage/.profile 2>/dev/null)" if [ -z "$alias_set" ]; then echo "" >>/storage/.profile - echo "[ -f /storage/.xbmc/addons/driver.dvb.sundtek/lib/libmediaclient.so ] && export LD_PRELOAD=/storage/.xbmc/addons/driver.dvb.sundtek/lib/libmediaclient.so" >>/storage/.profile + echo "[ -f /storage/.xbmc/addons/driver.dvb.sundtek-mediatv/lib/libmediaclient.so ] && export LD_PRELOAD=/storage/.xbmc/addons/driver.dvb.sundtek-mediatv/lib/libmediaclient.so" >>/storage/.profile echo "" >>/storage/.profile +else + # fix name + sed -i 's|/driver.dvb.sundtek/|/driver.dvb.sundtek-mediatv/|g' /storage/.profile fi export LD_PRELOAD=$ADDON_DIR/lib/libmediaclient.so @@ -160,7 +168,6 @@ fi if [ -z "$(pidof mediasrv)" ]; then rm -f /var/log/mediasrv.log rm -f /var/log/mediaclient.log - rm -f $SUNDTEK_READY SUNDTEK_CONF_TMP=/tmp/sundtek.conf cp $ADDON_HOME/sundtek.conf $SUNDTEK_CONF_TMP @@ -247,29 +254,15 @@ if [ -z "$(pidof mediasrv)" ]; then cp $SUNDTEK_CONF_TMP $ADDON_HOME/sundtek.conf fi - #rm "$SUNDTEK_CONF_TMP" - mediasrv --wait-for-devices -p $ADDON_DIR/bin -c $ADDON_HOME/sundtek.conf -d - # wait for device to get attached or connected - for i in $(seq 1 240); do - if [ -f $SUNDTEK_READY ]; then - rm -f $SUNDTEK_READY - logger -t Sundtek "### Sundtek ready ###" - - if [ -n $SETTLE_TIME -a $SETTLE_TIME -gt 0 ]; then - logger -t Sundtek "### Settle for $SETTLE_TIME sec ###" - sleep $SETTLE_TIME - fi - - break - elif [ "$i" = "240" ]; then - logger -t Sundtek "### No Sundtek device attached or connected ###" - return - else - usleep 500000 - fi - done + # wait few seconds + [ -z "$SETTLE_TIME" ] && SETTLE_TIME=0 + SETTLE_TIME=$(( $SETTLE_TIME *1 )) + if [ $SETTLE_TIME -gt 0 ]; then + logger -t Sundtek "### Settle for $SETTLE_TIME sec ###" + sleep $SETTLE_TIME + fi if [ "$ANALOG_TV" = "true" ]; then logger -t Sundtek "### Switching to analog TV mode ###" @@ -292,3 +285,5 @@ if [ -z "$(pidof mediasrv)" ]; then fi )& fi + +logger -t Sundtek "### Sundtek ready ###" diff --git a/packages/addons/driver/sundtek/source/default.py b/packages/addons/driver/sundtek-mediatv/source/default.py similarity index 100% rename from packages/addons/driver/sundtek/source/default.py rename to packages/addons/driver/sundtek-mediatv/source/default.py diff --git a/packages/addons/driver/sundtek/source/resources/language/English/strings.xml b/packages/addons/driver/sundtek-mediatv/source/resources/language/English/strings.xml similarity index 100% rename from packages/addons/driver/sundtek/source/resources/language/English/strings.xml rename to packages/addons/driver/sundtek-mediatv/source/resources/language/English/strings.xml diff --git a/packages/addons/driver/sundtek/source/resources/settings.xml b/packages/addons/driver/sundtek-mediatv/source/resources/settings.xml similarity index 72% rename from packages/addons/driver/sundtek/source/resources/settings.xml rename to packages/addons/driver/sundtek-mediatv/source/resources/settings.xml index cd2d13eedd..6b4940cfdc 100644 --- a/packages/addons/driver/sundtek/source/resources/settings.xml +++ b/packages/addons/driver/sundtek-mediatv/source/resources/settings.xml @@ -3,13 +3,13 @@ - - - - - - - + + + + + + + diff --git a/packages/addons/driver/sundtek/source/sleep.d/sundtek.power b/packages/addons/driver/sundtek-mediatv/source/sleep.d/sundtek-mediatv.power similarity index 91% rename from packages/addons/driver/sundtek/source/sleep.d/sundtek.power rename to packages/addons/driver/sundtek-mediatv/source/sleep.d/sundtek-mediatv.power index b81f5ea9cc..967e1dee91 100644 --- a/packages/addons/driver/sundtek/source/sleep.d/sundtek.power +++ b/packages/addons/driver/sundtek-mediatv/source/sleep.d/sundtek-mediatv.power @@ -23,22 +23,22 @@ . /etc/profile LOCKDIR="/var/lock/" -LOCKFILE="sundtek" +LOCKFILE="$LOCKDIR/sundtek-mediatv" case "$1" in hibernate|suspend) if [ -n "$(pidof mediasrv)" ]; then progress "Shutting down Sundtek DVB driver for suspending..." mkdir -p "$LOCKDIR" - touch "$LOCKDIR/$LOCKFILE" + touch "$LOCKFILE" mediaclient --shutdown fi ;; thaw|resume) - if [ -f "$LOCKDIR/$LOCKFILE" ]; then + if [ -f "$LOCKFILE" ]; then # driver started within Tvheadend/VDR - rm -rf "$LOCKDIR/$LOCKFILE" + rm -f "$LOCKFILE" fi ;; diff --git a/packages/addons/driver/sundtek/source/bin/device-attached.sh b/packages/addons/driver/sundtek/source/bin/device-attached.sh deleted file mode 100644 index 9b62feb274..0000000000 --- a/packages/addons/driver/sundtek/source/bin/device-attached.sh +++ /dev/null @@ -1,25 +0,0 @@ -#!/bin/sh - -################################################################################ -# This file is part of OpenELEC - http://www.openelec.tv -# Copyright (C) 2009-2012 Stephan Raue (stephan@openelec.tv) -# -# 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 OpenELEC.tv; see the file COPYING. If not, write to -# the Free Software Foundation, 51 Franklin Street, Suite 500, Boston, MA 02110, USA. -# http://www.gnu.org/copyleft/gpl.html -################################################################################ - -SUNDTEK_READY="/var/run/sundtek.ready" - -touch $SUNDTEK_READY From bfa75c711f168844aabb6e438f5e80f7b0a3fc6a Mon Sep 17 00:00:00 2001 From: Stefan Saraev Date: Thu, 21 Feb 2013 21:15:56 +0200 Subject: [PATCH 02/13] sundtek-mediatv: bump --- packages/addons/driver/sundtek-mediatv/meta | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/addons/driver/sundtek-mediatv/meta b/packages/addons/driver/sundtek-mediatv/meta index 725a629276..163e8d3de9 100644 --- a/packages/addons/driver/sundtek-mediatv/meta +++ b/packages/addons/driver/sundtek-mediatv/meta @@ -20,7 +20,7 @@ PKG_NAME="sundtek-mediatv" PKG_VERSION="3.0" -PKG_REV="1" +PKG_REV="2" PKG_ARCH="any" PKG_LICENSE="nonfree" PKG_SITE="http://support.sundtek.com/" From 1965e3511c2c53150feb68189cf66b517af53b7d Mon Sep 17 00:00:00 2001 From: Stefan Saraev Date: Thu, 21 Feb 2013 21:17:46 +0200 Subject: [PATCH 03/13] sundtek-mediatv: ups, also update changelog --- packages/addons/driver/sundtek-mediatv/changelog.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/addons/driver/sundtek-mediatv/changelog.txt b/packages/addons/driver/sundtek-mediatv/changelog.txt index f3f1d1e893..000cb4f4e1 100644 --- a/packages/addons/driver/sundtek-mediatv/changelog.txt +++ b/packages/addons/driver/sundtek-mediatv/changelog.txt @@ -1,4 +1,4 @@ -3.0.1 +3.0.2 added addon settings enable HW PID filter (enabled for RPi by default) enable IR receiver From f7d7a8aad8e8538e0be0093dae80c31664615603 Mon Sep 17 00:00:00 2001 From: Stefan Saraev Date: Thu, 21 Feb 2013 21:32:10 +0200 Subject: [PATCH 04/13] tvheadend: update to tvheadend-3.3.485 --- packages/addons/service/multimedia/tvheadend/changelog.txt | 3 +++ packages/addons/service/multimedia/tvheadend/meta | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/packages/addons/service/multimedia/tvheadend/changelog.txt b/packages/addons/service/multimedia/tvheadend/changelog.txt index f3b59c4772..151f64fad0 100644 --- a/packages/addons/service/multimedia/tvheadend/changelog.txt +++ b/packages/addons/service/multimedia/tvheadend/changelog.txt @@ -1,3 +1,6 @@ +3.0.5 +- update to TVHeadend 3.3.485 + 3.0.4 - update to TVHeadend 3.3.403 diff --git a/packages/addons/service/multimedia/tvheadend/meta b/packages/addons/service/multimedia/tvheadend/meta index 75b6582070..81cb85629c 100644 --- a/packages/addons/service/multimedia/tvheadend/meta +++ b/packages/addons/service/multimedia/tvheadend/meta @@ -19,8 +19,8 @@ ################################################################################ PKG_NAME="tvheadend" -PKG_VERSION="3.3.403" -PKG_REV="4" +PKG_VERSION="3.3.485" +PKG_REV="5" PKG_ARCH="any" PKG_LICENSE="GPL" PKG_SITE="http://www.lonelycoder.com/hts/tvheadend_overview.html" From 61130bb896c119f21fbcb63ddba71dca89db52ea Mon Sep 17 00:00:00 2001 From: Stefan Saraev Date: Thu, 21 Feb 2013 21:40:37 +0200 Subject: [PATCH 05/13] transmission: update to transmission-2.77 --- .../addons/service/downloadmanager/transmission/changelog.txt | 3 +++ packages/addons/service/downloadmanager/transmission/meta | 4 ++-- ...omake-1.13.patch => transmission-2.77-automake-1.13.patch} | 0 3 files changed, 5 insertions(+), 2 deletions(-) rename packages/addons/service/downloadmanager/transmission/patches/{transmission-2.76-automake-1.13.patch => transmission-2.77-automake-1.13.patch} (100%) diff --git a/packages/addons/service/downloadmanager/transmission/changelog.txt b/packages/addons/service/downloadmanager/transmission/changelog.txt index 5948f06547..170c42563f 100644 --- a/packages/addons/service/downloadmanager/transmission/changelog.txt +++ b/packages/addons/service/downloadmanager/transmission/changelog.txt @@ -1,3 +1,6 @@ +3.0.4 +- update to transmission-2.77 + 3.0.3 - update to transmission-2.76 - update libevent to libevent-2.0.21-stable diff --git a/packages/addons/service/downloadmanager/transmission/meta b/packages/addons/service/downloadmanager/transmission/meta index beea61d136..f22bac6e70 100644 --- a/packages/addons/service/downloadmanager/transmission/meta +++ b/packages/addons/service/downloadmanager/transmission/meta @@ -19,8 +19,8 @@ ################################################################################ PKG_NAME="transmission" -PKG_VERSION="2.76" -PKG_REV="3" +PKG_VERSION="2.77" +PKG_REV="4" PKG_ARCH="any" PKG_LICENSE="OSS" PKG_SITE="http://www.transmissionbt.com/" diff --git a/packages/addons/service/downloadmanager/transmission/patches/transmission-2.76-automake-1.13.patch b/packages/addons/service/downloadmanager/transmission/patches/transmission-2.77-automake-1.13.patch similarity index 100% rename from packages/addons/service/downloadmanager/transmission/patches/transmission-2.76-automake-1.13.patch rename to packages/addons/service/downloadmanager/transmission/patches/transmission-2.77-automake-1.13.patch From e243a066b1b3c2fa5f73137812cc566c8f4a5aa6 Mon Sep 17 00:00:00 2001 From: Christian Hewitt Date: Sat, 23 Feb 2013 08:40:01 +0400 Subject: [PATCH 06/13] fix xbmc connection-check patch Checking releases.openelec.tv returns a 403 error as directory listings are denied. XBMC interprets this as a failure resulting in "Connected, but no DNS available" in system info. We now use online.openelec.tv which does not return an error. --- .../xbmc/patches/xbmc-457-fix_connection_check-0.1.patch | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/mediacenter/xbmc/patches/xbmc-457-fix_connection_check-0.1.patch b/packages/mediacenter/xbmc/patches/xbmc-457-fix_connection_check-0.1.patch index e2ff800e71..2bb87be74e 100644 --- a/packages/mediacenter/xbmc/patches/xbmc-457-fix_connection_check-0.1.patch +++ b/packages/mediacenter/xbmc/patches/xbmc-457-fix_connection_check-0.1.patch @@ -6,10 +6,10 @@ diff -Naur a/xbmc/filesystem/CurlFile.cpp b/xbmc/filesystem/CurlFile.cpp bool CFileCurl::IsInternet(bool checkDNS /* = true */) { - CStdString strURL = "http://www.google.com"; -+ CStdString strURL = "http://releases.openelec.tv"; ++ CStdString strURL = "http://online.openelec.tv"; if (!checkDNS) - strURL = "http://74.125.19.103"; // www.google.com ip -+ strURL = "http://212.101.13.11"; // openelec.tv ip ++ strURL = "http://212.101.13.11"; // online.openelec.tv ip bool found = Exists(strURL); Close(); From 79bfcdbee8a132ea11c7487dd1997ebc7ee30064 Mon Sep 17 00:00:00 2001 From: fritsch Date: Sat, 23 Feb 2013 23:58:49 +0100 Subject: [PATCH 07/13] AE: fix segfault when stopping of stream and switching between tracks --- .../patches/xbmc-991.15-ae-fix-segfault.patch | 48 +++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 packages/mediacenter/xbmc/patches/xbmc-991.15-ae-fix-segfault.patch diff --git a/packages/mediacenter/xbmc/patches/xbmc-991.15-ae-fix-segfault.patch b/packages/mediacenter/xbmc/patches/xbmc-991.15-ae-fix-segfault.patch new file mode 100644 index 0000000000..c18991e6b8 --- /dev/null +++ b/packages/mediacenter/xbmc/patches/xbmc-991.15-ae-fix-segfault.patch @@ -0,0 +1,48 @@ +From dc648b78c4c571cc0a5d3df3e7b64c21c7d0901e Mon Sep 17 00:00:00 2001 +From: fritsch +Date: Sat, 23 Feb 2013 10:44:33 +0100 +Subject: [PATCH] AE: fix segfault after indirection patches + +--- + xbmc/cores/AudioEngine/Engines/SoftAE/SoftAE.cpp | 8 +++++--- + 1 file changed, 5 insertions(+), 3 deletions(-) + +diff --git a/xbmc/cores/AudioEngine/Engines/SoftAE/SoftAE.cpp b/xbmc/cores/AudioEngine/Engines/SoftAE/SoftAE.cpp +index cfb7be5..6ec78c5 100644 +--- a/xbmc/cores/AudioEngine/Engines/SoftAE/SoftAE.cpp ++++ b/xbmc/cores/AudioEngine/Engines/SoftAE/SoftAE.cpp +@@ -728,7 +728,6 @@ void CSoftAE::PauseStream(CSoftAEStream *stream) + CSingleLock streamLock(m_streamLock); + RemoveStream(m_playingStreams, stream); + stream->m_paused = true; +- streamLock.Leave(); + + m_reOpen = true; + m_wake.Set(); +@@ -874,7 +873,10 @@ IAEStream *CSoftAE::FreeStream(IAEStream *stream) + RemoveStream(m_streams , (CSoftAEStream*)stream); + // Reopen is old behaviour. Not opening when masterstream stops means clipping on S/PDIF. + if(!m_isSuspended && (m_masterStream == stream)) ++ { + m_reOpen = true; ++ m_masterStream = NULL; ++ } + + delete (CSoftAEStream*)stream; + return NULL; +@@ -1058,11 +1060,11 @@ void CSoftAE::Run() + bool restart = false; + + /* with the new non blocking implementation - we just reOpen here, when it tells reOpen */ +- if (!m_reOpen && (this->*m_outputStageFn)(hasAudio) > 0) ++ if ((this->*m_outputStageFn)(hasAudio) > 0) + hasAudio = false; /* taken some audio - reset our silence flag */ + + /* if we have enough room in the buffer */ +- if (!m_reOpen && m_buffer.Free() >= m_frameSize) ++ if (m_buffer.Free() >= m_frameSize) + { + /* take some data for our use from the buffer */ + uint8_t *out = (uint8_t*)m_buffer.Take(m_frameSize); +-- +1.7.10 From 3349daf476a385b00506acae4320ffa407451400 Mon Sep 17 00:00:00 2001 From: Stefan Saraev Date: Sun, 24 Feb 2013 21:53:41 +0200 Subject: [PATCH 08/13] intel-gpu-tools: issue intel_reg_write again after xrandr... https://bugs.freedesktop.org/show_bug.cgi?id=46800 --- packages/x11/other/intel-gpu-tools/scripts/set-intel-color-space | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/x11/other/intel-gpu-tools/scripts/set-intel-color-space b/packages/x11/other/intel-gpu-tools/scripts/set-intel-color-space index be054bd483..c09fac667a 100755 --- a/packages/x11/other/intel-gpu-tools/scripts/set-intel-color-space +++ b/packages/x11/other/intel-gpu-tools/scripts/set-intel-color-space @@ -41,6 +41,7 @@ if [ $# -gt 0 ] ; then intel_reg_write 0x70180 0xDA004400 # set new mode xrandr --output $OUTPUT --set "Broadcast RGB" "Full" + intel_reg_write 0x70180 0xDA004400 fi else echo "Usage: $0 limited | full" From 8fcded8e795b5698cb23ee93d1647808fcf321db Mon Sep 17 00:00:00 2001 From: Stefan Saraev Date: Sun, 24 Feb 2013 22:55:18 +0200 Subject: [PATCH 09/13] projects/Fusion: xbmc: disable & hide unsupported lpcm, dts-hd, truehd etc.. --- projects/Fusion/xbmc/advancedsettings.xml | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 projects/Fusion/xbmc/advancedsettings.xml diff --git a/projects/Fusion/xbmc/advancedsettings.xml b/projects/Fusion/xbmc/advancedsettings.xml new file mode 100644 index 0000000000..a77140b427 --- /dev/null +++ b/projects/Fusion/xbmc/advancedsettings.xml @@ -0,0 +1,11 @@ + + + + + false + false + false + false + false + + From d2944b96fae9a747737df1003ee9fab174378edd Mon Sep 17 00:00:00 2001 From: Stephan Raue Date: Sun, 24 Feb 2013 23:32:36 +0100 Subject: [PATCH 10/13] xbmc: add patch to bump XBMC addon version Signed-off-by: Stephan Raue --- .../xbmc-990.01-bump_xbmc_addon_version.patch | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 packages/mediacenter/xbmc/patches/xbmc-990.01-bump_xbmc_addon_version.patch diff --git a/packages/mediacenter/xbmc/patches/xbmc-990.01-bump_xbmc_addon_version.patch b/packages/mediacenter/xbmc/patches/xbmc-990.01-bump_xbmc_addon_version.patch new file mode 100644 index 0000000000..21407ac94d --- /dev/null +++ b/packages/mediacenter/xbmc/patches/xbmc-990.01-bump_xbmc_addon_version.patch @@ -0,0 +1,23 @@ +From 65a8eb83549ef092f6f192c944befa6f762c885d Mon Sep 17 00:00:00 2001 +From: ronie +Date: Sat, 23 Feb 2013 17:40:04 +0100 +Subject: [PATCH] bump xbmc.addon to 12.1.0 + +--- + addons/xbmc.addon/addon.xml | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/addons/xbmc.addon/addon.xml b/addons/xbmc.addon/addon.xml +index db32072..7d38949 100644 +--- a/addons/xbmc.addon/addon.xml ++++ b/addons/xbmc.addon/addon.xml +@@ -1,5 +1,5 @@ + +- ++ + + + +-- +1.7.10 + From 0aadee2badfc8b602c8d7c10ed657f994a608297 Mon Sep 17 00:00:00 2001 From: Stephan Raue Date: Sun, 24 Feb 2013 23:35:25 +0100 Subject: [PATCH 11/13] xbmc: update XVBA/VDPAU/OMX patches Signed-off-by: Stephan Raue --- .../xbmc-995.10-xvba_rpi_fixes-81496e1.patch | 549 - ...ti-screen_fix_compilation_on_windows.patch | 75 - .../xbmc-995.01-xvba_support-1ea917e.patch | 19295 ++++++++++++++++ .../xbmc-995.09-revert-rpi-fixes.patch | 64 + .../xbmc-995.10-xvba_rpi_fixes-059b89b.patch | 1148 + 5 files changed, 20507 insertions(+), 624 deletions(-) delete mode 100644 packages/mediacenter/xbmc/patches/todo/xbmc-995.10-xvba_rpi_fixes-81496e1.patch delete mode 100644 packages/mediacenter/xbmc/patches/todo/xbmc-995.11-multi-screen_fix_compilation_on_windows.patch create mode 100644 packages/mediacenter/xbmc/patches/xbmc-995.01-xvba_support-1ea917e.patch create mode 100644 packages/mediacenter/xbmc/patches/xbmc-995.09-revert-rpi-fixes.patch create mode 100644 packages/mediacenter/xbmc/patches/xbmc-995.10-xvba_rpi_fixes-059b89b.patch diff --git a/packages/mediacenter/xbmc/patches/todo/xbmc-995.10-xvba_rpi_fixes-81496e1.patch b/packages/mediacenter/xbmc/patches/todo/xbmc-995.10-xvba_rpi_fixes-81496e1.patch deleted file mode 100644 index 029e8fa7a0..0000000000 --- a/packages/mediacenter/xbmc/patches/todo/xbmc-995.10-xvba_rpi_fixes-81496e1.patch +++ /dev/null @@ -1,549 +0,0 @@ -From d33a276284356e974dcf14e6c86b74064fb0715f Mon Sep 17 00:00:00 2001 -From: xbmc -Date: Sun, 10 Feb 2013 18:38:56 +0100 -Subject: [PATCH 1/4] renderer: add buffering - get clock via IPlayer - ---- - xbmc/cores/IPlayer.h | 2 ++ - xbmc/cores/VideoRenderers/RenderManager.cpp | 9 ++++++--- - xbmc/cores/VideoRenderers/RenderManager.h | 3 +-- - xbmc/cores/dvdplayer/DVDPlayer.cpp | 7 ++++++- - xbmc/cores/dvdplayer/DVDPlayer.h | 2 ++ - 5 files changed, 17 insertions(+), 6 deletions(-) - -diff --git a/xbmc/cores/IPlayer.h b/xbmc/cores/IPlayer.h -index 5ed88d1..f136998 100644 ---- a/xbmc/cores/IPlayer.h -+++ b/xbmc/cores/IPlayer.h -@@ -229,6 +229,8 @@ class IPlayer - */ - virtual void GetSubtitleCapabilities(std::vector &subCaps) { subCaps.assign(1,IPC_SUBS_ALL); }; - -+ virtual double GetClock(double& absolute, bool interpolated = true) {return 0; }; -+ - protected: - IPlayerCallback& m_callback; - }; -diff --git a/xbmc/cores/VideoRenderers/RenderManager.cpp b/xbmc/cores/VideoRenderers/RenderManager.cpp -index 9290f80..4664426 100644 ---- a/xbmc/cores/VideoRenderers/RenderManager.cpp -+++ b/xbmc/cores/VideoRenderers/RenderManager.cpp -@@ -325,7 +325,7 @@ void CXBMCRenderManager::RenderUpdate(bool clear, DWORD flags, DWORD alpha) - m_presentevent.Set(); - } - --unsigned int CXBMCRenderManager::PreInit(CDVDClock *pClock) -+unsigned int CXBMCRenderManager::PreInit() - { - CRetakeLock lock(m_sharedSection); - -@@ -333,7 +333,6 @@ unsigned int CXBMCRenderManager::PreInit(CDVDClock *pClock) - m_presenterr = 0.0; - m_errorindex = 0; - memset(m_errorbuff, 0, sizeof(m_errorbuff)); -- m_pClock = pClock; - - m_bIsStarted = false; - m_bPauseDrawing = false; -@@ -1045,7 +1044,11 @@ void CXBMCRenderManager::PrepareNextRender() - } - - double iClockSleep, iPlayingClock, iCurrentClock; -- iPlayingClock = m_pClock->GetClock(iCurrentClock, false); -+ if (g_application.m_pPlayer) -+ iPlayingClock = g_application.m_pPlayer->GetClock(iCurrentClock, false); -+ else -+ iPlayingClock = iCurrentClock = 0; -+ - iClockSleep = m_renderBuffers[idx].pts - iPlayingClock; - - if (m_speed) -diff --git a/xbmc/cores/VideoRenderers/RenderManager.h b/xbmc/cores/VideoRenderers/RenderManager.h -index 6746957..b931f7d 100644 ---- a/xbmc/cores/VideoRenderers/RenderManager.h -+++ b/xbmc/cores/VideoRenderers/RenderManager.h -@@ -72,7 +72,7 @@ class CXBMCRenderManager - int AddVideoPicture(DVDVideoPicture& picture); - - void FlipPage(volatile bool& bStop, double timestamp = 0.0, int source = -1, EFIELDSYNC sync = FS_NONE, int speed = 0); -- unsigned int PreInit(CDVDClock *pClock); -+ unsigned int PreInit(); - void UnInit(); - bool Flush(); - -@@ -225,7 +225,6 @@ class CXBMCRenderManager - int m_presentsource; - CEvent m_presentevent; - CEvent m_flushEvent; -- CDVDClock *m_pClock; - - - OVERLAY::CRenderer m_overlays; -diff --git a/xbmc/cores/dvdplayer/DVDPlayer.cpp b/xbmc/cores/dvdplayer/DVDPlayer.cpp -index 9e6e470..d0c7cd2 100644 ---- a/xbmc/cores/dvdplayer/DVDPlayer.cpp -+++ b/xbmc/cores/dvdplayer/DVDPlayer.cpp -@@ -463,7 +463,7 @@ bool CDVDPlayer::OpenFile(const CFileItem& file, const CPlayerOptions &options) - m_ready.Reset(); - - #if defined(HAS_VIDEO_PLAYBACK) -- g_renderManager.PreInit(&m_clock); -+ g_renderManager.PreInit(); - #endif - - Create(); -@@ -4129,3 +4129,8 @@ bool CDVDPlayer::CachePVRStream(void) const - !g_PVRManager.IsPlayingRecording() && - g_advancedSettings.m_bPVRCacheInDvdPlayer; - } -+ -+double CDVDPlayer::GetClock(double& absolute, bool interpolated) -+{ -+ return m_clock.GetClock(absolute, interpolated); -+} -diff --git a/xbmc/cores/dvdplayer/DVDPlayer.h b/xbmc/cores/dvdplayer/DVDPlayer.h -index 35bf762..ab73950 100644 ---- a/xbmc/cores/dvdplayer/DVDPlayer.h -+++ b/xbmc/cores/dvdplayer/DVDPlayer.h -@@ -254,6 +254,8 @@ class CDVDPlayer : public IPlayer, public CThread, public IDVDPlayer - virtual bool SwitchChannel(const PVR::CPVRChannel &channel); - virtual bool CachePVRStream(void) const; - -+ virtual double GetClock(double& absolute, bool interpolated = true); -+ - enum ECacheState - { CACHESTATE_DONE = 0 - , CACHESTATE_FULL // player is filling up the demux queue --- -1.7.10 - - -From 113de500903cbe1933e1a50fc7809b8f6b7f2636 Mon Sep 17 00:00:00 2001 -From: xbmc -Date: Fri, 15 Feb 2013 17:00:47 +0100 -Subject: [PATCH 2/4] buffering: some rework - ---- - xbmc/cores/VideoRenderers/OverlayRenderer.cpp | 17 +++++++---------- - xbmc/cores/VideoRenderers/OverlayRenderer.h | 5 ++--- - xbmc/cores/VideoRenderers/RenderManager.cpp | 10 +++------- - xbmc/cores/VideoRenderers/RenderManager.h | 4 ++-- - xbmc/cores/dvdplayer/DVDPlayerVideo.cpp | 18 +++++++++++++++++- - 5 files changed, 31 insertions(+), 23 deletions(-) - -diff --git a/xbmc/cores/VideoRenderers/OverlayRenderer.cpp b/xbmc/cores/VideoRenderers/OverlayRenderer.cpp -index 94aaaf5..f7f74ce 100644 ---- a/xbmc/cores/VideoRenderers/OverlayRenderer.cpp -+++ b/xbmc/cores/VideoRenderers/OverlayRenderer.cpp -@@ -93,24 +93,28 @@ long COverlayMainThread::Release() - - CRenderer::~CRenderer() - { -- for(int i = 0; i < 2; i++) -+ for(int i = 0; i < 10; i++) - Release(m_buffers[i]); - } - --void CRenderer::AddOverlay(CDVDOverlay* o, double pts) -+void CRenderer::AddOverlay(CDVDOverlay* o, double pts, int index) - { - CSingleLock lock(m_section); - -+ m_decode = index; -+ - SElement e; - e.pts = pts; - e.overlay_dvd = o->Acquire(); - m_buffers[m_decode].push_back(e); - } - --void CRenderer::AddOverlay(COverlay* o, double pts) -+void CRenderer::AddOverlay(COverlay* o, double pts, int index) - { - CSingleLock lock(m_section); - -+ m_decode = index; -+ - SElement e; - e.pts = pts; - e.overlay = o->Acquire(); -@@ -163,13 +167,6 @@ void CRenderer::Flip() - m_render = (m_render + 1) % m_iNumBuffers; - } - --void CRenderer::SetBuffer(int idx) --{ -- CSingleLock lock(m_section); -- Release(m_buffers[idx]); -- m_decode = idx; --} -- - void CRenderer::ReleaseBuffer(int idx) - { - CSingleLock lock(m_section); -diff --git a/xbmc/cores/VideoRenderers/OverlayRenderer.h b/xbmc/cores/VideoRenderers/OverlayRenderer.h -index c6740a5..0921fc5 100644 ---- a/xbmc/cores/VideoRenderers/OverlayRenderer.h -+++ b/xbmc/cores/VideoRenderers/OverlayRenderer.h -@@ -92,14 +92,13 @@ - CRenderer(); - ~CRenderer(); - -- void AddOverlay(CDVDOverlay* o, double pts); -- void AddOverlay(COverlay* o, double pts); -+ void AddOverlay(CDVDOverlay* o, double pts, int index); -+ void AddOverlay(COverlay* o, double pts, int index); - void AddCleanup(COverlay* o); - void Flip(); - void Render(); - void Flush(); - void SetNumBuffers(int numBuffers) { m_iNumBuffers = numBuffers; } -- void SetBuffer(int idx); - void ReleaseBuffer(int idx); - - protected: -diff --git a/xbmc/cores/VideoRenderers/RenderManager.cpp b/xbmc/cores/VideoRenderers/RenderManager.cpp -index 4664426..7094913 100644 ---- a/xbmc/cores/VideoRenderers/RenderManager.cpp -+++ b/xbmc/cores/VideoRenderers/RenderManager.cpp -@@ -228,7 +228,7 @@ CStdString CXBMCRenderManager::GetVSyncState() - return state; - } - --bool CXBMCRenderManager::Configure(unsigned int width, unsigned int height, unsigned int d_width, unsigned int d_height, float fps, unsigned flags, ERenderFormat format, unsigned extended_format, unsigned int orientation) -+bool CXBMCRenderManager::Configure(unsigned int width, unsigned int height, unsigned int d_width, unsigned int d_height, float fps, unsigned flags, ERenderFormat format, unsigned extended_format, unsigned int orientation, bool buffering) - { - /* make sure any queued frame was fully presented */ - double timeout = m_presenttime + 0.1; -@@ -248,8 +248,8 @@ bool CXBMCRenderManager::Configure(unsigned int width, unsigned int height, unsi - return false; - } - -- // check if decoder supports buffering -- m_bCodecSupportsBuffering = false; -+ // set buffering -+ m_bCodecSupportsBuffering = buffering; - if (format == RENDER_FMT_VDPAU - || format == RENDER_FMT_VDPAU_420 - || format == RENDER_FMT_XVBA) -@@ -959,10 +959,6 @@ int CXBMCRenderManager::WaitForBuffer(volatile bool& bStop) - } - lock.Leave(); - -- { CRetakeLock lock(m_sharedSection); -- m_overlays.SetBuffer((m_iOutputRenderBuffer + 1) % m_iNumRenderBuffers); -- } -- - if (bStop) - return -1; - -diff --git a/xbmc/cores/VideoRenderers/RenderManager.h b/xbmc/cores/VideoRenderers/RenderManager.h -index b931f7d..27bb8a2 100644 ---- a/xbmc/cores/VideoRenderers/RenderManager.h -+++ b/xbmc/cores/VideoRenderers/RenderManager.h -@@ -66,7 +66,7 @@ class CXBMCRenderManager - void SetViewMode(int iViewMode); - - // Functions called from mplayer -- bool Configure(unsigned int width, unsigned int height, unsigned int d_width, unsigned int d_height, float fps, unsigned flags, ERenderFormat format, unsigned extended_format, unsigned int orientation); -+ bool Configure(unsigned int width, unsigned int height, unsigned int d_width, unsigned int d_height, float fps, unsigned flags, ERenderFormat format, unsigned extended_format, unsigned int orientation, bool buffering); - bool IsConfigured(); - - int AddVideoPicture(DVDVideoPicture& picture); -@@ -79,7 +79,7 @@ class CXBMCRenderManager - void AddOverlay(CDVDOverlay* o, double pts) - { - CSharedLock lock(m_sharedSection); -- m_overlays.AddOverlay(o, pts); -+ m_overlays.AddOverlay(o, pts, (m_iOutputRenderBuffer + 1) % m_iNumRenderBuffers); - } - - void AddCleanup(OVERLAY::COverlay* o) -diff --git a/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp b/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp -index 109d75b..8a6599c 100644 ---- a/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp -+++ b/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp -@@ -1132,53 +1132,69 @@ int CDVDPlayerVideo::OutputPicture(const DVDVideoPicture* src, double pts) - } - - CStdString formatstr; -+ bool buffering; - - switch(pPicture->format) - { - case RENDER_FMT_YUV420P: - formatstr = "YV12"; -+ buffering = true; - break; - case RENDER_FMT_YUV420P16: - formatstr = "YV12P16"; -+ buffering = true; - break; - case RENDER_FMT_YUV420P10: - formatstr = "YV12P10"; -+ buffering = true; - break; - case RENDER_FMT_NV12: - formatstr = "NV12"; -+ buffering = true; - break; - case RENDER_FMT_UYVY422: - formatstr = "UYVY"; -+ buffering = true; - break; - case RENDER_FMT_YUYV422: - formatstr = "YUY2"; -+ buffering = true; - break; - case RENDER_FMT_VDPAU: - formatstr = "VDPAU"; -+ buffering = true; - break; - case RENDER_FMT_VDPAU_420: - formatstr = "VDPAU_420"; -+ buffering = true; - break; - case RENDER_FMT_DXVA: - formatstr = "DXVA"; -+ buffering = false; - break; - case RENDER_FMT_VAAPI: - formatstr = "VAAPI"; -+ buffering = false; - break; - case RENDER_FMT_OMXEGL: - formatstr = "OMXEGL"; -+ buffering = false; - break; - case RENDER_FMT_CVBREF: - formatstr = "BGRA"; -+ buffering = false; - break; - case RENDER_FMT_BYPASS: - formatstr = "BYPASS"; -+ buffering = false; - break; - case RENDER_FMT_NONE: - formatstr = "NONE"; -+ buffering = false; - break; - case RENDER_FMT_XVBA: - formatstr = "XVBA"; -+ buffering = true; - break; - } - -@@ -1189,7 +1205,7 @@ int CDVDPlayerVideo::OutputPicture(const DVDVideoPicture* src, double pts) - } - - CLog::Log(LOGDEBUG,"%s - change configuration. %dx%d. framerate: %4.2f. format: %s",__FUNCTION__,pPicture->iWidth, pPicture->iHeight, config_framerate, formatstr.c_str()); -- if(!g_renderManager.Configure(pPicture->iWidth, pPicture->iHeight, pPicture->iDisplayWidth, pPicture->iDisplayHeight, config_framerate, flags, pPicture->format, pPicture->extended_format, m_hints.orientation)) -+ if(!g_renderManager.Configure(pPicture->iWidth, pPicture->iHeight, pPicture->iDisplayWidth, pPicture->iDisplayHeight, config_framerate, flags, pPicture->format, pPicture->extended_format, m_hints.orientation, buffering)) - { - CLog::Log(LOGERROR, "%s - failed to configure renderer", __FUNCTION__); - return EOS_ABORT; --- -1.7.10 - - -From 4d71be9fa0e34dccbb977199f1bde2f200f8b56e Mon Sep 17 00:00:00 2001 -From: xbmc -Date: Sat, 16 Feb 2013 08:32:18 +0100 -Subject: [PATCH 3/4] add buffering for GLES - ---- - xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp | 10 ---------- - xbmc/cores/VideoRenderers/LinuxRendererGLES.h | 6 ++++-- - 2 files changed, 4 insertions(+), 12 deletions(-) - -diff --git a/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp b/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp -index 2a59e2b..1bf2f3b 100644 ---- a/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp -+++ b/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp -@@ -135,13 +135,6 @@ - delete m_dllSwScale; - } - --void CLinuxRendererGLES::ManageTextures() --{ -- m_NumYV12Buffers = 2; -- //m_iYV12RenderBuffer = 0; -- return; --} -- - bool CLinuxRendererGLES::ValidateRenderTarget() - { - if (!m_bValidated) -@@ -395,7 +388,6 @@ void CLinuxRendererGLES::Update(bool bPauseDrawing) - { - if (!m_bConfigured) return; - ManageDisplay(); -- ManageTextures(); - } - - void CLinuxRendererGLES::RenderUpdate(bool clear, DWORD flags, DWORD alpha) -@@ -409,7 +401,6 @@ void CLinuxRendererGLES::RenderUpdate(bool clear, DWORD flags, DWORD alpha) - if (m_renderMethod & RENDER_BYPASS) - { - ManageDisplay(); -- ManageTextures(); - // if running bypass, then the player might need the src/dst rects - // for sizing video playback on a layer other than the gles layer. - if (m_RenderUpdateCallBackFn) -@@ -449,7 +440,6 @@ void CLinuxRendererGLES::RenderUpdate(bool clear, DWORD flags, DWORD alpha) - return; - - ManageDisplay(); -- ManageTextures(); - - g_graphicsContext.BeginPaint(); - -diff --git a/xbmc/cores/VideoRenderers/LinuxRendererGLES.h b/xbmc/cores/VideoRenderers/LinuxRendererGLES.h -index c6b69db..7bdc3bc 100644 ---- a/xbmc/cores/VideoRenderers/LinuxRendererGLES.h -+++ b/xbmc/cores/VideoRenderers/LinuxRendererGLES.h -@@ -41,7 +41,7 @@ - class COpenMaxVideo; - typedef std::vector Features; - --#define NUM_BUFFERS 3 -+#define NUM_BUFFERS 10 - - - #undef ALIGN -@@ -138,6 +138,9 @@ class CLinuxRendererGLES : public CBaseRenderer - virtual void UnInit(); - virtual void Reset(); /* resets renderer after seek for example */ - virtual void ReorderDrawPoints(); -+ virtual void SetProcessorSize(int numBuffers) { m_NumYV12Buffers = numBuffers; } -+ virtual unsigned int GetMaxProcessorSize() { return NUM_BUFFERS; } -+ virtual unsigned int GetProcessorSize() { return m_NumYV12Buffers; } - - virtual void RenderUpdate(bool clear, DWORD flags = 0, DWORD alpha = 255); - -@@ -162,7 +165,6 @@ class CLinuxRendererGLES : public CBaseRenderer - protected: - virtual void Render(DWORD flags, int index); - -- virtual void ManageTextures(); - int NextYV12Texture(); - virtual bool ValidateRenderTarget(); - virtual void LoadShaders(int field=FIELD_FULL); --- -1.7.10 - - -From 81496e1f405980d3be6b05c883bdbfb65d617e3e Mon Sep 17 00:00:00 2001 -From: xbmc -Date: Sun, 10 Feb 2013 18:40:30 +0100 -Subject: [PATCH 4/4] OMXPlayer: adopt to buffering in renderer - ---- - xbmc/cores/omxplayer/OMXPlayer.cpp | 5 +++++ - xbmc/cores/omxplayer/OMXPlayer.h | 2 ++ - xbmc/cores/omxplayer/OMXPlayerVideo.cpp | 24 +++++++++++++++++++----- - 3 files changed, 26 insertions(+), 5 deletions(-) - -diff --git a/xbmc/cores/omxplayer/OMXPlayer.cpp b/xbmc/cores/omxplayer/OMXPlayer.cpp -index 60aa9ab..1acb9e2 100644 ---- a/xbmc/cores/omxplayer/OMXPlayer.cpp -+++ b/xbmc/cores/omxplayer/OMXPlayer.cpp -@@ -4210,4 +4210,9 @@ void COMXPlayer::GetSubtitleCapabilities(std::vector &subCaps) - subCaps.push_back(IPC_SUBS_ALL); - } - -+double COMXPlayer::GetClock(double& absolute, bool interpolated) -+{ -+ return m_av_clock.GetClock(absolute, interpolated); -+} -+ - #endif -diff --git a/xbmc/cores/omxplayer/OMXPlayer.h b/xbmc/cores/omxplayer/OMXPlayer.h -index ca824c2..57fc7a0 100644 ---- a/xbmc/cores/omxplayer/OMXPlayer.h -+++ b/xbmc/cores/omxplayer/OMXPlayer.h -@@ -332,6 +332,8 @@ class COMXPlayer : public IPlayer, public CThread, public IDVDPlayer - virtual void GetScalingMethods(std::vector &scalingMethods); - virtual void GetAudioCapabilities(std::vector &audioCaps); - virtual void GetSubtitleCapabilities(std::vector &subCaps); -+ -+ virtual double GetClock(double& absolute, bool interpolated = true); - protected: - friend class COMXSelectionStreams; - -diff --git a/xbmc/cores/omxplayer/OMXPlayerVideo.cpp b/xbmc/cores/omxplayer/OMXPlayerVideo.cpp -index 5f3f050..88c75db 100644 ---- a/xbmc/cores/omxplayer/OMXPlayerVideo.cpp -+++ b/xbmc/cores/omxplayer/OMXPlayerVideo.cpp -@@ -158,6 +158,8 @@ bool OMXPlayerVideo::OpenStream(CDVDStreamInfo &hints) - m_open = true; - m_send_eos = false; - -+ g_renderManager.EnableBuffering(false); -+ - return true; - } - -@@ -358,7 +360,7 @@ void OMXPlayerVideo::Output(int iGroupId, double pts, bool bDropPacket) - - if(!g_renderManager.Configure(m_hints.width, m_hints.height, - iDisplayWidth, iDisplayHeight, m_fps, flags, format, 0, -- m_hints.orientation)) -+ m_hints.orientation, true)) - { - CLog::Log(LOGERROR, "%s - failed to configure renderer", __FUNCTION__); - return; -@@ -452,13 +454,22 @@ void OMXPlayerVideo::Output(int iGroupId, double pts, bool bDropPacket) - m_dropbase = 0.0f; - #endif - -- double pts_media = m_av_clock->OMXMediaTime(false, false); -- ProcessOverlays(iGroupId, pts_media); -- - if (!CThread::m_bStop && m_av_clock->GetAbsoluteClock(false) < (iCurrentClock + iSleepTime + DVD_MSEC_TO_TIME(500)) ) - return; - -- g_renderManager.FlipPage(CThread::m_bStop, (iCurrentClock + iSleepTime) / DVD_TIME_BASE, -1, FS_NONE); -+ int buffer = g_renderManager.WaitForBuffer(m_bStop); -+ while (buffer < 0 && !CThread::m_bStop) -+ { -+ Sleep(1); -+ buffer = g_renderManager.WaitForBuffer(m_bStop); -+ } -+ if (buffer < 0) -+ return; -+ -+ double pts_media = m_av_clock->OMXMediaTime(false, false); -+ ProcessOverlays(iGroupId, pts_media); -+ -+ g_renderManager.FlipPage(CThread::m_bStop, pts, -1, FS_NONE, m_speed); - - //m_av_clock->WaitAbsoluteClock((iCurrentClock + iSleepTime)); - } -@@ -569,6 +580,7 @@ void OMXPlayerVideo::Process() - m_av_clock->OMXReset(false); - m_av_clock->UnLock(); - m_started = false; -+ g_renderManager.EnableBuffering(false); - } - else if (pMsg->IsType(CDVDMsg::GENERAL_FLUSH)) // private message sent by (COMXPlayerVideo::Flush()) - { -@@ -580,6 +592,7 @@ void OMXPlayerVideo::Process() - m_omxVideo.Reset(); - m_av_clock->OMXReset(false); - m_av_clock->UnLock(); -+ g_renderManager.EnableBuffering(false); - } - else if (pMsg->IsType(CDVDMsg::PLAYER_SETSPEED)) - { -@@ -664,6 +677,7 @@ void OMXPlayerVideo::Process() - m_codecname = m_omxVideo.GetDecoderName(); - 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 --- -1.7.10 - diff --git a/packages/mediacenter/xbmc/patches/todo/xbmc-995.11-multi-screen_fix_compilation_on_windows.patch b/packages/mediacenter/xbmc/patches/todo/xbmc-995.11-multi-screen_fix_compilation_on_windows.patch deleted file mode 100644 index 265c9ae628..0000000000 --- a/packages/mediacenter/xbmc/patches/todo/xbmc-995.11-multi-screen_fix_compilation_on_windows.patch +++ /dev/null @@ -1,75 +0,0 @@ -From bf4d77aeb9ff7c198914031ec0d8268dae0c5973 Mon Sep 17 00:00:00 2001 -From: unknown -Date: Fri, 18 Jan 2013 15:16:38 +0100 -Subject: [PATCH] multi-screen: fix compilation on windows - ---- - xbmc/settings/GUIWindowSettingsCategory.cpp | 11 ++++++++++- - 1 file changed, 10 insertions(+), 1 deletion(-) - -diff --git a/xbmc/settings/GUIWindowSettingsCategory.cpp b/xbmc/settings/GUIWindowSettingsCategory.cpp -index bb29daa..c468a73 100644 ---- a/xbmc/settings/GUIWindowSettingsCategory.cpp -+++ b/xbmc/settings/GUIWindowSettingsCategory.cpp -@@ -525,12 +525,14 @@ void CGUIWindowSettingsCategory::CreateSettings() - FillInRefreshRates(strSetting, g_guiSettings.GetResolution(), false); - continue; - } -+#if defined(HAS_GLX) - else if (strSetting.Equals("videoscreen.monitor")) - { - AddSetting(pSetting, group->GetWidth(), iControlID); - FillInMonitors(strSetting); - continue; - } -+#endif - else if (strSetting.Equals("lookandfeel.skintheme")) - { - AddSetting(pSetting, group->GetWidth(), iControlID); -@@ -1463,6 +1465,7 @@ void CGUIWindowSettingsCategory::OnSettingChanged(BaseSettingControlPtr pSetting - // Cascade - FillInResolutions("videoscreen.resolution", mode, RES_DESKTOP, true); - } -+#if defined(HAS_GLX) - else if (strSetting.Equals("videoscreen.monitor")) - { - CSettingString *pSettingString = (CSettingString *)pSettingControl->GetSetting(); -@@ -1477,6 +1480,7 @@ void CGUIWindowSettingsCategory::OnSettingChanged(BaseSettingControlPtr pSetting - FillInResolutions("videoscreen.resolution", mode, RES_DESKTOP, true); - } - } -+#endif - else if (strSetting.Equals("videoscreen.resolution")) - { - RESOLUTION nextRes = (RESOLUTION) g_guiSettings.GetInt("videoscreen.resolution"); -@@ -2431,6 +2435,7 @@ DisplayMode CGUIWindowSettingsCategory::FillInScreens(CStdString strSetting, RES - - void CGUIWindowSettingsCategory::FillInMonitors(CStdString strSetting) - { -+#if defined(HAS_GLX) - // we expect "videoscreen.monitor" but it might be hidden on some platforms, - // so check that we actually have a visable control. - BaseSettingControlPtr control = GetSetting(strSetting); -@@ -2456,6 +2461,7 @@ void CGUIWindowSettingsCategory::FillInMonitors(CStdString strSetting) - pControl->SetValue(currentMonitor); - g_guiSettings.SetString("videoscreen.monitor", g_settings.m_ResInfo[RES_DESKTOP].strOutput); - } -+#endif - } - - -@@ -2587,7 +2593,10 @@ void CGUIWindowSettingsCategory::OnRefreshRateChanged(RESOLUTION nextRes) - RESOLUTION lastRes = g_graphicsContext.GetVideoResolution(); - bool cancelled = false; - -- bool outputChanged = !g_Windowing.IsCurrentOutput(g_guiSettings.GetString("videoscreen.monitor")); -+ bool outputChanged = true; -+#if defined(HAS_GLX) -+ outputChanged = !g_Windowing.IsCurrentOutput(g_guiSettings.GetString("videoscreen.monitor")); -+#endif - - g_guiSettings.SetResolution(nextRes); - g_graphicsContext.SetVideoResolution(nextRes, outputChanged); --- -1.7.10 - diff --git a/packages/mediacenter/xbmc/patches/xbmc-995.01-xvba_support-1ea917e.patch b/packages/mediacenter/xbmc/patches/xbmc-995.01-xvba_support-1ea917e.patch new file mode 100644 index 0000000000..ac7780f5c2 --- /dev/null +++ b/packages/mediacenter/xbmc/patches/xbmc-995.01-xvba_support-1ea917e.patch @@ -0,0 +1,19295 @@ +From bfd49543c49747236d401df4351767d584f756ac Mon Sep 17 00:00:00 2001 +From: wsnipex +Date: Sun, 4 Nov 2012 14:05:52 +0100 +Subject: [PATCH 01/73] configure: add --enable-pvraddons-with-dependencies + switch for intree building of PVR Addons + +--- + configure.in | 12 ++++++++++++ + 1 file changed, 12 insertions(+) + +diff --git a/configure.in b/configure.in +index 4769315..350d960 100644 +--- a/configure.in ++++ b/configure.in +@@ -521,6 +521,14 @@ AC_ARG_ENABLE([external-ffmpeg], + [use_external_ffmpeg=$use_external_libraries]) + + ### End of external library options ++### PVR addons specific ++AC_ARG_ENABLE([pvraddons-with-dependencies], ++ [AS_HELP_STRING([--enable-pvraddons-with-dependencies], ++ [enable build of pvr addons with dependencies (default is no) 'Linux only'])], ++ [use_pvraddons_with_deps=$enableval], ++ [use_pvraddons_with_deps=no]) ++ ++### End PVR addons specific + + if test "x$host_vendor" != "xapple"; then + DEFAULT_COMPILE_FLAGS="-fPIC -DPIC -D_REENTRANT" +@@ -2770,12 +2778,16 @@ XB_CONFIG_MODULE([pvr-addons], [ + if test "$USE_EXTERNAL_FFMPEG" = 1; then + PVR_EXT_FFMPEG="--enable-external-ffmpeg" + fi ++ if test "$use_pvraddons_with_deps" = "yes"; then ++ ADDONS_WITH_DEPS="--enable-addons-with-dependencies" ++ fi + ./configure \ + --prefix="${prefix}" \ + --host=$host_alias \ + --build=$build_alias \ + --target=$target_alias \ + $PVR_EXT_FFMPEG \ ++ $ADDONS_WITH_DEPS \ + CC="$CC" \ + CXX="$CXX" \ + CFLAGS="$CFLAGS" \ +-- +1.7.10 + + +From dc83e2351e8bf8e904102782ea489d2c8caa2802 Mon Sep 17 00:00:00 2001 +From: xbmc +Date: Mon, 28 May 2012 10:03:31 +0200 +Subject: [PATCH 02/73] VideoRenerers: add buffering + +--- + xbmc/Application.cpp | 3 + + xbmc/cores/VideoRenderers/BaseRenderer.h | 5 +- + xbmc/cores/VideoRenderers/LinuxRendererGL.cpp | 41 ++-- + xbmc/cores/VideoRenderers/LinuxRendererGL.h | 13 +- + xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp | 8 +- + xbmc/cores/VideoRenderers/LinuxRendererGLES.h | 4 +- + xbmc/cores/VideoRenderers/OverlayRenderer.cpp | 19 +- + xbmc/cores/VideoRenderers/OverlayRenderer.h | 6 +- + xbmc/cores/VideoRenderers/RenderManager.cpp | 296 +++++++++++++++++++---- + xbmc/cores/VideoRenderers/RenderManager.h | 48 +++- + xbmc/cores/VideoRenderers/WinRenderer.cpp | 8 +- + xbmc/cores/VideoRenderers/WinRenderer.h | 2 +- + xbmc/cores/dvdplayer/DVDPlayer.cpp | 2 +- + xbmc/cores/dvdplayer/DVDPlayerVideo.cpp | 18 +- + 14 files changed, 380 insertions(+), 93 deletions(-) + +diff --git a/xbmc/Application.cpp b/xbmc/Application.cpp +index c6f0a14..18e6310 100644 +--- a/xbmc/Application.cpp ++++ b/xbmc/Application.cpp +@@ -2367,7 +2367,10 @@ void CApplication::Render() + m_lastFrameTime = XbmcThreads::SystemClockMillis(); + + if (flip) ++ { + g_graphicsContext.Flip(dirtyRegions); ++ g_renderManager.NotifyDisplayFlip(); ++ } + CTimeUtils::UpdateFrameTime(flip); + + g_TextureManager.FreeUnusedTextures(); +diff --git a/xbmc/cores/VideoRenderers/BaseRenderer.h b/xbmc/cores/VideoRenderers/BaseRenderer.h +index 81d21d8..b02d536 100644 +--- a/xbmc/cores/VideoRenderers/BaseRenderer.h ++++ b/xbmc/cores/VideoRenderers/BaseRenderer.h +@@ -80,10 +80,13 @@ class CBaseRenderer + void GetVideoRect(CRect &source, CRect &dest); + float GetAspectRatio() const; + +- virtual bool AddVideoPicture(DVDVideoPicture* picture) { return false; } ++ virtual bool AddVideoPicture(DVDVideoPicture* picture, int index) { return false; } + virtual void Flush() {}; + + virtual unsigned int GetProcessorSize() { return 0; } ++ virtual unsigned int GetMaxProcessorSize() { return 0; } ++ virtual void SetProcessorSize(int numBuffers) { } ++ virtual void ReleaseBuffer(int idx) { } + + virtual bool Supports(ERENDERFEATURE feature) { return false; } + +diff --git a/xbmc/cores/VideoRenderers/LinuxRendererGL.cpp b/xbmc/cores/VideoRenderers/LinuxRendererGL.cpp +index 1cf52d3..b32a7ea 100644 +--- a/xbmc/cores/VideoRenderers/LinuxRendererGL.cpp ++++ b/xbmc/cores/VideoRenderers/LinuxRendererGL.cpp +@@ -235,14 +235,6 @@ bool CLinuxRendererGL::ValidateRenderer() + return true; + } + +- +-void CLinuxRendererGL::ManageTextures() +-{ +- m_NumYV12Buffers = 2; +- //m_iYV12RenderBuffer = 0; +- return; +-} +- + bool CLinuxRendererGL::ValidateRenderTarget() + { + if (!m_bValidated) +@@ -603,13 +595,28 @@ void CLinuxRendererGL::Flush() + glFinish(); + m_bValidated = false; + m_fbo.fbo.Cleanup(); ++ m_iYV12RenderBuffer = 0; ++} ++ ++void CLinuxRendererGL::ReleaseBuffer(int idx) ++{ ++ YUVBUFFER &buf = m_buffers[idx]; ++#ifdef HAVE_LIBVDPAU ++ SAFE_RELEASE(buf.vdpau); ++#endif ++#ifdef HAVE_LIBVA ++ buf.vaapi.surface.reset(); ++#endif ++#ifdef TARGET_DARWIN ++ if (buf.cvBufferRef) ++ CVBufferRelease(buf.cvBufferRef); ++#endif + } + + void CLinuxRendererGL::Update(bool bPauseDrawing) + { + if (!m_bConfigured) return; + ManageDisplay(); +- ManageTextures(); + } + + void CLinuxRendererGL::RenderUpdate(bool clear, DWORD flags, DWORD alpha) +@@ -625,7 +632,6 @@ void CLinuxRendererGL::RenderUpdate(bool clear, DWORD flags, DWORD alpha) + } + + ManageDisplay(); +- ManageTextures(); + + g_graphicsContext.BeginPaint(); + +@@ -782,7 +788,6 @@ unsigned int CLinuxRendererGL::PreInit() + m_resolution = RES_DESKTOP; + + m_iYV12RenderBuffer = 0; +- m_NumYV12Buffers = 2; + + m_formats.push_back(RENDER_FMT_YUV420P); + GLint size; +@@ -2465,7 +2470,7 @@ void CLinuxRendererGL::UploadVAAPITexture(int index) + || status == VA_STATUS_ERROR_INVALID_DISPLAY) + { + va.display->lost(true); +- for(int i = 0; i < NUM_BUFFERS; i++) ++ for(int i = 0; i < m_NumYV12Buffers; i++) + { + m_buffers[i].vaapi.display.reset(); + m_buffers[i].vaapi.surface.reset(); +@@ -3412,26 +3417,26 @@ void CLinuxRendererGL::UnBindPbo(YUVBUFFER& buff) + } + + #ifdef HAVE_LIBVDPAU +-void CLinuxRendererGL::AddProcessor(CVDPAU* vdpau) ++void CLinuxRendererGL::AddProcessor(CVDPAU* vdpau, int index) + { +- YUVBUFFER &buf = m_buffers[NextYV12Texture()]; ++ YUVBUFFER &buf = m_buffers[index]; + SAFE_RELEASE(buf.vdpau); + buf.vdpau = (CVDPAU*)vdpau->Acquire(); + } + #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 TARGET_DARWIN +-void CLinuxRendererGL::AddProcessor(struct __CVBuffer *cvBufferRef) ++void CLinuxRendererGL::AddProcessor(struct __CVBuffer *cvBufferRef, int index) + { +- YUVBUFFER &buf = m_buffers[NextYV12Texture()]; ++ YUVBUFFER &buf = m_buffers[index]; + if (buf.cvBufferRef) + CVBufferRelease(buf.cvBufferRef); + buf.cvBufferRef = cvBufferRef; +diff --git a/xbmc/cores/VideoRenderers/LinuxRendererGL.h b/xbmc/cores/VideoRenderers/LinuxRendererGL.h +index acebfe0..9f55fcb 100644 +--- a/xbmc/cores/VideoRenderers/LinuxRendererGL.h ++++ b/xbmc/cores/VideoRenderers/LinuxRendererGL.h +@@ -44,7 +44,7 @@ + namespace Shaders { class BaseVideoFilterShader; } + namespace VAAPI { struct CHolder; } + +-#define NUM_BUFFERS 3 ++#define NUM_BUFFERS 10 + + + #undef ALIGN +@@ -138,15 +138,19 @@ class CLinuxRendererGL : public CBaseRenderer + 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 GetMaxProcessorSize() { return NUM_BUFFERS; } ++ virtual unsigned int GetProcessorSize() { return m_NumYV12Buffers; } + + #ifdef HAVE_LIBVDPAU +- virtual void AddProcessor(CVDPAU* vdpau); ++ virtual void AddProcessor(CVDPAU* vdpau, int index); + #endif + #ifdef HAVE_LIBVA +- virtual void AddProcessor(VAAPI::CHolder& holder); ++ virtual void AddProcessor(VAAPI::CHolder& holder, int index); + #endif + #ifdef TARGET_DARWIN +- virtual void AddProcessor(struct __CVBuffer *cvBufferRef); ++ virtual void AddProcessor(struct __CVBuffer *cvBufferRef, int index); + #endif + + virtual void RenderUpdate(bool clear, DWORD flags = 0, DWORD alpha = 255); +@@ -168,7 +172,6 @@ class CLinuxRendererGL : public CBaseRenderer + void DrawBlackBars(); + + bool ValidateRenderer(); +- virtual void ManageTextures(); + int NextYV12Texture(); + virtual bool ValidateRenderTarget(); + virtual void LoadShaders(int field=FIELD_FULL); +diff --git a/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp b/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp +index cb0939f..2a59e2b 100644 +--- a/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp ++++ b/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp +@@ -1982,16 +1982,16 @@ EINTERLACEMETHOD CLinuxRendererGLES::AutoInterlaceMethod() + } + + #ifdef HAVE_LIBOPENMAX +-void CLinuxRendererGLES::AddProcessor(COpenMax* openMax, DVDVideoPicture *picture) ++void CLinuxRendererGLES::AddProcessor(COpenMax* openMax, DVDVideoPicture *picture, int index) + { +- YUVBUFFER &buf = m_buffers[NextYV12Texture()]; ++ YUVBUFFER &buf = m_buffers[index]; + buf.openMaxBuffer = picture->openMaxBuffer; + } + #endif + #ifdef HAVE_VIDEOTOOLBOXDECODER +-void CLinuxRendererGLES::AddProcessor(struct __CVBuffer *cvBufferRef) ++void CLinuxRendererGLES::AddProcessor(struct __CVBuffer *cvBufferRef, int index) + { +- YUVBUFFER &buf = m_buffers[NextYV12Texture()]; ++ YUVBUFFER &buf = m_buffers[index]; + if (buf.cvBufferRef) + CVBufferRelease(buf.cvBufferRef); + buf.cvBufferRef = cvBufferRef; +diff --git a/xbmc/cores/VideoRenderers/LinuxRendererGLES.h b/xbmc/cores/VideoRenderers/LinuxRendererGLES.h +index 76b5437..c6b69db 100644 +--- a/xbmc/cores/VideoRenderers/LinuxRendererGLES.h ++++ b/xbmc/cores/VideoRenderers/LinuxRendererGLES.h +@@ -153,10 +153,10 @@ class CLinuxRendererGLES : public CBaseRenderer + virtual std::vector SupportedFormats() { return m_formats; } + + #ifdef HAVE_LIBOPENMAX +- virtual void AddProcessor(COpenMax* openMax, DVDVideoPicture *picture); ++ virtual void AddProcessor(COpenMax* openMax, DVDVideoPicture *picture, int index); + #endif + #ifdef HAVE_VIDEOTOOLBOXDECODER +- virtual void AddProcessor(struct __CVBuffer *cvBufferRef); ++ virtual void AddProcessor(struct __CVBuffer *cvBufferRef, int index); + #endif + + protected: +diff --git a/xbmc/cores/VideoRenderers/OverlayRenderer.cpp b/xbmc/cores/VideoRenderers/OverlayRenderer.cpp +index 19d2d7d..94aaaf5 100644 +--- a/xbmc/cores/VideoRenderers/OverlayRenderer.cpp ++++ b/xbmc/cores/VideoRenderers/OverlayRenderer.cpp +@@ -89,7 +89,6 @@ long COverlayMainThread::Release() + CRenderer::CRenderer() + { + m_render = 0; +- m_decode = (m_render + 1) % 2; + } + + CRenderer::~CRenderer() +@@ -151,20 +150,30 @@ void CRenderer::Flush() + { + 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); + } + + void CRenderer::Flip() + { + CSingleLock lock(m_section); ++ m_render = (m_render + 1) % m_iNumBuffers; ++} + +- m_render = m_decode; +- m_decode =(m_decode + 1) % 2; ++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 --git a/xbmc/cores/VideoRenderers/OverlayRenderer.h b/xbmc/cores/VideoRenderers/OverlayRenderer.h +index d2175d8..c6740a5 100644 +--- a/xbmc/cores/VideoRenderers/OverlayRenderer.h ++++ b/xbmc/cores/VideoRenderers/OverlayRenderer.h +@@ -98,6 +98,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 --git a/xbmc/cores/VideoRenderers/RenderManager.cpp b/xbmc/cores/VideoRenderers/RenderManager.cpp +index d22287d..eeb6c6f 100644 +--- a/xbmc/cores/VideoRenderers/RenderManager.cpp ++++ b/xbmc/cores/VideoRenderers/RenderManager.cpp +@@ -28,6 +28,7 @@ + #include "utils/MathUtils.h" + #include "threads/SingleLock.h" + #include "utils/log.h" ++#include "utils/TimeUtils.h" + + #include "Application.h" + #include "ApplicationMessenger.h" +@@ -247,6 +248,11 @@ bool CXBMCRenderManager::Configure(unsigned int width, unsigned int height, unsi + return false; + } + ++ // check if decoder supports buffering ++ m_bCodecSupportsBuffering = false; ++// if (format == RENDER_FMT_VDPAU) ++// m_bCodecSupportsBuffering = true; ++ + bool result = m_pRenderer->Configure(width, height, d_width, d_height, fps, flags, format, extended_format, orientation); + if(result) + { +@@ -261,6 +267,7 @@ bool CXBMCRenderManager::Configure(unsigned int width, unsigned int height, unsi + m_bReconfigured = true; + m_presentstep = PRESENT_IDLE; + m_presentevent.Set(); ++ ResetRenderBuffer(); + } + + return result; +@@ -292,8 +299,12 @@ void CXBMCRenderManager::RenderUpdate(bool clear, DWORD flags, DWORD alpha) + 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; +@@ -312,7 +323,7 @@ void CXBMCRenderManager::RenderUpdate(bool clear, DWORD flags, DWORD alpha) + m_presentevent.Set(); + } + +-unsigned int CXBMCRenderManager::PreInit() ++unsigned int CXBMCRenderManager::PreInit(CDVDClock *pClock) + { + CRetakeLock lock(m_sharedSection); + +@@ -320,6 +331,7 @@ unsigned int CXBMCRenderManager::PreInit() + m_presenterr = 0.0; + m_errorindex = 0; + memset(m_errorbuff, 0, sizeof(m_errorbuff)); ++ m_pClock = pClock; + + m_bIsStarted = false; + m_bPauseDrawing = false; +@@ -338,6 +350,10 @@ unsigned int CXBMCRenderManager::PreInit() + + UpdateDisplayLatency(); + ++ m_bUseBuffering = false; ++ m_bCodecSupportsBuffering = true; ++ ResetRenderBuffer(); ++ + return m_pRenderer->PreInit(); + } + +@@ -366,7 +382,9 @@ bool CXBMCRenderManager::Flush() + + CRetakeLock lock(m_sharedSection); + m_pRenderer->Flush(); ++ m_overlays.Flush(); + m_flushEvent.Set(); ++ ResetRenderBuffer(); + } + else + { +@@ -534,25 +552,21 @@ void CXBMCRenderManager::SetViewMode(int iViewMode) + m_pRenderer->SetViewMode(iViewMode); + } + +-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; +@@ -560,58 +574,67 @@ void CXBMCRenderManager::FlipPage(volatile bool& bStop, double timestamp /* = 0L + { 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; ++ } + } + } + } +@@ -675,8 +698,12 @@ void CXBMCRenderManager::Present() + 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; +@@ -800,11 +827,11 @@ int CXBMCRenderManager::AddVideoPicture(DVDVideoPicture& pic) + if (!m_pRenderer) + return -1; + +- if(m_pRenderer->AddVideoPicture(&pic)) ++ if(m_pRenderer->AddVideoPicture(&pic, (m_iOutputRenderBuffer + 1) % m_iNumRenderBuffers)) + 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; +@@ -830,19 +857,19 @@ int CXBMCRenderManager::AddVideoPicture(DVDVideoPicture& pic) + } + #ifdef HAVE_LIBVDPAU + else if(pic.format == RENDER_FMT_VDPAU) +- m_pRenderer->AddProcessor(pic.vdpau); ++ m_pRenderer->AddProcessor(pic.vdpau, index); + #endif + #ifdef HAVE_LIBOPENMAX + else if(pic.format == RENDER_FMT_OMXEGL) +- m_pRenderer->AddProcessor(pic.openMax, &pic); ++ m_pRenderer->AddProcessor(pic.openMax, &pic, index); + #endif + #ifdef TARGET_DARWIN + else if(pic.format == RENDER_FMT_CVBREF) +- m_pRenderer->AddProcessor(pic.cvBufferRef); ++ m_pRenderer->AddProcessor(pic.cvBufferRef, index); + #endif + #ifdef HAVE_LIBVA + else if(pic.format == RENDER_FMT_VAAPI) +- m_pRenderer->AddProcessor(*pic.vaapi); ++ m_pRenderer->AddProcessor(*pic.vaapi, index); + #endif + m_pRenderer->ReleaseImage(index, false); + +@@ -904,3 +931,176 @@ EINTERLACEMETHOD CXBMCRenderManager::AutoInterlaceMethodInternal(EINTERLACEMETHO + + 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(); ++} ++ ++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 outputPlus1 = (m_iOutputRenderBuffer + 1) % m_iNumRenderBuffers; ++ if ((m_iOutputRenderBuffer == m_iDisplayedRenderBuffer && !m_bAllRenderBuffersDisplayed) ++ || outputPlus1 == m_iCurrentRenderBuffer) ++ return false; ++ else ++ return true; ++} ++ ++void CXBMCRenderManager::ResetRenderBuffer() ++{ ++ m_iNumRenderBuffers = m_pRenderer->GetMaxProcessorSize(); ++ m_iNumRenderBuffers = std::min(5, m_iNumRenderBuffers); ++ m_iNumRenderBuffers = std::max(2, m_iNumRenderBuffers); ++ ++ if (!m_bCodecSupportsBuffering) ++ m_iNumRenderBuffers = 2; ++ ++ CLog::Log(LOGNOTICE,"CXBMCRenderManager::ResetRenderBuffer - using %d render buffers", m_iNumRenderBuffers); ++ m_overlays.SetNumBuffers(m_iNumRenderBuffers); ++ m_pRenderer->SetProcessorSize(m_iNumRenderBuffers); ++ ++ m_iCurrentRenderBuffer = 0; ++ m_iOutputRenderBuffer = 0; ++ m_iDisplayedRenderBuffer = 0; ++ m_bAllRenderBuffersDisplayed = true; ++ m_sleeptime = 1.0; ++ m_presentPts = DVD_NOPTS_VALUE; ++ m_speed = 0; ++} ++ ++void CXBMCRenderManager::PrepareNextRender() ++{ ++ int idx = GetNextRenderBufferIndex(); ++ if (idx < 0) ++ { ++ if (m_speed >= DVD_PLAYSPEED_NORMAL && g_graphicsContext.IsFullScreenVideo()) ++ CLog::Log(LOGDEBUG,"%s no buffer, out: %d, current: %d, display: %d", ++ __FUNCTION__, 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; ++ ++ 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); ++ ++ if (m_iNumRenderBuffers < 3) ++ return; ++ ++ 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 (m_iNumRenderBuffers < 3) ++ return; ++ ++ int last = m_iDisplayedRenderBuffer; ++ m_iDisplayedRenderBuffer = (m_iCurrentRenderBuffer + m_iNumRenderBuffers - 1) % m_iNumRenderBuffers; ++ ++ if (last != m_iDisplayedRenderBuffer ++ && m_iDisplayedRenderBuffer != m_iCurrentRenderBuffer) ++ { ++ m_pRenderer->ReleaseBuffer(m_iDisplayedRenderBuffer); ++ m_overlays.ReleaseBuffer(m_iDisplayedRenderBuffer); ++ } ++ ++ lock.Leave(); ++ m_flipEvent.Set(); ++} +diff --git a/xbmc/cores/VideoRenderers/RenderManager.h b/xbmc/cores/VideoRenderers/RenderManager.h +index 7fe6bb2..34ff8d0 100644 +--- a/xbmc/cores/VideoRenderers/RenderManager.h ++++ b/xbmc/cores/VideoRenderers/RenderManager.h +@@ -31,6 +31,7 @@ + #include "OverlayRenderer.h" + + class CRenderCapture; ++class CDVDClock; + + namespace DXVA { class CProcessor; } + namespace VAAPI { class CSurfaceHolder; } +@@ -70,8 +71,8 @@ class CXBMCRenderManager + + 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(); + +@@ -131,6 +132,10 @@ class CXBMCRenderManager + CSharedSection& GetSection() { return m_sharedSection; }; + + void RegisterRenderUpdateCallBack(const void *ctx, RenderUpdateCallBackFn fn); ++ int WaitForBuffer(volatile bool& bStop); ++ void NotifyDisplayFlip(); ++ void EnableBuffering(bool enable); ++ void DiscardBuffer(); + + protected: + void Render(bool clear, DWORD flags, DWORD alpha); +@@ -139,6 +144,13 @@ class CXBMCRenderManager + void PresentFields(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 +@@ -169,6 +181,37 @@ class CXBMCRenderManager + 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). ++ // 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). ++ ++ int m_iCurrentRenderBuffer; ++ int m_iNumRenderBuffers; ++ int m_iOutputRenderBuffer; ++ int m_iDisplayedRenderBuffer; ++ bool m_bAllRenderBuffersDisplayed; ++ bool m_bUseBuffering; ++ bool m_bCodecSupportsBuffering; ++ 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; +@@ -180,6 +223,7 @@ class CXBMCRenderManager + int m_presentsource; + CEvent m_presentevent; + CEvent m_flushEvent; ++ CDVDClock *m_pClock; + + + OVERLAY::CRenderer m_overlays; +diff --git a/xbmc/cores/VideoRenderers/WinRenderer.cpp b/xbmc/cores/VideoRenderers/WinRenderer.cpp +index 7842089..6e4433c 100644 +--- a/xbmc/cores/VideoRenderers/WinRenderer.cpp ++++ b/xbmc/cores/VideoRenderers/WinRenderer.cpp +@@ -253,12 +253,12 @@ int CWinRenderer::NextYV12Texture() + return -1; + } + +-bool CWinRenderer::AddVideoPicture(DVDVideoPicture* picture) ++bool CWinRenderer::AddVideoPicture(DVDVideoPicture* picture, int index) + { + if (m_renderMethod == RENDER_DXVA) + { +- int source = NextYV12Texture(); +- if(source < 0) ++ int source = index; ++ if(source < 0 || NextYV12Texture() < 0) + return false; + + DXVABuffer *buf = (DXVABuffer*)m_VideoBuffers[source]; +@@ -274,7 +274,7 @@ int CWinRenderer::GetImage(YV12Image *image, int source, bool readonly) + if( source == AUTOSOURCE ) + source = NextYV12Texture(); + +- if( source < 0 ) ++ if( source < 0 || NextYV12Texture() < 0) + return -1; + + YUVBuffer *buf = (YUVBuffer*)m_VideoBuffers[source]; +diff --git a/xbmc/cores/VideoRenderers/WinRenderer.h b/xbmc/cores/VideoRenderers/WinRenderer.h +index 2ab5684..f493ba7 100644 +--- a/xbmc/cores/VideoRenderers/WinRenderer.h ++++ b/xbmc/cores/VideoRenderers/WinRenderer.h +@@ -157,7 +157,7 @@ class CWinRenderer : public CBaseRenderer + virtual bool Configure(unsigned int width, unsigned int height, unsigned int d_width, unsigned int d_height, float fps, unsigned flags, ERenderFormat format, unsigned extended_format, unsigned int orientation); + virtual int GetImage(YV12Image *image, int source = AUTOSOURCE, bool readonly = false); + virtual void ReleaseImage(int source, bool preserve = false); +- virtual bool AddVideoPicture(DVDVideoPicture* picture); ++ virtual bool AddVideoPicture(DVDVideoPicture* picture, int index); + virtual void FlipPage(int source); + virtual unsigned int PreInit(); + virtual void UnInit(); +diff --git a/xbmc/cores/dvdplayer/DVDPlayer.cpp b/xbmc/cores/dvdplayer/DVDPlayer.cpp +index 0cd2510..315d64a 100644 +--- a/xbmc/cores/dvdplayer/DVDPlayer.cpp ++++ b/xbmc/cores/dvdplayer/DVDPlayer.cpp +@@ -463,7 +463,7 @@ bool CDVDPlayer::OpenFile(const CFileItem& file, const CPlayerOptions &options) + m_ready.Reset(); + + #if defined(HAS_VIDEO_PLAYBACK) +- g_renderManager.PreInit(); ++ g_renderManager.PreInit(&m_clock); + #endif + + Create(); +diff --git a/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp b/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp +index 3008c25..a4bb1ba 100644 +--- a/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp ++++ b/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp +@@ -261,6 +261,7 @@ void CDVDPlayerVideo::OpenStream(CDVDStreamInfo &hint, CDVDVideoCodec* codec) + 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) +@@ -436,6 +437,7 @@ void CDVDPlayerVideo::Process() + picture.iFlags &= ~DVP_FLAG_ALLOCATED; + m_packets.clear(); + m_started = false; ++ g_renderManager.EnableBuffering(false); + } + else if (pMsg->IsType(CDVDMsg::GENERAL_FLUSH)) // private message sent by (CDVDPlayerVideo::Flush()) + { +@@ -448,6 +450,7 @@ void CDVDPlayerVideo::Process() + //we need to recalculate the framerate + //TODO: this needs to be set on a streamchange instead + ResetFrameRateCalc(); ++ g_renderManager.EnableBuffering(false); + + m_stalled = true; + m_started = false; +@@ -586,6 +589,8 @@ void CDVDPlayerVideo::Process() + + m_pVideoCodec->Reset(); + m_packets.clear(); ++ picture.iFlags &= ~DVP_FLAG_ALLOCATED; ++ g_renderManager.DiscardBuffer(); + break; + } + +@@ -700,6 +705,7 @@ void CDVDPlayerVideo::Process() + 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 +@@ -1317,6 +1323,16 @@ int CDVDPlayerVideo::OutputPicture(const DVDVideoPicture* src, double pts) + 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); + +@@ -1333,7 +1349,7 @@ int CDVDPlayerVideo::OutputPicture(const DVDVideoPicture* src, double pts) + 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 +-- +1.7.10 + + +From dacc0167c993efa6ac884fd3c439fc5f0c823934 Mon Sep 17 00:00:00 2001 +From: xbmc +Date: Tue, 2 Oct 2012 10:49:09 +0200 +Subject: [PATCH 03/73] linuxrenderer: delete all textures on reconfigure + +--- + xbmc/cores/VideoRenderers/LinuxRendererGL.cpp | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/xbmc/cores/VideoRenderers/LinuxRendererGL.cpp b/xbmc/cores/VideoRenderers/LinuxRendererGL.cpp +index b32a7ea..a2dc2be 100644 +--- a/xbmc/cores/VideoRenderers/LinuxRendererGL.cpp ++++ b/xbmc/cores/VideoRenderers/LinuxRendererGL.cpp +@@ -251,7 +251,7 @@ bool CLinuxRendererGL::ValidateRenderTarget() + // function pointer for texture might change in + // call to LoadShaders + glFinish(); +- for (int i = 0 ; i < m_NumYV12Buffers ; i++) ++ for (int i = 0 ; i < NUM_BUFFERS ; i++) + (this->*m_textureDelete)(i); + + // trigger update of video filters +-- +1.7.10 + + +From 226539d21ba940ea8add89417df7102302c7ba79 Mon Sep 17 00:00:00 2001 +From: xbmc +Date: Mon, 28 May 2012 10:17:33 +0200 +Subject: [PATCH 04/73] drop frame counter in application, ask render manager + instead + +--- + xbmc/Application.cpp | 50 +++++---------------------- + xbmc/Application.h | 6 ++-- + xbmc/cores/VideoRenderers/RenderManager.cpp | 11 ++++++ + xbmc/cores/VideoRenderers/RenderManager.h | 1 + + 4 files changed, 23 insertions(+), 45 deletions(-) + +diff --git a/xbmc/Application.cpp b/xbmc/Application.cpp +index 18e6310..9a7b900 100644 +--- a/xbmc/Application.cpp ++++ b/xbmc/Application.cpp +@@ -415,8 +415,6 @@ + #endif + m_currentStack = new CFileItemList; + +- m_frameCount = 0; +- + m_bPresentFrame = false; + m_bPlatformDirectories = true; + +@@ -2227,28 +2225,18 @@ float CApplication::GetDimScreenSaverLevel() const + + 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() +@@ -2268,7 +2256,6 @@ void CApplication::Render() + + int vsync_mode = g_guiSettings.GetInt("videoscreen.vsync"); + +- bool decrement = false; + bool hasRendered = false; + bool limitFrames = false; + unsigned int singleFrameTime = 10; // default limit 100 fps +@@ -2282,13 +2269,10 @@ void CApplication::Render() + m_bPresentFrame = false; + if (!extPlayerActive && g_graphicsContext.IsFullScreenVideo() && !IsPaused()) + { +- CSingleLock lock(m_frameMutex); +- +- TightConditionVariable cv(m_frameCond,m_frameCount); +- cv.wait(lock,100); +- +- m_bPresentFrame = m_frameCount > 0; +- decrement = m_bPresentFrame; ++ m_frameEvent.Reset(); ++ m_bPresentFrame = g_renderManager.HasFrame(); ++ if (!m_bPresentFrame && m_frameEvent.WaitMSec(100)) ++ m_bPresentFrame = g_renderManager.HasFrame(); + hasRendered = true; + } + else +@@ -2312,8 +2296,6 @@ void CApplication::Render() + else if (lowfps) + singleFrameTime = 200; // 5 fps, <=200 ms latency to wake up + } +- +- decrement = true; + } + } + +@@ -2377,13 +2359,6 @@ void CApplication::Render() + + 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) +@@ -5638,12 +5613,6 @@ bool CApplication::SwitchToFullScreen() + // 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; +@@ -5876,7 +5845,6 @@ bool CApplication::IsCurrentThread() const + + bool CApplication::IsPresentFrame() + { +- CSingleLock lock(m_frameMutex); + bool ret = m_bPresentFrame; + + return ret; +diff --git a/xbmc/Application.h b/xbmc/Application.h +index 69609fa..6764a60 100644 +--- a/xbmc/Application.h ++++ b/xbmc/Application.h +@@ -422,10 +422,8 @@ class CApplication : public CXBApplicationEx, public IPlayerCallback, public IMs + bool m_bEnableLegacyRes; + bool m_bTestMode; + bool m_bSystemScreenSaverEnable; +- +- int m_frameCount; +- CCriticalSection m_frameMutex; +- XbmcThreads::ConditionVariable m_frameCond; ++ ++ CEvent m_frameEvent; + + VIDEO::CVideoInfoScanner *m_videoInfoScanner; + MUSIC_INFO::CMusicInfoScanner *m_musicInfoScanner; +diff --git a/xbmc/cores/VideoRenderers/RenderManager.cpp b/xbmc/cores/VideoRenderers/RenderManager.cpp +index eeb6c6f..4b897da 100644 +--- a/xbmc/cores/VideoRenderers/RenderManager.cpp ++++ b/xbmc/cores/VideoRenderers/RenderManager.cpp +@@ -1104,3 +1104,14 @@ void CXBMCRenderManager::NotifyDisplayFlip() + lock.Leave(); + m_flipEvent.Set(); + } ++ ++bool CXBMCRenderManager::HasFrame() ++{ ++ CSharedLock lock(m_sharedSection); ++ if (m_presentstep == PRESENT_IDLE && ++ GetNextRenderBufferIndex() < 0 && ++ m_speed > 0) ++ return false; ++ else ++ return true; ++} +diff --git a/xbmc/cores/VideoRenderers/RenderManager.h b/xbmc/cores/VideoRenderers/RenderManager.h +index 34ff8d0..288175e 100644 +--- a/xbmc/cores/VideoRenderers/RenderManager.h ++++ b/xbmc/cores/VideoRenderers/RenderManager.h +@@ -134,6 +134,7 @@ class CXBMCRenderManager + void RegisterRenderUpdateCallBack(const void *ctx, RenderUpdateCallBackFn fn); + int WaitForBuffer(volatile bool& bStop); + void NotifyDisplayFlip(); ++ bool HasFrame(); + void EnableBuffering(bool enable); + void DiscardBuffer(); + +-- +1.7.10 + + +From 0f81843cb7279f3b99607551967354ff30e15e4d Mon Sep 17 00:00:00 2001 +From: xbmc +Date: Mon, 28 May 2012 10:34:39 +0200 +Subject: [PATCH 05/73] videoplayer: adopt lateness detection and dropping to + buffering + +--- + xbmc/cores/VideoRenderers/RenderManager.cpp | 12 ++ + xbmc/cores/VideoRenderers/RenderManager.h | 1 + + .../dvdplayer/DVDCodecs/Video/DVDVideoCodec.h | 14 ++ + .../DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp | 31 +++ + .../DVDCodecs/Video/DVDVideoCodecFFmpeg.h | 7 + + xbmc/cores/dvdplayer/DVDPlayerVideo.cpp | 224 ++++++++++++++++---- + xbmc/cores/dvdplayer/DVDPlayerVideo.h | 24 +++ + 7 files changed, 268 insertions(+), 45 deletions(-) + +diff --git a/xbmc/cores/VideoRenderers/RenderManager.cpp b/xbmc/cores/VideoRenderers/RenderManager.cpp +index 4b897da..f19797c 100644 +--- a/xbmc/cores/VideoRenderers/RenderManager.cpp ++++ b/xbmc/cores/VideoRenderers/RenderManager.cpp +@@ -1105,6 +1105,18 @@ void CXBMCRenderManager::NotifyDisplayFlip() + m_flipEvent.Set(); + } + ++bool CXBMCRenderManager::GetStats(double &sleeptime, double &pts, int &bufferLevel) ++{ ++ CSharedLock lock(m_sharedSection); ++ sleeptime = m_sleeptime; ++ pts = m_presentPts; ++ if (m_iNumRenderBuffers < 3) ++ bufferLevel = -1; ++ else ++ bufferLevel = (m_iOutputRenderBuffer - m_iCurrentRenderBuffer + m_iNumRenderBuffers) % m_iNumRenderBuffers; ++ return true; ++} ++ + bool CXBMCRenderManager::HasFrame() + { + CSharedLock lock(m_sharedSection); +diff --git a/xbmc/cores/VideoRenderers/RenderManager.h b/xbmc/cores/VideoRenderers/RenderManager.h +index 288175e..9342586 100644 +--- a/xbmc/cores/VideoRenderers/RenderManager.h ++++ b/xbmc/cores/VideoRenderers/RenderManager.h +@@ -134,6 +134,7 @@ class CXBMCRenderManager + void RegisterRenderUpdateCallBack(const void *ctx, RenderUpdateCallBackFn fn); + int WaitForBuffer(volatile bool& bStop); + void NotifyDisplayFlip(); ++ bool GetStats(double &sleeptime, double &pts, int &bufferLevel); + bool HasFrame(); + void EnableBuffering(bool enable); + void DiscardBuffer(); +diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodec.h b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodec.h +index 1d8bad3..5001aac 100644 +--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodec.h ++++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodec.h +@@ -110,6 +110,10 @@ struct DVDVideoUserData + #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_NO_POSTPROC 0x00000100 ++#define DVP_FLAG_DRAIN 0x00000200 ++ + // DVP_FLAG 0x00000100 - 0x00000f00 is in use by libmpeg2! + + #define DVP_QSCALE_UNKNOWN 0 +@@ -127,6 +131,9 @@ struct DVDVideoUserData + #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 ++ + class CDVDVideoCodec + { + public: +@@ -237,4 +244,11 @@ class CDVDVideoCodec + { + return 0; + } ++ ++ virtual bool GetPts(double &pts, int &skippedDeint, int &interlaced) ++ { ++ return false; ++ } ++ ++ virtual void SetCodecControl(int flags) {} + }; +diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp +index 8f81637..af706bd 100644 +--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp ++++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp +@@ -142,6 +142,7 @@ enum PixelFormat CDVDVideoCodecFFmpeg::GetFormat( struct AVCodecContext * avctx + m_iLastKeyframe = 0; + m_dts = DVD_NOPTS_VALUE; + m_started = false; ++ m_decoderPts = DVD_NOPTS_VALUE; + } + + CDVDVideoCodecFFmpeg::~CDVDVideoCodecFFmpeg() +@@ -340,6 +341,14 @@ void CDVDVideoCodecFFmpeg::SetDropState(bool bDrop) + { + 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 +@@ -541,6 +550,7 @@ int CDVDVideoCodecFFmpeg::Decode(BYTE* pData, int iSize, double dts, double pts) + 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); + +@@ -639,6 +649,22 @@ bool CDVDVideoCodecFFmpeg::GetPictureCommon(DVDVideoPicture* pDvdVideoPicture) + 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_codecControlFlags; ++ + if(!m_started) + pDvdVideoPicture->iFlags |= DVP_FLAG_DROPPED; + +@@ -861,3 +887,8 @@ unsigned CDVDVideoCodecFFmpeg::GetConvergeCount() + else + return 0; + } ++ ++void CDVDVideoCodecFFmpeg::SetCodecControl(int flags) ++{ ++ m_codecControlFlags = flags; ++} +diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.h b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.h +index 61d0305..52e1113 100644 +--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.h ++++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.h +@@ -44,6 +44,7 @@ class CDVDVideoCodecFFmpeg : public CDVDVideoCodec + 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 const std::string Name() = 0; + virtual CCriticalSection* Section() { return NULL; } + }; +@@ -60,6 +61,8 @@ class CDVDVideoCodecFFmpeg : public CDVDVideoCodec + 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 SetCodecControl(int flags); + + bool IsHardwareAllowed() { return !m_bSoftware; } + IHardwareDecoder * GetHardware() { return m_pHardware; }; +@@ -119,4 +122,8 @@ class CDVDVideoCodecFFmpeg : public CDVDVideoCodec + double m_dts; + bool m_started; + std::vector m_formats; ++ double m_decoderPts, m_decoderInterval; ++ int m_skippedDeint; ++ bool m_requestSkipDeint; ++ int m_codecControlFlags; + }; +diff --git a/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp b/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp +index a4bb1ba..93908a7 100644 +--- a/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp ++++ b/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp +@@ -326,8 +326,10 @@ void CDVDPlayerVideo::Process() + + int iDropped = 0; //frames dropped in a row + bool bRequestDrop = false; ++ int iDropDirective; + + m_videoStats.Start(); ++ m_droppingStats.Reset(); + + while (!m_bStop) + { +@@ -437,6 +439,7 @@ void CDVDPlayerVideo::Process() + picture.iFlags &= ~DVP_FLAG_ALLOCATED; + m_packets.clear(); + m_started = false; ++ m_droppingStats.Reset(); + g_renderManager.EnableBuffering(false); + } + else if (pMsg->IsType(CDVDMsg::GENERAL_FLUSH)) // private message sent by (CDVDPlayerVideo::Flush()) +@@ -450,6 +453,7 @@ void CDVDPlayerVideo::Process() + //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; +@@ -468,6 +472,7 @@ void CDVDPlayerVideo::Process() + m_speed = static_cast(pMsg)->m_value; + if(m_speed == DVD_PLAYSPEED_PAUSE) + m_iNrOfPicturesNotToSkip = 0; ++ m_droppingStats.Reset(); + } + else if (pMsg->IsType(CDVDMsg::PLAYER_STARTED)) + { +@@ -502,6 +507,28 @@ void CDVDPlayerVideo::Process() + 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) ++ codecControl |= DVP_FLAG_DRAIN; ++ if (m_speed > DVD_PLAYSPEED_NORMAL) ++ codecControl |= DVP_FLAG_NO_POSTPROC; ++ m_pVideoCodec->SetCodecControl(codecControl); ++ if (iDropDirective & EOS_DROPPED) ++ { ++ m_iDroppedFrames++; ++ iDropped++; ++ } ++ + #ifdef PROFILE + bRequestDrop = false; + #else +@@ -511,6 +538,7 @@ void CDVDPlayerVideo::Process() + bRequestDrop = false; + m_iDroppedRequest = 0; + m_iLateFrames = 0; ++ m_droppingStats.m_requestOutputDrop = false; + } + #endif + +@@ -558,15 +586,8 @@ void CDVDPlayerVideo::Process() + } + + m_videoStats.AddSampleBytes(pPacket->iSize); +- // assume decoder dropped a picture if it didn't give us any +- // 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++; +- } ++ ++ bRequestDrop = false; + + // loop while no error + while (!m_bStop) +@@ -1244,50 +1265,30 @@ int CDVDPlayerVideo::OutputPicture(const DVDVideoPicture* src, double pts) + m_FlipTimeStamp += max(0.0, iSleepTime); + m_FlipTimeStamp += iFrameDuration; + +- 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 ++ if ((m_droppingStats.m_requestOutputDrop && !(pPicture->iFlags & DVP_FLAG_NOSKIP)) ++ || (pPicture->iFlags & DVP_FLAG_DROPPED)) + { +- m_iDroppedRequest = 0; ++ m_droppingStats.AddOutputDropGain(pts, 1/m_fFrameRate); ++ m_droppingStats.m_requestOutputDrop = false; ++ CLog::Log(LOGDEBUG,"%s - dropped in output", __FUNCTION__); ++ return result | EOS_DROPPED; + } + + if( m_speed < 0 ) + { +- if( iClockSleep < -DVD_MSEC_TO_TIME(200) +- && !(pPicture->iFlags & DVP_FLAG_NOSKIP) ) ++ double decoderPts = m_droppingStats.m_lastDecoderPts; ++ double renderPts = m_droppingStats.m_lastRenderPts; ++ if (pts > renderPts) ++ { ++ if (decoderPts >= renderPts) ++ { ++ Sleep(200); ++ } + 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 +@@ -1648,3 +1649,136 @@ void CDVDPlayerVideo::CalcFrameRate() + 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; ++ if (iDecoderPts == DVD_NOPTS_VALUE) ++ iDecoderPts = pts; ++ ++ // get render stats ++ g_renderManager.GetStats(iSleepTime, iRenderPts, iBufferLevel); ++ ++ if (iBufferLevel < 0) ++ result |= EOS_BUFFER_LEVEL; ++ else if (iBufferLevel < 2) ++ { ++ result |= EOS_BUFFER_LEVEL; ++ CLog::Log(LOGDEBUG,"CDVDPlayerVideo::CalcDropRequirement - 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; ++ ++ 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(); ++ } ++ ++ // 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; ++ } ++ 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 --git a/xbmc/cores/dvdplayer/DVDPlayerVideo.h b/xbmc/cores/dvdplayer/DVDPlayerVideo.h +index fe7e12c..4913712 100644 +--- a/xbmc/cores/dvdplayer/DVDPlayerVideo.h ++++ b/xbmc/cores/dvdplayer/DVDPlayerVideo.h +@@ -37,6 +37,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: +@@ -110,6 +130,7 @@ class CDVDPlayerVideo : public CThread + #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); +@@ -135,6 +156,7 @@ class CDVDPlayerVideo : public CThread + + 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 +@@ -195,5 +217,7 @@ class CDVDPlayerVideo : public CThread + CPullupCorrection m_pullupCorrection; + + std::list m_packets; ++ ++ CDroppingStats m_droppingStats; + }; + +-- +1.7.10 + + +From 4bc6ff77b121468020578f9d393e8aaae1a419f6 Mon Sep 17 00:00:00 2001 +From: xbmc +Date: Mon, 28 May 2012 10:41:31 +0200 +Subject: [PATCH 06/73] videoplayer: update frametime, it might change due to + fps detection + +--- + xbmc/cores/dvdplayer/DVDPlayerVideo.cpp | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp b/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp +index 93908a7..4675556 100644 +--- a/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp ++++ b/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp +@@ -721,6 +721,8 @@ void CDVDPlayerVideo::Process() + CDVDCodecUtils::FreePicture(pTempYUVPackedPicture); + #endif + ++ frametime = (double)DVD_TIME_BASE/m_fFrameRate; ++ + if(m_started == false) + { + m_codecname = m_pVideoCodec->GetName(); +-- +1.7.10 + + +From 723a731d68b9360f9804e8711255afa62c4ce34d Mon Sep 17 00:00:00 2001 +From: xbmc +Date: Mon, 28 May 2012 10:43:06 +0200 +Subject: [PATCH 07/73] videoplayer: give streams with invalid fps a chance + for fps detection + +--- + xbmc/cores/dvdplayer/DVDPlayerVideo.cpp | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp b/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp +index 4675556..2ef6358 100644 +--- a/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp ++++ b/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp +@@ -1595,7 +1595,7 @@ void CDVDPlayerVideo::CalcFrameRate() + 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; +-- +1.7.10 + + +From 60c955c30cdfcf361396e47fc92a1e1883b085fe Mon Sep 17 00:00:00 2001 +From: xbmc +Date: Mon, 28 May 2012 10:49:05 +0200 +Subject: [PATCH 08/73] dvdplayer: allow rewinding at end of stream, do a seek + after rewind + +--- + xbmc/cores/dvdplayer/DVDPlayer.cpp | 8 +++++++- + 1 file changed, 7 insertions(+), 1 deletion(-) + +diff --git a/xbmc/cores/dvdplayer/DVDPlayer.cpp b/xbmc/cores/dvdplayer/DVDPlayer.cpp +index 315d64a..6fcb6b3 100644 +--- a/xbmc/cores/dvdplayer/DVDPlayer.cpp ++++ b/xbmc/cores/dvdplayer/DVDPlayer.cpp +@@ -1542,7 +1542,7 @@ void CDVDPlayer::HandlePlaySpeed() + + } + else if (m_CurrentVideo.id >= 0 +- && m_CurrentVideo.inited == true ++ && (m_CurrentVideo.inited == true || GetPlaySpeed() < 0) // allow rewind at end of file + && m_SpeedState.lastpts != m_dvdPlayerVideo.GetCurrentPts() + && m_SpeedState.lasttime != GetTime()) + { +@@ -2183,6 +2183,12 @@ void CDVDPlayer::HandleMessages() + pvrinputstream->Pause( speed == 0 ); + } + ++ // do a seek after rewind, clock is not in sync with current pts ++ 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 +-- +1.7.10 + + +From 8d237cf023501560fc394679819463034a209413 Mon Sep 17 00:00:00 2001 +From: xbmc +Date: Sun, 2 Sep 2012 16:05:21 +0200 +Subject: [PATCH 09/73] video player: present correct pts to user for a/v sync + (after buffering in renderer) + +--- + xbmc/cores/dvdplayer/DVDPlayerVideo.cpp | 41 +++++++++++++++++++------------ + xbmc/cores/dvdplayer/DVDPlayerVideo.h | 2 +- + 2 files changed, 26 insertions(+), 17 deletions(-) + +diff --git a/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp b/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp +index 2ef6358..10e2225 100644 +--- a/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp ++++ b/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp +@@ -1251,22 +1251,6 @@ int CDVDPlayerVideo::OutputPicture(const DVDVideoPicture* src, double pts) + else + iSleepTime = iFrameSleep + (iClockSleep - iFrameSleep) / m_autosync; + +-#ifdef PROFILE /* during profiling, try to play as fast as possible */ +- iSleepTime = 0; +-#endif +- +- // present the current pts of this frame to user, and include the actual +- // presentation delay, to allow him to adjust for it +- if( m_stalled ) +- m_iCurrentPts = DVD_NOPTS_VALUE; +- else +- m_iCurrentPts = pts - max(0.0, iSleepTime); +- +- // timestamp when we think next picture should be displayed based on current duration +- m_FlipTimeStamp = iCurrentClock; +- m_FlipTimeStamp += max(0.0, iSleepTime); +- m_FlipTimeStamp += iFrameDuration; +- + if ((m_droppingStats.m_requestOutputDrop && !(pPicture->iFlags & DVP_FLAG_NOSKIP)) + || (pPicture->iFlags & DVP_FLAG_DROPPED)) + { +@@ -1571,6 +1555,22 @@ void CDVDPlayerVideo::ResetFrameRateCalc() + g_advancedSettings.m_videoFpsDetect == 0; + } + ++double CDVDPlayerVideo::GetCurrentPts() ++{ ++ double iSleepTime, iRenderPts; ++ int iBufferLevel; ++ ++ // get render stats ++ g_renderManager.GetStats(iSleepTime, iRenderPts, iBufferLevel); ++ ++ if( m_stalled ) ++ iRenderPts = DVD_NOPTS_VALUE; ++ else ++ iRenderPts = iRenderPts - max(0.0, iSleepTime); ++ ++ return iRenderPts; ++} ++ + #define MAXFRAMERATEDIFF 0.01 + #define MAXFRAMESERR 1000 + +@@ -1689,6 +1689,15 @@ int CDVDPlayerVideo::CalcDropRequirement(double pts) + else + iInterval = 1/m_fFrameRate*(double)DVD_TIME_BASE; + ++ ++ m_FlipTimeStamp = m_pClock->GetAbsoluteClock() + max(0.0, iSleepTime) + iInterval; ++ ++ if( m_stalled ) ++ m_iCurrentPts = DVD_NOPTS_VALUE; ++ else ++ m_iCurrentPts = iRenderPts - max(0.0, iSleepTime); ++ ++ + if (m_droppingStats.m_lastDecoderPts > 0 + && bNewFrame + && m_bAllowDrop +diff --git a/xbmc/cores/dvdplayer/DVDPlayerVideo.h b/xbmc/cores/dvdplayer/DVDPlayerVideo.h +index 4913712..509d5f7 100644 +--- a/xbmc/cores/dvdplayer/DVDPlayerVideo.h ++++ b/xbmc/cores/dvdplayer/DVDPlayerVideo.h +@@ -108,7 +108,7 @@ class CDVDPlayerVideo : public CThread + + bool InitializedOutputDevice(); + +- double GetCurrentPts() { return m_iCurrentPts; } ++ double GetCurrentPts(); + int GetPullupCorrection() { return m_pullupCorrection.GetPatternLength(); } + + double GetOutputDelay(); /* returns the expected delay, from that a packet is put in queue */ +-- +1.7.10 + + +From 04a6a8b4ca29c17da6bbb9591685922b2f6f1442 Mon Sep 17 00:00:00 2001 +From: xbmc +Date: Mon, 28 May 2012 11:02:29 +0200 +Subject: [PATCH 10/73] vaapi: adopt to buffering in renderer + +--- + xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp | 2 +- + xbmc/cores/dvdplayer/DVDCodecs/Video/VAAPI.cpp | 3 ++- + xbmc/cores/dvdplayer/DVDCodecs/Video/VAAPI.h | 1 + + 3 files changed, 4 insertions(+), 2 deletions(-) + +diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp +index af706bd..dae3b8e 100644 +--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp ++++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp +@@ -106,7 +106,7 @@ enum PixelFormat CDVDVideoCodecFFmpeg::GetFormat( struct AVCodecContext * avctx + && (avctx->codec_id != CODEC_ID_MPEG4 || g_advancedSettings.m_videoAllowMpeg4VAAPI)) + { + VAAPI::CDecoder* dec = new VAAPI::CDecoder(); +- if(dec->Open(avctx, *cur)) ++ if(dec->Open(avctx, *cur, ctx->m_uSurfacesCount)) + { + ctx->SetHardware(dec); + return *cur; +diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/VAAPI.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/VAAPI.cpp +index 9f5a960..a2b9195 100644 +--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/VAAPI.cpp ++++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/VAAPI.cpp +@@ -357,6 +357,7 @@ bool CDecoder::Open(AVCodecContext *avctx, enum PixelFormat fmt, unsigned int su + CHECK(vaCreateConfig(m_display->get(), profile, entrypoint, &attrib, 1, &m_hwaccel->config_id)) + m_config = m_hwaccel->config_id; + ++ m_renderbuffers_count = surfaces; + if (!EnsureContext(avctx)) + return false; + +@@ -388,7 +389,7 @@ bool CDecoder::EnsureContext(AVCodecContext *avctx) + else + m_refs = 2; + } +- return EnsureSurfaces(avctx, m_refs + 3); ++ return EnsureSurfaces(avctx, m_refs + m_renderbuffers_count + 1); + } + + bool CDecoder::EnsureSurfaces(AVCodecContext *avctx, unsigned n_surfaces_count) +diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/VAAPI.h b/xbmc/cores/dvdplayer/DVDCodecs/Video/VAAPI.h +index 863edc4..417cbc0 100644 +--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/VAAPI.h ++++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/VAAPI.h +@@ -122,6 +122,7 @@ class CDecoder + static const unsigned m_surfaces_max = 32; + unsigned m_surfaces_count; + VASurfaceID m_surfaces[m_surfaces_max]; ++ unsigned m_renderbuffers_count; + + int m_refs; + std::list m_surfaces_used; +-- +1.7.10 + + +From 4d237410264bbff9c4ac373de498f80ecb15f7a3 Mon Sep 17 00:00:00 2001 +From: xbmc +Date: Sat, 7 Apr 2012 09:19:00 +0200 +Subject: [PATCH 11/73] vdpau: redesign + +--- + language/English/strings.po | 12 +- + system/shaders/yuv2rgb_basic.glsl | 12 + + xbmc/cores/VideoRenderers/LinuxRendererGL.cpp | 203 +- + xbmc/cores/VideoRenderers/LinuxRendererGL.h | 13 +- + xbmc/cores/VideoRenderers/RenderFormats.h | 1 + + xbmc/cores/VideoRenderers/RenderManager.cpp | 8 +- + xbmc/cores/VideoRenderers/RenderManager.h | 2 +- + .../VideoRenderers/VideoShaders/YUV2RGBShader.cpp | 2 + + .../dvdplayer/DVDCodecs/Video/DVDVideoCodec.h | 4 +- + .../DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp | 23 +- + .../DVDCodecs/Video/DVDVideoCodecFFmpeg.h | 1 - + xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp | 3798 +++++++++++++++----- + xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.h | 662 +++- + xbmc/cores/dvdplayer/DVDPlayerVideo.cpp | 3 + + xbmc/settings/AdvancedSettings.cpp | 8 +- + xbmc/settings/AdvancedSettings.h | 4 +- + xbmc/settings/GUISettings.cpp | 2 + + xbmc/settings/GUIWindowSettingsCategory.cpp | 34 + + xbmc/utils/ActorProtocol.cpp | 253 ++ + xbmc/utils/ActorProtocol.h | 87 + + xbmc/utils/Makefile | 1 + + xbmc/video/dialogs/GUIDialogVideoSettings.cpp | 2 +- + xbmc/windowing/X11/WinSystemX11.h | 1 + + 23 files changed, 3942 insertions(+), 1194 deletions(-) + create mode 100644 xbmc/utils/ActorProtocol.cpp + create mode 100644 xbmc/utils/ActorProtocol.h + +diff --git a/language/English/strings.po b/language/English/strings.po +index dff2978..88292d3 100644 +--- a/language/English/strings.po ++++ b/language/English/strings.po +@@ -5114,7 +5114,15 @@ msgctxt "#13434" + msgid "Play only this" + msgstr "" + +-#empty strings from id 13435 to 13499 ++msgctxt "#13435" ++msgid "Allow Vdpau OpenGL interop" ++msgstr "" ++ ++msgctxt "#13436" ++msgid "Allow Vdpau OpenGL interop YUV" ++msgstr "" ++ ++#empty strings from id 13437 to 13499 + + msgctxt "#13500" + msgid "A/V sync method" +@@ -6333,7 +6341,7 @@ msgid "Software Blend" + msgstr "" + + msgctxt "#16325" +-msgid "Auto - ION Optimized" ++msgid "VDPAU - Bob" + msgstr "" + + #empty strings from id 16326 to 16399 +diff --git a/system/shaders/yuv2rgb_basic.glsl b/system/shaders/yuv2rgb_basic.glsl +index 88c33b2..aa26174 100644 +--- a/system/shaders/yuv2rgb_basic.glsl ++++ b/system/shaders/yuv2rgb_basic.glsl +@@ -70,6 +70,18 @@ void main() + 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 --git a/xbmc/cores/VideoRenderers/LinuxRendererGL.cpp b/xbmc/cores/VideoRenderers/LinuxRendererGL.cpp +index a2dc2be..4ee50c1 100644 +--- a/xbmc/cores/VideoRenderers/LinuxRendererGL.cpp ++++ b/xbmc/cores/VideoRenderers/LinuxRendererGL.cpp +@@ -689,6 +689,18 @@ void CLinuxRendererGL::RenderUpdate(bool clear, DWORD flags, DWORD alpha) + glDisable(GL_POLYGON_STIPPLE); + + } ++ else if(m_format == RENDER_FMT_VDPAU_420 ++ && !(flags & RENDER_FLAG_BOTH)) ++ { ++ 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); + +@@ -769,11 +781,6 @@ void CLinuxRendererGL::FlipPage(int source) + + 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; + } + +@@ -1100,6 +1107,12 @@ void CLinuxRendererGL::LoadShaders(int field) + m_textureCreate = &CLinuxRendererGL::CreateVDPAUTexture; + m_textureDelete = &CLinuxRendererGL::DeleteVDPAUTexture; + } ++ else if (m_format == RENDER_FMT_VDPAU_420) ++ { ++ m_textureUpload = &CLinuxRendererGL::UploadVDPAUTexture420; ++ m_textureCreate = &CLinuxRendererGL::CreateVDPAUTexture420; ++ m_textureDelete = &CLinuxRendererGL::DeleteVDPAUTexture420; ++ } + else if (m_format == RENDER_FMT_VAAPI) + { + m_textureUpload = &CLinuxRendererGL::UploadVAAPITexture; +@@ -1175,7 +1188,10 @@ void CLinuxRendererGL::Render(DWORD flags, int renderBuffer) + m_currentField = FIELD_FULL; + + // call texture load function ++ m_skipRender = false; + (this->*m_textureUpload)(renderBuffer); ++ if (m_skipRender) ++ return; + + if (m_renderMethod & RENDER_GLSL) + { +@@ -1541,17 +1557,12 @@ void CLinuxRendererGL::RenderFromFBO() + 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); +@@ -1609,8 +1620,6 @@ void CLinuxRendererGL::RenderVDPAU(int index, int field) + if (m_pVideoFilterShader) + m_pVideoFilterShader->Disable(); + +- vdpau->ReleasePixmap(); +- + glBindTexture (m_textureTarget, 0); + glDisable(m_textureTarget); + #endif +@@ -2295,12 +2304,14 @@ void CLinuxRendererGL::DeleteVDPAUTexture(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[0][1].id = 0; + #endif + } + +@@ -2334,11 +2345,152 @@ bool CLinuxRendererGL::CreateVDPAUTexture(int index) + 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 || !vdpau->valid) ++ { ++ m_eventTexturesDone[index]->Set(); ++ m_skipRender = true; ++ return; ++ } ++ ++ 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(); +- glPixelStorei(GL_UNPACK_ALIGNMENT,1); //what's this for? + #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 || !vdpau->valid) ++ { ++ m_eventTexturesDone[index]->Set(); ++ m_skipRender = true; ++ 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(); ++#endif ++} + + void CLinuxRendererGL::DeleteVAAPITexture(int index) + { +@@ -3276,12 +3428,13 @@ bool CLinuxRendererGL::Supports(EINTERLACEMETHOD method) + if(method == VS_INTERLACEMETHOD_AUTO) + return true; + +- if(m_renderMethod & RENDER_VDPAU) ++ if(m_renderMethod & RENDER_VDPAU || ++ m_format == RENDER_FMT_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; + } +@@ -3367,14 +3520,7 @@ EINTERLACEMETHOD CLinuxRendererGL::AutoInterlaceMethod() + return VS_INTERLACEMETHOD_NONE; + + if(m_renderMethod & RENDER_VDPAU) +- { +-#ifdef HAVE_LIBVDPAU +- CVDPAU *vdpau = m_buffers[m_iYV12RenderBuffer].vdpau; +- if(vdpau) +- return vdpau->AutoInterlaceMethod(); +-#endif + return VS_INTERLACEMETHOD_NONE; +- } + + if(Supports(VS_INTERLACEMETHOD_RENDER_BOB)) + return VS_INTERLACEMETHOD_RENDER_BOB; +@@ -3417,11 +3563,12 @@ void CLinuxRendererGL::UnBindPbo(YUVBUFFER& buff) + } + + #ifdef HAVE_LIBVDPAU +-void CLinuxRendererGL::AddProcessor(CVDPAU* vdpau, int index) ++void CLinuxRendererGL::AddProcessor(VDPAU::CVdpauRenderPicture *vdpau, int index) + { + YUVBUFFER &buf = m_buffers[index]; ++ VDPAU::CVdpauRenderPicture *pic = vdpau->Acquire(); + SAFE_RELEASE(buf.vdpau); +- buf.vdpau = (CVDPAU*)vdpau->Acquire(); ++ buf.vdpau = pic; + } + #endif + +diff --git a/xbmc/cores/VideoRenderers/LinuxRendererGL.h b/xbmc/cores/VideoRenderers/LinuxRendererGL.h +index 9f55fcb..3218cd5 100644 +--- a/xbmc/cores/VideoRenderers/LinuxRendererGL.h ++++ b/xbmc/cores/VideoRenderers/LinuxRendererGL.h +@@ -38,15 +38,14 @@ + + class CRenderCapture; + +-class CVDPAU; + class CBaseTexture; + namespace Shaders { class BaseYUV2RGBShader; } + namespace Shaders { class BaseVideoFilterShader; } + namespace VAAPI { struct CHolder; } ++namespace VDPAU { class CVdpauRenderPicture; } + + #define NUM_BUFFERS 10 + +- + #undef ALIGN + #define ALIGN(value, alignment) (((value)+((alignment)-1))&~((alignment)-1)) + #define CLAMP(a, min, max) ((a) > (max) ? (max) : ( (a) < (min) ? (min) : a )) +@@ -144,7 +143,7 @@ class CLinuxRendererGL : public CBaseRenderer + virtual unsigned int GetProcessorSize() { return m_NumYV12Buffers; } + + #ifdef HAVE_LIBVDPAU +- virtual void AddProcessor(CVDPAU* vdpau, int index); ++ virtual void AddProcessor(VDPAU::CVdpauRenderPicture* vdpau, int index); + #endif + #ifdef HAVE_LIBVA + virtual void AddProcessor(VAAPI::CHolder& holder, int index); +@@ -195,6 +194,10 @@ class CLinuxRendererGL : public CBaseRenderer + 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); +@@ -221,6 +224,7 @@ class CLinuxRendererGL : public CBaseRenderer + 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 + + struct +@@ -281,7 +285,7 @@ class CLinuxRendererGL : public CBaseRenderer + GLuint pbo[MAX_PLANES]; + + #ifdef HAVE_LIBVDPAU +- CVDPAU* vdpau; ++ VDPAU::CVdpauRenderPicture *vdpau; + #endif + #ifdef HAVE_LIBVA + VAAPI::CHolder& vaapi; +@@ -327,6 +331,7 @@ class CLinuxRendererGL : public CBaseRenderer + bool m_nonLinStretch; + bool m_nonLinStretchGui; + float m_pixelRatio; ++ bool m_skipRender; + }; + + +diff --git a/xbmc/cores/VideoRenderers/RenderFormats.h b/xbmc/cores/VideoRenderers/RenderFormats.h +index 09f8f5d..0262c60 100644 +--- a/xbmc/cores/VideoRenderers/RenderFormats.h ++++ b/xbmc/cores/VideoRenderers/RenderFormats.h +@@ -26,6 +26,7 @@ enum ERenderFormat { + RENDER_FMT_YUV420P10, + RENDER_FMT_YUV420P16, + RENDER_FMT_VDPAU, ++ RENDER_FMT_VDPAU_420, + RENDER_FMT_NV12, + RENDER_FMT_UYVY422, + RENDER_FMT_YUYV422, +diff --git a/xbmc/cores/VideoRenderers/RenderManager.cpp b/xbmc/cores/VideoRenderers/RenderManager.cpp +index f19797c..a521680 100644 +--- a/xbmc/cores/VideoRenderers/RenderManager.cpp ++++ b/xbmc/cores/VideoRenderers/RenderManager.cpp +@@ -250,8 +250,9 @@ bool CXBMCRenderManager::Configure(unsigned int width, unsigned int height, unsi + + // check if decoder supports buffering + m_bCodecSupportsBuffering = false; +-// if (format == RENDER_FMT_VDPAU) +-// m_bCodecSupportsBuffering = true; ++ if (format == RENDER_FMT_VDPAU || ++ format == RENDER_FMT_VDPAU_420) ++ m_bCodecSupportsBuffering = true; + + bool result = m_pRenderer->Configure(width, height, d_width, d_height, fps, flags, format, extended_format, orientation); + if(result) +@@ -856,7 +857,8 @@ int CXBMCRenderManager::AddVideoPicture(DVDVideoPicture& pic) + CDVDCodecUtils::CopyDXVA2Picture(&image, &pic); + } + #ifdef HAVE_LIBVDPAU +- else if(pic.format == RENDER_FMT_VDPAU) ++ else if(pic.format == RENDER_FMT_VDPAU ++ || pic.format == RENDER_FMT_VDPAU_420) + m_pRenderer->AddProcessor(pic.vdpau, index); + #endif + #ifdef HAVE_LIBOPENMAX +diff --git a/xbmc/cores/VideoRenderers/RenderManager.h b/xbmc/cores/VideoRenderers/RenderManager.h +index 9342586..6746957 100644 +--- a/xbmc/cores/VideoRenderers/RenderManager.h ++++ b/xbmc/cores/VideoRenderers/RenderManager.h +@@ -35,7 +35,7 @@ + + namespace DXVA { class CProcessor; } + namespace VAAPI { class CSurfaceHolder; } +-class CVDPAU; ++namespace VDPAU { class CVdpauRenderPicture; } + struct DVDVideoPicture; + + #define ERRORBUFFSIZE 30 +diff --git a/xbmc/cores/VideoRenderers/VideoShaders/YUV2RGBShader.cpp b/xbmc/cores/VideoRenderers/VideoShaders/YUV2RGBShader.cpp +index 58f26b0..50606eb 100644 +--- a/xbmc/cores/VideoRenderers/VideoShaders/YUV2RGBShader.cpp ++++ b/xbmc/cores/VideoRenderers/VideoShaders/YUV2RGBShader.cpp +@@ -201,6 +201,8 @@ static void CalculateYUVMatrixGL(GLfloat res[4][4] + m_defines += "#define XBMC_YUY2\n"; + else if (m_format == RENDER_FMT_UYVY422) + m_defines += "#define XBMC_UYVY\n"; ++ else if (RENDER_FMT_VDPAU_420) ++ m_defines += "#define XBMC_VDPAU_NV12\n"; + else + CLog::Log(LOGERROR, "GL: BaseYUV2RGBGLSLShader - unsupported format %d", m_format); + +diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodec.h b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodec.h +index 5001aac..98d8f89 100644 +--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodec.h ++++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodec.h +@@ -34,7 +34,7 @@ + + namespace DXVA { class CSurfaceContext; } + namespace VAAPI { struct CHolder; } +-class CVDPAU; ++namespace VDPAU { class CVdpauRenderPicture; } + class COpenMax; + class COpenMaxVideo; + struct OpenMaxVideoBuffer; +@@ -55,7 +55,7 @@ struct DVDVideoPicture + DXVA::CSurfaceContext* context; + }; + struct { +- CVDPAU* vdpau; ++ VDPAU::CVdpauRenderPicture* vdpau; + }; + struct { + VAAPI::CHolder* vaapi; +diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp +index dae3b8e..a6e42e5 100644 +--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp ++++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp +@@ -71,14 +71,14 @@ enum PixelFormat CDVDVideoCodecFFmpeg::GetFormat( struct AVCodecContext * avctx + 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; +@@ -205,14 +205,27 @@ bool CDVDVideoCodecFFmpeg::Open(CDVDStreamInfo &hints, CDVDCodecOptions &options + 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 = m_dllAvCodec.avcodec_alloc_context3(pCodec); + 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(std::vector::iterator it = options.m_keys.begin(); it != options.m_keys.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 +diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.h b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.h +index 52e1113..bf4367c 100644 +--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.h ++++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.h +@@ -28,7 +28,6 @@ + #include "DllSwScale.h" + #include "DllAvFilter.h" + +-class CVDPAU; + class CCriticalSection; + + class CDVDVideoCodecFFmpeg : public CDVDVideoCodec +diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp +index f70a4f9..235f565 100644 +--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp ++++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp +@@ -32,11 +32,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}, +@@ -50,14 +55,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 + { +@@ -68,88 +75,30 @@ + , {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; ++void* CDecoder::dl_handle; ++ ++//----------------------------------------------------------------------------- ++// CVDPAU ++//----------------------------------------------------------------------------- + +-CVDPAU::CVDPAU() ++CDecoder::CDecoder() : m_vdpauOutput(&m_inMsgEvent) + { +- 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; ++ m_vdpauConfig.vdpDevice = VDP_INVALID_HANDLE; ++ m_vdpauConfig.videoSurfaces = &m_videoSurfaces; ++ m_vdpauConfig.videoSurfaceSec = &m_videoSurfaceSec; + +- m_glPixmap = 0; +- m_Pixmap = 0; +- if (!glXBindTexImageEXT) +- glXBindTexImageEXT = (PFNGLXBINDTEXIMAGEEXTPROC)glXGetProcAddress((GLubyte *) "glXBindTexImageEXT"); +- if (!glXReleaseTexImageEXT) +- glXReleaseTexImageEXT = (PFNGLXRELEASETEXIMAGEEXTPROC)glXGetProcAddress((GLubyte *) "glXReleaseTexImageEXT"); ++ m_vdpauConfigured = false; ++ m_DisplayState = VDPAU_OPEN; ++} + +- 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; +- surface_width = surface_height = 0; +- +- memset(&decoder, 0, sizeof(decoder)); +- memset(&outRect, 0, sizeof(outRect)); +- memset(&outRectVid, 0, sizeof(outRectVid)); +- +- m_Display = NULL; +- +- 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; +- +- videoMixer = VDP_INVALID_HANDLE; +- m_BlackBar = NULL; +- +- memset(m_features, 0, sizeof(m_features)); +- m_feature_count = 0; +- m_vdpauOutputMethod = OUTPUT_NONE; +- +- upScale = g_advancedSettings.m_videoVDPAUScaling; +- +- vdp_video_mixer_set_attribute_values = NULL; +- vdp_generate_csc_matrix = NULL; +- vdp_presentation_queue_target_destroy = NULL; +- vdp_presentation_queue_create = NULL; +- vdp_presentation_queue_destroy = NULL; +- vdp_presentation_queue_display = NULL; +- vdp_presentation_queue_block_until_surface_idle = NULL; +- vdp_presentation_queue_target_create_x11 = NULL; +- vdp_presentation_queue_query_surface_status = NULL; +- vdp_presentation_queue_get_time = NULL; +- vdp_get_error_string = NULL; +- vdp_decoder_create = NULL; +- vdp_decoder_destroy = NULL; +- vdp_decoder_render = NULL; +- vdp_decoder_query_caps = NULL; +- vdp_preemption_callback_register = NULL; +- dl_vdp_device_create_x11 = NULL; +- dl_vdp_get_proc_address = NULL; +- dl_vdp_preemption_callback_register = NULL; +-} +- +-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) +@@ -157,6 +106,8 @@ bool CVDPAU::Open(AVCodecContext* avctx, const enum PixelFormat, unsigned int su + CLog::Log(LOGWARNING,"(VDPAU) no width/height available, can't init"); + return false; + } ++ m_vdpauConfig.numRenderBuffers = surfaces; ++ m_decoderThread = CThread::GetCurrentThreadId(); + + if (!dl_handle) + { +@@ -168,8 +119,6 @@ bool CVDPAU::Open(AVCodecContext* avctx, const enum PixelFormat, unsigned int su + 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; + } + } +@@ -178,8 +127,9 @@ bool CVDPAU::Open(AVCodecContext* avctx, const enum PixelFormat, unsigned int su + return false; + + InitVDPAUProcs(); ++ m_presentPicture = 0; + +- if (vdp_device != VDP_INVALID_HANDLE) ++ if (m_vdpauConfig.vdpDevice != VDP_INVALID_HANDLE) + { + SpewHardwareAvailable(); + +@@ -197,25 +147,23 @@ bool CVDPAU::Open(AVCodecContext* avctx, const enum PixelFormat, unsigned int su + + /* 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); +@@ -224,17 +172,20 @@ bool CVDPAU::Open(AVCodecContext* avctx, const enum PixelFormat, unsigned int su + 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()) + { +@@ -250,188 +201,111 @@ void CVDPAU::Close() + 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 +- }; +- +- GLXFBConfig *fbConfigs; +- fbConfigs = glXChooseFBConfig(m_Display, DefaultScreen(m_Display), doubleVisAttributes, &num); +- if (fbConfigs==NULL) ++ // check if we should do some pre-cleanup here ++ // a second decoder might need resources ++ if (m_vdpauConfigured == true) + { +- CLog::Log(LOGERROR, "GLX Error: MakePixmap: No compatible framebuffers found"); +- return false; +- } +- CLog::Log(LOGDEBUG, "Found %d fbconfigs.", num); +- fbConfigIndex = 0; +- CLog::Log(LOGDEBUG, "Using fbconfig index %d.", fbConfigIndex); ++ CSingleLock lock(m_DecoderSection); ++ CLog::Log(LOGNOTICE,"CVDPAU::Release pre-cleanup"); + +- m_glPixmap = glXCreatePixmap(m_Display, fbConfigs[fbConfigIndex], m_Pixmap, pixmapAttribs); ++ 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; ++ } + +- if (!m_glPixmap) +- { +- CLog::Log(LOGINFO, "GLX Error: Could not create Pixmap"); +- XFree(fbConfigs); +- 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; ++ } ++ } + } +- XFree(fbConfigs); ++ IHardwareDecoder::Release(); ++} + +- return true; ++long CDecoder::ReleasePicReference() ++{ ++ return IHardwareDecoder::Release(); + } + +-bool CVDPAU::MakePixmap(int width, int height) ++void CDecoder::SetWidthHeight(int width, int height) + { ++ m_vdpauConfig.upscale = g_advancedSettings.m_videoVDPAUScaling; ++ + //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", m_vdpauConfig.outWidth, m_vdpauConfig.outHeight); + } + +-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; + } + +@@ -445,16 +319,13 @@ int CVDPAU::Check(AVCodecContext* avctx) + } + 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(); +@@ -469,7 +340,7 @@ int CVDPAU::Check(AVCodecContext* avctx) + 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) +@@ -478,91 +349,28 @@ bool CVDPAU::IsVDPAUFormat(PixelFormat format) + 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 +- || method == VS_INTERLACEMETHOD_AUTO_ION) ++ || 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) +@@ -571,162 +379,12 @@ bool CVDPAU::Supports(EINTERLACEMETHOD method) + 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_AUTO_ION) +- { +- if (vid_height <= 576) +- { +- VdpBool enabled[]={1,1,0}; +- vdp_st = vdp_video_mixer_set_feature_enables(videoMixer, ARSIZE(feature), feature, enabled); +- } +- else if (vid_height > 576) +- { +- 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 +- || 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; + +@@ -736,151 +394,115 @@ void CVDPAU::InitVDPAUProcs() + 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(); +- } +- else +- { +- CLog::Log(LOGERROR,"(VDPAU) - Unable to get dl_vdp_device_create_x11 in %s", __FUNCTION__); +- vdp_device = VDP_INVALID_HANDLE; +- return; ++ m_Display = XOpenDisplay(NULL); + } + +- int mScreen = DefaultScreen(m_Display); ++ int mScreen = g_Windowing.GetCurrentScreen(); + 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; + } + + #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; ++ ++ 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) ++ 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__)) +@@ -888,8 +510,7 @@ void CVDPAU::FiniVDPAUOutput() + } + } + +- +-void CVDPAU::ReadFormatOf( PixelFormat fmt ++void CDecoder::ReadFormatOf( PixelFormat fmt + , VdpDecoderProfile &vdp_decoder_profile + , VdpChromaType &vdp_chroma_type) + { +@@ -916,9 +537,9 @@ void CVDPAU::ReadFormatOf( PixelFormat fmt + vdp_chroma_type = VDP_CHROMA_TYPE_420; + break; + #if (defined PIX_FMT_VDPAU_MPEG4_IN_AVUTIL) && \ +- (defined VDP_DECODER_PROFILE_MPEG4_PART2_ASP) ++ (defined VDP_DECODER_PROFILE_MP) + case PIX_FMT_VDPAU_MPEG4: +- vdp_decoder_profile = VDP_DECODER_PROFILE_MPEG4_PART2_ASP; ++ vdp_decoder_profile = VDP_DECOPEG4_PART2_ASP; + vdp_chroma_type = VDP_CHROMA_TYPE_420; + break; + #endif +@@ -929,170 +550,78 @@ void CVDPAU::ReadFormatOf( PixelFormat fmt + } + } + +- +-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; +- 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:"); +@@ -1102,7 +631,7 @@ void CVDPAU::SpewHardwareAvailable() //Copyright (c) 2008 Wladimir J. van der L + { + 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) + { +@@ -1111,13 +640,13 @@ void CVDPAU::SpewHardwareAvailable() //Copyright (c) 2008 Wladimir J. van der L + } + } + 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) + +@@ -1141,7 +670,7 @@ void CVDPAU::SpewHardwareAvailable() //Copyright (c) 2008 Wladimir J. van der L + + } + +-bool CVDPAU::IsSurfaceValid(vdpau_render_state *render) ++bool CDecoder::IsSurfaceValid(vdpau_render_state *render) + { + // find render state in queue + bool found(false); +@@ -1168,34 +697,33 @@ bool CVDPAU::IsSurfaceValid(vdpau_render_state *render) + 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(); + + // 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; ++ } + } + } + +@@ -1204,21 +732,22 @@ int CVDPAU::FFGetBuffer(AVCodecContext *avctx, AVFrame *pic) + { + // 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); +@@ -1239,18 +768,6 @@ int CVDPAU::FFGetBuffer(AVCodecContext *avctx, AVFrame *pic) + + pic->linesize[0] = pic->linesize[1] = pic->linesize[2] = 0; + +- if(pic->reference) +- { +- pA->ip_age[0]= pA->ip_age[1]+1; +- pA->ip_age[1]= 1; +- pA->b_age++; +- } +- else +- { +- pA->ip_age[0]++; +- pA->ip_age[1]++; +- pA->b_age = 1; +- } + pic->type= FF_BUFFER_TYPE_USER; + + render->state |= FF_VDPAU_STATE_USED_FOR_REFERENCE; +@@ -1258,15 +775,16 @@ int CVDPAU::FFGetBuffer(AVCodecContext *avctx, AVFrame *pic) + 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) +@@ -1275,6 +793,8 @@ void CVDPAU::FFReleaseBuffer(AVCodecContext *avctx, AVFrame *pic) + return; + } + ++ CSingleLock vLock(vdp->m_videoSurfaceSec); ++ render->state &= ~FF_VDPAU_STATE_USED_FOR_REFERENCE; + for(i=0; i<4; i++) + pic->data[i]= NULL; + +@@ -1289,21 +809,18 @@ void CVDPAU::FFReleaseBuffer(AVCodecContext *avctx, AVFrame *pic) + } + + +-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]) +@@ -1333,59 +850,41 @@ void CVDPAU::FFDrawSlice(struct AVCodecContext *s, + 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) ++{ + 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 + +@@ -1393,7 +892,10 @@ int CVDPAU::Decode(AVCodecContext *avctx, AVFrame *pFrame) + 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)) +@@ -1402,258 +904,166 @@ int CVDPAU::Decode(AVCodecContext *avctx, AVFrame *pFrame) + return VC_BUFFER; + } + ++ CSingleLock lock(m_videoSurfaceSec); + render->state |= FF_VDPAU_STATE_USED_FOR_RENDER; ++ lock.Leave(); + +- ClearUsedForRender(&past[0]); +- past[0] = past[1]; +- past[1] = current; +- current = future; +- future = render; ++ // 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)); + +- DVDVideoPicture DVDPic; +- memset(&DVDPic, 0, sizeof(DVDVideoPicture)); +- ((CDVDVideoCodecFFmpeg*)avctx->opaque)->GetPictureCommon(&DVDPic); +- m_DVDVideoPics.push(DVDPic); ++ m_codecControl = pic.DVDPic.iFlags & (DVP_FLAG_DRAIN | DVP_FLAG_NO_POSTPROC); ++ } + +- int pics = m_DVDVideoPics.size(); +- if (pics < 2) +- return VC_BUFFER; +- else if (pics > 2) ++ int retval = 0; ++ uint16_t decoded, processed, render; ++ Message *msg; ++ while (m_vdpauOutput.m_controlPort.ReceiveInMessage(&msg)) ++ { ++ if (msg->signal == COutputControlProtocol::ERROR) + { +- // this should not normally happen +- CLog::Log(LOGERROR, "CVDPAU::Decode - invalid number of pictures in queue"); +- while (pics-- != 2) +- m_DVDVideoPics.pop(); ++ m_DisplayState = VDPAU_ERROR; ++ retval |= VC_ERROR; + } ++ msg->Release(); ++ } + +- if (mode == VS_DEINTERLACEMODE_FORCE +- || (mode == VS_DEINTERLACEMODE_AUTO && m_DVDVideoPics.front().iFlags & DVP_FLAG_INTERLACED)) ++ m_bufferStats.Get(decoded, processed, render); ++ ++ uint64_t startTime = CurrentHostCounter(); ++ while (!retval) ++ { ++ if (m_vdpauOutput.m_dataPort.ReceiveInMessage(&msg)) + { +- if((method == VS_INTERLACEMETHOD_AUTO_ION +- || 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 (msg->signal == COutputDataProtocol::PICTURE) + { +- if((method == VS_INTERLACEMETHOD_AUTO_ION && vid_height > 576) +- || 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_codecControl); + } ++ 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 (!retval) + { +- if (past[0]) +- past_surfaces[1] = past[0]->surface; +- if (past[1]) +- past_surfaces[0] = past[1]->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; + } +- else +- { +- 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; +- } +- } +- +- 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; +- } +- +- *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(); ++ CSingleLock lock(m_DecoderSection); + +- picture->format = RENDER_FMT_VDPAU; +- picture->iFlags &= DVP_FLAG_DROPPED; +- picture->iWidth = OutWidth; +- picture->iHeight = OutHeight; +- picture->vdpau = this; ++ if (!m_vdpauConfigured) ++ return; + +- if(m_mixerstep) ++ Message *reply; ++ if (m_vdpauOutput.m_controlPort.SendOutMessageSync(COutputControlProtocol::FLUSH, ++ &reply, ++ 2000)) + { +- picture->iRepeatPicture = -0.5; +- if(m_mixerstep > 1) ++ 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::ReturnRenderPicture(CVdpauRenderPicture *renderPic) + { +- //CLog::Log(LOGNOTICE,"%s",__FUNCTION__); +- VdpStatus vdp_st; +- +- CSharedLock lock(m_DecoderSection); +- +- { CSharedLock dLock(m_DisplaySection); +- if (m_DisplayState != VDPAU_OPEN) +- return; +- } +- +- presentSurface = outputSurface; +- +- vdp_st = vdp_presentation_queue_display(vdp_flip_queue, +- presentSurface, +- 0, +- 0, +- 0); +- CheckStatus(vdp_st, __LINE__); ++ 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) + { +@@ -1671,4 +1081,2422 @@ bool CVDPAU::CheckStatus(VdpStatus vdp_st, int line) + 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 != RENDER_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 != RENDER_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,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 ++ || 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 flags; ++ m_config.stats->GetParams(latency, flags); ++ latency = (latency*1000)/CurrentHostFrequency(); ++ if (flags & DVP_FLAG_NO_POSTPROC) ++ 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 = RENDER_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 = RENDER_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 = RENDER_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 = RENDER_FMT_VDPAU_420; ++ else ++ { ++ m_mixerInput[1].DVDPic.format = RENDER_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 == RENDER_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 != RENDER_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 == RENDER_FMT_VDPAU_420) ++ 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 == RENDER_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 == RENDER_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 == RENDER_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 == RENDER_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 == RENDER_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, g_Windowing.GetWindow(), &wndattribs); ++ ++ pixmap.pixmap = XCreatePixmap(m_Display, ++ g_Windowing.GetWindow(), ++ 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, g_Windowing.GetCurrentScreen(), 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.usevdpauinterop"); ++ ++#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.usevdpauinterop",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.GetWindow(); ++ ++ // 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, ++ m_Window, ++ 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 --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.h b/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.h +index 2f53edf..4d1559c 100644 +--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.h ++++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.h +@@ -1,5 +1,3 @@ +- +-#pragma once + /* + * Copyright (C) 2005-2012 Team XBMC + * http://www.xbmc.org +@@ -20,9 +18,32 @@ + * + */ + ++/** ++ * 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. ++ */ ++ ++#pragma once ++ + #include "system_gl.h" + +-#include ++#include "DllAvUtil.h" ++#include "DVDVideoCodec.h" ++#include "DVDVideoCodecFFmpeg.h" ++#include "libavcodec/vdpau.h" + #include + #include + #define GLX_GLXEXT_PROTOTYPES +@@ -37,118 +58,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... */ +- }; +- +- 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; +- +- 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); ++#include "threads/Thread.h" ++#include "utils/ActorProtocol.h" + +- void CheckFeatures(); +- void SetColor(); +- void SetNoiseReduction(); +- void SetSharpness(); +- void SetDeinterlacing(); +- void SetHWUpscaling(); ++using namespace Actor; + +- 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; +- } +- } +- +- VdpProcamp m_Procamp; +- VdpCSCMatrix m_CSCMatrix; +- VdpDevice HasDevice() { return vdp_device != VDP_INVALID_HANDLE; }; +- VdpChromaType vdp_chroma_type; ++#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 + ++namespace VDPAU ++{ + +- // protected: +- void InitVDPAUProcs(); +- void FiniVDPAUProcs(); +- void FiniVDPAUOutput(); +- bool ConfigOutputMethod(AVCodecContext *avctx, AVFrame *pFrame); +- bool FiniOutputMethod(); ++/** ++ * VDPAU interface to driver ++ */ + +- VdpDevice vdp_device; +- VdpGetProcAddress * vdp_get_proc_address; +- VdpPresentationQueueTarget vdp_flip_target; +- VdpPresentationQueue vdp_flip_queue; +- VdpDeviceDestroy * vdp_device_destroy; ++struct VDPAU_procs ++{ ++ VdpGetProcAddress * vdp_get_proc_address; ++ 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 +92,15 @@ class CVDPAU + 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 +113,459 @@ class CVDPAU + + 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; ++//----------------------------------------------------------------------------- ++// VDPAU data structs ++//----------------------------------------------------------------------------- + +- 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); ++class CDecoder; + +- 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; ++/** ++ * 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[14]; ++ 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 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); ++ virtual bool GetPicture(AVCodecContext* avctx, AVFrame* frame, DVDVideoPicture* picture); ++ virtual void Reset(); ++ virtual void Close(); ++ virtual long Release(); ++ virtual bool CanSkipDeint(); ++ ++ 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[14]; +- 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 +576,24 @@ class CVDPAU + , 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; ++ ++ COutput m_vdpauOutput; ++ CVdpauBufferStats m_bufferStats; ++ CEvent m_inMsgEvent; ++ CVdpauRenderPicture *m_presentPicture; ++ ++ int m_codecControl; + }; ++ ++} +diff --git a/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp b/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp +index 10e2225..15a39fa 100644 +--- a/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp ++++ b/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp +@@ -1141,6 +1141,9 @@ int CDVDPlayerVideo::OutputPicture(const DVDVideoPicture* src, double pts) + case RENDER_FMT_VDPAU: + formatstr = "VDPAU"; + break; ++ case RENDER_FMT_VDPAU_420: ++ formatstr = "VDPAU_420"; ++ break; + case RENDER_FMT_DXVA: + formatstr = "DXVA"; + break; +diff --git a/xbmc/settings/AdvancedSettings.cpp b/xbmc/settings/AdvancedSettings.cpp +index 16800b7..844f8e8 100644 +--- a/xbmc/settings/AdvancedSettings.cpp ++++ b/xbmc/settings/AdvancedSettings.cpp +@@ -98,7 +98,7 @@ void CAdvancedSettings::Initialize() + m_videoIgnoreSecondsAtStart = 3*60; + m_videoIgnorePercentAtEnd = 8.0f; + m_videoPlayCountMinimumPercent = 90.0f; +- m_videoVDPAUScaling = false; ++ m_videoVDPAUScaling = -1; + m_videoNonLinStretchRatio = 0.5f; + m_videoEnableHighQualityHwScalers = false; + m_videoAutoScaleMaxFps = 30.0f; +@@ -106,6 +106,8 @@ void CAdvancedSettings::Initialize() + m_videoAllowMpeg4VAAPI = false; + m_videoDisableBackgroundDeinterlace = false; + m_videoCaptureUseOcclusionQuery = -1; //-1 is auto detect ++ m_videoVDPAUtelecine = false; ++ m_videoVDPAUdeintSkipChromaHD = false; + m_DXVACheckCompatibility = false; + m_DXVACheckCompatibilityPresent = false; + m_DXVAForceProcessorRenderer = true; +@@ -493,7 +495,7 @@ void CAdvancedSettings::ParseSettingsFile(const CStdString &file) + XMLUtils::GetString(pElement,"cleandatetime", m_videoCleanDateTimeRegExp); + XMLUtils::GetString(pElement,"ppffmpegdeinterlacing",m_videoPPFFmpegDeint); + XMLUtils::GetString(pElement,"ppffmpegpostprocessing",m_videoPPFFmpegPostProc); +- XMLUtils::GetBoolean(pElement,"vdpauscaling",m_videoVDPAUScaling); ++ XMLUtils::GetInt(pElement,"vdpauscaling",m_videoVDPAUScaling); + XMLUtils::GetFloat(pElement, "nonlinearstretchratio", m_videoNonLinStretchRatio, 0.01f, 1.0f); + XMLUtils::GetBoolean(pElement,"enablehighqualityhwscalers", m_videoEnableHighQualityHwScalers); + XMLUtils::GetFloat(pElement,"autoscalemaxfps",m_videoAutoScaleMaxFps, 0.0f, 1000.0f); +@@ -501,6 +503,8 @@ void CAdvancedSettings::ParseSettingsFile(const CStdString &file) + XMLUtils::GetBoolean(pElement,"allowmpeg4vaapi",m_videoAllowMpeg4VAAPI); + XMLUtils::GetBoolean(pElement, "disablebackgrounddeinterlace", m_videoDisableBackgroundDeinterlace); + XMLUtils::GetInt(pElement, "useocclusionquery", m_videoCaptureUseOcclusionQuery, -1, 1); ++ XMLUtils::GetBoolean(pElement,"vdpauInvTelecine",m_videoVDPAUtelecine); ++ XMLUtils::GetBoolean(pElement,"vdpauHDdeintSkipChroma",m_videoVDPAUdeintSkipChromaHD); + + TiXmlElement* pAdjustRefreshrate = pElement->FirstChildElement("adjustrefreshrate"); + if (pAdjustRefreshrate) +diff --git a/xbmc/settings/AdvancedSettings.h b/xbmc/settings/AdvancedSettings.h +index 27887d4..72718e5 100644 +--- a/xbmc/settings/AdvancedSettings.h ++++ b/xbmc/settings/AdvancedSettings.h +@@ -133,6 +133,8 @@ class CAdvancedSettings + int m_videoPercentSeekBackwardBig; + CStdString m_videoPPFFmpegDeint; + CStdString m_videoPPFFmpegPostProc; ++ bool m_videoVDPAUtelecine; ++ bool m_videoVDPAUdeintSkipChromaHD; + bool m_musicUseTimeSeeking; + int m_musicTimeSeekForward; + int m_musicTimeSeekBackward; +@@ -148,7 +150,7 @@ class CAdvancedSettings + CStdString m_audioHost; + bool m_audioApplyDrc; + +- bool m_videoVDPAUScaling; ++ int m_videoVDPAUScaling; + float m_videoNonLinStretchRatio; + bool m_videoEnableHighQualityHwScalers; + float m_videoAutoScaleMaxFps; +diff --git a/xbmc/settings/GUISettings.cpp b/xbmc/settings/GUISettings.cpp +index 76ec0cc..4cdb093 100644 +--- a/xbmc/settings/GUISettings.cpp ++++ b/xbmc/settings/GUISettings.cpp +@@ -685,6 +685,8 @@ void CGUISettings::Initialize() + + #ifdef HAVE_LIBVDPAU + AddBool(vp, "videoplayer.usevdpau", 13425, true); ++ AddBool(vp, "videoplayer.usevdpauinterop", 13435, true); ++ AddBool(vp, "videoplayer.usevdpauinteropyuv", 13436, false); + #endif + #ifdef HAVE_LIBVA + AddBool(vp, "videoplayer.usevaapi", 13426, true); +diff --git a/xbmc/settings/GUIWindowSettingsCategory.cpp b/xbmc/settings/GUIWindowSettingsCategory.cpp +index 4ac2663..d988598 100644 +--- a/xbmc/settings/GUIWindowSettingsCategory.cpp ++++ b/xbmc/settings/GUIWindowSettingsCategory.cpp +@@ -596,6 +596,40 @@ void CGUIWindowSettingsCategory::UpdateSettings() + pControl->SetEnabled(true); + } + } ++ else if (strSetting.Equals("videoplayer.usevdpauinteropyuv")) ++ { ++ bool hasInterop = g_guiSettings.GetBool("videoplayer.usevdpauinterop"); ++#ifndef GL_NV_vdpau_interop ++ hasInterop = false; ++#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.usevdpauinterop")) ++ { ++ bool hasInterop = g_guiSettings.GetBool("videoplayer.usevdpau"); ++#ifndef GL_NV_vdpau_interop ++ hasInterop = false; ++#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.usevdpauinterop",false); ++ } ++ } + else + #endif + if (strSetting.Equals("videoscreen.resolution")) +diff --git a/xbmc/utils/ActorProtocol.cpp b/xbmc/utils/ActorProtocol.cpp +new file mode 100644 +index 0000000..e0cfd0e +--- /dev/null ++++ b/xbmc/utils/ActorProtocol.cpp +@@ -0,0 +1,253 @@ ++/* ++ * Copyright (C) 2005-2012 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, see ++ * . ++ * ++ */ ++ ++#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 --git a/xbmc/utils/ActorProtocol.h b/xbmc/utils/ActorProtocol.h +new file mode 100644 +index 0000000..e7108ac +--- /dev/null ++++ b/xbmc/utils/ActorProtocol.h +@@ -0,0 +1,87 @@ ++/* ++ * Copyright (C) 2005-2012 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, see ++ * . ++ * ++ */ ++ ++#pragma once ++ ++#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) ++ : portName(name), inDefered(false), outDefered(false) {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 --git a/xbmc/utils/Makefile b/xbmc/utils/Makefile +index d201884..7d1f9f0 100644 +--- a/xbmc/utils/Makefile ++++ b/xbmc/utils/Makefile +@@ -70,6 +70,7 @@ SRCS=AlarmClock.cpp \ + Weather.cpp \ + XBMCTinyXML.cpp \ + XMLUtils.cpp \ ++ ActorProtocol.cpp \ + + LIB=utils.a + +diff --git a/xbmc/video/dialogs/GUIDialogVideoSettings.cpp b/xbmc/video/dialogs/GUIDialogVideoSettings.cpp +index ac5f007..f25d10d 100644 +--- a/xbmc/video/dialogs/GUIDialogVideoSettings.cpp ++++ b/xbmc/video/dialogs/GUIDialogVideoSettings.cpp +@@ -103,7 +103,7 @@ void CGUIDialogVideoSettings::CreateSettings() + 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 , 16325)); + 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)); +diff --git a/xbmc/windowing/X11/WinSystemX11.h b/xbmc/windowing/X11/WinSystemX11.h +index e7af3cb..2dd8a9f 100644 +--- a/xbmc/windowing/X11/WinSystemX11.h ++++ b/xbmc/windowing/X11/WinSystemX11.h +@@ -63,6 +63,7 @@ class CWinSystemX11 : public CWinSystemBase + // Local to WinSystemX11 only + Display* GetDisplay() { return m_dpy; } + GLXWindow GetWindow() { return m_glWindow; } ++ GLXContext GetGlxContext() { return m_glContext; } + + protected: + bool RefreshGlxContext(); +-- +1.7.10 + + +From c088467d9d0955051a510dadbddb270ddc3e3c20 Mon Sep 17 00:00:00 2001 +From: xbmc +Date: Tue, 25 Sep 2012 12:14:15 +0200 +Subject: [PATCH 12/73] linuxrenderer: drop method RenderMultiPass + +--- + xbmc/cores/VideoRenderers/LinuxRendererGL.cpp | 9 ++------- + xbmc/cores/VideoRenderers/LinuxRendererGL.h | 1 - + 2 files changed, 2 insertions(+), 8 deletions(-) + +diff --git a/xbmc/cores/VideoRenderers/LinuxRendererGL.cpp b/xbmc/cores/VideoRenderers/LinuxRendererGL.cpp +index 4ee50c1..ea58c85 100644 +--- a/xbmc/cores/VideoRenderers/LinuxRendererGL.cpp ++++ b/xbmc/cores/VideoRenderers/LinuxRendererGL.cpp +@@ -1205,7 +1205,8 @@ void CLinuxRendererGL::Render(DWORD flags, int renderBuffer) + break; + + case RQ_MULTIPASS: +- RenderMultiPass(renderBuffer, m_currentField); ++ RenderToFBO(renderBuffer, m_currentField); ++ RenderFromFBO(); + VerifyGLState(); + break; + } +@@ -1328,12 +1329,6 @@ void CLinuxRendererGL::RenderSinglePass(int index, int field) + VerifyGLState(); + } + +-void CLinuxRendererGL::RenderMultiPass(int index, int field) +-{ +- RenderToFBO(index, field); +- RenderFromFBO(); +-} +- + void CLinuxRendererGL::RenderToFBO(int index, int field) + { + YUVPLANES &planes = m_buffers[index].fields[field]; +diff --git a/xbmc/cores/VideoRenderers/LinuxRendererGL.h b/xbmc/cores/VideoRenderers/LinuxRendererGL.h +index 3218cd5..afc78c2 100644 +--- a/xbmc/cores/VideoRenderers/LinuxRendererGL.h ++++ b/xbmc/cores/VideoRenderers/LinuxRendererGL.h +@@ -218,7 +218,6 @@ class CLinuxRendererGL : public CBaseRenderer + void CalculateTextureSourceRects(int source, int num_planes); + + // renderers +- void RenderMultiPass(int renderBuffer, int field); // multi pass glsl renderer + void RenderToFBO(int renderBuffer, int field); + void RenderFromFBO(); + void RenderSinglePass(int renderBuffer, int field); // single pass glsl renderer +-- +1.7.10 + + +From 0de3939247a63509e6bfab2e77c298eaa28aa29c Mon Sep 17 00:00:00 2001 +From: xbmc +Date: Tue, 25 Sep 2012 13:20:47 +0200 +Subject: [PATCH 13/73] linuxrenderer: implement progressive weave for vdpau + +--- + xbmc/cores/VideoRenderers/LinuxRendererGL.cpp | 55 ++++++++++++++++++------- + xbmc/cores/VideoRenderers/LinuxRendererGL.h | 4 +- + 2 files changed, 41 insertions(+), 18 deletions(-) + +diff --git a/xbmc/cores/VideoRenderers/LinuxRendererGL.cpp b/xbmc/cores/VideoRenderers/LinuxRendererGL.cpp +index ea58c85..b281ca7 100644 +--- a/xbmc/cores/VideoRenderers/LinuxRendererGL.cpp ++++ b/xbmc/cores/VideoRenderers/LinuxRendererGL.cpp +@@ -689,18 +689,6 @@ void CLinuxRendererGL::RenderUpdate(bool clear, DWORD flags, DWORD alpha) + glDisable(GL_POLYGON_STIPPLE); + + } +- else if(m_format == RENDER_FMT_VDPAU_420 +- && !(flags & RENDER_FLAG_BOTH)) +- { +- 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); + +@@ -1200,13 +1188,21 @@ void CLinuxRendererGL::Render(DWORD flags, int renderBuffer) + { + case RQ_LOW: + case RQ_SINGLEPASS: +- RenderSinglePass(renderBuffer, m_currentField); ++ if (m_format == RENDER_FMT_VDPAU_420 && m_currentField == FIELD_FULL) ++ RenderProgressiveWeave(renderBuffer, m_currentField); ++ else ++ RenderSinglePass(renderBuffer, m_currentField); + VerifyGLState(); + break; + + case RQ_MULTIPASS: +- RenderToFBO(renderBuffer, m_currentField); +- RenderFromFBO(); ++ if (m_format == RENDER_FMT_VDPAU_420 && m_currentField == FIELD_FULL) ++ RenderProgressiveWeave(renderBuffer, m_currentField); ++ else ++ { ++ RenderToFBO(renderBuffer, m_currentField); ++ RenderFromFBO(); ++ } + VerifyGLState(); + break; + } +@@ -1329,7 +1325,7 @@ void CLinuxRendererGL::RenderSinglePass(int index, int field) + VerifyGLState(); + } + +-void CLinuxRendererGL::RenderToFBO(int index, int field) ++void CLinuxRendererGL::RenderToFBO(int index, int field, bool weave /*= false*/) + { + YUVPLANES &planes = m_buffers[index].fields[field]; + +@@ -1431,6 +1427,8 @@ void CLinuxRendererGL::RenderToFBO(int index, int field) + } + m_fbo.width *= planes[0].pixpertex_x; + m_fbo.height *= planes[0].pixpertex_y; ++ if (weave) ++ m_fbo.height *= 2; + + // 1st Pass to video frame size + glBegin(GL_QUADS); +@@ -1549,6 +1547,31 @@ void CLinuxRendererGL::RenderFromFBO() + VerifyGLState(); + } + ++void CLinuxRendererGL::RenderProgressiveWeave(int index, int field) ++{ ++ bool scaleUp = (int)m_sourceHeight < g_graphicsContext.GetHeight() || (int)m_sourceWidth < g_graphicsContext.GetWidth(); ++ ++ if (m_fbo.fbo.IsSupported() && (scaleUp || m_renderQuality == RQ_MULTIPASS)) ++ { ++ glEnable(GL_POLYGON_STIPPLE); ++ glPolygonStipple(stipple_weave); ++ RenderToFBO(index, FIELD_TOP, true); ++ glPolygonStipple(stipple_weave+4); ++ RenderToFBO(index, FIELD_BOT, true); ++ glDisable(GL_POLYGON_STIPPLE); ++ RenderFromFBO(); ++ } ++ else ++ { ++ glEnable(GL_POLYGON_STIPPLE); ++ glPolygonStipple(stipple_weave); ++ RenderSinglePass(index, FIELD_TOP); ++ glPolygonStipple(stipple_weave+4); ++ RenderSinglePass(index, FIELD_BOT); ++ glDisable(GL_POLYGON_STIPPLE); ++ } ++} ++ + void CLinuxRendererGL::RenderVDPAU(int index, int field) + { + #ifdef HAVE_LIBVDPAU +diff --git a/xbmc/cores/VideoRenderers/LinuxRendererGL.h b/xbmc/cores/VideoRenderers/LinuxRendererGL.h +index afc78c2..2fc34ae 100644 +--- a/xbmc/cores/VideoRenderers/LinuxRendererGL.h ++++ b/xbmc/cores/VideoRenderers/LinuxRendererGL.h +@@ -218,12 +218,12 @@ class CLinuxRendererGL : public CBaseRenderer + void CalculateTextureSourceRects(int source, int num_planes); + + // renderers +- void RenderToFBO(int renderBuffer, int field); ++ void RenderToFBO(int renderBuffer, int field, bool weave = false); + void RenderFromFBO(); + 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 RenderProgressiveWeave(int renderBuffer, int field); // render using vdpau hardware + void RenderVAAPI(int renderBuffer, int field); // render using vdpau hardware + + struct +-- +1.7.10 + + +From c12380f4b9c9c2671bfd1ebd3e29ba7cd83ac95e Mon Sep 17 00:00:00 2001 +From: FernetMenta +Date: Thu, 5 Jul 2012 15:22:05 +0200 +Subject: [PATCH 14/73] X11: ditch SDL for video and window events + +--- + xbmc/Application.cpp | 2 +- + xbmc/system.h | 5 + + xbmc/windowing/Makefile | 1 + + xbmc/windowing/WinEvents.h | 4 + + xbmc/windowing/WinEventsX11.cpp | 765 +++++++++++++++++++++++++++++++++++ + xbmc/windowing/WinEventsX11.h | 57 +++ + xbmc/windowing/X11/WinSystemX11.cpp | 370 ++++++++++++----- + xbmc/windowing/X11/WinSystemX11.h | 9 +- + 8 files changed, 1112 insertions(+), 101 deletions(-) + create mode 100644 xbmc/windowing/WinEventsX11.cpp + create mode 100644 xbmc/windowing/WinEventsX11.h + +diff --git a/xbmc/Application.cpp b/xbmc/Application.cpp +index 9a7b900..fc8e721 100644 +--- a/xbmc/Application.cpp ++++ b/xbmc/Application.cpp +@@ -790,7 +790,7 @@ bool CApplication::CreateGUI() + + uint32_t sdlFlags = 0; + +-#if defined(HAS_SDL_OPENGL) || (HAS_GLES == 2) ++#if (defined(HAS_SDL_OPENGL) || (HAS_GLES == 2)) && !defined(HAS_GLX) + sdlFlags |= SDL_INIT_VIDEO; + #endif + +diff --git a/xbmc/system.h b/xbmc/system.h +index 4165c01..32584b1 100644 +--- a/xbmc/system.h ++++ b/xbmc/system.h +@@ -162,16 +162,21 @@ + #define HAS_GL + #ifdef HAVE_X11 + #define HAS_GLX ++#define HAS_X11_WIN_EVENTS + #endif + #ifdef HAVE_SDL + #define HAS_SDL + #ifndef HAS_SDL_OPENGL + #define HAS_SDL_OPENGL + #endif ++#ifndef HAVE_X11 + #define HAS_SDL_WIN_EVENTS ++#endif + #else ++#ifndef HAVE_X11 + #define HAS_LINUX_EVENTS + #endif ++#endif + #define HAS_LINUX_NETWORK + #define HAS_LIRC + #ifdef HAVE_LIBPULSE +diff --git a/xbmc/windowing/Makefile b/xbmc/windowing/Makefile +index f109bec..f981642 100644 +--- a/xbmc/windowing/Makefile ++++ b/xbmc/windowing/Makefile +@@ -1,6 +1,7 @@ + SRCS=WinEventsSDL.cpp \ + WinEventsLinux.cpp \ + WinSystem.cpp \ ++ WinEventsX11.cpp \ + + LIB=windowing.a + +diff --git a/xbmc/windowing/WinEvents.h b/xbmc/windowing/WinEvents.h +index 6d322a9..5a671cc 100644 +--- a/xbmc/windowing/WinEvents.h ++++ b/xbmc/windowing/WinEvents.h +@@ -58,6 +58,10 @@ class CWinEventsBase + #include "WinEventsSDL.h" + #define CWinEvents CWinEventsSDL + ++#elif defined(TARGET_LINUX) && defined(HAS_X11_WIN_EVENTS) ++#include "WinEventsX11.h" ++#define CWinEvents CWinEventsX11 ++ + #elif defined(TARGET_LINUX) && defined(HAS_LINUX_EVENTS) + #include "WinEventsLinux.h" + #define CWinEvents CWinEventsLinux +diff --git a/xbmc/windowing/WinEventsX11.cpp b/xbmc/windowing/WinEventsX11.cpp +new file mode 100644 +index 0000000..24477ae +--- /dev/null ++++ b/xbmc/windowing/WinEventsX11.cpp +@@ -0,0 +1,765 @@ ++/* ++* Copyright (C) 2005-2012 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 HAS_X11_WIN_EVENTS ++ ++#include "WinEvents.h" ++#include "WinEventsX11.h" ++#include "Application.h" ++#include "ApplicationMessenger.h" ++#include ++#include "X11/WinSystemX11GL.h" ++#include "X11/keysymdef.h" ++#include "X11/XF86keysym.h" ++#include "utils/log.h" ++#include "guilib/GUIWindowManager.h" ++#include "input/MouseStat.h" ++ ++CWinEventsX11* CWinEventsX11::WinEvents = 0; ++ ++static uint32_t SymMappingsX11[][2] = ++{ ++ {XK_BackSpace, XBMCK_BACKSPACE} ++, {XK_Tab, XBMCK_TAB} ++, {XK_Clear, XBMCK_CLEAR} ++, {XK_Return, XBMCK_RETURN} ++, {XK_Pause, XBMCK_PAUSE} ++, {XK_Escape, XBMCK_ESCAPE} ++, {XK_Delete, XBMCK_DELETE} ++// multi-media keys ++, {XF86XK_Back, XBMCK_BROWSER_BACK} ++, {XF86XK_Forward, XBMCK_BROWSER_FORWARD} ++, {XF86XK_Refresh, XBMCK_BROWSER_REFRESH} ++, {XF86XK_Stop, XBMCK_BROWSER_STOP} ++, {XF86XK_Search, XBMCK_BROWSER_SEARCH} ++, {XF86XK_Favorites, XBMCK_BROWSER_FAVORITES} ++, {XF86XK_HomePage, XBMCK_BROWSER_HOME} ++, {XF86XK_AudioMute, XBMCK_VOLUME_MUTE} ++, {XF86XK_AudioLowerVolume, XBMCK_VOLUME_DOWN} ++, {XF86XK_AudioRaiseVolume, XBMCK_VOLUME_UP} ++, {XF86XK_AudioNext, XBMCK_MEDIA_NEXT_TRACK} ++, {XF86XK_AudioPrev, XBMCK_MEDIA_PREV_TRACK} ++, {XF86XK_AudioStop, XBMCK_MEDIA_STOP} ++, {XF86XK_AudioPause, XBMCK_MEDIA_PLAY_PAUSE} ++, {XF86XK_Mail, XBMCK_LAUNCH_MAIL} ++, {XF86XK_Select, XBMCK_LAUNCH_MEDIA_SELECT} ++, {XF86XK_Launch0, XBMCK_LAUNCH_APP1} ++, {XF86XK_Launch1, XBMCK_LAUNCH_APP2} ++, {XF86XK_WWW, XBMCK_LAUNCH_FILE_BROWSER} ++, {XF86XK_AudioMedia, XBMCK_LAUNCH_MEDIA_CENTER } ++ // Numeric keypad ++, {XK_KP_0, XBMCK_KP0} ++, {XK_KP_1, XBMCK_KP1} ++, {XK_KP_2, XBMCK_KP2} ++, {XK_KP_3, XBMCK_KP3} ++, {XK_KP_4, XBMCK_KP4} ++, {XK_KP_5, XBMCK_KP5} ++, {XK_KP_6, XBMCK_KP6} ++, {XK_KP_7, XBMCK_KP7} ++, {XK_KP_8, XBMCK_KP8} ++, {XK_KP_9, XBMCK_KP9} ++, {XK_KP_Separator, XBMCK_KP_PERIOD} ++, {XK_KP_Divide, XBMCK_KP_DIVIDE} ++, {XK_KP_Multiply, XBMCK_KP_MULTIPLY} ++, {XK_KP_Subtract, XBMCK_KP_MINUS} ++, {XK_KP_Add, XBMCK_KP_PLUS} ++, {XK_KP_Enter, XBMCK_KP_ENTER} ++, {XK_KP_Equal, XBMCK_KP_EQUALS} ++ // Arrows + Home/End pad ++, {XK_Up, XBMCK_UP} ++, {XK_Down, XBMCK_DOWN} ++, {XK_Right, XBMCK_RIGHT} ++, {XK_Left, XBMCK_LEFT} ++, {XK_Insert, XBMCK_INSERT} ++, {XK_Home, XBMCK_HOME} ++, {XK_End, XBMCK_END} ++, {XK_Page_Up, XBMCK_PAGEUP} ++, {XK_Page_Down, XBMCK_PAGEDOWN} ++ // Function keys ++, {XK_F1, XBMCK_F1} ++, {XK_F2, XBMCK_F2} ++, {XK_F3, XBMCK_F3} ++, {XK_F4, XBMCK_F4} ++, {XK_F5, XBMCK_F5} ++, {XK_F6, XBMCK_F6} ++, {XK_F7, XBMCK_F7} ++, {XK_F8, XBMCK_F8} ++, {XK_F9, XBMCK_F9} ++, {XK_F10, XBMCK_F10} ++, {XK_F11, XBMCK_F11} ++, {XK_F12, XBMCK_F12} ++, {XK_F13, XBMCK_F13} ++, {XK_F14, XBMCK_F14} ++, {XK_F15, XBMCK_F15} ++ // Key state modifier keys ++, {XK_Num_Lock, XBMCK_NUMLOCK} ++, {XK_Caps_Lock, XBMCK_CAPSLOCK} ++, {XK_Scroll_Lock, XBMCK_SCROLLOCK} ++, {XK_Shift_R, XBMCK_RSHIFT} ++, {XK_Shift_L, XBMCK_LSHIFT} ++, {XK_Control_R, XBMCK_RCTRL} ++, {XK_Control_L, XBMCK_LCTRL} ++, {XK_Alt_R, XBMCK_RALT} ++, {XK_Alt_L, XBMCK_LALT} ++, {XK_Meta_R, XBMCK_RMETA} ++, {XK_Meta_L, XBMCK_LMETA} ++, {XK_Super_L, XBMCK_LSUPER} ++, {XK_Super_R, XBMCK_RSUPER} ++, {XK_Mode_switch, XBMCK_MODE} ++, {XK_Multi_key, XBMCK_COMPOSE} ++ // Miscellaneous function keys ++, {XK_Help, XBMCK_HELP} ++, {XK_Print, XBMCK_PRINT} ++//, {0, XBMCK_SYSREQ} ++, {XK_Break, XBMCK_BREAK} ++, {XK_Menu, XBMCK_MENU} ++, {XF86XK_PowerOff, XBMCK_POWER} ++, {XK_EcuSign, XBMCK_EURO} ++, {XK_Undo, XBMCK_UNDO} ++ /* Media keys */ ++, {XF86XK_Eject, XBMCK_EJECT} ++, {XF86XK_Stop, XBMCK_STOP} ++, {XF86XK_AudioRecord, XBMCK_RECORD} ++, {XF86XK_AudioRewind, XBMCK_REWIND} ++, {XF86XK_Phone, XBMCK_PHONE} ++, {XF86XK_AudioPlay, XBMCK_PLAY} ++, {XF86XK_AudioRandomPlay, XBMCK_SHUFFLE} ++, {XF86XK_AudioForward, XBMCK_FASTFORWARD} ++}; ++ ++ ++CWinEventsX11::CWinEventsX11() ++{ ++ m_display = 0; ++ m_window = 0; ++ m_keybuf = 0; ++ m_utf16buf = 0; ++} ++ ++CWinEventsX11::~CWinEventsX11() ++{ ++ if (m_keybuf); ++ { ++ free(m_keybuf); ++ m_keybuf = 0; ++ } ++ ++ if (m_utf16buf) ++ { ++ free(m_utf16buf); ++ m_utf16buf = 0; ++ } ++ ++ if (m_xic) ++ { ++ XUnsetICFocus(m_xic); ++ XDestroyIC(m_xic); ++ m_xic = 0; ++ } ++ ++ if (m_xim) ++ { ++ XCloseIM(m_xim); ++ m_xim = 0; ++ } ++ ++ m_symLookupTable.clear(); ++} ++ ++bool CWinEventsX11::Init(Display *dpy, Window win) ++{ ++ if (WinEvents) ++ return true; ++ ++ WinEvents = new CWinEventsX11(); ++ WinEvents->m_display = dpy; ++ WinEvents->m_window = win; ++ WinEvents->m_keybuf = (char*)malloc(32*sizeof(char)); ++ WinEvents->m_utf16buf = (uint16_t*)malloc(32*sizeof(uint16_t)); ++ WinEvents->m_keymodState = 0; ++ WinEvents->m_wmDeleteMessage = XInternAtom(dpy, "WM_DELETE_WINDOW", False); ++ WinEvents->m_structureChanged = false; ++ memset(&(WinEvents->m_lastKey), 0, sizeof(XBMC_Event)); ++ ++ // open input method ++ char *old_locale = NULL, *old_modifiers = NULL; ++ char res_name[8]; ++ const char *p; ++ size_t n; ++ ++ // set resource name to xbmc, not used ++ strcpy(res_name, "xbmc"); ++ ++ // save current locale, this should be "C" ++ p = setlocale(LC_ALL, NULL); ++ if (p) ++ { ++ old_locale = (char*)malloc(strlen(p) +1); ++ strcpy(old_locale, p); ++ } ++ p = XSetLocaleModifiers(NULL); ++ if (p) ++ { ++ old_modifiers = (char*)malloc(strlen(p) +1); ++ strcpy(old_modifiers, p); ++ } ++ ++ // set users preferences and open input method ++ p = setlocale(LC_ALL, ""); ++ XSetLocaleModifiers(""); ++ WinEvents->m_xim = XOpenIM(WinEvents->m_display, NULL, res_name, res_name); ++ ++ // restore old locale ++ if (old_locale) ++ { ++ setlocale(LC_ALL, old_locale); ++ free(old_locale); ++ } ++ if (old_modifiers) ++ { ++ XSetLocaleModifiers(old_modifiers); ++ free(old_modifiers); ++ } ++ ++ WinEvents->m_xic = NULL; ++ if (WinEvents->m_xim) ++ { ++ WinEvents->m_xic = XCreateIC(WinEvents->m_xim, ++ XNClientWindow, WinEvents->m_window, ++ XNFocusWindow, WinEvents->m_window, ++ XNInputStyle, XIMPreeditNothing | XIMStatusNothing, ++ XNResourceName, res_name, ++ XNResourceClass, res_name, ++ NULL); ++ } ++ ++ if (!WinEvents->m_xic) ++ CLog::Log(LOGWARNING,"CWinEventsX11::Init - no input method found"); ++ ++ // build Keysym lookup table ++ for (unsigned int i = 0; i < sizeof(SymMappingsX11)/(2*sizeof(uint32_t)); ++i) ++ { ++ WinEvents->m_symLookupTable[SymMappingsX11[i][0]] = SymMappingsX11[i][1]; ++ } ++ ++ return true; ++} ++ ++void CWinEventsX11::Quit() ++{ ++ if (!WinEvents) ++ return; ++ ++ delete WinEvents; ++ WinEvents = 0; ++} ++ ++bool CWinEventsX11::HasStructureChanged() ++{ ++ if (!WinEvents) ++ return false; ++ ++ bool ret = WinEvents->m_structureChanged; ++ WinEvents->m_structureChanged = false; ++ return ret; ++} ++ ++bool CWinEventsX11::MessagePump() ++{ ++ if (!WinEvents) ++ return false; ++ ++ bool ret = false; ++ XEvent xevent; ++ unsigned long serial = 0; ++ ++ while (WinEvents && XPending(WinEvents->m_display)) ++ { ++ memset(&xevent, 0, sizeof (XEvent)); ++ XNextEvent(WinEvents->m_display, &xevent); ++ ++ // ignore events generated by auto-repeat ++ if (xevent.type == KeyRelease && XPending(WinEvents->m_display)) ++ { ++ XEvent peekevent; ++ XPeekEvent(WinEvents->m_display, &peekevent); ++ if ((peekevent.type == KeyPress) && ++ (peekevent.xkey.keycode == xevent.xkey.keycode) && ++ ((peekevent.xkey.time - xevent.xkey.time) < 2)) ++ { ++ XNextEvent(WinEvents->m_display, &peekevent); ++ continue; ++ } ++ } ++ ++ if (XFilterEvent(&xevent, None)) ++ continue; ++ ++ switch (xevent.type) ++ { ++ case MapNotify: ++ { ++ g_application.m_AppActive = true; ++ break; ++ } ++ ++ case UnmapNotify: ++ { ++ g_application.m_AppActive = false; ++ break; ++ } ++ ++ case FocusIn: ++ { ++ if (WinEvents->m_xic) ++ XSetICFocus(WinEvents->m_xic); ++ g_application.m_AppFocused = true; ++ if (serial == xevent.xfocus.serial) ++ break; ++ g_Windowing.NotifyAppFocusChange(g_application.m_AppFocused); ++ break; ++ } ++ ++ case FocusOut: ++ { ++ if (WinEvents->m_xic) ++ XUnsetICFocus(WinEvents->m_xic); ++ g_application.m_AppFocused = false; ++ g_Windowing.NotifyAppFocusChange(g_application.m_AppFocused); ++ serial = xevent.xfocus.serial; ++ break; ++ } ++ ++ case Expose: ++ { ++ g_windowManager.MarkDirty(); ++ break; ++ } ++ ++ case ConfigureNotify: ++ { ++ if (xevent.xconfigure.window != WinEvents->m_window) ++ break; ++ ++ WinEvents->m_structureChanged = true; ++ XBMC_Event newEvent; ++ memset(&newEvent, 0, sizeof(newEvent)); ++ newEvent.type = XBMC_VIDEORESIZE; ++ newEvent.resize.w = xevent.xconfigure.width; ++ newEvent.resize.h = xevent.xconfigure.height; ++ ret |= g_application.OnEvent(newEvent); ++ g_windowManager.MarkDirty(); ++ break; ++ } ++ ++ case ClientMessage: ++ { ++ if (xevent.xclient.data.l[0] == WinEvents->m_wmDeleteMessage) ++ if (!g_application.m_bStop) CApplicationMessenger::Get().Quit(); ++ break; ++ } ++ ++ case KeyPress: ++ { ++ XBMC_Event newEvent; ++ memset(&newEvent, 0, sizeof(newEvent)); ++ newEvent.type = XBMC_KEYDOWN; ++ KeySym xkeysym; ++ ++ // fallback if we have no IM ++ if (!WinEvents->m_xic) ++ { ++ static XComposeStatus state; ++ char keybuf[32]; ++ xkeysym = XLookupKeysym(&xevent.xkey, 0); ++ newEvent.key.keysym.sym = LookupXbmcKeySym(xkeysym); ++ newEvent.key.keysym.scancode = xevent.xkey.keycode; ++ newEvent.key.state = xevent.xkey.state; ++ newEvent.key.type = xevent.xkey.type; ++ if (XLookupString(&xevent.xkey, keybuf, sizeof(keybuf), NULL, &state)) ++ { ++ newEvent.key.keysym.unicode = keybuf[0]; ++ } ++ ret |= ProcessKey(newEvent, 500); ++ break; ++ } ++ ++ Status status; ++ int utf16size; ++ int utf16length; ++ int len; ++ len = Xutf8LookupString(WinEvents->m_xic, &xevent.xkey, ++ WinEvents->m_keybuf, sizeof(WinEvents->m_keybuf), ++ &xkeysym, &status); ++ if (status == XBufferOverflow) ++ { ++ WinEvents->m_keybuf = (char*)realloc(WinEvents->m_keybuf, len*sizeof(char)); ++ len = Xutf8LookupString(WinEvents->m_xic, &xevent.xkey, ++ WinEvents->m_keybuf, sizeof(WinEvents->m_keybuf), ++ &xkeysym, &status); ++ } ++ switch (status) ++ { ++ case XLookupNone: ++ break; ++ case XLookupChars: ++ case XLookupBoth: ++ { ++ if (len == 0) ++ break; ++ utf16size = len * sizeof(uint16_t); ++ if (utf16size > sizeof(WinEvents->m_utf16buf)) ++ { ++ WinEvents->m_utf16buf = (uint16_t *)realloc(WinEvents->m_utf16buf,utf16size); ++ if (WinEvents->m_utf16buf == NULL) ++ { ++ break; ++ } ++ } ++ utf16length = Utf8ToUnicode(WinEvents->m_keybuf, len, WinEvents->m_utf16buf, utf16size); ++ if (utf16length < 0) ++ { ++ break; ++ } ++ for (unsigned int i = 0; i < utf16length - 1; i++) ++ { ++ newEvent.key.keysym.sym = XBMCK_UNKNOWN; ++ newEvent.key.keysym.unicode = WinEvents->m_utf16buf[i]; ++ newEvent.key.state = xevent.xkey.state; ++ newEvent.key.type = xevent.xkey.type; ++ ret |= ProcessKey(newEvent, 500); ++ } ++ if (utf16length > 0) ++ { ++ newEvent.key.keysym.scancode = xevent.xkey.keycode; ++ xkeysym = XLookupKeysym(&xevent.xkey, 0); ++ newEvent.key.keysym.sym = LookupXbmcKeySym(xkeysym); ++ newEvent.key.keysym.unicode = WinEvents->m_utf16buf[utf16length - 1]; ++ newEvent.key.state = xevent.xkey.state; ++ newEvent.key.type = xevent.xkey.type; ++ ++ ret |= ProcessKey(newEvent, 500); ++ } ++ break; ++ } ++ ++ case XLookupKeySym: ++ { ++ newEvent.key.keysym.scancode = xevent.xkey.keycode; ++ newEvent.key.keysym.sym = LookupXbmcKeySym(xkeysym); ++ newEvent.key.state = xevent.xkey.state; ++ newEvent.key.type = xevent.xkey.type; ++ ret |= ProcessKey(newEvent, 500); ++ break; ++ } ++ ++ }// switch status ++ break; ++ } //KeyPress ++ ++ case KeyRelease: ++ { ++ XBMC_Event newEvent; ++ KeySym xkeysym; ++ memset(&newEvent, 0, sizeof(newEvent)); ++ newEvent.type = XBMC_KEYUP; ++ xkeysym = XLookupKeysym(&xevent.xkey, 0); ++ newEvent.key.keysym.scancode = xevent.xkey.keycode; ++ newEvent.key.keysym.sym = LookupXbmcKeySym(xkeysym); ++ newEvent.key.state = xevent.xkey.state; ++ newEvent.key.type = xevent.xkey.type; ++ ret |= ProcessKey(newEvent, 0); ++ break; ++ } ++ ++ // lose mouse coverage ++ case LeaveNotify: ++ { ++ g_Mouse.SetActive(false); ++ break; ++ } ++ ++ case MotionNotify: ++ { ++ XBMC_Event newEvent; ++ memset(&newEvent, 0, sizeof(newEvent)); ++ newEvent.type = XBMC_MOUSEMOTION; ++ newEvent.motion.xrel = (int16_t)xevent.xmotion.x_root; ++ newEvent.motion.yrel = (int16_t)xevent.xmotion.y_root; ++ newEvent.motion.x = (int16_t)xevent.xmotion.x; ++ newEvent.motion.y = (int16_t)xevent.xmotion.y; ++ ret |= g_application.OnEvent(newEvent); ++ break; ++ } ++ ++ case ButtonPress: ++ { ++ XBMC_Event newEvent; ++ memset(&newEvent, 0, sizeof(newEvent)); ++ newEvent.type = XBMC_MOUSEBUTTONDOWN; ++ newEvent.button.button = (unsigned char)xevent.xbutton.button; ++ newEvent.button.state = XBMC_PRESSED; ++ newEvent.button.x = (int16_t)xevent.xbutton.x; ++ newEvent.button.y = (int16_t)xevent.xbutton.y; ++ ret |= g_application.OnEvent(newEvent); ++ break; ++ } ++ ++ case ButtonRelease: ++ { ++ XBMC_Event newEvent; ++ memset(&newEvent, 0, sizeof(newEvent)); ++ newEvent.type = XBMC_MOUSEBUTTONUP; ++ newEvent.button.button = (unsigned char)xevent.xbutton.button; ++ newEvent.button.state = XBMC_RELEASED; ++ newEvent.button.x = (int16_t)xevent.xbutton.x; ++ newEvent.button.y = (int16_t)xevent.xbutton.y; ++ ret |= g_application.OnEvent(newEvent); ++ break; ++ } ++ ++ default: ++ { ++ break; ++ } ++ }// switch event.type ++ }// while ++ ++ ret |= ProcessKeyRepeat(); ++ ++ return ret; ++} ++ ++bool CWinEventsX11::ProcessKey(XBMC_Event &event, int repeatDelay) ++{ ++ if (event.type == XBMC_KEYDOWN) ++ { ++ // check key modifiers ++ switch(event.key.keysym.sym) ++ { ++ case XBMCK_LSHIFT: ++ WinEvents->m_keymodState |= XBMCKMOD_LSHIFT; ++ break; ++ case XBMCK_RSHIFT: ++ WinEvents->m_keymodState |= XBMCKMOD_RSHIFT; ++ break; ++ case XBMCK_LCTRL: ++ WinEvents->m_keymodState |= XBMCKMOD_LCTRL; ++ break; ++ case XBMCK_RCTRL: ++ WinEvents->m_keymodState |= XBMCKMOD_RCTRL; ++ break; ++ case XBMCK_LALT: ++ WinEvents->m_keymodState |= XBMCKMOD_LALT; ++ break; ++ case XBMCK_RALT: ++ WinEvents->m_keymodState |= XBMCKMOD_RCTRL; ++ break; ++ case XBMCK_LMETA: ++ WinEvents->m_keymodState |= XBMCKMOD_LMETA; ++ break; ++ case XBMCK_RMETA: ++ WinEvents->m_keymodState |= XBMCKMOD_RMETA; ++ break; ++ case XBMCK_MODE: ++ WinEvents->m_keymodState |= XBMCKMOD_MODE; ++ break; ++ default: ++ break; ++ } ++ event.key.keysym.mod = (XBMCMod)WinEvents->m_keymodState; ++ memcpy(&(WinEvents->m_lastKey), &event, sizeof(event)); ++ WinEvents->m_repeatKeyTimeout.Set(repeatDelay); ++ ++ bool ret = ProcessShortcuts(event); ++ if (ret) ++ return ret; ++ } ++ else if (event.type == XBMC_KEYUP) ++ { ++ switch(event.key.keysym.sym) ++ { ++ case XBMCK_LSHIFT: ++ WinEvents->m_keymodState &= ~XBMCKMOD_LSHIFT; ++ break; ++ case XBMCK_RSHIFT: ++ WinEvents->m_keymodState &= ~XBMCKMOD_RSHIFT; ++ break; ++ case XBMCK_LCTRL: ++ WinEvents->m_keymodState &= ~XBMCKMOD_LCTRL; ++ break; ++ case XBMCK_RCTRL: ++ WinEvents->m_keymodState &= ~XBMCKMOD_RCTRL; ++ break; ++ case XBMCK_LALT: ++ WinEvents->m_keymodState &= ~XBMCKMOD_LALT; ++ break; ++ case XBMCK_RALT: ++ WinEvents->m_keymodState &= ~XBMCKMOD_RCTRL; ++ break; ++ case XBMCK_LMETA: ++ WinEvents->m_keymodState &= ~XBMCKMOD_LMETA; ++ break; ++ case XBMCK_RMETA: ++ WinEvents->m_keymodState &= ~XBMCKMOD_RMETA; ++ break; ++ case XBMCK_MODE: ++ WinEvents->m_keymodState &= ~XBMCKMOD_MODE; ++ break; ++ default: ++ break; ++ } ++ event.key.keysym.mod = (XBMCMod)WinEvents->m_keymodState; ++ memset(&(WinEvents->m_lastKey), 0, sizeof(event)); ++ } ++ ++ return g_application.OnEvent(event); ++} ++ ++bool CWinEventsX11::ProcessShortcuts(XBMC_Event& event) ++{ ++ if (event.key.keysym.mod & XBMCKMOD_ALT) ++ { ++ switch(event.key.keysym.sym) ++ { ++ case XBMCK_TAB: // ALT+TAB to minimize/hide ++ g_application.Minimize(); ++ return true; ++ ++ default: ++ return false; ++ } ++ } ++ return false; ++} ++ ++bool CWinEventsX11::ProcessKeyRepeat() ++{ ++ if (WinEvents && (WinEvents->m_lastKey.type == XBMC_KEYDOWN)) ++ { ++ if (WinEvents->m_repeatKeyTimeout.IsTimePast()) ++ { ++ return ProcessKey(WinEvents->m_lastKey, 10); ++ } ++ } ++ return false; ++} ++ ++int CWinEventsX11::Utf8ToUnicode(const char *utf8, const int utf8Length, uint16_t *utf16, const int utf16MaxLength) ++{ ++ // p moves over the output buffer. max_ptr points to the next to the last slot of the buffer. ++ uint16_t *p = utf16; ++ uint16_t const *const maxPtr = utf16 + utf16MaxLength; ++ ++ // end_of_input points to the last byte of input as opposed to the next to the last byte. ++ char const *const endOfInput = utf8 + utf8Length - 1; ++ ++ while (utf8 <= endOfInput) ++ { ++ unsigned char const c = *utf8; ++ if (p >= maxPtr) ++ { ++ //No more output space. ++ return -1; ++ } ++ if (c < 0x80) ++ { ++ //One byte ASCII. ++ *p++ = c; ++ utf8 += 1; ++ } ++ else if (c < 0xC0) ++ { ++ // Follower byte without preceding leader bytes. ++ return -1; ++ } ++ // 11 bits ++ else if (c < 0xE0) ++ { ++ // Two byte sequence. We need one follower byte. ++ if (endOfInput - utf8 < 1 || (((utf8[1] ^ 0x80)) & 0xC0)) ++ { ++ return -1; ++ } ++ *p++ = (uint16_t)(((c & 0x1F) << 6) + (utf8[1] & 0x3F)); ++ utf8 += 2; ++ } ++ // 16 bis ++ else if (c < 0xF0) ++ { ++ // Three byte sequence. We need two follower byte. ++ if (endOfInput - utf8 < 2 || ((utf8[1] ^ 0x80) & 0xC0) || ((utf8[2] ^ 0x80) & 0xC0)) ++ { ++ return -1; ++ } ++ *p++ = (uint16_t)(((c & 0xF) << 12) + ((utf8[1] & 0x3F) << 6) + (utf8[2] & 0x3F)); ++ utf8 += 3; ++ } ++ // 21 bits ++ else if (c < 0xF8) ++ { ++ int plane; ++ // Four byte sequence. We need three follower bytes. ++ if (endOfInput - utf8 < 3 || ((utf8[1] ^ 0x80) & 0xC0) || ++ ((utf8[2] ^ 0x80) & 0xC0) || ((utf8[3] ^ 0x80) & 0xC0)) ++ { ++ return -1; ++ } ++ uint32_t unicode = ((c & 0x7) << 18) + ((utf8[1] & 0x3F) << 12) + ++ ((utf8[2] & 0x3F) << 6) + (utf8[3] & 0x3F); ++ utf8 += 4; ++ CLog::Log(LOGERROR, "CWinEventsX11::Utf8ToUnicode: 4 byte unicode not supported"); ++ } ++ // 26 bits ++ else if (c < 0xFC) ++ { ++ CLog::Log(LOGERROR, "CWinEventsX11::Utf8ToUnicode: 4 byte unicode not supported"); ++ utf8 += 5; ++ } ++ // 31 bit ++ else ++ { ++ CLog::Log(LOGERROR, "CWinEventsX11::Utf8ToUnicode: 4 byte unicode not supported"); ++ utf8 += 6; ++ } ++ } ++ return p - utf16; ++} ++ ++XBMCKey CWinEventsX11::LookupXbmcKeySym(KeySym keysym) ++{ ++ // try direct mapping first ++ std::map::iterator it; ++ it = WinEvents->m_symLookupTable.find(keysym); ++ if (it != WinEvents->m_symLookupTable.end()) ++ { ++ return (XBMCKey)(it->second); ++ } ++ ++ // try ascii mappings ++ if (keysym>>8 == 0x00) ++ return (XBMCKey)(keysym & 0xFF); ++ ++ return (XBMCKey)keysym; ++} ++#endif +diff --git a/xbmc/windowing/WinEventsX11.h b/xbmc/windowing/WinEventsX11.h +new file mode 100644 +index 0000000..e9b7553 +--- /dev/null ++++ b/xbmc/windowing/WinEventsX11.h +@@ -0,0 +1,57 @@ ++/* ++* Copyright (C) 2005-2012 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 "WinEvents.h" ++#include ++#include "threads/SystemClock.h" ++#include ++ ++class CWinEventsX11 : public CWinEventsBase ++{ ++public: ++ CWinEventsX11(); ++ virtual ~CWinEventsX11(); ++ static bool Init(Display *dpy, Window win); ++ static void Quit(); ++ static bool HasStructureChanged(); ++ static bool MessagePump(); ++ ++protected: ++ static int Utf8ToUnicode(const char *utf8, const int utf8Length, uint16_t *utf16, const int utf16MaxLength); ++ static XBMCKey LookupXbmcKeySym(KeySym keysym); ++ static bool ProcessKey(XBMC_Event &event, int repeatDelay); ++ static bool ProcessKeyRepeat(); ++ static bool ProcessShortcuts(XBMC_Event& event); ++ static CWinEventsX11 *WinEvents; ++ Display *m_display; ++ Window m_window; ++ Atom m_wmDeleteMessage; ++ char *m_keybuf; ++ uint16_t *m_utf16buf; ++ XIM m_xim; ++ XIC m_xic; ++ XBMC_Event m_lastKey; ++ XbmcThreads::EndTime m_repeatKeyTimeout; ++ std::map m_symLookupTable; ++ int m_keymodState; ++ bool m_structureChanged; ++}; +diff --git a/xbmc/windowing/X11/WinSystemX11.cpp b/xbmc/windowing/X11/WinSystemX11.cpp +index a839709..76ef462 100644 +--- a/xbmc/windowing/X11/WinSystemX11.cpp ++++ b/xbmc/windowing/X11/WinSystemX11.cpp +@@ -22,7 +22,6 @@ + + #ifdef HAS_GLX + +-#include + #include "WinSystemX11.h" + #include "settings/Settings.h" + #include "guilib/Texture.h" +@@ -31,27 +30,30 @@ + #include "XRandR.h" + #include + #include "threads/SingleLock.h" +-#include + #include "cores/VideoRenderers/RenderManager.h" + #include "utils/TimeUtils.h" ++#include "settings/GUISettings.h" + + #if defined(HAS_XRANDR) + #include + #endif + ++#include "../WinEvents.h" ++#include "input/MouseStat.h" ++ + using namespace std; + + CWinSystemX11::CWinSystemX11() : CWinSystemBase() + { + m_eWindowSystem = WINDOW_SYSTEM_X11; + m_glContext = NULL; +- m_SDLSurface = NULL; + m_dpy = NULL; + m_glWindow = 0; +- m_wmWindow = 0; + m_bWasFullScreenBeforeMinimize = false; + m_minimized = false; ++ m_bIgnoreNextFocusMessage = false; + m_dpyLostTime = 0; ++ m_invisibleCursor = 0; + + XSetErrorHandler(XErrorHandler); + } +@@ -64,18 +66,6 @@ bool CWinSystemX11::InitWindowSystem() + { + if ((m_dpy = XOpenDisplay(NULL))) + { +- +- SDL_EnableUNICODE(1); +- // set repeat to 10ms to ensure repeat time < frame time +- // so that hold times can be reliably detected +- SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, 10); +- +- SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8); +- SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8); +- SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8); +- SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 8); +- SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); +- + return CWinSystemBase::InitWindowSystem(); + } + else +@@ -113,45 +103,37 @@ bool CWinSystemX11::DestroyWindowSystem() + + bool CWinSystemX11::CreateNewWindow(const CStdString& name, bool fullScreen, RESOLUTION_INFO& res, PHANDLE_EVENT_FUNC userFunction) + { +- RESOLUTION_INFO& desktop = g_settings.m_ResInfo[RES_DESKTOP]; +- +- if (fullScreen && +- (res.iWidth != desktop.iWidth || res.iHeight != desktop.iHeight || +- res.fRefreshRate != desktop.fRefreshRate || res.iScreen != desktop.iScreen)) +- { +- //on the first call to SDL_SetVideoMode, SDL stores the current displaymode +- //SDL restores the displaymode on SDL_QUIT(), if we change the displaymode +- //before the first call to SDL_SetVideoMode, SDL changes the displaymode back +- //to the wrong mode on exit +- +- CLog::Log(LOGINFO, "CWinSystemX11::CreateNewWindow initializing to desktop resolution first"); +- if (!SetFullScreen(true, desktop, false)) +- return false; +- } +- + if(!SetFullScreen(fullScreen, res, false)) + return false; + +- CBaseTexture* iconTexture = CTexture::LoadFromFile("special://xbmc/media/icon.png"); +- +- if (iconTexture) +- SDL_WM_SetIcon(SDL_CreateRGBSurfaceFrom(iconTexture->GetPixels(), iconTexture->GetWidth(), iconTexture->GetHeight(), 32, iconTexture->GetPitch(), 0xff0000, 0x00ff00, 0x0000ff, 0xff000000L), NULL); +- SDL_WM_SetCaption("XBMC Media Center", NULL); +- delete iconTexture; +- +- // register XRandR Events +-#if defined(HAS_XRANDR) +- int iReturn; +- XRRQueryExtension(m_dpy, &m_RREventBase, &iReturn); +- XRRSelectInput(m_dpy, m_wmWindow, RRScreenChangeNotifyMask); +-#endif +- + m_bWindowCreated = true; + return true; + } + + bool CWinSystemX11::DestroyWindow() + { ++ if (!m_glWindow) ++ return true; ++ ++ if (m_glContext) ++ glXMakeCurrent(m_dpy, None, NULL); ++ ++ if (m_invisibleCursor) ++ { ++ XUndefineCursor(m_dpy, m_glWindow); ++ XFreeCursor(m_dpy, m_invisibleCursor); ++ m_invisibleCursor = 0; ++ } ++ ++ CWinEvents::Quit(); ++ ++ XUnmapWindow(m_dpy, m_glWindow); ++ XSync(m_dpy,TRUE); ++ XUngrabKeyboard(m_dpy, CurrentTime); ++ XUngrabPointer(m_dpy, CurrentTime); ++ XDestroyWindow(m_dpy, m_glWindow); ++ m_glWindow = 0; ++ + return true; + } + +@@ -161,65 +143,105 @@ bool CWinSystemX11::ResizeWindow(int newWidth, int newHeight, int newLeft, int n + && m_nHeight == newHeight) + return true; + ++ if (!SetWindow(newWidth, newHeight, false)) ++ { ++ return false; ++ } ++ ++ RefreshGlxContext(); + m_nWidth = newWidth; + m_nHeight = newHeight; ++ m_bFullScreen = false; + +- int options = SDL_OPENGL; +- if (m_bFullScreen) +- options |= SDL_FULLSCREEN; +- else +- options |= SDL_RESIZABLE; ++ return false; ++} ++ ++void CWinSystemX11::RefreshWindow() ++{ ++ g_xrandr.Query(true); ++ XOutput out = g_xrandr.GetCurrentOutput(); ++ XMode mode = g_xrandr.GetCurrentMode(out.name); + +- if ((m_SDLSurface = SDL_SetVideoMode(m_nWidth, m_nHeight, 0, options))) ++ // only overwrite desktop resolution, if we are not in fullscreen mode ++ if (!g_graphicsContext.IsFullScreenVideo()) + { +- RefreshGlxContext(); +- return true; ++ CLog::Log(LOGDEBUG, "CWinSystemX11::RefreshWindow - store desktop resolution, width: %d, height: %d, hz: %2.2f", mode.w, mode.h, mode.hz); ++ UpdateDesktopResolution(g_settings.m_ResInfo[RES_DESKTOP], 0, mode.w, mode.h, mode.hz); ++ g_settings.m_ResInfo[RES_DESKTOP].strId = mode.id; ++ g_settings.m_ResInfo[RES_DESKTOP].strOutput = out.name; + } + +- return false; ++ 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; ++ } ++ ++ if (g_graphicsContext.IsFullScreenRoot()) ++ g_graphicsContext.SetVideoResolution((RESOLUTION)i, true); ++ else ++ g_graphicsContext.SetVideoResolution(RES_WINDOW, true); + } + + bool CWinSystemX11::SetFullScreen(bool fullScreen, RESOLUTION_INFO& res, bool blankOtherDisplays) + { +- m_nWidth = res.iWidth; +- m_nHeight = res.iHeight; +- m_bFullScreen = fullScreen; + + #if defined(HAS_XRANDR) + XOutput out; + XMode mode; +- out.name = res.strOutput; +- mode.w = res.iWidth; +- mode.h = res.iHeight; +- mode.hz = res.fRefreshRate; +- mode.id = res.strId; ++ ++ if (fullScreen) ++ { ++ out.name = res.strOutput; ++ mode.w = res.iWidth; ++ mode.h = res.iHeight; ++ mode.hz = res.fRefreshRate; ++ mode.id = res.strId; ++ } ++ else ++ { ++ out.name = g_settings.m_ResInfo[RES_DESKTOP].strOutput; ++ mode.w = g_settings.m_ResInfo[RES_DESKTOP].iWidth; ++ mode.h = g_settings.m_ResInfo[RES_DESKTOP].iHeight; ++ mode.hz = g_settings.m_ResInfo[RES_DESKTOP].fRefreshRate; ++ mode.id = g_settings.m_ResInfo[RES_DESKTOP].strId; ++ } + +- if(m_bFullScreen) ++ XOutput currout = g_xrandr.GetCurrentOutput(); ++ XMode currmode = g_xrandr.GetCurrentMode(currout.name); ++ ++ // 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(); + g_xrandr.SetMode(out, mode); + } +- else +- g_xrandr.RestoreState(); + #endif + +- int options = SDL_OPENGL; +- if (m_bFullScreen) +- options |= SDL_FULLSCREEN; +- else +- options |= SDL_RESIZABLE; +- +- if ((m_SDLSurface = SDL_SetVideoMode(m_nWidth, m_nHeight, 0, options))) +- { +- if ((m_SDLSurface->flags & SDL_OPENGL) != SDL_OPENGL) +- CLog::Log(LOGERROR, "CWinSystemX11::SetFullScreen SDL_OPENGL not set, SDL_GetError:%s", SDL_GetError()); ++ if (!SetWindow(res.iWidth, res.iHeight, fullScreen)) ++ return false; + +- RefreshGlxContext(); ++ RefreshGlxContext(); + +- return true; +- } ++ m_nWidth = res.iWidth; ++ m_nHeight = res.iHeight; ++ m_bFullScreen = fullScreen; + +- return false; ++ return true; + } + + void CWinSystemX11::UpdateResolutions() +@@ -321,17 +343,10 @@ bool CWinSystemX11::IsSuitableVisual(XVisualInfo *vInfo) + bool CWinSystemX11::RefreshGlxContext() + { + bool retVal = false; +- SDL_SysWMinfo info; +- SDL_VERSION(&info.version); +- if (SDL_GetWMInfo(&info) <= 0) +- { +- CLog::Log(LOGERROR, "Failed to get window manager info from SDL"); +- return false; +- } + +- if(m_glWindow == info.info.x11.window && m_glContext) ++ if (m_glContext) + { +- CLog::Log(LOGERROR, "GLX: Same window as before, refreshing context"); ++ CLog::Log(LOGDEBUG, "CWinSystemX11::RefreshGlxContext: refreshing context"); + glXMakeCurrent(m_dpy, None, NULL); + glXMakeCurrent(m_dpy, m_glWindow, m_glContext); + return true; +@@ -343,8 +358,6 @@ bool CWinSystemX11::RefreshGlxContext() + int availableVisuals = 0; + vMask.screen = DefaultScreen(m_dpy); + XWindowAttributes winAttr; +- m_glWindow = info.info.x11.window; +- m_wmWindow = info.info.x11.wmwindow; + + /* Assume a depth of 24 in case the below calls to XGetWindowAttributes() + or XGetVisualInfo() fail. That shouldn't happen unless something is +@@ -415,7 +428,10 @@ bool CWinSystemX11::RefreshGlxContext() + + void CWinSystemX11::ShowOSMouse(bool show) + { +- SDL_ShowCursor(show ? 1 : 0); ++ if (show) ++ XUndefineCursor(m_dpy,m_glWindow); ++ else if (m_invisibleCursor) ++ XDefineCursor(m_dpy,m_glWindow, m_invisibleCursor); + } + + void CWinSystemX11::ResetOSScreensaver() +@@ -429,8 +445,6 @@ void CWinSystemX11::ResetOSScreensaver() + { + m_screensaverReset.StartZero(); + XResetScreenSaver(m_dpy); +- //need to flush the output buffer, since we don't check for events on m_dpy +- XFlush(m_dpy); + } + } + else +@@ -446,13 +460,27 @@ void CWinSystemX11::NotifyAppActiveChange(bool bActivated) + + m_minimized = !bActivated; + } ++ ++void CWinSystemX11::NotifyAppFocusChange(bool bGaining) ++{ ++ if (bGaining && m_bWasFullScreenBeforeMinimize && !m_bIgnoreNextFocusMessage && ++ !g_graphicsContext.IsFullScreenRoot()) ++ g_graphicsContext.ToggleFullScreenRoot(); ++ if (!bGaining) ++ m_bIgnoreNextFocusMessage = false; ++} ++ + bool CWinSystemX11::Minimize() + { + m_bWasFullScreenBeforeMinimize = g_graphicsContext.IsFullScreenRoot(); + if (m_bWasFullScreenBeforeMinimize) ++ { ++ m_bIgnoreNextFocusMessage = true; + g_graphicsContext.ToggleFullScreenRoot(); ++ } ++ ++ XIconifyWindow(m_dpy, m_glWindow, DefaultScreen(m_dpy)); + +- SDL_WM_IconifyWindow(); + m_minimized = true; + return true; + } +@@ -462,13 +490,13 @@ bool CWinSystemX11::Restore() + } + bool CWinSystemX11::Hide() + { +- XUnmapWindow(m_dpy, m_wmWindow); ++ XUnmapWindow(m_dpy, m_glWindow); + XSync(m_dpy, False); + return true; + } + bool CWinSystemX11::Show(bool raise) + { +- XMapWindow(m_dpy, m_wmWindow); ++ XMapWindow(m_dpy, m_glWindow); + XSync(m_dpy, False); + m_minimized = false; + return true; +@@ -500,6 +528,7 @@ void CWinSystemX11::CheckDisplayEvents() + if (bGotEvent || bTimeout) + { + CLog::Log(LOGDEBUG, "%s - notify display reset event", __FUNCTION__); ++ RefreshWindow(); + + CSingleLock lock(m_resourceSection); + +@@ -558,4 +587,151 @@ bool CWinSystemX11::EnableFrameLimiter() + return m_minimized; + } + ++bool CWinSystemX11::SetWindow(int width, int height, bool fullscreen) ++{ ++ bool changeWindow = false; ++ bool changeSize = false; ++ bool mouseActive = false; ++ float mouseX, mouseY; ++ ++ if (m_glWindow && (m_bFullScreen != fullscreen)) ++ { ++ mouseActive = g_Mouse.IsActive(); ++ if (mouseActive) ++ { ++ Window root_return, child_return; ++ int root_x_return, root_y_return; ++ int win_x_return, win_y_return; ++ unsigned int mask_return; ++ bool isInWin = XQueryPointer(m_dpy, m_glWindow, &root_return, &child_return, ++ &root_x_return, &root_y_return, ++ &win_x_return, &win_y_return, ++ &mask_return); ++ if (isInWin) ++ { ++ mouseX = (float)win_x_return/m_nWidth; ++ mouseY = (float)win_y_return/m_nHeight; ++ g_Mouse.SetActive(false); ++ } ++ else ++ mouseActive = false; ++ } ++ DestroyWindow(); ++ } ++ ++ // create main window ++ if (!m_glWindow) ++ { ++ GLint att[] = ++ { ++ GLX_RGBA, ++ GLX_RED_SIZE, 8, ++ GLX_GREEN_SIZE, 8, ++ GLX_BLUE_SIZE, 8, ++ GLX_ALPHA_SIZE, 8, ++ GLX_DEPTH_SIZE, 24, ++ GLX_DOUBLEBUFFER, ++ None ++ }; ++ Colormap cmap; ++ XSetWindowAttributes swa; ++ XVisualInfo *vi; ++ ++ vi = glXChooseVisual(m_dpy, DefaultScreen(m_dpy), att); ++ cmap = XCreateColormap(m_dpy, RootWindow(m_dpy, vi->screen), vi->visual, AllocNone); ++ ++ int def_vis = (vi->visual == DefaultVisual(m_dpy, vi->screen)); ++ swa.override_redirect = fullscreen ? True : False; ++ swa.border_pixel = fullscreen ? 0 : 5; ++ swa.background_pixel = def_vis ? BlackPixel(m_dpy, vi->screen) : 0; ++ swa.colormap = cmap; ++ swa.background_pixel = def_vis ? BlackPixel(m_dpy, vi->screen) : 0; ++ swa.event_mask = FocusChangeMask | KeyPressMask | KeyReleaseMask | ++ ButtonPressMask | ButtonReleaseMask | PointerMotionMask | ++ PropertyChangeMask | StructureNotifyMask | KeymapStateMask | ++ EnterWindowMask | LeaveWindowMask | ExposureMask; ++ unsigned long mask = CWBackPixel | CWBorderPixel | CWColormap | CWOverrideRedirect | CWEventMask; ++ ++ m_glWindow = XCreateWindow(m_dpy, RootWindow(m_dpy, vi->screen), ++ 0, 0, width, height, 0, vi->depth, ++ InputOutput, vi->visual, ++ mask, &swa); ++ ++ // define invisible cursor ++ Pixmap bitmapNoData; ++ XColor black; ++ static char noData[] = { 0,0,0,0,0,0,0,0 }; ++ black.red = black.green = black.blue = 0; ++ ++ bitmapNoData = XCreateBitmapFromData(m_dpy, m_glWindow, noData, 8, 8); ++ m_invisibleCursor = XCreatePixmapCursor(m_dpy, bitmapNoData, bitmapNoData, ++ &black, &black, 0, 0); ++ XFreePixmap(m_dpy, bitmapNoData); ++ XDefineCursor(m_dpy,m_glWindow, m_invisibleCursor); ++ ++ //init X11 events ++ CWinEvents::Init(m_dpy, m_glWindow); ++ ++ changeWindow = true; ++ changeSize = true; ++ } ++ ++ if (!CWinEvents::HasStructureChanged() && ((width != m_nWidth) || (height != m_nHeight))) ++ { ++ changeSize = true; ++ } ++ ++ if (changeSize || changeWindow) ++ { ++ XResizeWindow(m_dpy, m_glWindow, width, height); ++ } ++ ++ if (changeWindow) ++ { ++ if (!fullscreen) ++ { ++ XWMHints wm_hints; ++ XClassHint class_hints; ++ XTextProperty windowName, iconName; ++ std::string titleString = "XBMC Media Center"; ++ char *title = (char*)titleString.c_str(); ++ ++ XStringListToTextProperty(&title, 1, &windowName); ++ XStringListToTextProperty(&title, 1, &iconName); ++ wm_hints.initial_state = NormalState; ++ wm_hints.input = True; ++ wm_hints.icon_pixmap = None; ++ wm_hints.flags = StateHint | IconPixmapHint | InputHint; ++ ++ XSetWMProperties(m_dpy, m_glWindow, &windowName, &iconName, ++ NULL, 0, NULL, &wm_hints, ++ NULL); ++ ++ // register interest in the delete window message ++ Atom wmDeleteMessage = XInternAtom(m_dpy, "WM_DELETE_WINDOW", False); ++ XSetWMProtocols(m_dpy, m_glWindow, &wmDeleteMessage, 1); ++ } ++ XMapRaised(m_dpy, m_glWindow); ++ XSync(m_dpy,TRUE); ++ ++ if (changeWindow && mouseActive) ++ { ++ XWarpPointer(m_dpy, None, m_glWindow, 0, 0, 0, 0, mouseX*width, mouseY*height); ++ } ++ ++ if (fullscreen) ++ { ++ int result = -1; ++ while (result != GrabSuccess) ++ { ++ result = XGrabPointer(m_dpy, m_glWindow, True, ButtonPressMask, GrabModeAsync, GrabModeAsync, m_glWindow, None, CurrentTime); ++ XbmcThreads::ThreadSleep(100); ++ } ++ XGrabKeyboard(m_dpy, m_glWindow, True, GrabModeAsync, GrabModeAsync, CurrentTime); ++ ++ } ++ } ++ return true; ++} ++ + #endif +diff --git a/xbmc/windowing/X11/WinSystemX11.h b/xbmc/windowing/X11/WinSystemX11.h +index 2dd8a9f..9616d17 100644 +--- a/xbmc/windowing/X11/WinSystemX11.h ++++ b/xbmc/windowing/X11/WinSystemX11.h +@@ -52,6 +52,7 @@ class CWinSystemX11 : public CWinSystemBase + virtual bool EnableFrameLimiter(); + + virtual void NotifyAppActiveChange(bool bActivated); ++ virtual void NotifyAppFocusChange(bool bGaining); + + virtual bool Minimize(); + virtual bool Restore() ; +@@ -64,19 +65,21 @@ class CWinSystemX11 : public CWinSystemBase + Display* GetDisplay() { return m_dpy; } + GLXWindow GetWindow() { return m_glWindow; } + GLXContext GetGlxContext() { return m_glContext; } ++ void RefreshWindow(); + + protected: + bool RefreshGlxContext(); + void CheckDisplayEvents(); + void OnLostDevice(); ++ bool SetWindow(int width, int height, bool fullscreen); + +- SDL_Surface* m_SDLSurface; ++ Window m_glWindow; + GLXContext m_glContext; +- GLXWindow m_glWindow; +- Window m_wmWindow; + Display* m_dpy; ++ Cursor m_invisibleCursor; + bool m_bWasFullScreenBeforeMinimize; + bool m_minimized; ++ bool m_bIgnoreNextFocusMessage; + int m_RREventBase; + CCriticalSection m_resourceSection; + std::vector m_resources; +-- +1.7.10 + + +From 58fa894afaffbc990ee1ab87ff55db30e36ab2c2 Mon Sep 17 00:00:00 2001 +From: FernetMenta +Date: Thu, 5 Jul 2012 15:24:22 +0200 +Subject: [PATCH 15/73] X11: Add xbmc icon + +--- + xbmc/windowing/X11/WinSystemX11.cpp | 126 ++++++++++++++++++++++++++++++++++- + xbmc/windowing/X11/WinSystemX11.h | 2 + + 2 files changed, 127 insertions(+), 1 deletion(-) + +diff --git a/xbmc/windowing/X11/WinSystemX11.cpp b/xbmc/windowing/X11/WinSystemX11.cpp +index 76ef462..c854598 100644 +--- a/xbmc/windowing/X11/WinSystemX11.cpp ++++ b/xbmc/windowing/X11/WinSystemX11.cpp +@@ -134,6 +134,9 @@ bool CWinSystemX11::DestroyWindow() + XDestroyWindow(m_dpy, m_glWindow); + m_glWindow = 0; + ++ if (m_icon) ++ XFreePixmap(m_dpy, m_icon); ++ + return true; + } + +@@ -688,8 +691,10 @@ bool CWinSystemX11::SetWindow(int width, int height, bool fullscreen) + + if (changeWindow) + { ++ m_icon = None; + if (!fullscreen) + { ++ CreateIconPixmap(); + XWMHints wm_hints; + XClassHint class_hints; + XTextProperty windowName, iconName; +@@ -700,7 +705,7 @@ bool CWinSystemX11::SetWindow(int width, int height, bool fullscreen) + XStringListToTextProperty(&title, 1, &iconName); + wm_hints.initial_state = NormalState; + wm_hints.input = True; +- wm_hints.icon_pixmap = None; ++ wm_hints.icon_pixmap = m_icon; + wm_hints.flags = StateHint | IconPixmapHint | InputHint; + + XSetWMProperties(m_dpy, m_glWindow, &windowName, &iconName, +@@ -734,4 +739,123 @@ bool CWinSystemX11::SetWindow(int width, int height, bool fullscreen) + return true; + } + ++bool CWinSystemX11::CreateIconPixmap() ++{ ++ int depth; ++ XImage *img = NULL; ++ Visual *vis; ++ XWindowAttributes wndattribs; ++ XVisualInfo visInfo; ++ double rRatio; ++ double gRatio; ++ double bRatio; ++ int outIndex = 0; ++ int i,j; ++ int numBufBytes; ++ unsigned char *buf; ++ uint32_t *newBuf = 0; ++ size_t numNewBufBytes; ++ ++ // Get visual Info ++ XGetWindowAttributes(m_dpy, m_glWindow, &wndattribs); ++ visInfo.visualid = wndattribs.visual->visualid; ++ int nvisuals = 0; ++ XVisualInfo* visuals = XGetVisualInfo(m_dpy, VisualIDMask, &visInfo, &nvisuals); ++ if (nvisuals != 1) ++ { ++ CLog::Log(LOGERROR, "CWinSystemX11::CreateIconPixmap - could not find visual"); ++ return false; ++ } ++ visInfo = visuals[0]; ++ XFree(visuals); ++ ++ depth = visInfo.depth; ++ vis = visInfo.visual; ++ ++ if (depth < 15) ++ { ++ CLog::Log(LOGERROR, "CWinSystemX11::CreateIconPixmap - no suitable depth"); ++ return false; ++ } ++ ++ rRatio = vis->red_mask / 255.0; ++ gRatio = vis->green_mask / 255.0; ++ bRatio = vis->blue_mask / 255.0; ++ ++ CTexture iconTexture; ++ iconTexture.LoadFromFile("special://xbmc/media/icon.png"); ++ buf = iconTexture.GetPixels(); ++ ++ numBufBytes = iconTexture.GetWidth() * iconTexture.GetHeight() * 4; ++ ++ if (depth>=24) ++ numNewBufBytes = (4 * (iconTexture.GetWidth() * iconTexture.GetHeight())); ++ else ++ numNewBufBytes = (2 * (iconTexture.GetWidth() * iconTexture.GetHeight())); ++ ++ newBuf = (uint32_t*)malloc(numNewBufBytes); ++ if (!newBuf) ++ { ++ CLog::Log(LOGERROR, "CWinSystemX11::CreateIconPixmap - malloc failed"); ++ return false; ++ } ++ ++ for (i=0; ired_mask; ++ g &= vis->green_mask; ++ b &= vis->blue_mask; ++ newBuf[outIndex] = r | g | b; ++ ++outIndex; ++ } ++ } ++ img = XCreateImage(m_dpy, vis, depth,ZPixmap, 0, (char *)newBuf, ++ iconTexture.GetWidth(), iconTexture.GetHeight(), ++ (depth>=24)?32:16, 0); ++ if (!img) ++ { ++ CLog::Log(LOGERROR, "CWinSystemX11::CreateIconPixmap - could not create image"); ++ free(newBuf); ++ return false; ++ } ++ if (!XInitImage(img)) ++ { ++ CLog::Log(LOGERROR, "CWinSystemX11::CreateIconPixmap - init image failed"); ++ XDestroyImage(img); ++ return false; ++ } ++ ++ // set byte order ++ union ++ { ++ char c[sizeof(short)]; ++ short s; ++ } order; ++ order.s = 1; ++ if ((1 == order.c[0])) ++ { ++ img->byte_order = LSBFirst; ++ } ++ else ++ { ++ img->byte_order = MSBFirst; ++ } ++ ++ // create icon pixmap from image ++ m_icon = XCreatePixmap(m_dpy, m_glWindow, img->width, img->height, depth); ++ GC gc = XCreateGC(m_dpy, m_glWindow, 0, NULL); ++ XPutImage(m_dpy, m_icon, gc, img, 0, 0, 0, 0, img->width, img->height); ++ XFreeGC(m_dpy, gc); ++ XDestroyImage(img); // this also frees newBuf ++ ++ return true; ++} ++ + #endif +diff --git a/xbmc/windowing/X11/WinSystemX11.h b/xbmc/windowing/X11/WinSystemX11.h +index 9616d17..debf714 100644 +--- a/xbmc/windowing/X11/WinSystemX11.h ++++ b/xbmc/windowing/X11/WinSystemX11.h +@@ -77,6 +77,7 @@ class CWinSystemX11 : public CWinSystemBase + GLXContext m_glContext; + Display* m_dpy; + Cursor m_invisibleCursor; ++ Pixmap m_icon; + bool m_bWasFullScreenBeforeMinimize; + bool m_minimized; + bool m_bIgnoreNextFocusMessage; +@@ -88,6 +89,7 @@ class CWinSystemX11 : public CWinSystemBase + private: + bool IsSuitableVisual(XVisualInfo *vInfo); + static int XErrorHandler(Display* dpy, XErrorEvent* error); ++ bool CreateIconPixmap(); + + CStopWatch m_screensaverReset; + }; +-- +1.7.10 + + +From cad2ac7f357906f10f100a038ff28e83a69c68e8 Mon Sep 17 00:00:00 2001 +From: xbmc +Date: Sun, 20 May 2012 14:11:26 +0200 +Subject: [PATCH 16/73] X11: add SDL joystick until we have a better solution + +--- + xbmc/windowing/WinEventsX11.cpp | 26 ++++++++++++++++++++++++++ + 1 file changed, 26 insertions(+) + +diff --git a/xbmc/windowing/WinEventsX11.cpp b/xbmc/windowing/WinEventsX11.cpp +index 24477ae..2ec86a8 100644 +--- a/xbmc/windowing/WinEventsX11.cpp ++++ b/xbmc/windowing/WinEventsX11.cpp +@@ -35,6 +35,10 @@ + #include "guilib/GUIWindowManager.h" + #include "input/MouseStat.h" + ++#ifdef HAS_SDL_JOYSTICK ++#include "input/SDLJoystick.h" ++#endif ++ + CWinEventsX11* CWinEventsX11::WinEvents = 0; + + static uint32_t SymMappingsX11[][2] = +@@ -547,6 +551,28 @@ bool CWinEventsX11::MessagePump() + + ret |= ProcessKeyRepeat(); + ++#ifdef HAS_SDL_JOYSTICK ++ SDL_Event event; ++ while (SDL_PollEvent(&event)) ++ { ++ switch(event.type) ++ { ++ case SDL_JOYBUTTONUP: ++ case SDL_JOYBUTTONDOWN: ++ case SDL_JOYAXISMOTION: ++ case SDL_JOYBALLMOTION: ++ case SDL_JOYHATMOTION: ++ g_Joystick.Update(event); ++ ret = true; ++ break; ++ ++ default: ++ break; ++ } ++ memset(&event, 0, sizeof(SDL_Event)); ++ } ++#endif ++ + return ret; + } + +-- +1.7.10 + + +From fdefd4cf296518f31ad1165268fccd651e08dd3c Mon Sep 17 00:00:00 2001 +From: Joakim Plate +Date: Thu, 5 Jul 2012 12:35:55 +0200 +Subject: [PATCH 17/73] X11: factor out code handling device reset + notification + +--- + xbmc/windowing/X11/WinSystemX11.cpp | 22 ++++++++++++++-------- + xbmc/windowing/X11/WinSystemX11.h | 1 + + 2 files changed, 15 insertions(+), 8 deletions(-) + +diff --git a/xbmc/windowing/X11/WinSystemX11.cpp b/xbmc/windowing/X11/WinSystemX11.cpp +index c854598..70557d0 100644 +--- a/xbmc/windowing/X11/WinSystemX11.cpp ++++ b/xbmc/windowing/X11/WinSystemX11.cpp +@@ -530,14 +530,7 @@ void CWinSystemX11::CheckDisplayEvents() + + if (bGotEvent || bTimeout) + { +- CLog::Log(LOGDEBUG, "%s - notify display reset event", __FUNCTION__); +- RefreshWindow(); +- +- CSingleLock lock(m_resourceSection); +- +- // tell any shared resources +- for (vector::iterator i = m_resources.begin(); i != m_resources.end(); i++) +- (*i)->OnResetDevice(); ++ NotifyXRREvent(); + + // reset fail safe timer + m_dpyLostTime = 0; +@@ -545,6 +538,19 @@ void CWinSystemX11::CheckDisplayEvents() + #endif + } + ++void CWinSystemX11::NotifyXRREvent() ++{ ++ CLog::Log(LOGDEBUG, "%s - notify display reset event", __FUNCTION__); ++ RefreshWindow(); ++ ++ CSingleLock lock(m_resourceSection); ++ ++ // tell any shared resources ++ for (vector::iterator i = m_resources.begin(); i != m_resources.end(); i++) ++ (*i)->OnResetDevice(); ++ ++} ++ + void CWinSystemX11::OnLostDevice() + { + CLog::Log(LOGDEBUG, "%s - notify display change event", __FUNCTION__); +diff --git a/xbmc/windowing/X11/WinSystemX11.h b/xbmc/windowing/X11/WinSystemX11.h +index debf714..8c28e3f 100644 +--- a/xbmc/windowing/X11/WinSystemX11.h ++++ b/xbmc/windowing/X11/WinSystemX11.h +@@ -66,6 +66,7 @@ class CWinSystemX11 : public CWinSystemBase + GLXWindow GetWindow() { return m_glWindow; } + GLXContext GetGlxContext() { return m_glContext; } + void RefreshWindow(); ++ void NotifyXRREvent(); + + protected: + bool RefreshGlxContext(); +-- +1.7.10 + + +From 9a409794d1eb8ee0c4b0b1124dea7dd30af32c06 Mon Sep 17 00:00:00 2001 +From: FernetMenta +Date: Thu, 5 Jul 2012 15:02:00 +0200 +Subject: [PATCH 18/73] X11: move xrandr events to WinEventsX11 + +--- + xbmc/windowing/WinEventsX11.cpp | 42 +++++++++++++++++++++++++++++++++++ + xbmc/windowing/WinEventsX11.h | 5 +++++ + xbmc/windowing/X11/WinSystemX11.cpp | 6 ++++- + 3 files changed, 52 insertions(+), 1 deletion(-) + +diff --git a/xbmc/windowing/WinEventsX11.cpp b/xbmc/windowing/WinEventsX11.cpp +index 2ec86a8..5946a33 100644 +--- a/xbmc/windowing/WinEventsX11.cpp ++++ b/xbmc/windowing/WinEventsX11.cpp +@@ -35,6 +35,10 @@ + #include "guilib/GUIWindowManager.h" + #include "input/MouseStat.h" + ++#if defined(HAS_XRANDR) ++#include ++#endif ++ + #ifdef HAS_SDL_JOYSTICK + #include "input/SDLJoystick.h" + #endif +@@ -203,6 +207,7 @@ bool CWinEventsX11::Init(Display *dpy, Window win) + WinEvents->m_keymodState = 0; + WinEvents->m_wmDeleteMessage = XInternAtom(dpy, "WM_DELETE_WINDOW", False); + WinEvents->m_structureChanged = false; ++ WinEvents->m_xrrEventPending = false; + memset(&(WinEvents->m_lastKey), 0, sizeof(XBMC_Event)); + + // open input method +@@ -266,6 +271,13 @@ bool CWinEventsX11::Init(Display *dpy, Window win) + WinEvents->m_symLookupTable[SymMappingsX11[i][0]] = SymMappingsX11[i][1]; + } + ++ // register for xrandr events ++#if defined(HAS_XRANDR) ++ int iReturn; ++ XRRQueryExtension(WinEvents->m_display, &WinEvents->m_RREventBase, &iReturn); ++ XRRSelectInput(WinEvents->m_display, WinEvents->m_window, RRScreenChangeNotifyMask); ++#endif ++ + return true; + } + +@@ -288,6 +300,15 @@ bool CWinEventsX11::HasStructureChanged() + return ret; + } + ++void CWinEventsX11::SetXRRFailSafeTimer(int millis) ++{ ++ if (!WinEvents) ++ return; ++ ++ WinEvents->m_xrrFailSafeTimer.Set(millis); ++ WinEvents->m_xrrEventPending = true; ++} ++ + bool CWinEventsX11::MessagePump() + { + if (!WinEvents) +@@ -547,10 +568,31 @@ bool CWinEventsX11::MessagePump() + break; + } + }// switch event.type ++ ++#if defined(HAS_XRANDR) ++ if (WinEvents && (xevent.type == WinEvents->m_RREventBase + RRScreenChangeNotify)) ++ { ++ XRRUpdateConfiguration(&xevent); ++ if (xevent.xgeneric.serial != serial) ++ g_Windowing.NotifyXRREvent(); ++ WinEvents->m_xrrEventPending = false; ++ serial = xevent.xgeneric.serial; ++ } ++#endif ++ + }// while + + ret |= ProcessKeyRepeat(); + ++#if defined(HAS_XRANDR) ++ if (WinEvents && WinEvents->m_xrrEventPending && WinEvents->m_xrrFailSafeTimer.IsTimePast()) ++ { ++ CLog::Log(LOGERROR,"CWinEventsX11::MessagePump - missed XRR Events"); ++ g_Windowing.NotifyXRREvent(); ++ WinEvents->m_xrrEventPending = false; ++ } ++#endif ++ + #ifdef HAS_SDL_JOYSTICK + SDL_Event event; + while (SDL_PollEvent(&event)) +diff --git a/xbmc/windowing/WinEventsX11.h b/xbmc/windowing/WinEventsX11.h +index e9b7553..6100933 100644 +--- a/xbmc/windowing/WinEventsX11.h ++++ b/xbmc/windowing/WinEventsX11.h +@@ -33,6 +33,8 @@ class CWinEventsX11 : public CWinEventsBase + static bool Init(Display *dpy, Window win); + static void Quit(); + static bool HasStructureChanged(); ++ static void PendingResize(int width, int height); ++ static void SetXRRFailSafeTimer(int millis); + static bool MessagePump(); + + protected: +@@ -54,4 +56,7 @@ class CWinEventsX11 : public CWinEventsBase + std::map m_symLookupTable; + int m_keymodState; + bool m_structureChanged; ++ int m_RREventBase; ++ XbmcThreads::EndTime m_xrrFailSafeTimer; ++ bool m_xrrEventPending; + }; +diff --git a/xbmc/windowing/X11/WinSystemX11.cpp b/xbmc/windowing/X11/WinSystemX11.cpp +index 70557d0..1cce843 100644 +--- a/xbmc/windowing/X11/WinSystemX11.cpp ++++ b/xbmc/windowing/X11/WinSystemX11.cpp +@@ -507,7 +507,7 @@ bool CWinSystemX11::Show(bool raise) + + void CWinSystemX11::CheckDisplayEvents() + { +-#if defined(HAS_XRANDR) ++#if defined(HAS_XRANDR) && defined(HAS_SDL_VIDEO_X11) + bool bGotEvent(false); + bool bTimeout(false); + XEvent Event; +@@ -563,8 +563,12 @@ void CWinSystemX11::OnLostDevice() + (*i)->OnLostDevice(); + } + ++#if defined(HAS_SDL_VIDEO_X11) + // fail safe timer + m_dpyLostTime = CurrentHostCounter(); ++#else ++ CWinEvents::SetXRRFailSafeTimer(3000); ++#endif + } + + void CWinSystemX11::Register(IDispResource *resource) +-- +1.7.10 + + +From 1dc579a2d5c608cfd4f799971759d18cbd2957e5 Mon Sep 17 00:00:00 2001 +From: FernetMenta +Date: Thu, 12 Apr 2012 15:43:56 +0200 +Subject: [PATCH 19/73] xrandr: remove method RestoreState + +--- + xbmc/windowing/X11/WinSystemX11.cpp | 13 +++++++++++-- + xbmc/windowing/X11/XRandR.cpp | 19 ------------------- + xbmc/windowing/X11/XRandR.h | 1 - + 3 files changed, 11 insertions(+), 22 deletions(-) + +diff --git a/xbmc/windowing/X11/WinSystemX11.cpp b/xbmc/windowing/X11/WinSystemX11.cpp +index 1cce843..e13ffa4 100644 +--- a/xbmc/windowing/X11/WinSystemX11.cpp ++++ b/xbmc/windowing/X11/WinSystemX11.cpp +@@ -77,9 +77,18 @@ bool CWinSystemX11::InitWindowSystem() + bool CWinSystemX11::DestroyWindowSystem() + { + #if defined(HAS_XRANDR) +- //restore videomode on exit ++ //restore desktop resolution on exit + if (m_bFullScreen) +- g_xrandr.RestoreState(); ++ { ++ XOutput out; ++ XMode mode; ++ out.name = g_settings.m_ResInfo[RES_DESKTOP].strOutput; ++ mode.w = g_settings.m_ResInfo[RES_DESKTOP].iWidth; ++ mode.h = g_settings.m_ResInfo[RES_DESKTOP].iHeight; ++ mode.hz = g_settings.m_ResInfo[RES_DESKTOP].fRefreshRate; ++ mode.id = g_settings.m_ResInfo[RES_DESKTOP].strId; ++ g_xrandr.SetMode(out, mode); ++ } + #endif + + if (m_dpy) +diff --git a/xbmc/windowing/X11/XRandR.cpp b/xbmc/windowing/X11/XRandR.cpp +index d8e9161..59755a6 100644 +--- a/xbmc/windowing/X11/XRandR.cpp ++++ b/xbmc/windowing/X11/XRandR.cpp +@@ -139,25 +139,6 @@ void CXRandR::SaveState() + Query(true); + } + +-void CXRandR::RestoreState() +-{ +- vector::iterator outiter; +- for (outiter=m_current.begin() ; outiter!=m_current.end() ; outiter++) +- { +- vector modes = (*outiter).modes; +- vector::iterator modeiter; +- for (modeiter=modes.begin() ; modeiter!=modes.end() ; modeiter++) +- { +- XMode mode = *modeiter; +- if (mode.isCurrent) +- { +- SetMode(*outiter, mode); +- return; +- } +- } +- } +-} +- + bool CXRandR::SetMode(XOutput output, XMode mode) + { + if ((output.name == m_currentOutput && mode.id == m_currentMode) || (output.name == "" && mode.id == "")) +diff --git a/xbmc/windowing/X11/XRandR.h b/xbmc/windowing/X11/XRandR.h +index 2a269d0..5b64633 100644 +--- a/xbmc/windowing/X11/XRandR.h ++++ b/xbmc/windowing/X11/XRandR.h +@@ -99,7 +99,6 @@ class CXRandR + bool SetMode(XOutput output, XMode mode); + void LoadCustomModeLinesToAllOutputs(void); + void SaveState(); +- void RestoreState(); + //bool Has1080i(); + //bool Has1080p(); + //bool Has720p(); +-- +1.7.10 + + +From 4a6f0e986fc27b356041a4b1bb989e0e594c8aa7 Mon Sep 17 00:00:00 2001 +From: xbmc +Date: Sun, 20 May 2012 13:17:10 +0200 +Subject: [PATCH 20/73] xrandr: observe orientation + +--- + xbmc/windowing/X11/WinSystemX11.cpp | 61 +++++++++++++++++++++++++++++++++-- + xbmc/windowing/X11/WinSystemX11.h | 2 ++ + xbmc/windowing/X11/XRandR.cpp | 7 ++++ + xbmc/windowing/X11/XRandR.h | 1 + + 4 files changed, 68 insertions(+), 3 deletions(-) + +diff --git a/xbmc/windowing/X11/WinSystemX11.cpp b/xbmc/windowing/X11/WinSystemX11.cpp +index e13ffa4..6b0aa92 100644 +--- a/xbmc/windowing/X11/WinSystemX11.cpp ++++ b/xbmc/windowing/X11/WinSystemX11.cpp +@@ -170,15 +170,24 @@ bool CWinSystemX11::ResizeWindow(int newWidth, int newHeight, int newLeft, int n + + void CWinSystemX11::RefreshWindow() + { +- g_xrandr.Query(true); ++ if (!g_xrandr.Query(true)) ++ { ++ CLog::Log(LOGERROR, "WinSystemX11::RefreshWindow - failed to query xrandr"); ++ return; ++ } + XOutput out = g_xrandr.GetCurrentOutput(); + XMode mode = g_xrandr.GetCurrentMode(out.name); + ++ RotateResolutions(); ++ + // only overwrite desktop resolution, if we are not in fullscreen mode + if (!g_graphicsContext.IsFullScreenVideo()) + { + CLog::Log(LOGDEBUG, "CWinSystemX11::RefreshWindow - store desktop resolution, width: %d, height: %d, hz: %2.2f", mode.w, mode.h, mode.hz); +- UpdateDesktopResolution(g_settings.m_ResInfo[RES_DESKTOP], 0, mode.w, mode.h, mode.hz); ++ if (!out.isRotated) ++ UpdateDesktopResolution(g_settings.m_ResInfo[RES_DESKTOP], 0, mode.w, mode.h, mode.hz); ++ else ++ UpdateDesktopResolution(g_settings.m_ResInfo[RES_DESKTOP], 0, mode.h, mode.w, mode.hz); + g_settings.m_ResInfo[RES_DESKTOP].strId = mode.id; + g_settings.m_ResInfo[RES_DESKTOP].strOutput = out.name; + } +@@ -234,6 +243,14 @@ bool CWinSystemX11::SetFullScreen(bool fullScreen, RESOLUTION_INFO& res, bool bl + XOutput currout = g_xrandr.GetCurrentOutput(); + XMode currmode = g_xrandr.GetCurrentMode(currout.name); + ++ // flip h/w when rotated ++ if (m_bIsRotated) ++ { ++ int w = mode.w; ++ mode.w = mode.h; ++ mode.h = w; ++ } ++ + // 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) +@@ -266,7 +283,11 @@ void CWinSystemX11::UpdateResolutions() + { + XOutput out = g_xrandr.GetCurrentOutput(); + XMode mode = g_xrandr.GetCurrentMode(out.name); +- UpdateDesktopResolution(g_settings.m_ResInfo[RES_DESKTOP], 0, mode.w, mode.h, mode.hz); ++ m_bIsRotated = out.isRotated; ++ if (!m_bIsRotated) ++ UpdateDesktopResolution(g_settings.m_ResInfo[RES_DESKTOP], 0, mode.w, mode.h, mode.hz); ++ else ++ UpdateDesktopResolution(g_settings.m_ResInfo[RES_DESKTOP], 0, mode.h, mode.w, mode.hz); + g_settings.m_ResInfo[RES_DESKTOP].strId = mode.id; + g_settings.m_ResInfo[RES_DESKTOP].strOutput = out.name; + } +@@ -305,6 +326,16 @@ void CWinSystemX11::UpdateResolutions() + res.iHeight = mode.h; + res.iScreenWidth = mode.w; + res.iScreenHeight = mode.h; ++ if (!m_bIsRotated) ++ { ++ res.iWidth = mode.w; ++ res.iHeight = mode.h; ++ } ++ else ++ { ++ res.iWidth = mode.h; ++ res.iHeight = mode.w; ++ } + if (mode.h>0 && mode.w>0 && out.hmm>0 && out.wmm>0) + res.fPixelRatio = ((float)out.wmm/(float)mode.w) / (((float)out.hmm/(float)mode.h)); + else +@@ -332,6 +363,30 @@ void CWinSystemX11::UpdateResolutions() + + } + ++void CWinSystemX11::RotateResolutions() ++{ ++#if defined(HAS_XRANDR) ++ XOutput out = g_xrandr.GetCurrentOutput(); ++ if (out.isRotated == m_bIsRotated) ++ return; ++ ++ for (unsigned int i = 0; i < g_settings.m_ResInfo.size(); ++i) ++ { ++ int width = g_settings.m_ResInfo[i].iWidth; ++ g_settings.m_ResInfo[i].iWidth = g_settings.m_ResInfo[i].iHeight; ++ g_settings.m_ResInfo[i].iHeight = width; ++ } ++ // update desktop resolution ++// int h = g_settings.m_ResInfo[RES_DESKTOP].iHeight; ++// int w = g_settings.m_ResInfo[RES_DESKTOP].iWidth; ++// float hz = g_settings.m_ResInfo[RES_DESKTOP].fRefreshRate; ++// UpdateDesktopResolution(g_settings.m_ResInfo[RES_DESKTOP], 0, w, h, hz); ++ ++ m_bIsRotated = out.isRotated; ++ ++#endif ++} ++ + bool CWinSystemX11::IsSuitableVisual(XVisualInfo *vInfo) + { + int value; +diff --git a/xbmc/windowing/X11/WinSystemX11.h b/xbmc/windowing/X11/WinSystemX11.h +index 8c28e3f..93cf5db 100644 +--- a/xbmc/windowing/X11/WinSystemX11.h ++++ b/xbmc/windowing/X11/WinSystemX11.h +@@ -73,12 +73,14 @@ class CWinSystemX11 : public CWinSystemBase + void CheckDisplayEvents(); + void OnLostDevice(); + bool SetWindow(int width, int height, bool fullscreen); ++ void RotateResolutions(); + + Window m_glWindow; + GLXContext m_glContext; + Display* m_dpy; + Cursor m_invisibleCursor; + Pixmap m_icon; ++ bool m_bIsRotated; + bool m_bWasFullScreenBeforeMinimize; + bool m_minimized; + bool m_bIgnoreNextFocusMessage; +diff --git a/xbmc/windowing/X11/XRandR.cpp b/xbmc/windowing/X11/XRandR.cpp +index 59755a6..45aeb71 100644 +--- a/xbmc/windowing/X11/XRandR.cpp ++++ b/xbmc/windowing/X11/XRandR.cpp +@@ -98,6 +98,13 @@ bool CXRandR::Query(bool force) + xoutput.y = (output->Attribute("y") != NULL ? atoi(output->Attribute("y")) : 0); + xoutput.wmm = (output->Attribute("wmm") != NULL ? atoi(output->Attribute("wmm")) : 0); + xoutput.hmm = (output->Attribute("hmm") != NULL ? atoi(output->Attribute("hmm")) : 0); ++ if (output->Attribute("rotation") != NULL ++ && (strcasecmp(output->Attribute("rotation"), "left") == 0 || strcasecmp(output->Attribute("rotation"), "right") == 0)) ++ { ++ xoutput.isRotated = true; ++ } ++ else ++ xoutput.isRotated = false; + + if (!xoutput.isConnected) + continue; +diff --git a/xbmc/windowing/X11/XRandR.h b/xbmc/windowing/X11/XRandR.h +index 5b64633..618bd68 100644 +--- a/xbmc/windowing/X11/XRandR.h ++++ b/xbmc/windowing/X11/XRandR.h +@@ -86,6 +86,7 @@ class XOutput + int wmm; + int hmm; + std::vector modes; ++ bool isRotated; + }; + + class CXRandR +-- +1.7.10 + + +From 97e5811e05a4ecde7249b2f76283729ff300fda9 Mon Sep 17 00:00:00 2001 +From: FernetMenta +Date: Thu, 5 Jul 2012 11:54:15 +0200 +Subject: [PATCH 21/73] xrandr: allow getting info for multiple screen's + +Refactored by: Joakim Plate +--- + xbmc/windowing/X11/XRandR.cpp | 65 ++++++++++++++++++++++++++++++++--------- + xbmc/windowing/X11/XRandR.h | 8 +++-- + 2 files changed, 57 insertions(+), 16 deletions(-) + +diff --git a/xbmc/windowing/X11/XRandR.cpp b/xbmc/windowing/X11/XRandR.cpp +index 45aeb71..cc933b9 100644 +--- a/xbmc/windowing/X11/XRandR.cpp ++++ b/xbmc/windowing/X11/XRandR.cpp +@@ -39,6 +39,7 @@ + CXRandR::CXRandR(bool query) + { + m_bInit = false; ++ m_numScreens = 1; + if (query) + Query(); + } +@@ -55,11 +56,21 @@ bool CXRandR::Query(bool force) + return false; + + m_outputs.clear(); +- m_current.clear(); ++ // query all screens ++ for(unsigned int screennum=0; screennumValue(), "screen") != 0) ++ if (strcasecmp(pRootElement->Value(), "screen") != screennum) + { + // TODO ERROR + return false; +@@ -92,6 +103,7 @@ bool CXRandR::Query(bool force) + xoutput.name.TrimLeft(" \n\r\t"); + xoutput.name.TrimRight(" \n\r\t"); + xoutput.isConnected = (strcasecmp(output->Attribute("connected"), "true") == 0); ++ xoutput.screen = screennum; + xoutput.w = (output->Attribute("w") != NULL ? atoi(output->Attribute("w")) : 0); + xoutput.h = (output->Attribute("h") != NULL ? atoi(output->Attribute("h")) : 0); + xoutput.x = (output->Attribute("x") != NULL ? atoi(output->Attribute("x")) : 0); +@@ -123,7 +135,6 @@ bool CXRandR::Query(bool force) + xoutput.modes.push_back(xmode); + if (xmode.isCurrent) + { +- m_current.push_back(xoutput); + hascurrent = true; + } + } +@@ -247,17 +258,6 @@ bool CXRandR::SetMode(XOutput output, XMode mode) + return true; + } + +-XOutput CXRandR::GetCurrentOutput() +-{ +- Query(); +- for (unsigned int j = 0; j < m_outputs.size(); j++) +- { +- if(m_outputs[j].isConnected) +- return m_outputs[j]; +- } +- XOutput empty; +- return empty; +-} + XMode CXRandR::GetCurrentMode(CStdString outputName) + { + Query(); +@@ -331,6 +331,43 @@ void CXRandR::LoadCustomModeLinesToAllOutputs(void) + } + } + ++void CXRandR::SetNumScreens(unsigned int num) ++{ ++ m_numScreens = num; ++ m_bInit = false; ++} ++ ++bool CXRandR::IsOutputConnected(CStdString name) ++{ ++ bool result = false; ++ Query(); ++ ++ for (unsigned int i = 0; i < m_outputs.size(); ++i) ++ { ++ if (m_outputs[i].name == name) ++ { ++ result = true; ++ break; ++ } ++ } ++ return result; ++} ++ ++XOutput* CXRandR::GetOutput(CStdString outputName) ++{ ++ XOutput *result = 0; ++ Query(); ++ for (unsigned int i = 0; i < m_outputs.size(); ++i) ++ { ++ if (m_outputs[i].name == outputName) ++ { ++ result = &m_outputs[i]; ++ break; ++ } ++ } ++ return result; ++} ++ + CXRandR g_xrandr; + + #endif // HAS_XRANDR +diff --git a/xbmc/windowing/X11/XRandR.h b/xbmc/windowing/X11/XRandR.h +index 618bd68..0824af5 100644 +--- a/xbmc/windowing/X11/XRandR.h ++++ b/xbmc/windowing/X11/XRandR.h +@@ -79,6 +79,7 @@ class XOutput + } + CStdString name; + bool isConnected; ++ int screen; + int w; + int h; + int x; +@@ -94,12 +95,15 @@ class CXRandR + public: + CXRandR(bool query=false); + bool Query(bool force=false); ++ bool Query(bool force, int screennum); + std::vector GetModes(void); +- XOutput GetCurrentOutput(); + XMode GetCurrentMode(CStdString outputName); ++ XOutput *GetOutput(CStdString outputName); + bool SetMode(XOutput output, XMode mode); + void LoadCustomModeLinesToAllOutputs(void); + void SaveState(); ++ void SetNumScreens(unsigned int num); ++ bool IsOutputConnected(CStdString name); + //bool Has1080i(); + //bool Has1080p(); + //bool Has720p(); +@@ -107,10 +111,10 @@ class CXRandR + + private: + bool m_bInit; +- std::vector m_current; + std::vector m_outputs; + CStdString m_currentOutput; + CStdString m_currentMode; ++ unsigned int m_numScreens; + }; + + extern CXRandR g_xrandr; +-- +1.7.10 + + +From 2b379b9ce21b6d61b44b647b79ef3587dbbcf0ec Mon Sep 17 00:00:00 2001 +From: FernetMenta +Date: Thu, 5 Jul 2012 11:44:00 +0200 +Subject: [PATCH 22/73] X11: fix multi-head setups + +--- + language/English/strings.po | 4 +- + xbmc/rendering/gl/RenderSystemGL.h | 1 + + xbmc/settings/GUISettings.cpp | 5 + + xbmc/settings/GUIWindowSettingsCategory.cpp | 60 +++++- + xbmc/settings/GUIWindowSettingsCategory.h | 1 + + xbmc/windowing/WinEventsX11.cpp | 7 + + xbmc/windowing/X11/WinSystemX11.cpp | 262 ++++++++++++++++----------- + xbmc/windowing/X11/WinSystemX11.h | 10 +- + 8 files changed, 235 insertions(+), 115 deletions(-) + +diff --git a/language/English/strings.po b/language/English/strings.po +index 88292d3..bba7284 100644 +--- a/language/English/strings.po ++++ b/language/English/strings.po +@@ -895,7 +895,9 @@ msgctxt "#245" + msgid "Sizing: (%i,%i)->(%i,%i) (Zoom x%2.2f) AR:%2.2f:1 (Pixels: %2.2f:1) (VShift: %2.2f)" + msgstr "" + +-#empty string with id 246 ++msgctxt "#246" ++msgid "Monitor" ++msgstr "" + + msgctxt "#247" + msgid "Scripts" +diff --git a/xbmc/rendering/gl/RenderSystemGL.h b/xbmc/rendering/gl/RenderSystemGL.h +index efe5493..85d780d 100644 +--- a/xbmc/rendering/gl/RenderSystemGL.h ++++ b/xbmc/rendering/gl/RenderSystemGL.h +@@ -44,6 +44,7 @@ class CRenderSystemGL : public CRenderSystemBase + virtual bool IsExtSupported(const char* extension); + + virtual void SetVSync(bool vsync); ++ virtual void ResetVSync() { m_bVsyncInit = false; } + + virtual void SetViewPort(CRect& viewPort); + virtual void GetViewPort(CRect& viewPort); +diff --git a/xbmc/settings/GUISettings.cpp b/xbmc/settings/GUISettings.cpp +index 4cdb093..0e320e1 100644 +--- a/xbmc/settings/GUISettings.cpp ++++ b/xbmc/settings/GUISettings.cpp +@@ -392,11 +392,16 @@ void CGUISettings::Initialize() + AddGroup(SETTINGS_SYSTEM, 13000); + CSettingsCategory* vs = AddCategory(SETTINGS_SYSTEM, "videoscreen", 21373); + ++#if defined(HAS_GLX) ++ AddString(vs, "videoscreen.monitor", 246, "", SPIN_CONTROL_TEXT); ++#endif ++ + // this setting would ideally not be saved, as its value is systematically derived from videoscreen.screenmode. + // contains a DISPLAYMODE + #if !defined(TARGET_DARWIN_IOS_ATV2) && !defined(TARGET_RASPBERRY_PI) + AddInt(vs, "videoscreen.screen", 240, 0, -1, 1, 32, SPIN_CONTROL_TEXT); + #endif ++ + // this setting would ideally not be saved, as its value is systematically derived from videoscreen.screenmode. + // contains an index to the g_settings.m_ResInfo array. the only meaningful fields are iScreen, iWidth, iHeight. + #if defined(TARGET_DARWIN) +diff --git a/xbmc/settings/GUIWindowSettingsCategory.cpp b/xbmc/settings/GUIWindowSettingsCategory.cpp +index d988598..3c19a06 100644 +--- a/xbmc/settings/GUIWindowSettingsCategory.cpp ++++ b/xbmc/settings/GUIWindowSettingsCategory.cpp +@@ -528,6 +528,12 @@ void CGUIWindowSettingsCategory::CreateSettings() + FillInRefreshRates(strSetting, g_guiSettings.GetResolution(), false); + continue; + } ++ else if (strSetting.Equals("videoscreen.monitor")) ++ { ++ AddSetting(pSetting, group->GetWidth(), iControlID); ++ FillInMonitors(strSetting); ++ continue; ++ } + else if (strSetting.Equals("lookandfeel.skintheme")) + { + AddSetting(pSetting, group->GetWidth(), iControlID); +@@ -1494,6 +1500,20 @@ void CGUIWindowSettingsCategory::OnSettingChanged(BaseSettingControlPtr pSetting + // Cascade + FillInResolutions("videoscreen.resolution", mode, RES_DESKTOP, true); + } ++ else if (strSetting.Equals("videoscreen.monitor")) ++ { ++ CSettingString *pSettingString = (CSettingString *)pSettingControl->GetSetting(); ++ CGUISpinControlEx *pControl = (CGUISpinControlEx *)GetControl(pSettingControl->GetID()); ++ CStdString currentMonitor = pControl->GetCurrentLabel(); ++ if (!g_Windowing.IsCurrentOutput(currentMonitor)) ++ { ++ g_guiSettings.SetString("videoscreen.monitor", currentMonitor); ++ g_Windowing.UpdateResolutions(); ++ DisplayMode mode = g_guiSettings.GetInt("videoscreen.screen"); ++ // Cascade ++ FillInResolutions("videoscreen.resolution", mode, RES_DESKTOP, true); ++ } ++ } + else if (strSetting.Equals("videoscreen.resolution")) + { + RESOLUTION nextRes = (RESOLUTION) g_guiSettings.GetInt("videoscreen.resolution"); +@@ -2430,11 +2450,15 @@ DisplayMode CGUIWindowSettingsCategory::FillInScreens(CStdString strSetting, RES + if (g_advancedSettings.m_canWindowed) + pControl->AddLabel(g_localizeStrings.Get(242), -1); + ++#if !defined(HAS_GLX) + for (int idx = 0; idx < g_Windowing.GetNumScreens(); idx++) + { + strScreen.Format(g_localizeStrings.Get(241), g_settings.m_ResInfo[RES_DESKTOP + idx].iScreen + 1); + pControl->AddLabel(strScreen, g_settings.m_ResInfo[RES_DESKTOP + idx].iScreen); + } ++#else ++ pControl->AddLabel(g_localizeStrings.Get(244), 0); ++#endif + pControl->SetValue(mode); + g_guiSettings.SetInt("videoscreen.screen", mode); + } +@@ -2442,6 +2466,36 @@ DisplayMode CGUIWindowSettingsCategory::FillInScreens(CStdString strSetting, RES + return mode; + } + ++void CGUIWindowSettingsCategory::FillInMonitors(CStdString strSetting) ++{ ++ // we expect "videoscreen.monitor" but it might be hidden on some platforms, ++ // so check that we actually have a visable control. ++ CBaseSettingControl *control = GetSetting(strSetting); ++ if (control) ++ { ++ control->SetDelayed(); ++ CGUISpinControlEx *pControl = (CGUISpinControlEx *)GetControl(control->GetID()); ++ pControl->Clear(); ++ ++ std::vector monitors; ++ g_Windowing.GetConnectedOutputs(&monitors); ++ ++ int currentMonitor = 0; ++ for (unsigned int i=0; iAddLabel(monitors[i], i); ++ } ++ ++ pControl->SetValue(currentMonitor); ++ g_guiSettings.SetString("videoscreen.monitor", g_settings.m_ResInfo[RES_DESKTOP].strOutput); ++ } ++} ++ ++ + void CGUIWindowSettingsCategory::FillInResolutions(CStdString strSetting, DisplayMode mode, RESOLUTION res, bool UserChange) + { + BaseSettingControlPtr control = GetSetting(strSetting); +@@ -2570,13 +2624,15 @@ void CGUIWindowSettingsCategory::OnRefreshRateChanged(RESOLUTION nextRes) + RESOLUTION lastRes = g_graphicsContext.GetVideoResolution(); + bool cancelled = false; + ++ bool outputChanged = !g_Windowing.IsCurrentOutput(g_guiSettings.GetString("videoscreen.monitor")); ++ + g_guiSettings.SetResolution(nextRes); +- g_graphicsContext.SetVideoResolution(nextRes); ++ g_graphicsContext.SetVideoResolution(nextRes, outputChanged); + + if (!CGUIDialogYesNo::ShowAndGetInput(13110, 13111, 20022, 20022, -1, -1, cancelled, 10000)) + { + g_guiSettings.SetResolution(lastRes); +- g_graphicsContext.SetVideoResolution(lastRes); ++ g_graphicsContext.SetVideoResolution(lastRes, outputChanged); + + DisplayMode mode = FillInScreens("videoscreen.screen", lastRes); + FillInResolutions("videoscreen.resolution", mode, lastRes, false); +diff --git a/xbmc/settings/GUIWindowSettingsCategory.h b/xbmc/settings/GUIWindowSettingsCategory.h +index 5142c6e..0d4649d 100644 +--- a/xbmc/settings/GUIWindowSettingsCategory.h ++++ b/xbmc/settings/GUIWindowSettingsCategory.h +@@ -51,6 +51,7 @@ class CGUIWindowSettingsCategory : + void FillInSoundSkins(CSetting *pSetting); + void FillInLanguages(CSetting *pSetting, const std::vector &languages = std::vector(), const std::vector &languageKeys = std::vector()); + DisplayMode FillInScreens(CStdString strSetting, RESOLUTION res); ++ void FillInMonitors(CStdString strSetting); + void FillInResolutions(CStdString strSetting, DisplayMode mode, RESOLUTION res, bool UserChange); + void FillInRefreshRates(CStdString strSetting, RESOLUTION res, bool UserChange); + void OnRefreshRateChanged(RESOLUTION resolution); +diff --git a/xbmc/windowing/WinEventsX11.cpp b/xbmc/windowing/WinEventsX11.cpp +index 5946a33..6c22358 100644 +--- a/xbmc/windowing/WinEventsX11.cpp ++++ b/xbmc/windowing/WinEventsX11.cpp +@@ -517,9 +517,16 @@ bool CWinEventsX11::MessagePump() + break; + } + ++ case EnterNotify: ++ { ++ g_Windowing.NotifyMouseCoverage(true); ++ break; ++ } ++ + // lose mouse coverage + case LeaveNotify: + { ++ g_Windowing.NotifyMouseCoverage(false); + g_Mouse.SetActive(false); + break; + } +diff --git a/xbmc/windowing/X11/WinSystemX11.cpp b/xbmc/windowing/X11/WinSystemX11.cpp +index 6b0aa92..5f913f1 100644 +--- a/xbmc/windowing/X11/WinSystemX11.cpp ++++ b/xbmc/windowing/X11/WinSystemX11.cpp +@@ -33,6 +33,7 @@ + #include "cores/VideoRenderers/RenderManager.h" + #include "utils/TimeUtils.h" + #include "settings/GUISettings.h" ++#include "windowing/WindowingFactory.h" + + #if defined(HAS_XRANDR) + #include +@@ -54,6 +55,7 @@ + m_bIgnoreNextFocusMessage = false; + m_dpyLostTime = 0; + m_invisibleCursor = 0; ++ m_bIsInternalXrr = false; + + XSetErrorHandler(XErrorHandler); + } +@@ -66,7 +68,8 @@ bool CWinSystemX11::InitWindowSystem() + { + if ((m_dpy = XOpenDisplay(NULL))) + { +- return CWinSystemBase::InitWindowSystem(); ++ bool ret = CWinSystemBase::InitWindowSystem(); ++ return ret; + } + else + CLog::Log(LOGERROR, "GLX Error: No Display found"); +@@ -103,6 +106,8 @@ bool CWinSystemX11::DestroyWindowSystem() + + //we don't call XCloseDisplay() here, since ati keeps a pointer to our m_dpy + //so instead we just let m_dpy die on exit ++ // i have seen core dumps on ATI if the display is not closed here ++ XCloseDisplay(m_dpy); + } + + // m_SDLSurface is free()'d by SDL_Quit(). +@@ -125,7 +130,10 @@ bool CWinSystemX11::DestroyWindow() + return true; + + if (m_glContext) ++ { ++ glFinish(); + glXMakeCurrent(m_dpy, None, NULL); ++ } + + if (m_invisibleCursor) + { +@@ -155,7 +163,7 @@ bool CWinSystemX11::ResizeWindow(int newWidth, int newHeight, int newLeft, int n + && m_nHeight == newHeight) + return true; + +- if (!SetWindow(newWidth, newHeight, false)) ++ if (!SetWindow(newWidth, newHeight, false, g_guiSettings.GetString("videoscreen.monitor"))) + { + return false; + } +@@ -164,58 +172,11 @@ bool CWinSystemX11::ResizeWindow(int newWidth, int newHeight, int newLeft, int n + m_nWidth = newWidth; + m_nHeight = newHeight; + m_bFullScreen = false; ++ m_currentOutput = g_guiSettings.GetString("videoscreen.monitor"); + + return false; + } + +-void CWinSystemX11::RefreshWindow() +-{ +- if (!g_xrandr.Query(true)) +- { +- CLog::Log(LOGERROR, "WinSystemX11::RefreshWindow - failed to query xrandr"); +- return; +- } +- XOutput out = g_xrandr.GetCurrentOutput(); +- XMode mode = g_xrandr.GetCurrentMode(out.name); +- +- RotateResolutions(); +- +- // only overwrite desktop resolution, if we are not in fullscreen mode +- if (!g_graphicsContext.IsFullScreenVideo()) +- { +- CLog::Log(LOGDEBUG, "CWinSystemX11::RefreshWindow - store desktop resolution, width: %d, height: %d, hz: %2.2f", mode.w, mode.h, mode.hz); +- if (!out.isRotated) +- UpdateDesktopResolution(g_settings.m_ResInfo[RES_DESKTOP], 0, mode.w, mode.h, mode.hz); +- else +- UpdateDesktopResolution(g_settings.m_ResInfo[RES_DESKTOP], 0, mode.h, mode.w, mode.hz); +- g_settings.m_ResInfo[RES_DESKTOP].strId = mode.id; +- g_settings.m_ResInfo[RES_DESKTOP].strOutput = 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; +- } +- +- if (g_graphicsContext.IsFullScreenRoot()) +- g_graphicsContext.SetVideoResolution((RESOLUTION)i, true); +- else +- g_graphicsContext.SetVideoResolution(RES_WINDOW, true); +-} +- + bool CWinSystemX11::SetFullScreen(bool fullScreen, RESOLUTION_INFO& res, bool blankOtherDisplays) + { + +@@ -240,8 +201,7 @@ bool CWinSystemX11::SetFullScreen(bool fullScreen, RESOLUTION_INFO& res, bool bl + mode.id = g_settings.m_ResInfo[RES_DESKTOP].strId; + } + +- XOutput currout = g_xrandr.GetCurrentOutput(); +- XMode currmode = g_xrandr.GetCurrentMode(currout.name); ++ XMode currmode = g_xrandr.GetCurrentMode(out.name); + + // flip h/w when rotated + if (m_bIsRotated) +@@ -252,16 +212,17 @@ bool CWinSystemX11::SetFullScreen(bool fullScreen, RESOLUTION_INFO& res, bool bl + } + + // only call xrandr if mode changes +- if (currout.name != out.name || currmode.w != mode.w || currmode.h != mode.h || ++ if (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_bIsInternalXrr = true; + g_xrandr.SetMode(out, mode); + } + #endif + +- if (!SetWindow(res.iWidth, res.iHeight, fullScreen)) ++ if (!SetWindow(res.iWidth, res.iHeight, fullScreen, g_guiSettings.GetString("videoscreen.monitor"))) + return false; + + RefreshGlxContext(); +@@ -269,6 +230,7 @@ bool CWinSystemX11::SetFullScreen(bool fullScreen, RESOLUTION_INFO& res, bool bl + m_nWidth = res.iWidth; + m_nHeight = res.iHeight; + m_bFullScreen = fullScreen; ++ m_currentOutput = g_guiSettings.GetString("videoscreen.monitor"); + + return true; + } +@@ -277,19 +239,30 @@ void CWinSystemX11::UpdateResolutions() + { + CWinSystemBase::UpdateResolutions(); + +- + #if defined(HAS_XRANDR) +- if(g_xrandr.Query()) +- { +- XOutput out = g_xrandr.GetCurrentOutput(); +- XMode mode = g_xrandr.GetCurrentMode(out.name); +- m_bIsRotated = out.isRotated; ++ CStdString currentMonitor; ++ int numScreens = XScreenCount(m_dpy); ++ g_xrandr.SetNumScreens(numScreens); ++ if(g_xrandr.Query(true)) ++ { ++ currentMonitor = g_guiSettings.GetString("videoscreen.monitor"); ++ // check if the monitor is connected ++ XOutput *out = g_xrandr.GetOutput(currentMonitor); ++ if (!out) ++ { ++ // choose first output ++ currentMonitor = g_xrandr.GetModes()[0].name; ++ out = g_xrandr.GetOutput(currentMonitor); ++ g_guiSettings.SetString("videoscreen.monitor", currentMonitor); ++ } ++ XMode mode = g_xrandr.GetCurrentMode(currentMonitor); ++ m_bIsRotated = out->isRotated; + if (!m_bIsRotated) +- UpdateDesktopResolution(g_settings.m_ResInfo[RES_DESKTOP], 0, mode.w, mode.h, mode.hz); ++ UpdateDesktopResolution(g_settings.m_ResInfo[RES_DESKTOP], out->screen, mode.w, mode.h, mode.hz); + else +- UpdateDesktopResolution(g_settings.m_ResInfo[RES_DESKTOP], 0, mode.h, mode.w, mode.hz); ++ UpdateDesktopResolution(g_settings.m_ResInfo[RES_DESKTOP], out->screen, mode.h, mode.w, mode.hz); + g_settings.m_ResInfo[RES_DESKTOP].strId = mode.id; +- g_settings.m_ResInfo[RES_DESKTOP].strOutput = out.name; ++ g_settings.m_ResInfo[RES_DESKTOP].strOutput = currentMonitor; + } + else + #endif +@@ -300,23 +273,26 @@ void CWinSystemX11::UpdateResolutions() + UpdateDesktopResolution(g_settings.m_ResInfo[RES_DESKTOP], 0, w, h, 0.0); + } + +- + #if defined(HAS_XRANDR) + ++ // erase previous stored modes ++ if (g_settings.m_ResInfo.size() > RES_CUSTOM) ++ { ++ std::vector::iterator firstCustom = g_settings.m_ResInfo.begin()+RES_CUSTOM; ++ g_settings.m_ResInfo.erase(firstCustom, g_settings.m_ResInfo.end()); ++ } ++ + CLog::Log(LOGINFO, "Available videomodes (xrandr):"); +- vector::iterator outiter; +- vector outs; +- outs = g_xrandr.GetModes(); +- CLog::Log(LOGINFO, "Number of connected outputs: %"PRIdS"", outs.size()); ++ ++ XOutput *out = g_xrandr.GetOutput(currentMonitor); + string modename = ""; + +- for (outiter = outs.begin() ; outiter != outs.end() ; outiter++) ++ if (out != NULL) + { +- XOutput out = *outiter; + vector::iterator modeiter; +- CLog::Log(LOGINFO, "Output '%s' has %"PRIdS" modes", out.name.c_str(), out.modes.size()); ++ CLog::Log(LOGINFO, "Output '%s' has %"PRIdS" modes", out->name.c_str(), out->modes.size()); + +- for (modeiter = out.modes.begin() ; modeiter!=out.modes.end() ; modeiter++) ++ for (modeiter = out->modes.begin() ; modeiter!=out->modes.end() ; modeiter++) + { + XMode mode = *modeiter; + CLog::Log(LOGINFO, "ID:%s Name:%s Refresh:%f Width:%d Height:%d", +@@ -336,15 +312,15 @@ void CWinSystemX11::UpdateResolutions() + res.iWidth = mode.h; + res.iHeight = mode.w; + } +- if (mode.h>0 && mode.w>0 && out.hmm>0 && out.wmm>0) +- res.fPixelRatio = ((float)out.wmm/(float)mode.w) / (((float)out.hmm/(float)mode.h)); ++ if (mode.h>0 && mode.w>0 && out->hmm>0 && out->wmm>0) ++ res.fPixelRatio = ((float)out->wmm/(float)mode.w) / (((float)out->hmm/(float)mode.h)); + else + res.fPixelRatio = 1.0f; + + CLog::Log(LOGINFO, "Pixel Ratio: %f", res.fPixelRatio); + +- res.strMode.Format("%s: %s @ %.2fHz", out.name.c_str(), mode.name.c_str(), mode.hz); +- res.strOutput = out.name; ++ res.strMode.Format("%s: %s @ %.2fHz", out->name.c_str(), mode.name.c_str(), mode.hz); ++ res.strOutput = out->name; + res.strId = mode.id; + res.iSubtitles = (int)(0.95*mode.h); + res.fRefreshRate = mode.hz; +@@ -363,28 +339,19 @@ void CWinSystemX11::UpdateResolutions() + + } + +-void CWinSystemX11::RotateResolutions() ++void CWinSystemX11::GetConnectedOutputs(std::vector *outputs) + { +-#if defined(HAS_XRANDR) +- XOutput out = g_xrandr.GetCurrentOutput(); +- if (out.isRotated == m_bIsRotated) +- return; +- +- for (unsigned int i = 0; i < g_settings.m_ResInfo.size(); ++i) ++ vector outs; ++ outs = g_xrandr.GetModes(); ++ for(unsigned int i=0; ipush_back(outs[i].name); + } +- // update desktop resolution +-// int h = g_settings.m_ResInfo[RES_DESKTOP].iHeight; +-// int w = g_settings.m_ResInfo[RES_DESKTOP].iWidth; +-// float hz = g_settings.m_ResInfo[RES_DESKTOP].fRefreshRate; +-// UpdateDesktopResolution(g_settings.m_ResInfo[RES_DESKTOP], 0, w, h, hz); +- +- m_bIsRotated = out.isRotated; ++} + +-#endif ++bool CWinSystemX11::IsCurrentOutput(CStdString output) ++{ ++ return m_currentOutput.Equals(output); + } + + bool CWinSystemX11::IsSuitableVisual(XVisualInfo *vInfo) +@@ -414,8 +381,11 @@ bool CWinSystemX11::RefreshGlxContext() + if (m_glContext) + { + CLog::Log(LOGDEBUG, "CWinSystemX11::RefreshGlxContext: refreshing context"); ++ glFinish(); + glXMakeCurrent(m_dpy, None, NULL); + glXMakeCurrent(m_dpy, m_glWindow, m_glContext); ++ XSync(m_dpy, FALSE); ++ g_Windowing.ResetVSync(); + return true; + } + +@@ -481,6 +451,8 @@ bool CWinSystemX11::RefreshGlxContext() + { + // make this context current + glXMakeCurrent(m_dpy, m_glWindow, m_glContext); ++ g_Windowing.ResetVSync(); ++ XSync(m_dpy, False); + retVal = true; + } + else +@@ -522,24 +494,53 @@ void CWinSystemX11::ResetOSScreensaver() + + void CWinSystemX11::NotifyAppActiveChange(bool bActivated) + { +- if (bActivated && m_bWasFullScreenBeforeMinimize && !g_graphicsContext.IsFullScreenRoot()) ++ if (bActivated && m_bWasFullScreenBeforeMinimize && !m_bFullScreen) ++ { + g_graphicsContext.ToggleFullScreenRoot(); + ++ m_bWasFullScreenBeforeMinimize = false; ++ } + m_minimized = !bActivated; + } + + void CWinSystemX11::NotifyAppFocusChange(bool bGaining) + { + if (bGaining && m_bWasFullScreenBeforeMinimize && !m_bIgnoreNextFocusMessage && +- !g_graphicsContext.IsFullScreenRoot()) ++ !m_bFullScreen) ++ { ++ m_bWasFullScreenBeforeMinimize = false; + g_graphicsContext.ToggleFullScreenRoot(); ++ m_minimized = false; ++ } + if (!bGaining) + m_bIgnoreNextFocusMessage = false; + } + ++void CWinSystemX11::NotifyMouseCoverage(bool covered) ++{ ++ if (!m_bFullScreen) ++ return; ++ ++ if (covered) ++ { ++ int result = -1; ++ while (result != GrabSuccess && result != AlreadyGrabbed) ++ { ++ result = XGrabPointer(m_dpy, m_glWindow, True, ButtonPressMask, GrabModeAsync, GrabModeAsync, None, None, CurrentTime); ++ XbmcThreads::ThreadSleep(100); ++ } ++ XGrabKeyboard(m_dpy, m_glWindow, True, GrabModeAsync, GrabModeAsync, CurrentTime); ++ } ++ else ++ { ++ XUngrabKeyboard(m_dpy, CurrentTime); ++ XUngrabPointer(m_dpy, CurrentTime); ++ } ++} ++ + bool CWinSystemX11::Minimize() + { +- m_bWasFullScreenBeforeMinimize = g_graphicsContext.IsFullScreenRoot(); ++ m_bWasFullScreenBeforeMinimize = m_bFullScreen; + if (m_bWasFullScreenBeforeMinimize) + { + m_bIgnoreNextFocusMessage = true; +@@ -605,13 +606,46 @@ void CWinSystemX11::CheckDisplayEvents() + void CWinSystemX11::NotifyXRREvent() + { + CLog::Log(LOGDEBUG, "%s - notify display reset event", __FUNCTION__); +- RefreshWindow(); ++ m_windowDirty = true; + +- CSingleLock lock(m_resourceSection); ++ // if external event update resolutions ++ if (!m_bIsInternalXrr) ++ { ++ UpdateResolutions(); ++ } ++ else if (!g_xrandr.Query(true)) ++ { ++ CLog::Log(LOGERROR, "WinSystemX11::RefreshWindow - failed to query xrandr"); ++ return; ++ } ++ m_bIsInternalXrr = false; + +- // tell any shared resources +- for (vector::iterator i = m_resources.begin(); i != m_resources.end(); i++) +- (*i)->OnResetDevice(); ++ CStdString currentOutput = g_guiSettings.GetString("videoscreen.monitor"); ++ XOutput *out = g_xrandr.GetOutput(currentOutput); ++ XMode mode = g_xrandr.GetCurrentMode(currentOutput); ++ ++ 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"); ++ i = RES_DESKTOP; ++ } ++ ++ if (g_graphicsContext.IsFullScreenRoot()) ++ g_graphicsContext.SetVideoResolution((RESOLUTION)i, true); ++ else ++ g_graphicsContext.SetVideoResolution(RES_WINDOW, true); + + } + +@@ -664,14 +698,14 @@ bool CWinSystemX11::EnableFrameLimiter() + return m_minimized; + } + +-bool CWinSystemX11::SetWindow(int width, int height, bool fullscreen) ++bool CWinSystemX11::SetWindow(int width, int height, bool fullscreen, const CStdString &output) + { + bool changeWindow = false; + bool changeSize = false; + bool mouseActive = false; + float mouseX, mouseY; + +- if (m_glWindow && (m_bFullScreen != fullscreen)) ++ if (m_glWindow && ((m_bFullScreen != fullscreen) || !m_currentOutput.Equals(output) || m_windowDirty)) + { + mouseActive = g_Mouse.IsActive(); + if (mouseActive) +@@ -693,6 +727,7 @@ bool CWinSystemX11::SetWindow(int width, int height, bool fullscreen) + else + mouseActive = false; + } ++ OnLostDevice(); + DestroyWindow(); + } + +@@ -714,7 +749,11 @@ bool CWinSystemX11::SetWindow(int width, int height, bool fullscreen) + XSetWindowAttributes swa; + XVisualInfo *vi; + +- vi = glXChooseVisual(m_dpy, DefaultScreen(m_dpy), att); ++ XOutput *out = g_xrandr.GetOutput(output); ++ if (!out) ++ out = g_xrandr.GetOutput(m_currentOutput); ++ m_nScreen = out->screen; ++ vi = glXChooseVisual(m_dpy, m_nScreen, att); + cmap = XCreateColormap(m_dpy, RootWindow(m_dpy, vi->screen), vi->visual, AllocNone); + + int def_vis = (vi->visual == DefaultVisual(m_dpy, vi->screen)); +@@ -730,7 +769,7 @@ bool CWinSystemX11::SetWindow(int width, int height, bool fullscreen) + unsigned long mask = CWBackPixel | CWBorderPixel | CWColormap | CWOverrideRedirect | CWEventMask; + + m_glWindow = XCreateWindow(m_dpy, RootWindow(m_dpy, vi->screen), +- 0, 0, width, height, 0, vi->depth, ++ out->x, out->y, width, height, 0, vi->depth, + InputOutput, vi->visual, + mask, &swa); + +@@ -801,14 +840,19 @@ bool CWinSystemX11::SetWindow(int width, int height, bool fullscreen) + if (fullscreen) + { + int result = -1; +- while (result != GrabSuccess) ++ while (result != GrabSuccess && result != AlreadyGrabbed) + { +- result = XGrabPointer(m_dpy, m_glWindow, True, ButtonPressMask, GrabModeAsync, GrabModeAsync, m_glWindow, None, CurrentTime); ++ result = XGrabPointer(m_dpy, m_glWindow, True, ButtonPressMask, GrabModeAsync, GrabModeAsync, None, None, CurrentTime); + XbmcThreads::ThreadSleep(100); + } + XGrabKeyboard(m_dpy, m_glWindow, True, GrabModeAsync, GrabModeAsync, CurrentTime); +- + } ++ CSingleLock lock(m_resourceSection); ++ // tell any shared resources ++ for (vector::iterator i = m_resources.begin(); i != m_resources.end(); i++) ++ (*i)->OnResetDevice(); ++ ++ m_windowDirty = false; + } + return true; + } +diff --git a/xbmc/windowing/X11/WinSystemX11.h b/xbmc/windowing/X11/WinSystemX11.h +index 93cf5db..71034fc 100644 +--- a/xbmc/windowing/X11/WinSystemX11.h ++++ b/xbmc/windowing/X11/WinSystemX11.h +@@ -65,15 +65,16 @@ class CWinSystemX11 : public CWinSystemBase + Display* GetDisplay() { return m_dpy; } + GLXWindow GetWindow() { return m_glWindow; } + GLXContext GetGlxContext() { return m_glContext; } +- void RefreshWindow(); + void NotifyXRREvent(); ++ void GetConnectedOutputs(std::vector *outputs); ++ bool IsCurrentOutput(CStdString output); ++ void NotifyMouseCoverage(bool covered); + + protected: + bool RefreshGlxContext(); + void CheckDisplayEvents(); + void OnLostDevice(); +- bool SetWindow(int width, int height, bool fullscreen); +- void RotateResolutions(); ++ bool SetWindow(int width, int height, bool fullscreen, const CStdString &output); + + Window m_glWindow; + GLXContext m_glContext; +@@ -88,6 +89,9 @@ class CWinSystemX11 : public CWinSystemBase + CCriticalSection m_resourceSection; + std::vector m_resources; + uint64_t m_dpyLostTime; ++ CStdString m_currentOutput; ++ bool m_windowDirty; ++ bool m_bIsInternalXrr; + + private: + bool IsSuitableVisual(XVisualInfo *vInfo); +-- +1.7.10 + + +From 2a747f13a0a50dea0883d0d3c701ef290235a99b Mon Sep 17 00:00:00 2001 +From: FernetMenta +Date: Thu, 5 Jul 2012 11:36:32 +0200 +Subject: [PATCH 23/73] X11: remove all DefaultScreen and RootWindow macros + +--- + xbmc/windowing/X11/WinSystemX11.cpp | 6 +++--- + xbmc/windowing/X11/WinSystemX11.h | 1 + + xbmc/windowing/X11/WinSystemX11GL.cpp | 2 +- + 3 files changed, 5 insertions(+), 4 deletions(-) + +diff --git a/xbmc/windowing/X11/WinSystemX11.cpp b/xbmc/windowing/X11/WinSystemX11.cpp +index 5f913f1..af1307c 100644 +--- a/xbmc/windowing/X11/WinSystemX11.cpp ++++ b/xbmc/windowing/X11/WinSystemX11.cpp +@@ -267,7 +267,7 @@ void CWinSystemX11::UpdateResolutions() + else + #endif + { +- int x11screen = DefaultScreen(m_dpy); ++ int x11screen = m_nScreen; + int w = DisplayWidth(m_dpy, x11screen); + int h = DisplayHeight(m_dpy, x11screen); + UpdateDesktopResolution(g_settings.m_ResInfo[RES_DESKTOP], 0, w, h, 0.0); +@@ -393,7 +393,7 @@ bool CWinSystemX11::RefreshGlxContext() + XVisualInfo *visuals; + XVisualInfo *vInfo = NULL; + int availableVisuals = 0; +- vMask.screen = DefaultScreen(m_dpy); ++ vMask.screen = m_nScreen; + XWindowAttributes winAttr; + + /* Assume a depth of 24 in case the below calls to XGetWindowAttributes() +@@ -547,7 +547,7 @@ bool CWinSystemX11::Minimize() + g_graphicsContext.ToggleFullScreenRoot(); + } + +- XIconifyWindow(m_dpy, m_glWindow, DefaultScreen(m_dpy)); ++ XIconifyWindow(m_dpy, m_glWindow, m_nScreen); + + m_minimized = true; + return true; +diff --git a/xbmc/windowing/X11/WinSystemX11.h b/xbmc/windowing/X11/WinSystemX11.h +index 71034fc..3bb4b8e 100644 +--- a/xbmc/windowing/X11/WinSystemX11.h ++++ b/xbmc/windowing/X11/WinSystemX11.h +@@ -47,6 +47,7 @@ class CWinSystemX11 : public CWinSystemBase + virtual bool SetFullScreen(bool fullScreen, RESOLUTION_INFO& res, bool blankOtherDisplays); + virtual void UpdateResolutions(); + virtual int GetNumScreens() { return 1; } ++ virtual int GetCurrentScreen() { return m_nScreen; } + virtual void ShowOSMouse(bool show); + virtual void ResetOSScreensaver(); + virtual bool EnableFrameLimiter(); +diff --git a/xbmc/windowing/X11/WinSystemX11GL.cpp b/xbmc/windowing/X11/WinSystemX11GL.cpp +index f858f88..d192697 100644 +--- a/xbmc/windowing/X11/WinSystemX11GL.cpp ++++ b/xbmc/windowing/X11/WinSystemX11GL.cpp +@@ -203,7 +203,7 @@ bool CWinSystemX11GL::CreateNewWindow(const CStdString& name, bool fullScreen, R + return false; + + m_glxext = " "; +- m_glxext += (const char*)glXQueryExtensionsString(m_dpy, DefaultScreen(m_dpy)); ++ m_glxext += (const char*)glXQueryExtensionsString(m_dpy, m_nScreen); + m_glxext += " "; + + CLog::Log(LOGDEBUG, "GLX_EXTENSIONS:%s", m_glxext.c_str()); +-- +1.7.10 + + +From cf018ebbf1eae8f5ae2914ef347aac5f963c0d71 Mon Sep 17 00:00:00 2001 +From: FernetMenta +Date: Thu, 5 Jul 2012 11:45:22 +0200 +Subject: [PATCH 24/73] X11: remove all DefaultScreen and RootWindow macros + (VideoRefClock) + +Note this is on a separate display connection. +--- + xbmc/video/VideoReferenceClock.cpp | 15 ++++++++------- + 1 file changed, 8 insertions(+), 7 deletions(-) + +diff --git a/xbmc/video/VideoReferenceClock.cpp b/xbmc/video/VideoReferenceClock.cpp +index 9785fe7..0004e07 100644 +--- a/xbmc/video/VideoReferenceClock.cpp ++++ b/xbmc/video/VideoReferenceClock.cpp +@@ -270,7 +270,7 @@ bool CVideoReferenceClock::SetupGLX() + } + + bool ExtensionFound = false; +- istringstream Extensions(glXQueryExtensionsString(m_Dpy, DefaultScreen(m_Dpy))); ++ istringstream Extensions(glXQueryExtensionsString(m_Dpy, g_Windowing.GetCurrentScreen())); + string ExtensionStr; + + while (!ExtensionFound) +@@ -297,7 +297,7 @@ bool CVideoReferenceClock::SetupGLX() + m_bIsATI = true; + } + +- m_vInfo = glXChooseVisual(m_Dpy, DefaultScreen(m_Dpy), singleBufferAttributes); ++ m_vInfo = glXChooseVisual(m_Dpy, g_Windowing.GetCurrentScreen(), singleBufferAttributes); + if (!m_vInfo) + { + CLog::Log(LOGDEBUG, "CVideoReferenceClock: glXChooseVisual returned NULL"); +@@ -308,15 +308,16 @@ bool CVideoReferenceClock::SetupGLX() + { + Swa.border_pixel = 0; + Swa.event_mask = StructureNotifyMask; +- Swa.colormap = XCreateColormap(m_Dpy, RootWindow(m_Dpy, m_vInfo->screen), m_vInfo->visual, AllocNone ); ++ Swa.colormap = XCreateColormap(m_Dpy, g_Windowing.GetWindow(), m_vInfo->visual, AllocNone ); + SwaMask = CWBorderPixel | CWColormap | CWEventMask; + +- m_Window = XCreateWindow(m_Dpy, RootWindow(m_Dpy, m_vInfo->screen), 0, 0, 256, 256, 0, ++ m_Window = XCreateWindow(m_Dpy, g_Windowing.GetWindow(), 0, 0, 256, 256, 0, + m_vInfo->depth, InputOutput, m_vInfo->visual, SwaMask, &Swa); + } + else + { +- m_pixmap = XCreatePixmap(m_Dpy, DefaultRootWindow(m_Dpy), 256, 256, m_vInfo->depth); ++ Window window = g_Windowing.GetWindow(); ++ m_pixmap = XCreatePixmap(m_Dpy, window, 256, 256, m_vInfo->depth); + if (!m_pixmap) + { + CLog::Log(LOGDEBUG, "CVideoReferenceClock: unable to create pixmap"); +@@ -383,7 +384,7 @@ bool CVideoReferenceClock::SetupGLX() + + //set up receiving of RandR events, we'll get one when the refreshrate changes + XRRQueryExtension(m_Dpy, &m_RREventBase, &ReturnV); +- XRRSelectInput(m_Dpy, RootWindow(m_Dpy, m_vInfo->screen), RRScreenChangeNotifyMask); ++ XRRSelectInput(m_Dpy, g_Windowing.GetWindow(), RRScreenChangeNotifyMask); + + UpdateRefreshrate(true); //forced refreshrate update + m_MissedVblanks = 0; +@@ -518,7 +519,7 @@ int CVideoReferenceClock::GetRandRRate() + int RefreshRate; + XRRScreenConfiguration *CurrInfo; + +- CurrInfo = XRRGetScreenInfo(m_Dpy, RootWindow(m_Dpy, m_vInfo->screen)); ++ CurrInfo = XRRGetScreenInfo(m_Dpy, g_Windowing.GetWindow()); + RefreshRate = XRRConfigCurrentRate(CurrInfo); + XRRFreeScreenConfigInfo(CurrInfo); + +-- +1.7.10 + + +From 5d8bfcd52e5a189515629c15c73434ef6c6bcc88 Mon Sep 17 00:00:00 2001 +From: xbmc +Date: Wed, 20 Jun 2012 17:37:11 +0200 +Subject: [PATCH 25/73] X11: recreate gl context after output has changed + +--- + xbmc/windowing/X11/WinSystemX11.cpp | 24 ++++++++++++++---------- + xbmc/windowing/X11/WinSystemX11.h | 1 + + xbmc/windowing/X11/WinSystemX11GL.cpp | 9 +++++++++ + 3 files changed, 24 insertions(+), 10 deletions(-) + +diff --git a/xbmc/windowing/X11/WinSystemX11.cpp b/xbmc/windowing/X11/WinSystemX11.cpp +index af1307c..d3d15e2 100644 +--- a/xbmc/windowing/X11/WinSystemX11.cpp ++++ b/xbmc/windowing/X11/WinSystemX11.cpp +@@ -168,7 +168,6 @@ bool CWinSystemX11::ResizeWindow(int newWidth, int newHeight, int newLeft, int n + return false; + } + +- RefreshGlxContext(); + m_nWidth = newWidth; + m_nHeight = newHeight; + m_bFullScreen = false; +@@ -219,14 +218,13 @@ bool CWinSystemX11::SetFullScreen(bool fullScreen, RESOLUTION_INFO& res, bool bl + OnLostDevice(); + m_bIsInternalXrr = true; + g_xrandr.SetMode(out, mode); ++ return true; + } + #endif + + if (!SetWindow(res.iWidth, res.iHeight, fullScreen, g_guiSettings.GetString("videoscreen.monitor"))) + return false; + +- RefreshGlxContext(); +- + m_nWidth = res.iWidth; + m_nHeight = res.iHeight; + m_bFullScreen = fullScreen; +@@ -381,11 +379,8 @@ bool CWinSystemX11::RefreshGlxContext() + if (m_glContext) + { + CLog::Log(LOGDEBUG, "CWinSystemX11::RefreshGlxContext: refreshing context"); +- glFinish(); + glXMakeCurrent(m_dpy, None, NULL); + glXMakeCurrent(m_dpy, m_glWindow, m_glContext); +- XSync(m_dpy, FALSE); +- g_Windowing.ResetVSync(); + return true; + } + +@@ -445,14 +440,14 @@ bool CWinSystemX11::RefreshGlxContext() + { + glXMakeCurrent(m_dpy, None, NULL); + glXDestroyContext(m_dpy, m_glContext); ++ XSync(m_dpy, FALSE); ++ m_newGlContext = true; + } + + if ((m_glContext = glXCreateContext(m_dpy, vInfo, NULL, True))) + { + // make this context current + glXMakeCurrent(m_dpy, m_glWindow, m_glContext); +- g_Windowing.ResetVSync(); +- XSync(m_dpy, False); + retVal = true; + } + else +@@ -729,6 +724,7 @@ bool CWinSystemX11::SetWindow(int width, int height, bool fullscreen, const CStd + } + OnLostDevice(); + DestroyWindow(); ++ m_windowDirty = true; + } + + // create main window +@@ -847,13 +843,21 @@ bool CWinSystemX11::SetWindow(int width, int height, bool fullscreen, const CStd + } + XGrabKeyboard(m_dpy, m_glWindow, True, GrabModeAsync, GrabModeAsync, CurrentTime); + } ++ ++ CDirtyRegionList dr; ++ RefreshGlxContext(); ++ XSync(m_dpy, FALSE); ++ g_graphicsContext.Clear(0); ++ g_graphicsContext.Flip(dr); ++ g_Windowing.ResetVSync(); ++ m_windowDirty = false; ++ + CSingleLock lock(m_resourceSection); + // tell any shared resources + for (vector::iterator i = m_resources.begin(); i != m_resources.end(); i++) + (*i)->OnResetDevice(); +- +- m_windowDirty = false; + } ++ + return true; + } + +diff --git a/xbmc/windowing/X11/WinSystemX11.h b/xbmc/windowing/X11/WinSystemX11.h +index 3bb4b8e..cc28f56 100644 +--- a/xbmc/windowing/X11/WinSystemX11.h ++++ b/xbmc/windowing/X11/WinSystemX11.h +@@ -93,6 +93,7 @@ class CWinSystemX11 : public CWinSystemBase + CStdString m_currentOutput; + bool m_windowDirty; + bool m_bIsInternalXrr; ++ bool m_newGlContext; + + private: + bool IsSuitableVisual(XVisualInfo *vInfo); +diff --git a/xbmc/windowing/X11/WinSystemX11GL.cpp b/xbmc/windowing/X11/WinSystemX11GL.cpp +index d192697..0f2d1d2 100644 +--- a/xbmc/windowing/X11/WinSystemX11GL.cpp ++++ b/xbmc/windowing/X11/WinSystemX11GL.cpp +@@ -23,6 +23,7 @@ + + #include "WinSystemX11GL.h" + #include "utils/log.h" ++#include "Application.h" + + CWinSystemX11GL::CWinSystemX11GL() + { +@@ -245,17 +246,25 @@ bool CWinSystemX11GL::CreateNewWindow(const CStdString& name, bool fullScreen, R + + bool CWinSystemX11GL::ResizeWindow(int newWidth, int newHeight, int newLeft, int newTop) + { ++ m_newGlContext = false; + CWinSystemX11::ResizeWindow(newWidth, newHeight, newLeft, newTop); + CRenderSystemGL::ResetRenderSystem(newWidth, newHeight, false, 0); + ++ if (m_newGlContext) ++ g_application.ReloadSkin(); ++ + return true; + } + + bool CWinSystemX11GL::SetFullScreen(bool fullScreen, RESOLUTION_INFO& res, bool blankOtherDisplays) + { ++ m_newGlContext = false; + CWinSystemX11::SetFullScreen(fullScreen, res, blankOtherDisplays); + CRenderSystemGL::ResetRenderSystem(res.iWidth, res.iHeight, fullScreen, res.fRefreshRate); + ++ if (m_newGlContext) ++ g_application.ReloadSkin(); ++ + return true; + } + +-- +1.7.10 + + +From bd9a29b7661c75152174959f9f269f32c13a658b Mon Sep 17 00:00:00 2001 +From: FernetMenta +Date: Thu, 5 Jul 2012 12:06:25 +0200 +Subject: [PATCH 26/73] X11: hook video reference clock in windowing + +--- + xbmc/video/VideoReferenceClock.cpp | 71 ++++++++++++++++++++++++++---------- + xbmc/video/VideoReferenceClock.h | 13 ++++++- + 2 files changed, 63 insertions(+), 21 deletions(-) + +diff --git a/xbmc/video/VideoReferenceClock.cpp b/xbmc/video/VideoReferenceClock.cpp +index 0004e07..fa8e35a 100644 +--- a/xbmc/video/VideoReferenceClock.cpp ++++ b/xbmc/video/VideoReferenceClock.cpp +@@ -135,12 +135,23 @@ + m_Context = NULL; + m_pixmap = None; + m_glPixmap = None; +- m_RREventBase = 0; + m_UseNvSettings = true; + m_bIsATI = false; + #endif + } + ++CVideoReferenceClock::~CVideoReferenceClock() ++{ ++#if defined(HAS_GLX) ++ // some ATI voodoo, if we don't close the display, we crash on exit ++ if (m_Dpy) ++ { ++ XCloseDisplay(m_Dpy); ++ m_Dpy = NULL; ++ } ++#endif ++} ++ + void CVideoReferenceClock::Process() + { + bool SetupSuccess = false; +@@ -151,6 +162,10 @@ void CVideoReferenceClock::Process() + m_D3dCallback.Reset(); + g_Windowing.Register(&m_D3dCallback); + #endif ++#if defined(HAS_GLX) && defined(HAS_XRANDR) ++ g_Windowing.Register(this); ++ m_xrrEvent = false; ++#endif + + while(!m_bStop) + { +@@ -211,6 +226,16 @@ void CVideoReferenceClock::Process() + //clean up the vblank clock + #if defined(HAS_GLX) && defined(HAS_XRANDR) + CleanupGLX(); ++ if (m_xrrEvent) ++ { ++ m_releaseEvent.Set(); ++ while (!m_bStop) ++ { ++ if (m_resetEvent.WaitMSec(100)) ++ break; ++ } ++ m_xrrEvent = false; ++ } + #elif defined(_WIN32) && defined(HAS_DX) + CleanupD3D(); + #elif defined(TARGET_DARWIN) +@@ -222,6 +247,9 @@ void CVideoReferenceClock::Process() + #if defined(_WIN32) && defined(HAS_DX) + g_Windowing.Unregister(&m_D3dCallback); + #endif ++#if defined(HAS_GLX) ++ g_Windowing.Unregister(this); ++#endif + } + + bool CVideoReferenceClock::WaitStarted(int MSecs) +@@ -231,6 +259,24 @@ bool CVideoReferenceClock::WaitStarted(int MSecs) + } + + #if defined(HAS_GLX) && defined(HAS_XRANDR) ++ ++void CVideoReferenceClock::OnLostDevice() ++{ ++ if (!m_xrrEvent) ++ { ++ m_releaseEvent.Reset(); ++ m_resetEvent.Reset(); ++ m_xrrEvent = true; ++ m_releaseEvent.Wait(); ++ } ++} ++ ++void CVideoReferenceClock::OnResetDevice() ++{ ++ m_xrrEvent = false; ++ m_resetEvent.Set(); ++} ++ + bool CVideoReferenceClock::SetupGLX() + { + int singleBufferAttributes[] = { +@@ -382,10 +428,6 @@ bool CVideoReferenceClock::SetupGLX() + return false; + } + +- //set up receiving of RandR events, we'll get one when the refreshrate changes +- XRRQueryExtension(m_Dpy, &m_RREventBase, &ReturnV); +- XRRSelectInput(m_Dpy, g_Windowing.GetWindow(), RRScreenChangeNotifyMask); +- + UpdateRefreshrate(true); //forced refreshrate update + m_MissedVblanks = 0; + +@@ -586,6 +628,9 @@ void CVideoReferenceClock::RunGLX() + + while(!m_bStop) + { ++ if (m_xrrEvent) ++ return; ++ + //wait for the next vblank + if (!m_bIsATI) + { +@@ -649,7 +694,6 @@ void CVideoReferenceClock::RunGLX() + UpdateClock((int)(VblankCount - PrevVblankCount), true); + SingleLock.Leave(); + SendVblankSignal(); +- UpdateRefreshrate(); + IsReset = false; + } + else if (!m_bStop) +@@ -1186,23 +1230,10 @@ bool CVideoReferenceClock::UpdateRefreshrate(bool Forced /*= false*/) + + #if defined(HAS_GLX) && defined(HAS_XRANDR) + +- //check for RandR events +- bool GotEvent = Forced || m_RefreshChanged == 2; +- XEvent Event; +- while (XCheckTypedEvent(m_Dpy, m_RREventBase + RRScreenChangeNotify, &Event)) +- { +- if (Event.type == m_RREventBase + RRScreenChangeNotify) +- { +- CLog::Log(LOGDEBUG, "CVideoReferenceClock: Received RandR event %i", Event.type); +- GotEvent = true; +- } +- XRRUpdateConfiguration(&Event); +- } +- + if (!Forced) + m_RefreshChanged = 0; + +- if (!GotEvent) //refreshrate did not change ++ if (!Forced) //refreshrate did not change + return false; + + //the refreshrate can be wrong on nvidia drivers, so read it from nvidia-settings when it's available +diff --git a/xbmc/video/VideoReferenceClock.h b/xbmc/video/VideoReferenceClock.h +index dcc4f09..7eb6317 100644 +--- a/xbmc/video/VideoReferenceClock.h ++++ b/xbmc/video/VideoReferenceClock.h +@@ -30,6 +30,7 @@ + #include + #include + #include ++ #include "guilib/DispResource.h" + #elif defined(_WIN32) && defined(HAS_DX) + #include + #include "guilib/D3DResource.h" +@@ -56,9 +57,13 @@ class CD3DCallback : public ID3DResource + #endif + + class CVideoReferenceClock : public CThread ++#if defined(HAS_GLX) && defined(HAS_XRANDR) ++ ,public IDispResource ++#endif + { + public: + CVideoReferenceClock(); ++ virtual ~CVideoReferenceClock(); + + int64_t GetTime(bool interpolated = true); + int64_t GetFrequency(); +@@ -75,6 +80,11 @@ class CVideoReferenceClock : public CThread + void VblankHandler(int64_t nowtime, double fps); + #endif + ++#if defined(HAS_GLX) && defined(HAS_XRANDR) ++ virtual void OnLostDevice(); ++ virtual void OnResetDevice(); ++#endif ++ + private: + void Process(); + bool UpdateRefreshrate(bool Forced = false); +@@ -121,7 +131,8 @@ class CVideoReferenceClock : public CThread + GLXContext m_Context; + Pixmap m_pixmap; + GLXPixmap m_glPixmap; +- int m_RREventBase; ++ bool m_xrrEvent; ++ CEvent m_releaseEvent, m_resetEvent; + + bool m_UseNvSettings; + bool m_bIsATI; +-- +1.7.10 + + +From 702f79eab647ec68030c99d6113976f3c602e87c Mon Sep 17 00:00:00 2001 +From: xbmc +Date: Thu, 21 Jun 2012 17:26:51 +0200 +Subject: [PATCH 27/73] X11: fix video calibrations + +--- + xbmc/settings/Settings.cpp | 1 + + xbmc/windowing/WinSystem.h | 1 + + xbmc/windowing/X11/WinSystemX11.cpp | 36 ++++++++++++++++++++++++++++++++++- + xbmc/windowing/X11/WinSystemX11.h | 1 + + 4 files changed, 38 insertions(+), 1 deletion(-) + +diff --git a/xbmc/settings/Settings.cpp b/xbmc/settings/Settings.cpp +index 8a430ad..fde6e4e 100644 +--- a/xbmc/settings/Settings.cpp ++++ b/xbmc/settings/Settings.cpp +@@ -55,6 +55,7 @@ + #include "filesystem/File.h" + #include "filesystem/DirectoryCache.h" + #include "DatabaseManager.h" ++#include "windowing/WindowingFactory.h" + + using namespace std; + using namespace XFILE; +diff --git a/xbmc/windowing/WinSystem.h b/xbmc/windowing/WinSystem.h +index 05c5eda..852d085 100644 +--- a/xbmc/windowing/WinSystem.h ++++ b/xbmc/windowing/WinSystem.h +@@ -100,6 +100,7 @@ class CWinSystemBase + std::vector ScreenResolutions(int screen); + std::vector RefreshRates(int screen, int width, int height, uint32_t dwFlags); + REFRESHRATE DefaultRefreshRate(int screen, std::vector rates); ++ virtual bool HasCalibration(const RESOLUTION_INFO &resInfo) { return true; }; + + protected: + void UpdateDesktopResolution(RESOLUTION_INFO& newRes, int screen, int width, int height, float refreshRate, uint32_t dwFlags = 0); +diff --git a/xbmc/windowing/X11/WinSystemX11.cpp b/xbmc/windowing/X11/WinSystemX11.cpp +index d3d15e2..487b324 100644 +--- a/xbmc/windowing/X11/WinSystemX11.cpp ++++ b/xbmc/windowing/X11/WinSystemX11.cpp +@@ -320,7 +320,7 @@ void CWinSystemX11::UpdateResolutions() + res.strMode.Format("%s: %s @ %.2fHz", out->name.c_str(), mode.name.c_str(), mode.hz); + res.strOutput = out->name; + res.strId = mode.id; +- res.iSubtitles = (int)(0.95*mode.h); ++ res.iSubtitles = (int)(0.965*mode.h); + res.fRefreshRate = mode.hz; + res.bFullScreen = true; + +@@ -333,8 +333,42 @@ void CWinSystemX11::UpdateResolutions() + g_settings.m_ResInfo.push_back(res); + } + } ++ g_settings.ApplyCalibrations(); + #endif ++} ++ ++bool CWinSystemX11::HasCalibration(const RESOLUTION_INFO &resInfo) ++{ ++ XOutput *out = g_xrandr.GetOutput(m_currentOutput); ++ ++ // keep calibrations done on a not connected output ++ if (!out->name.Equals(resInfo.strOutput)) ++ return true; ++ ++ // keep calibrations not updated with resolution data ++ if (resInfo.iWidth == 0) ++ return true; ++ ++ float fPixRatio; ++ if (resInfo.iHeight>0 && resInfo.iWidth>0 && out->hmm>0 && out->wmm>0) ++ fPixRatio = ((float)out->wmm/(float)resInfo.iWidth) / (((float)out->hmm/(float)resInfo.iHeight)); ++ else ++ fPixRatio = 1.0f; + ++ if (resInfo.Overscan.left != 0) ++ return true; ++ if (resInfo.Overscan.top != 0) ++ return true; ++ if (resInfo.Overscan.right != resInfo.iWidth) ++ return true; ++ if (resInfo.Overscan.bottom != resInfo.iHeight) ++ return true; ++ if (resInfo.fPixelRatio != fPixRatio) ++ return true; ++ if (resInfo.iSubtitles != (int)(0.965*resInfo.iHeight)) ++ return true; ++ ++ return false; + } + + void CWinSystemX11::GetConnectedOutputs(std::vector *outputs) +diff --git a/xbmc/windowing/X11/WinSystemX11.h b/xbmc/windowing/X11/WinSystemX11.h +index cc28f56..c046c86 100644 +--- a/xbmc/windowing/X11/WinSystemX11.h ++++ b/xbmc/windowing/X11/WinSystemX11.h +@@ -61,6 +61,7 @@ class CWinSystemX11 : public CWinSystemBase + virtual bool Show(bool raise = true); + virtual void Register(IDispResource *resource); + virtual void Unregister(IDispResource *resource); ++ virtual bool HasCalibration(const RESOLUTION_INFO &resInfo); + + // Local to WinSystemX11 only + Display* GetDisplay() { return m_dpy; } +-- +1.7.10 + + +From 07920e322c9770ebb99becd104ebce0789c502fa Mon Sep 17 00:00:00 2001 +From: FernetMenta +Date: Thu, 5 Jul 2012 12:00:26 +0200 +Subject: [PATCH 28/73] X11: deactivate screen saver on startup + +--- + xbmc/windowing/X11/WinSystemX11.cpp | 29 +++++++++++++++++++++++++++++ + xbmc/windowing/X11/WinSystemX11.h | 1 + + 2 files changed, 30 insertions(+) + +diff --git a/xbmc/windowing/X11/WinSystemX11.cpp b/xbmc/windowing/X11/WinSystemX11.cpp +index 487b324..b3e7ab5 100644 +--- a/xbmc/windowing/X11/WinSystemX11.cpp ++++ b/xbmc/windowing/X11/WinSystemX11.cpp +@@ -521,6 +521,33 @@ void CWinSystemX11::ResetOSScreensaver() + } + } + ++void CWinSystemX11::EnableSystemScreenSaver(bool bEnable) ++{ ++ if (!m_dpy) ++ return; ++ ++ if (bEnable) ++ XForceScreenSaver(m_dpy, ScreenSaverActive); ++ else ++ { ++ Window root_return, child_return; ++ int root_x_return, root_y_return; ++ int win_x_return, win_y_return; ++ unsigned int mask_return; ++ bool isInWin = XQueryPointer(m_dpy, RootWindow(m_dpy, m_nScreen), &root_return, &child_return, ++ &root_x_return, &root_y_return, ++ &win_x_return, &win_y_return, ++ &mask_return); ++ ++ XWarpPointer(m_dpy, None, RootWindow(m_dpy, m_nScreen), 0, 0, 0, 0, root_x_return+300, root_y_return+300); ++ XSync(m_dpy, FALSE); ++ XWarpPointer(m_dpy, None, RootWindow(m_dpy, m_nScreen), 0, 0, 0, 0, 0, 0); ++ XSync(m_dpy, FALSE); ++ XWarpPointer(m_dpy, None, RootWindow(m_dpy, m_nScreen), 0, 0, 0, 0, root_x_return, root_y_return); ++ XSync(m_dpy, FALSE); ++ } ++} ++ + void CWinSystemX11::NotifyAppActiveChange(bool bActivated) + { + if (bActivated && m_bWasFullScreenBeforeMinimize && !m_bFullScreen) +@@ -764,6 +791,8 @@ bool CWinSystemX11::SetWindow(int width, int height, bool fullscreen, const CStd + // create main window + if (!m_glWindow) + { ++ EnableSystemScreenSaver(false); ++ + GLint att[] = + { + GLX_RGBA, +diff --git a/xbmc/windowing/X11/WinSystemX11.h b/xbmc/windowing/X11/WinSystemX11.h +index c046c86..e953d2d 100644 +--- a/xbmc/windowing/X11/WinSystemX11.h ++++ b/xbmc/windowing/X11/WinSystemX11.h +@@ -51,6 +51,7 @@ class CWinSystemX11 : public CWinSystemBase + virtual void ShowOSMouse(bool show); + virtual void ResetOSScreensaver(); + virtual bool EnableFrameLimiter(); ++ virtual void EnableSystemScreenSaver(bool bEnable); + + virtual void NotifyAppActiveChange(bool bActivated); + virtual void NotifyAppFocusChange(bool bGaining); +-- +1.7.10 + + +From 835bcc9c7fd477012492ffc4cad2bdd9ce506064 Mon Sep 17 00:00:00 2001 +From: FernetMenta +Date: Thu, 5 Jul 2012 12:10:09 +0200 +Subject: [PATCH 29/73] X11: change method of going full-screen + +--- + xbmc/windowing/X11/WinSystemX11.cpp | 9 ++++++++- + 1 file changed, 8 insertions(+), 1 deletion(-) + +diff --git a/xbmc/windowing/X11/WinSystemX11.cpp b/xbmc/windowing/X11/WinSystemX11.cpp +index b3e7ab5..91f92c1 100644 +--- a/xbmc/windowing/X11/WinSystemX11.cpp ++++ b/xbmc/windowing/X11/WinSystemX11.cpp +@@ -34,6 +34,7 @@ + #include "utils/TimeUtils.h" + #include "settings/GUISettings.h" + #include "windowing/WindowingFactory.h" ++#include + + #if defined(HAS_XRANDR) + #include +@@ -816,7 +817,7 @@ bool CWinSystemX11::SetWindow(int width, int height, bool fullscreen, const CStd + cmap = XCreateColormap(m_dpy, RootWindow(m_dpy, vi->screen), vi->visual, AllocNone); + + int def_vis = (vi->visual == DefaultVisual(m_dpy, vi->screen)); +- swa.override_redirect = fullscreen ? True : False; ++ swa.override_redirect = False; + swa.border_pixel = fullscreen ? 0 : 5; + swa.background_pixel = def_vis ? BlackPixel(m_dpy, vi->screen) : 0; + swa.colormap = cmap; +@@ -832,6 +833,12 @@ bool CWinSystemX11::SetWindow(int width, int height, bool fullscreen, const CStd + InputOutput, vi->visual, + mask, &swa); + ++ if (fullscreen) ++ { ++ Atom fs = XInternAtom(m_dpy, "_NET_WM_STATE_FULLSCREEN", True); ++ XChangeProperty(m_dpy, m_glWindow, XInternAtom(m_dpy, "_NET_WM_STATE", True), XA_ATOM, 32, PropModeReplace, (unsigned char *) &fs, 1); ++ } ++ + // define invisible cursor + Pixmap bitmapNoData; + XColor black; +-- +1.7.10 + + +From e2442797ff82b3ed8053f1a6422863ffce9cbe5f Mon Sep 17 00:00:00 2001 +From: xbmc +Date: Thu, 28 Jun 2012 19:12:39 +0200 +Subject: [PATCH 30/73] X11: reset key repeat and key modifier on focus lost + and gain + +--- + xbmc/windowing/WinEventsX11.cpp | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/xbmc/windowing/WinEventsX11.cpp b/xbmc/windowing/WinEventsX11.cpp +index 6c22358..d86205d 100644 +--- a/xbmc/windowing/WinEventsX11.cpp ++++ b/xbmc/windowing/WinEventsX11.cpp +@@ -359,6 +359,8 @@ bool CWinEventsX11::MessagePump() + if (WinEvents->m_xic) + XSetICFocus(WinEvents->m_xic); + g_application.m_AppFocused = true; ++ memset(&(WinEvents->m_lastKey), 0, sizeof(XBMC_Event)); ++ WinEvents->m_keymodState = 0; + if (serial == xevent.xfocus.serial) + break; + g_Windowing.NotifyAppFocusChange(g_application.m_AppFocused); +@@ -370,6 +372,7 @@ bool CWinEventsX11::MessagePump() + if (WinEvents->m_xic) + XUnsetICFocus(WinEvents->m_xic); + g_application.m_AppFocused = false; ++ memset(&(WinEvents->m_lastKey), 0, sizeof(XBMC_Event)); + g_Windowing.NotifyAppFocusChange(g_application.m_AppFocused); + serial = xevent.xfocus.serial; + break; +-- +1.7.10 + + +From 77a22163a7f611e9183b7cd0b817fc51a42d45de Mon Sep 17 00:00:00 2001 +From: Joakim Plate +Date: Thu, 5 Jul 2012 14:18:46 +0200 +Subject: [PATCH 31/73] X11: replace custom utf8 to unicode with charset + convertor (squash to x11 events) + +--- + xbmc/windowing/WinEventsX11.cpp | 119 ++++----------------------------------- + xbmc/windowing/WinEventsX11.h | 2 - + 2 files changed, 11 insertions(+), 110 deletions(-) + +diff --git a/xbmc/windowing/WinEventsX11.cpp b/xbmc/windowing/WinEventsX11.cpp +index d86205d..76702e6 100644 +--- a/xbmc/windowing/WinEventsX11.cpp ++++ b/xbmc/windowing/WinEventsX11.cpp +@@ -32,6 +32,7 @@ + #include "X11/keysymdef.h" + #include "X11/XF86keysym.h" + #include "utils/log.h" ++#include "utils/CharsetConverter.h" + #include "guilib/GUIWindowManager.h" + #include "input/MouseStat.h" + +@@ -161,7 +162,6 @@ + m_display = 0; + m_window = 0; + m_keybuf = 0; +- m_utf16buf = 0; + } + + CWinEventsX11::~CWinEventsX11() +@@ -172,12 +172,6 @@ + m_keybuf = 0; + } + +- if (m_utf16buf) +- { +- free(m_utf16buf); +- m_utf16buf = 0; +- } +- + if (m_xic) + { + XUnsetICFocus(m_xic); +@@ -203,7 +197,6 @@ bool CWinEventsX11::Init(Display *dpy, Window win) + WinEvents->m_display = dpy; + WinEvents->m_window = win; + WinEvents->m_keybuf = (char*)malloc(32*sizeof(char)); +- WinEvents->m_utf16buf = (uint16_t*)malloc(32*sizeof(uint16_t)); + WinEvents->m_keymodState = 0; + WinEvents->m_wmDeleteMessage = XInternAtom(dpy, "WM_DELETE_WINDOW", False); + WinEvents->m_structureChanged = false; +@@ -433,8 +426,6 @@ bool CWinEventsX11::MessagePump() + } + + Status status; +- int utf16size; +- int utf16length; + int len; + len = Xutf8LookupString(WinEvents->m_xic, &xevent.xkey, + WinEvents->m_keybuf, sizeof(WinEvents->m_keybuf), +@@ -453,36 +444,29 @@ bool CWinEventsX11::MessagePump() + case XLookupChars: + case XLookupBoth: + { +- if (len == 0) +- break; +- utf16size = len * sizeof(uint16_t); +- if (utf16size > sizeof(WinEvents->m_utf16buf)) +- { +- WinEvents->m_utf16buf = (uint16_t *)realloc(WinEvents->m_utf16buf,utf16size); +- if (WinEvents->m_utf16buf == NULL) +- { +- break; +- } +- } +- utf16length = Utf8ToUnicode(WinEvents->m_keybuf, len, WinEvents->m_utf16buf, utf16size); +- if (utf16length < 0) ++ CStdString data(WinEvents->m_keybuf, len); ++ CStdStringW keys; ++ g_charsetConverter.utf8ToW(data, keys, false); ++ ++ if (keys.length() == 0) + { + break; + } +- for (unsigned int i = 0; i < utf16length - 1; i++) ++ ++ for (unsigned int i = 0; i < keys.length() - 1; i++) + { + newEvent.key.keysym.sym = XBMCK_UNKNOWN; +- newEvent.key.keysym.unicode = WinEvents->m_utf16buf[i]; ++ newEvent.key.keysym.unicode = keys[i]; + newEvent.key.state = xevent.xkey.state; + newEvent.key.type = xevent.xkey.type; + ret |= ProcessKey(newEvent, 500); + } +- if (utf16length > 0) ++ if (keys.length() > 0) + { + newEvent.key.keysym.scancode = xevent.xkey.keycode; + xkeysym = XLookupKeysym(&xevent.xkey, 0); + newEvent.key.keysym.sym = LookupXbmcKeySym(xkeysym); +- newEvent.key.keysym.unicode = WinEvents->m_utf16buf[utf16length - 1]; ++ newEvent.key.keysym.unicode = keys[keys.length() - 1]; + newEvent.key.state = xevent.xkey.state; + newEvent.key.type = xevent.xkey.type; + +@@ -743,87 +727,6 @@ bool CWinEventsX11::ProcessKeyRepeat() + return false; + } + +-int CWinEventsX11::Utf8ToUnicode(const char *utf8, const int utf8Length, uint16_t *utf16, const int utf16MaxLength) +-{ +- // p moves over the output buffer. max_ptr points to the next to the last slot of the buffer. +- uint16_t *p = utf16; +- uint16_t const *const maxPtr = utf16 + utf16MaxLength; +- +- // end_of_input points to the last byte of input as opposed to the next to the last byte. +- char const *const endOfInput = utf8 + utf8Length - 1; +- +- while (utf8 <= endOfInput) +- { +- unsigned char const c = *utf8; +- if (p >= maxPtr) +- { +- //No more output space. +- return -1; +- } +- if (c < 0x80) +- { +- //One byte ASCII. +- *p++ = c; +- utf8 += 1; +- } +- else if (c < 0xC0) +- { +- // Follower byte without preceding leader bytes. +- return -1; +- } +- // 11 bits +- else if (c < 0xE0) +- { +- // Two byte sequence. We need one follower byte. +- if (endOfInput - utf8 < 1 || (((utf8[1] ^ 0x80)) & 0xC0)) +- { +- return -1; +- } +- *p++ = (uint16_t)(((c & 0x1F) << 6) + (utf8[1] & 0x3F)); +- utf8 += 2; +- } +- // 16 bis +- else if (c < 0xF0) +- { +- // Three byte sequence. We need two follower byte. +- if (endOfInput - utf8 < 2 || ((utf8[1] ^ 0x80) & 0xC0) || ((utf8[2] ^ 0x80) & 0xC0)) +- { +- return -1; +- } +- *p++ = (uint16_t)(((c & 0xF) << 12) + ((utf8[1] & 0x3F) << 6) + (utf8[2] & 0x3F)); +- utf8 += 3; +- } +- // 21 bits +- else if (c < 0xF8) +- { +- int plane; +- // Four byte sequence. We need three follower bytes. +- if (endOfInput - utf8 < 3 || ((utf8[1] ^ 0x80) & 0xC0) || +- ((utf8[2] ^ 0x80) & 0xC0) || ((utf8[3] ^ 0x80) & 0xC0)) +- { +- return -1; +- } +- uint32_t unicode = ((c & 0x7) << 18) + ((utf8[1] & 0x3F) << 12) + +- ((utf8[2] & 0x3F) << 6) + (utf8[3] & 0x3F); +- utf8 += 4; +- CLog::Log(LOGERROR, "CWinEventsX11::Utf8ToUnicode: 4 byte unicode not supported"); +- } +- // 26 bits +- else if (c < 0xFC) +- { +- CLog::Log(LOGERROR, "CWinEventsX11::Utf8ToUnicode: 4 byte unicode not supported"); +- utf8 += 5; +- } +- // 31 bit +- else +- { +- CLog::Log(LOGERROR, "CWinEventsX11::Utf8ToUnicode: 4 byte unicode not supported"); +- utf8 += 6; +- } +- } +- return p - utf16; +-} +- + XBMCKey CWinEventsX11::LookupXbmcKeySym(KeySym keysym) + { + // try direct mapping first +diff --git a/xbmc/windowing/WinEventsX11.h b/xbmc/windowing/WinEventsX11.h +index 6100933..72955ad 100644 +--- a/xbmc/windowing/WinEventsX11.h ++++ b/xbmc/windowing/WinEventsX11.h +@@ -38,7 +38,6 @@ class CWinEventsX11 : public CWinEventsBase + static bool MessagePump(); + + protected: +- static int Utf8ToUnicode(const char *utf8, const int utf8Length, uint16_t *utf16, const int utf16MaxLength); + static XBMCKey LookupXbmcKeySym(KeySym keysym); + static bool ProcessKey(XBMC_Event &event, int repeatDelay); + static bool ProcessKeyRepeat(); +@@ -48,7 +47,6 @@ class CWinEventsX11 : public CWinEventsBase + Window m_window; + Atom m_wmDeleteMessage; + char *m_keybuf; +- uint16_t *m_utf16buf; + XIM m_xim; + XIC m_xic; + XBMC_Event m_lastKey; +-- +1.7.10 + + +From e060b3197bbac54b79b604bbbf9a8e86257980f5 Mon Sep 17 00:00:00 2001 +From: Joakim Plate +Date: Thu, 5 Jul 2012 14:23:54 +0200 +Subject: [PATCH 32/73] X11: fixed invalid usage of sizeof() (squash into x11 + changes) + +--- + xbmc/windowing/WinEventsX11.cpp | 11 +++++++---- + xbmc/windowing/WinEventsX11.h | 1 + + 2 files changed, 8 insertions(+), 4 deletions(-) + +diff --git a/xbmc/windowing/WinEventsX11.cpp b/xbmc/windowing/WinEventsX11.cpp +index 76702e6..c31877e 100644 +--- a/xbmc/windowing/WinEventsX11.cpp ++++ b/xbmc/windowing/WinEventsX11.cpp +@@ -162,6 +162,7 @@ + m_display = 0; + m_window = 0; + m_keybuf = 0; ++ m_keybuf_len = 0; + } + + CWinEventsX11::~CWinEventsX11() +@@ -196,7 +197,8 @@ bool CWinEventsX11::Init(Display *dpy, Window win) + WinEvents = new CWinEventsX11(); + WinEvents->m_display = dpy; + WinEvents->m_window = win; +- WinEvents->m_keybuf = (char*)malloc(32*sizeof(char)); ++ WinEvents->m_keybuf_len = 32*sizeof(char); ++ WinEvents->m_keybuf = (char*)malloc(WinEvents->m_keybuf_len); + WinEvents->m_keymodState = 0; + WinEvents->m_wmDeleteMessage = XInternAtom(dpy, "WM_DELETE_WINDOW", False); + WinEvents->m_structureChanged = false; +@@ -428,13 +430,14 @@ bool CWinEventsX11::MessagePump() + Status status; + int len; + len = Xutf8LookupString(WinEvents->m_xic, &xevent.xkey, +- WinEvents->m_keybuf, sizeof(WinEvents->m_keybuf), ++ WinEvents->m_keybuf, WinEvents->m_keybuf_len, + &xkeysym, &status); + if (status == XBufferOverflow) + { +- WinEvents->m_keybuf = (char*)realloc(WinEvents->m_keybuf, len*sizeof(char)); ++ WinEvents->m_keybuf_len = len; ++ WinEvents->m_keybuf = (char*)realloc(WinEvents->m_keybuf, WinEvents->m_keybuf_len); + len = Xutf8LookupString(WinEvents->m_xic, &xevent.xkey, +- WinEvents->m_keybuf, sizeof(WinEvents->m_keybuf), ++ WinEvents->m_keybuf, WinEvents->m_keybuf_len, + &xkeysym, &status); + } + switch (status) +diff --git a/xbmc/windowing/WinEventsX11.h b/xbmc/windowing/WinEventsX11.h +index 72955ad..102a076 100644 +--- a/xbmc/windowing/WinEventsX11.h ++++ b/xbmc/windowing/WinEventsX11.h +@@ -47,6 +47,7 @@ class CWinEventsX11 : public CWinEventsBase + Window m_window; + Atom m_wmDeleteMessage; + char *m_keybuf; ++ size_t m_keybuf_len; + XIM m_xim; + XIC m_xic; + XBMC_Event m_lastKey; +-- +1.7.10 + + +From c52af3ba68292f08331cbbbc940dfcea838a2f44 Mon Sep 17 00:00:00 2001 +From: xbmc +Date: Sat, 9 Jun 2012 18:23:53 +0200 +Subject: [PATCH 33/73] add missing keys to xbmc keytable + +--- + xbmc/input/XBMC_keytable.cpp | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/xbmc/input/XBMC_keytable.cpp b/xbmc/input/XBMC_keytable.cpp +index aaf65ba..9d7922f 100644 +--- a/xbmc/input/XBMC_keytable.cpp ++++ b/xbmc/input/XBMC_keytable.cpp +@@ -179,6 +179,8 @@ + , { XBMCK_LAUNCH_APP2, 0, 0, XBMCVK_LAUNCH_APP2, "launch_app2_pc_icon" } + , { XBMCK_LAUNCH_FILE_BROWSER, 0, 0, XBMCVK_LAUNCH_FILE_BROWSER, "launch_file_browser" } + , { XBMCK_LAUNCH_MEDIA_CENTER, 0, 0, XBMCVK_LAUNCH_MEDIA_CENTER, "launch_media_center" } ++, { XBMCK_PLAY, 0, 0, XBMCVK_MEDIA_PLAY_PAUSE, "play_pause" } ++, { XBMCK_STOP, 0, 0, XBMCVK_MEDIA_STOP, "stop" } + + // Function keys + , { XBMCK_F1, 0, 0, XBMCVK_F1, "f1"} +-- +1.7.10 + + +From 25587ee807eca2fc9dde4528e3fc930b337e38b0 Mon Sep 17 00:00:00 2001 +From: xbmc +Date: Fri, 16 Mar 2012 15:57:51 +0100 +Subject: [PATCH 34/73] videorefclock: temp deactivate of nv settings + +--- + xbmc/video/VideoReferenceClock.cpp | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/xbmc/video/VideoReferenceClock.cpp b/xbmc/video/VideoReferenceClock.cpp +index fa8e35a..85e36c7 100644 +--- a/xbmc/video/VideoReferenceClock.cpp ++++ b/xbmc/video/VideoReferenceClock.cpp +@@ -135,7 +135,7 @@ + m_Context = NULL; + m_pixmap = None; + m_glPixmap = None; +- m_UseNvSettings = true; ++ m_UseNvSettings = false; + m_bIsATI = false; + #endif + } +-- +1.7.10 + + +From 4f8a95de09408321e2df3da891536c314fe3b4d2 Mon Sep 17 00:00:00 2001 +From: xbmc +Date: Mon, 20 Aug 2012 09:09:09 +0200 +Subject: [PATCH 35/73] videorefclock: ask graphics context for refresh rate + +--- + xbmc/video/VideoReferenceClock.cpp | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/xbmc/video/VideoReferenceClock.cpp b/xbmc/video/VideoReferenceClock.cpp +index 85e36c7..8209163 100644 +--- a/xbmc/video/VideoReferenceClock.cpp ++++ b/xbmc/video/VideoReferenceClock.cpp +@@ -30,6 +30,7 @@ + #include + #include + #include "windowing/WindowingFactory.h" ++ #include "guilib/GraphicContext.h" + #define NVSETTINGSCMD "nvidia-settings -nt -q RefreshRate3" + #elif defined(TARGET_DARWIN_OSX) + #include +@@ -1254,7 +1255,7 @@ bool CVideoReferenceClock::UpdateRefreshrate(bool Forced /*= false*/) + } + + CSingleLock SingleLock(m_CritSection); +- m_RefreshRate = GetRandRRate(); ++ m_RefreshRate = MathUtils::round_int(g_graphicsContext.GetFPS()); + + CLog::Log(LOGDEBUG, "CVideoReferenceClock: Detected refreshrate: %i hertz", (int)m_RefreshRate); + +-- +1.7.10 + + +From 85d81f0c933cb0a75c2c21de86b4065e3db86002 Mon Sep 17 00:00:00 2001 +From: xbmc +Date: Mon, 9 Jul 2012 14:00:18 +0200 +Subject: [PATCH 36/73] X11: fix icon texture after + cc5ed3c2474084ebc0373a3046410e6f766e03f4 + +--- + xbmc/windowing/X11/WinSystemX11.cpp | 43 +++++++++++++++++++++-------------- + 1 file changed, 26 insertions(+), 17 deletions(-) + +diff --git a/xbmc/windowing/X11/WinSystemX11.cpp b/xbmc/windowing/X11/WinSystemX11.cpp +index 91f92c1..174ccef 100644 +--- a/xbmc/windowing/X11/WinSystemX11.cpp ++++ b/xbmc/windowing/X11/WinSystemX11.cpp +@@ -874,22 +874,24 @@ bool CWinSystemX11::SetWindow(int width, int height, bool fullscreen, const CStd + if (!fullscreen) + { + CreateIconPixmap(); +- XWMHints wm_hints; +- XClassHint class_hints; ++ XWMHints *wm_hints; + XTextProperty windowName, iconName; + std::string titleString = "XBMC Media Center"; + char *title = (char*)titleString.c_str(); + + XStringListToTextProperty(&title, 1, &windowName); + XStringListToTextProperty(&title, 1, &iconName); +- wm_hints.initial_state = NormalState; +- wm_hints.input = True; +- wm_hints.icon_pixmap = m_icon; +- wm_hints.flags = StateHint | IconPixmapHint | InputHint; + ++ wm_hints = XAllocWMHints(); ++ wm_hints->initial_state = NormalState; ++ wm_hints->icon_pixmap = m_icon; ++ wm_hints->flags = StateHint | IconPixmapHint; ++ ++ XSync(m_dpy,False); + XSetWMProperties(m_dpy, m_glWindow, &windowName, &iconName, +- NULL, 0, NULL, &wm_hints, ++ NULL, 0, NULL, wm_hints, + NULL); ++ XFree(wm_hints); + + // register interest in the delete window message + Atom wmDeleteMessage = XInternAtom(m_dpy, "WM_DELETE_WINDOW", False); +@@ -974,16 +976,21 @@ bool CWinSystemX11::CreateIconPixmap() + gRatio = vis->green_mask / 255.0; + bRatio = vis->blue_mask / 255.0; + +- CTexture iconTexture; +- iconTexture.LoadFromFile("special://xbmc/media/icon.png"); +- buf = iconTexture.GetPixels(); ++ CBaseTexture *iconTexture = CBaseTexture::LoadFromFile("special://xbmc/media/icon.png"); ++ ++ if (!iconTexture) ++ return false; + +- numBufBytes = iconTexture.GetWidth() * iconTexture.GetHeight() * 4; ++ buf = iconTexture->GetPixels(); ++ ++ numBufBytes = iconTexture->GetWidth() * iconTexture->GetHeight() * 4; ++ int wid = iconTexture->GetWidth(); ++ int hi = iconTexture->GetHeight(); + + if (depth>=24) +- numNewBufBytes = (4 * (iconTexture.GetWidth() * iconTexture.GetHeight())); ++ numNewBufBytes = (4 * (iconTexture->GetWidth() * iconTexture->GetHeight())); + else +- numNewBufBytes = (2 * (iconTexture.GetWidth() * iconTexture.GetHeight())); ++ numNewBufBytes = (2 * (iconTexture->GetWidth() * iconTexture->GetHeight())); + + newBuf = (uint32_t*)malloc(numNewBufBytes); + if (!newBuf) +@@ -992,11 +999,11 @@ bool CWinSystemX11::CreateIconPixmap() + return false; + } + +- for (i=0; iGetHeight();++i) + { +- for (j=0; jGetWidth();++j) + { +- unsigned int pos = i*iconTexture.GetPitch()+j*4; ++ unsigned int pos = i*iconTexture->GetPitch()+j*4; + unsigned int r, g, b; + r = (buf[pos+2] * rRatio); + g = (buf[pos+1] * gRatio); +@@ -1009,7 +1016,7 @@ bool CWinSystemX11::CreateIconPixmap() + } + } + img = XCreateImage(m_dpy, vis, depth,ZPixmap, 0, (char *)newBuf, +- iconTexture.GetWidth(), iconTexture.GetHeight(), ++ iconTexture->GetWidth(), iconTexture->GetHeight(), + (depth>=24)?32:16, 0); + if (!img) + { +@@ -1047,6 +1054,8 @@ bool CWinSystemX11::CreateIconPixmap() + XFreeGC(m_dpy, gc); + XDestroyImage(img); // this also frees newBuf + ++ delete iconTexture; ++ + return true; + } + +-- +1.7.10 + + +From 111c2f8fd0f6b698fbff0fda6dc6c17ce3644626 Mon Sep 17 00:00:00 2001 +From: xbmc +Date: Tue, 10 Jul 2012 11:14:12 +0200 +Subject: [PATCH 37/73] X11: check for window manager + +--- + xbmc/windowing/X11/WinSystemX11.cpp | 74 ++++++++++++++++++++++++++++++++++- + xbmc/windowing/X11/WinSystemX11.h | 1 + + 2 files changed, 73 insertions(+), 2 deletions(-) + +diff --git a/xbmc/windowing/X11/WinSystemX11.cpp b/xbmc/windowing/X11/WinSystemX11.cpp +index 174ccef..4f1ae26 100644 +--- a/xbmc/windowing/X11/WinSystemX11.cpp ++++ b/xbmc/windowing/X11/WinSystemX11.cpp +@@ -816,8 +816,10 @@ bool CWinSystemX11::SetWindow(int width, int height, bool fullscreen, const CStd + vi = glXChooseVisual(m_dpy, m_nScreen, att); + cmap = XCreateColormap(m_dpy, RootWindow(m_dpy, vi->screen), vi->visual, AllocNone); + ++ bool hasWM = HasWindowManager(); ++ + int def_vis = (vi->visual == DefaultVisual(m_dpy, vi->screen)); +- swa.override_redirect = False; ++ swa.override_redirect = hasWM ? False : True; + swa.border_pixel = fullscreen ? 0 : 5; + swa.background_pixel = def_vis ? BlackPixel(m_dpy, vi->screen) : 0; + swa.colormap = cmap; +@@ -833,7 +835,7 @@ bool CWinSystemX11::SetWindow(int width, int height, bool fullscreen, const CStd + InputOutput, vi->visual, + mask, &swa); + +- if (fullscreen) ++ if (fullscreen && hasWM) + { + Atom fs = XInternAtom(m_dpy, "_NET_WM_STATE_FULLSCREEN", True); + XChangeProperty(m_dpy, m_glWindow, XInternAtom(m_dpy, "_NET_WM_STATE", True), XA_ATOM, 32, PropModeReplace, (unsigned char *) &fs, 1); +@@ -1059,4 +1061,72 @@ bool CWinSystemX11::CreateIconPixmap() + return true; + } + ++bool CWinSystemX11::HasWindowManager() ++{ ++ Window wm_check; ++ unsigned char *data; ++ int status, real_format; ++ Atom real_type, prop; ++ unsigned long items_read, items_left, i; ++ char req = 0; ++ ++ prop = XInternAtom(m_dpy, "_NET_SUPPORTING_WM_CHECK", True); ++ if (prop == None) ++ return false; ++ status = XGetWindowProperty(m_dpy, DefaultRootWindow(m_dpy), prop, ++ 0L, 1L, False, XA_WINDOW, &real_type, &real_format, ++ &items_read, &items_left, &data); ++ if(status != Success || ! items_read) ++ { ++ if(status == Success) ++ XFree(data); ++ return false; ++ } ++ ++ wm_check = ((Window*)data)[0]; ++ XFree(data); ++ ++ status = XGetWindowProperty(m_dpy, wm_check, prop, ++ 0L, 1L, False, XA_WINDOW, &real_type, &real_format, ++ &items_read, &items_left, &data); ++ ++ if(status != Success || !items_read) ++ { ++ if(status == Success) ++ XFree(data); ++ return false; ++ } ++ ++ if(wm_check != ((Window*)data)[0]) ++ { ++ XFree(data); ++ return false; ++ } ++ ++ XFree(data); ++ ++ prop = XInternAtom(m_dpy, "_NET_WM_NAME", True); ++ if (prop == None) ++ { ++ CLog::Log(LOGDEBUG,"Window Manager Name: "); ++ return true; ++ } ++ ++ status = XGetWindowProperty(m_dpy, wm_check, prop, ++ 0L, (~0L), False, AnyPropertyType, &real_type, &real_format, ++ &items_read, &items_left, &data); ++ ++ if(status == Success && items_read) ++ { ++ CLog::Log(LOGDEBUG,"Window Manager Name: %s", data); ++ } ++ else ++ CLog::Log(LOGDEBUG,"Window Manager Name: "); ++ ++ if(status == Success) ++ XFree(data); ++ ++ return true; ++} ++ + #endif +diff --git a/xbmc/windowing/X11/WinSystemX11.h b/xbmc/windowing/X11/WinSystemX11.h +index e953d2d..0b7c10a 100644 +--- a/xbmc/windowing/X11/WinSystemX11.h ++++ b/xbmc/windowing/X11/WinSystemX11.h +@@ -101,6 +101,7 @@ class CWinSystemX11 : public CWinSystemBase + bool IsSuitableVisual(XVisualInfo *vInfo); + static int XErrorHandler(Display* dpy, XErrorEvent* error); + bool CreateIconPixmap(); ++ bool HasWindowManager(); + + CStopWatch m_screensaverReset; + }; +-- +1.7.10 + + +From f1051e1991e5ef5d83ce428b841ac365082042ec Mon Sep 17 00:00:00 2001 +From: xbmc +Date: Thu, 12 Jul 2012 11:11:47 +0200 +Subject: [PATCH 38/73] X11: dont set window on xrandr if no mode available + +--- + xbmc/windowing/X11/WinSystemX11.cpp | 11 ++++++----- + 1 file changed, 6 insertions(+), 5 deletions(-) + +diff --git a/xbmc/windowing/X11/WinSystemX11.cpp b/xbmc/windowing/X11/WinSystemX11.cpp +index 4f1ae26..c11ea89 100644 +--- a/xbmc/windowing/X11/WinSystemX11.cpp ++++ b/xbmc/windowing/X11/WinSystemX11.cpp +@@ -665,16 +665,17 @@ void CWinSystemX11::NotifyXRREvent() + CLog::Log(LOGDEBUG, "%s - notify display reset event", __FUNCTION__); + m_windowDirty = true; + ++ if (!g_xrandr.Query(true)) ++ { ++ CLog::Log(LOGERROR, "WinSystemX11::RefreshWindow - failed to query xrandr"); ++ return; ++ } ++ + // if external event update resolutions + if (!m_bIsInternalXrr) + { + UpdateResolutions(); + } +- else if (!g_xrandr.Query(true)) +- { +- CLog::Log(LOGERROR, "WinSystemX11::RefreshWindow - failed to query xrandr"); +- return; +- } + m_bIsInternalXrr = false; + + CStdString currentOutput = g_guiSettings.GetString("videoscreen.monitor"); +-- +1.7.10 + + +From 83b9c33e88077d957884ee22316c218e570dc3d5 Mon Sep 17 00:00:00 2001 +From: xbmc +Date: Thu, 26 Jul 2012 09:34:28 +0200 +Subject: [PATCH 39/73] X11: fix crash after a resolution change on startup + +--- + xbmc/windowing/X11/WinSystemX11.cpp | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/xbmc/windowing/X11/WinSystemX11.cpp b/xbmc/windowing/X11/WinSystemX11.cpp +index c11ea89..0bd72d4 100644 +--- a/xbmc/windowing/X11/WinSystemX11.cpp ++++ b/xbmc/windowing/X11/WinSystemX11.cpp +@@ -219,7 +219,8 @@ bool CWinSystemX11::SetFullScreen(bool fullScreen, RESOLUTION_INFO& res, bool bl + OnLostDevice(); + m_bIsInternalXrr = true; + g_xrandr.SetMode(out, mode); +- return true; ++ if (m_glWindow) ++ return true; + } + #endif + +-- +1.7.10 + + +From b8956ed57f1b683ae79d7306c7461a31c894e9a9 Mon Sep 17 00:00:00 2001 +From: xbmc +Date: Sat, 15 Sep 2012 18:27:29 +0200 +Subject: [PATCH 40/73] X11: lock graphics context in NotifyXRREvent + +--- + xbmc/windowing/X11/WinSystemX11.cpp | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/xbmc/windowing/X11/WinSystemX11.cpp b/xbmc/windowing/X11/WinSystemX11.cpp +index 0bd72d4..ef83133 100644 +--- a/xbmc/windowing/X11/WinSystemX11.cpp ++++ b/xbmc/windowing/X11/WinSystemX11.cpp +@@ -666,6 +666,8 @@ void CWinSystemX11::NotifyXRREvent() + CLog::Log(LOGDEBUG, "%s - notify display reset event", __FUNCTION__); + m_windowDirty = true; + ++ CSingleLock lock(g_graphicsContext); ++ + if (!g_xrandr.Query(true)) + { + CLog::Log(LOGERROR, "WinSystemX11::RefreshWindow - failed to query xrandr"); +-- +1.7.10 + + +From aed5d244b81b1a0b171b7fea3b332decafc96c56 Mon Sep 17 00:00:00 2001 +From: Rainer Hochecker +Date: Sat, 8 Oct 2011 16:45:13 +0200 +Subject: [PATCH 41/73] ffmpeg: add xvba hwaccel + +--- + lib/ffmpeg/configure | 8 ++ + lib/ffmpeg/libavcodec/Makefile | 7 +- + lib/ffmpeg/libavcodec/allcodecs.c | 4 + + lib/ffmpeg/libavcodec/h264.c | 1 + + lib/ffmpeg/libavcodec/mpegvideo.c | 1 + + lib/ffmpeg/libavcodec/xvba.c | 66 ++++++++++++ + lib/ffmpeg/libavcodec/xvba.h | 71 ++++++++++++ + lib/ffmpeg/libavcodec/xvba_h264.c | 189 ++++++++++++++++++++++++++++++++ + lib/ffmpeg/libavcodec/xvba_internal.h | 24 +++++ + lib/ffmpeg/libavcodec/xvba_mpeg2.c | 52 +++++++++ + lib/ffmpeg/libavcodec/xvba_vc1.c | 190 +++++++++++++++++++++++++++++++++ + lib/ffmpeg/libavcodec/xvmc_internal.h | 4 +- + lib/ffmpeg/libavutil/pixdesc.c | 6 ++ + lib/ffmpeg/libavutil/pixfmt.h | 1 + + 14 files changed, 622 insertions(+), 2 deletions(-) + create mode 100644 lib/ffmpeg/libavcodec/xvba.c + create mode 100644 lib/ffmpeg/libavcodec/xvba.h + create mode 100644 lib/ffmpeg/libavcodec/xvba_h264.c + create mode 100644 lib/ffmpeg/libavcodec/xvba_internal.h + create mode 100644 lib/ffmpeg/libavcodec/xvba_mpeg2.c + create mode 100644 lib/ffmpeg/libavcodec/xvba_vc1.c + +diff --git a/lib/ffmpeg/configure b/lib/ffmpeg/configure +index c06005b..157cfd3 100755 +--- a/lib/ffmpeg/configure ++++ b/lib/ffmpeg/configure +@@ -113,6 +113,7 @@ Configuration options: + --enable-vdpau enable VDPAU code [autodetect] + --disable-dxva2 disable DXVA2 code + --disable-vda disable VDA 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 + --disable-safe-bitstream-reader +@@ -1084,6 +1085,7 @@ CONFIG_LIST=" + vaapi + vda + vdpau ++ xvba + version3 + x11grab + zlib +@@ -1423,6 +1425,7 @@ h264_dxva2_hwaccel_select="dxva2 h264_decoder" + h264_vaapi_hwaccel_select="vaapi h264_decoder" + h264_vda_hwaccel_deps="VideoDecodeAcceleration_VDADecoder_h pthreads" + h264_vda_hwaccel_select="vda h264_decoder" ++h264_xvba_hwaccel_select="xvba h264_decoder" + h264_vdpau_decoder_select="vdpau h264_decoder" + imc_decoder_select="fft mdct sinewin" + jpegls_decoder_select="golomb" +@@ -1459,6 +1462,7 @@ mpeg4_crystalhd_decoder_select="crystalhd" + mpeg4_decoder_select="h263_decoder mpeg4video_parser" + mpeg4_encoder_select="h263_encoder" + mpeg4_vaapi_hwaccel_select="vaapi mpeg4_decoder" ++mpeg2_xvba_hwaccel_select="xvba mpeg2video_decoder" + mpeg4_vdpau_decoder_select="vdpau mpeg4_decoder" + msmpeg4_crystalhd_decoder_select="crystalhd" + msmpeg4v1_decoder_select="h263_decoder" +@@ -1501,6 +1505,7 @@ vc1_decoder_select="h263_decoder h264chroma" + vc1_dxva2_hwaccel_deps="dxva2api_h" + 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" + vc1image_decoder_select="vc1_decoder" + vorbis_decoder_select="mdct" +@@ -1525,6 +1530,7 @@ wmv3_dxva2_hwaccel_select="vc1_dxva2_hwaccel" + wmv3_vaapi_hwaccel_select="vc1_vaapi_hwaccel" + wmv3_vdpau_decoder_select="vc1_vdpau_decoder" + wmv3image_decoder_select="wmv3_decoder" ++wmv3_xvba_hwaccel_select="vc1_xvba_hwaccel" + zlib_decoder_select="zlib" + zlib_encoder_select="zlib" + zmbv_decoder_select="zlib" +@@ -1533,6 +1539,7 @@ zmbv_encoder_select="zlib" + crystalhd_deps="libcrystalhd_libcrystalhd_if_h" + vaapi_deps="va_va_h" + vda_deps="VideoDecodeAcceleration_VDADecoder_h pthreads" ++xvba_deps="amd_amdxvba_h" + vdpau_deps="vdpau_vdpau_h vdpau_vdpau_x11_h" + + # parsers +@@ -3062,6 +3069,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 972cc59..fc441bf 100644 +--- a/lib/ffmpeg/libavcodec/Makefile ++++ b/lib/ffmpeg/libavcodec/Makefile +@@ -3,7 +3,7 @@ include $(SUBDIR)../config.mak + NAME = avcodec + FFLIBS = avutil + +-HEADERS = avcodec.h avfft.h dxva2.h opt.h vaapi.h vda.h vdpau.h version.h xvmc.h ++HEADERS = avcodec.h avfft.h dxva2.h opt.h vaapi.h vda.h vdpau.h version.h xvmc.h xvba.h + + OBJS = allcodecs.o \ + audioconvert.o \ +@@ -51,6 +51,7 @@ OBJS-$(CONFIG_SINEWIN) += sinewin.o + OBJS-$(CONFIG_VAAPI) += vaapi.o + OBJS-$(CONFIG_VDA) += vda.o + OBJS-$(CONFIG_VDPAU) += vdpau.o ++OBJS-$(CONFIG_XVBA) += xvba.o + + # decoders/encoders/hardware accelerators + OBJS-$(CONFIG_A64MULTI_ENCODER) += a64multienc.o elbg.o +@@ -201,6 +202,7 @@ OBJS-$(CONFIG_H264_DECODER) += h264.o \ + OBJS-$(CONFIG_H264_DXVA2_HWACCEL) += dxva2_h264.o + OBJS-$(CONFIG_H264_VAAPI_HWACCEL) += vaapi_h264.o + OBJS-$(CONFIG_H264_VDA_HWACCEL) += vda_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 +@@ -284,6 +286,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 \ +@@ -431,6 +434,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 +@@ -732,6 +736,7 @@ SKIPHEADERS-$(CONFIG_LIBDIRAC) += libdirac.h + SKIPHEADERS-$(CONFIG_LIBSCHROEDINGER) += libschroedinger.h + SKIPHEADERS-$(CONFIG_VAAPI) += vaapi_internal.h + SKIPHEADERS-$(CONFIG_VDA) += vda_internal.h ++SKIPHEADERS-$(CONFIG_XVBA) += xvba_internal.h + SKIPHEADERS-$(CONFIG_VDPAU) += vdpau.h + SKIPHEADERS-$(CONFIG_XVMC) += xvmc.h + SKIPHEADERS-$(HAVE_W32THREADS) += w32pthreads.h +diff --git a/lib/ffmpeg/libavcodec/allcodecs.c b/lib/ffmpeg/libavcodec/allcodecs.c +index 32f3f52..0ff178e 100644 +--- a/lib/ffmpeg/libavcodec/allcodecs.c ++++ b/lib/ffmpeg/libavcodec/allcodecs.c +@@ -59,14 +59,18 @@ void avcodec_register_all(void) + REGISTER_HWACCEL (H264_VAAPI, h264_vaapi); + REGISTER_HWACCEL (H264_VDA, h264_vda); + REGISTER_HWACCEL (MPEG1_VDPAU, mpeg1_vdpau); ++ REGISTER_HWACCEL (H264_XVBA, h264_xvba); + REGISTER_HWACCEL (MPEG2_DXVA2, mpeg2_dxva2); + REGISTER_HWACCEL (MPEG2_VAAPI, mpeg2_vaapi); + REGISTER_HWACCEL (MPEG2_VDPAU, mpeg2_vdpau); + 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 c4785db..e9e7546 100644 +--- a/lib/ffmpeg/libavcodec/h264.c ++++ b/lib/ffmpeg/libavcodec/h264.c +@@ -60,6 +60,7 @@ + PIX_FMT_DXVA2_VLD, + PIX_FMT_VAAPI_VLD, + PIX_FMT_VDA_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 04c149a..b22b631 100644 +--- a/lib/ffmpeg/libavcodec/mpegvideo.c ++++ b/lib/ffmpeg/libavcodec/mpegvideo.c +@@ -136,6 +136,7 @@ static void dct_unquantize_h263_inter_c(MpegEncContext *s, + PIX_FMT_DXVA2_VLD, + PIX_FMT_VAAPI_VLD, + PIX_FMT_VDA_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..be29e5d +--- /dev/null ++++ b/lib/ffmpeg/libavcodec/xvba.c +@@ -0,0 +1,66 @@ ++/* ++ * 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 "xvba_internal.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 uint8_t *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..9f9ff0c +--- /dev/null ++++ b/lib/ffmpeg/libavcodec/xvba.h +@@ -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; ++ 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..a077442 +--- /dev/null ++++ b/lib/ffmpeg/libavcodec/xvba_h264.c +@@ -0,0 +1,189 @@ ++/* ++ * 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->f.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->f.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 == AV_PICTURE_TYPE_I) ? 1 : 0; ++ pic_descriptor->avc_reference = (s->current_picture_ptr->f.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; ++ ++ /* Set correct level */ ++ if (pic_descriptor->level == 41) { ++ const unsigned int mbw = pic_descriptor->width_in_mb; ++ const unsigned int mbh = pic_descriptor->height_in_mb; ++ const unsigned int max_ref_frames = 12288 * 1024 / (mbw * mbh * 384); ++ const unsigned int num_ref_frames = pic_descriptor->avc_num_ref_frames; ++ if (max_ref_frames < num_ref_frames) ++ pic_descriptor->level = 51; ++ } ++ ++ 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[0], h->pps.scaling_matrix8[0], sizeof(iq_matrix->bScalingLists8x8[0])); ++ memcpy(iq_matrix->bScalingLists8x8[1], h->pps.scaling_matrix8[3], sizeof(iq_matrix->bScalingLists8x8[0])); ++ ++ // Wait for an I-frame before start decoding. Workaround for ATI UVD and UVD+ GPUs ++ if (!h->got_first_iframe) { ++ if (h->slice_type != AV_PICTURE_TYPE_I && h->slice_type != AV_PICTURE_TYPE_SI) ++ 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 XVBA. */ ++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->f.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, ++ .start_frame = start_frame, ++ .end_frame = end_frame, ++ .decode_slice = decode_slice, ++}; +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..7315b62 +--- /dev/null ++++ b/lib/ffmpeg/libavcodec/xvba_vc1.c +@@ -0,0 +1,190 @@ ++/* ++ * 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->f.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->f.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 == AV_PICTURE_TYPE_I || v->bi_type == 1; ++ pic_descriptor->avc_reference = (s->current_picture_ptr->f.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 AV_PICTURE_TYPE_B: ++ next = (struct xvba_render_state *)s->next_picture.f.data[0]; ++ assert(next); ++ if (next) ++ pic_descriptor->past_surface = next->surface; ++ // fall-through ++ case AV_PICTURE_TYPE_P: ++ last = (struct xvba_render_state *)s->last_picture.f.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->f.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, ++ .start_frame = start_frame, ++ .end_frame = end_frame, ++ .decode_slice = decode_slice, ++}; ++#endif ++ ++AVHWAccel ff_vc1_xvba_hwaccel = { ++ .name = "vc1_xvba", ++ .type = AVMEDIA_TYPE_VIDEO, ++ .id = CODEC_ID_VC1, ++ .pix_fmt = PIX_FMT_XVBA_VLD, ++ .start_frame = start_frame, ++ .end_frame = end_frame, ++ .decode_slice = decode_slice, ++}; +diff --git a/lib/ffmpeg/libavcodec/xvmc_internal.h b/lib/ffmpeg/libavcodec/xvmc_internal.h +index 04197ce..d925eb1 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 e73fbfe..5abbd14 100644 +--- a/lib/ffmpeg/libavutil/pixdesc.c ++++ b/lib/ffmpeg/libavutil/pixdesc.c +@@ -874,6 +874,12 @@ void av_write_image_line(const uint16_t *src, uint8_t *data[4], const int linesi + .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_YUV420P9LE] = { + .name = "yuv420p9le", + .nb_components = 3, +diff --git a/lib/ffmpeg/libavutil/pixfmt.h b/lib/ffmpeg/libavutil/pixfmt.h +index f0d9c01..0f8cf7b 100644 +--- a/lib/ffmpeg/libavutil/pixfmt.h ++++ b/lib/ffmpeg/libavutil/pixfmt.h +@@ -129,6 +129,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_RGB444LE, ///< packed RGB 4:4:4, 16bpp, (msb)4A 4R 4G 4B(lsb), little-endian, most significant bits to 0 + PIX_FMT_RGB444BE, ///< packed RGB 4:4:4, 16bpp, (msb)4A 4R 4G 4B(lsb), big-endian, most significant bits to 0 +-- +1.7.10 + + +From 922cada27e255bc3f685b700c2ffa4a146f87624 Mon Sep 17 00:00:00 2001 +From: xbmc +Date: Thu, 12 Apr 2012 12:09:31 +0200 +Subject: [PATCH 42/73] xvba: add decoder + +--- + configure.in | 48 + + language/English/strings.po | 12 +- + xbmc/cores/VideoRenderers/LinuxRendererGL.cpp | 218 +- + xbmc/cores/VideoRenderers/LinuxRendererGL.h | 15 +- + xbmc/cores/VideoRenderers/RenderFormats.h | 1 + + xbmc/cores/VideoRenderers/RenderManager.cpp | 9 +- + .../dvdplayer/DVDCodecs/Video/DVDVideoCodec.h | 4 + + .../DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp | 16 + + xbmc/cores/dvdplayer/DVDCodecs/Video/Makefile.in | 4 + + xbmc/cores/dvdplayer/DVDCodecs/Video/XVBA.cpp | 2354 ++++++++++++++++++++ + xbmc/cores/dvdplayer/DVDCodecs/Video/XVBA.h | 382 ++++ + xbmc/cores/dvdplayer/DVDPlayerVideo.cpp | 3 + + xbmc/settings/GUISettings.cpp | 3 + + xbmc/settings/VideoSettings.h | 2 + + xbmc/video/dialogs/GUIDialogVideoSettings.cpp | 1 + + 15 files changed, 3064 insertions(+), 8 deletions(-) + create mode 100644 xbmc/cores/dvdplayer/DVDCodecs/Video/XVBA.cpp + create mode 100644 xbmc/cores/dvdplayer/DVDCodecs/Video/XVBA.h + +diff --git a/configure.in b/configure.in +index 350d960..3660fa4 100644 +--- a/configure.in ++++ b/configure.in +@@ -124,6 +124,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. ==" +@@ -247,6 +249,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], +@@ -1759,6 +1767,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 +@@ -1970,6 +2010,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 +@@ -2443,6 +2489,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) +@@ -2626,6 +2673,7 @@ XB_CONFIG_MODULE([lib/ffmpeg], [ + `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 "$use_optimizations" != "no"; then echo --enable-optimizations; else echo --disable-optimizations; 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.po b/language/English/strings.po +index bba7284..ede18b3 100644 +--- a/language/English/strings.po ++++ b/language/English/strings.po +@@ -5124,7 +5124,11 @@ msgctxt "#13436" + msgid "Allow Vdpau OpenGL interop YUV" + msgstr "" + +-#empty strings from id 13437 to 13499 ++msgctxt "#13437" ++msgid "Allow hardware acceleration (XVBA)" ++msgstr "" ++ ++#empty strings from id 13438 to 13499 + + msgctxt "#13500" + msgid "A/V sync method" +@@ -6346,7 +6350,11 @@ msgctxt "#16325" + msgid "VDPAU - Bob" + msgstr "" + +-#empty strings from id 16326 to 16399 ++msgctxt "#16326" ++msgid "XVBA" ++msgstr "" ++ ++#empty strings from id 16327 to 16399 + + msgctxt "#16400" + msgid "Post-processing" +diff --git a/xbmc/cores/VideoRenderers/LinuxRendererGL.cpp b/xbmc/cores/VideoRenderers/LinuxRendererGL.cpp +index b281ca7..ec3606a 100644 +--- a/xbmc/cores/VideoRenderers/LinuxRendererGL.cpp ++++ b/xbmc/cores/VideoRenderers/LinuxRendererGL.cpp +@@ -63,6 +63,9 @@ + VA_MICRO_VERSION == 0 && VA_SDS_VERSION < 5))) + + #endif ++#ifdef HAVE_LIBXVBA ++#include "cores/dvdplayer/DVDCodecs/Video/XVBA.h" ++#endif + + #ifdef TARGET_DARWIN + #include "osx/CocoaInterface.h" +@@ -129,6 +132,9 @@ + #ifdef HAVE_LIBVDPAU + vdpau = NULL; + #endif ++#ifdef HAVE_LIBXVBA ++ xvba = NULL; ++#endif + } + + CLinuxRendererGL::YUVBUFFER::~YUVBUFFER() +@@ -604,6 +610,9 @@ void CLinuxRendererGL::ReleaseBuffer(int idx) + #ifdef HAVE_LIBVDPAU + SAFE_RELEASE(buf.vdpau); + #endif ++#ifdef HAVE_LIBXVBA ++ SAFE_RELEASE(buf.xvba); ++#endif + #ifdef HAVE_LIBVA + buf.vaapi.surface.reset(); + #endif +@@ -879,7 +888,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()) +@@ -965,6 +974,11 @@ void CLinuxRendererGL::LoadShaders(int field) + CLog::Log(LOGNOTICE, "GL: Using CVBREF render method"); + m_renderMethod = RENDER_CVREF; + } ++ else if (m_format == RENDER_FMT_XVBA) ++ { ++ CLog::Log(LOGNOTICE, "GL: Using XVBA render method"); ++ m_renderMethod = RENDER_XVBA; ++ } + else + { + int requestedMethod = g_guiSettings.GetInt("videoplayer.rendermethod"); +@@ -1113,6 +1127,12 @@ void CLinuxRendererGL::LoadShaders(int field) + m_textureCreate = &CLinuxRendererGL::CreateCVRefTexture; + m_textureDelete = &CLinuxRendererGL::DeleteCVRefTexture; + } ++ else if (m_format == RENDER_FMT_XVBA) ++ { ++ m_textureUpload = &CLinuxRendererGL::UploadXVBATexture; ++ m_textureCreate = &CLinuxRendererGL::CreateXVBATexture; ++ m_textureDelete = &CLinuxRendererGL::DeleteXVBATexture; ++ } + else + { + // setup default YV12 texture handlers +@@ -1225,6 +1245,13 @@ void CLinuxRendererGL::Render(DWORD flags, int renderBuffer) + RenderVAAPI(renderBuffer, m_currentField); + } + #endif ++#ifdef HAVE_LIBXVBA ++ else if (m_renderMethod & RENDER_XVBA) ++ { ++ UpdateVideoFilter(); ++ RenderXVBA(renderBuffer, m_currentField); ++ } ++#endif + else + { + // RENDER_CVREF uses the same render as the default case +@@ -1732,6 +1759,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[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) + { + // used for textues uploaded from rgba or CVPixelBuffers. +@@ -2783,6 +2881,93 @@ bool CLinuxRendererGL::CreateCVRefTexture(int index) + return true; + } + ++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]; +@@ -3368,6 +3553,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); +@@ -3381,6 +3569,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); +@@ -3404,7 +3595,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; + } + +@@ -3476,6 +3668,16 @@ bool CLinuxRendererGL::Supports(EINTERLACEMETHOD method) + 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. +@@ -3518,7 +3720,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 +@@ -3610,4 +3812,14 @@ void CLinuxRendererGL::AddProcessor(struct __CVBuffer *cvBufferRef, int index) + } + #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 --git a/xbmc/cores/VideoRenderers/LinuxRendererGL.h b/xbmc/cores/VideoRenderers/LinuxRendererGL.h +index 2fc34ae..e76624b 100644 +--- a/xbmc/cores/VideoRenderers/LinuxRendererGL.h ++++ b/xbmc/cores/VideoRenderers/LinuxRendererGL.h +@@ -43,6 +43,8 @@ + namespace Shaders { class BaseVideoFilterShader; } + namespace VAAPI { struct CHolder; } + namespace VDPAU { class CVdpauRenderPicture; } ++namespace XVBA { class CXvbaRenderPicture; } ++ + + #define NUM_BUFFERS 10 + +@@ -90,6 +92,7 @@ enum RenderMethod + RENDER_POT=0x10, + RENDER_VAAPI=0x20, + RENDER_CVREF = 0x40, ++ RENDER_XVBA=0x80, + }; + + enum RenderQuality +@@ -151,7 +154,9 @@ class CLinuxRendererGL : public CBaseRenderer + #ifdef TARGET_DARWIN + virtual void AddProcessor(struct __CVBuffer *cvBufferRef, 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 +@@ -210,6 +215,10 @@ class CLinuxRendererGL : public CBaseRenderer + 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); +@@ -225,6 +234,7 @@ class CLinuxRendererGL : public CBaseRenderer + void RenderVDPAU(int renderBuffer, int field); // render using vdpau hardware + void RenderProgressiveWeave(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 + + struct + { +@@ -292,6 +302,9 @@ class CLinuxRendererGL : public CBaseRenderer + #ifdef TARGET_DARWIN_OSX + struct __CVBuffer *cvBufferRef; + #endif ++#ifdef HAVE_LIBXVBA ++ XVBA::CXvbaRenderPicture *xvba; ++#endif + }; + + typedef YUVBUFFER YUVBUFFERS[NUM_BUFFERS]; +diff --git a/xbmc/cores/VideoRenderers/RenderFormats.h b/xbmc/cores/VideoRenderers/RenderFormats.h +index 0262c60..a727d94 100644 +--- a/xbmc/cores/VideoRenderers/RenderFormats.h ++++ b/xbmc/cores/VideoRenderers/RenderFormats.h +@@ -35,6 +35,7 @@ enum ERenderFormat { + RENDER_FMT_OMXEGL, + RENDER_FMT_CVBREF, + RENDER_FMT_BYPASS, ++ RENDER_FMT_XVBA, + }; + + #endif +diff --git a/xbmc/cores/VideoRenderers/RenderManager.cpp b/xbmc/cores/VideoRenderers/RenderManager.cpp +index a521680..0506823 100644 +--- a/xbmc/cores/VideoRenderers/RenderManager.cpp ++++ b/xbmc/cores/VideoRenderers/RenderManager.cpp +@@ -250,8 +250,9 @@ bool CXBMCRenderManager::Configure(unsigned int width, unsigned int height, unsi + + // check if decoder supports buffering + m_bCodecSupportsBuffering = false; +- if (format == RENDER_FMT_VDPAU || +- format == RENDER_FMT_VDPAU_420) ++ if (format == RENDER_FMT_VDPAU ++ || format == RENDER_FMT_VDPAU_420 ++ || format == RENDER_FMT_XVBA) + m_bCodecSupportsBuffering = true; + + bool result = m_pRenderer->Configure(width, height, d_width, d_height, fps, flags, format, extended_format, orientation); +@@ -873,6 +874,10 @@ int CXBMCRenderManager::AddVideoPicture(DVDVideoPicture& pic) + else if(pic.format == RENDER_FMT_VAAPI) + m_pRenderer->AddProcessor(*pic.vaapi, index); + #endif ++#ifdef HAVE_LIBXVBA ++ else if(pic.format == RENDER_FMT_XVBA) ++ m_pRenderer->AddProcessor(pic.xvba, index); ++#endif + m_pRenderer->ReleaseImage(index, false); + + return index; +diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodec.h b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodec.h +index 98d8f89..76d3575 100644 +--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodec.h ++++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodec.h +@@ -35,6 +35,7 @@ + namespace DXVA { class CSurfaceContext; } + namespace VAAPI { struct CHolder; } + namespace VDPAU { class CVdpauRenderPicture; } ++namespace XVBA { class CXvbaRenderPicture; } + class COpenMax; + class COpenMaxVideo; + struct OpenMaxVideoBuffer; +@@ -60,6 +61,9 @@ struct DVDVideoPicture + struct { + VAAPI::CHolder* vaapi; + }; ++ struct { ++ XVBA::CXvbaRenderPicture* xvba; ++ }; + + struct { + COpenMax *openMax; +diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp +index a6e42e5..b3252ec 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,19 @@ enum PixelFormat CDVDVideoCodecFFmpeg::GetFormat( struct AVCodecContext * avctx + 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->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 176ceff..c58422b 100644 +--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/Makefile.in ++++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/Makefile.in +@@ -14,6 +14,10 @@ ifeq (@USE_CRYSTALHD@,1) + SRCS += CrystalHD.cpp + SRCS += DVDVideoCodecCrystalHD.cpp + endif ++ifeq (@USE_XVBA@,1) ++SRCS+= XVBA.cpp \ ++ ++endif + ifeq (@USE_VDA@,1) + SRCS += DVDVideoCodecVDA.cpp + endif +diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/XVBA.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/XVBA.cpp +new file mode 100644 +index 0000000..e8e376a +--- /dev/null ++++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/XVBA.cpp +@@ -0,0 +1,2354 @@ ++/* ++ * 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 "system_gl.h" ++#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; ++ 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"); ++ DestroySession(true); ++ } ++ return 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() ++{ ++ 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(bool precleanup /*= false*/) ++{ ++ // wait for unfinished decoding jobs ++ XbmcThreads::EndTime timer; ++ if (m_xvbaConfig.xvbaSession) ++ { ++ for (unsigned int i = 0; i < m_videoSurfaces.size(); ++i) ++ { ++ xvba_render_state *render = m_videoSurfaces[i]; ++ if (render->surface) ++ { ++ XVBA_Surface_Sync_Input syncInput; ++ XVBA_Surface_Sync_Output syncOutput; ++ syncInput.size = sizeof(syncInput); ++ syncInput.session = m_xvbaConfig.xvbaSession; ++ syncInput.surface = render->surface; ++ syncInput.query_status = XVBA_GET_SURFACE_STATUS; ++ syncOutput.size = sizeof(syncOutput); ++ timer.Set(1000); ++ while(!timer.IsTimePast()) ++ { ++ if (Success != g_XVBA_vtable.SyncSurface(&syncInput, &syncOutput)) ++ { ++ CLog::Log(LOGERROR,"XVBA::DestroySession - failed sync surface"); ++ break; ++ } ++ if (!(syncOutput.status_flags & XVBA_STILL_PENDING)) ++ break; ++ Sleep(10); ++ } ++ if (timer.IsTimePast()) ++ CLog::Log(LOGERROR,"XVBA::DestroySession - unfinished decoding job"); ++ } ++ } ++ } ++ ++ if (precleanup) ++ { ++ 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; ++ } ++ } ++ else ++ m_xvbaOutput.Dispose(); ++ ++ XVBA_Destroy_Decode_Buffers_Input bufInput; ++ bufInput.size = sizeof(bufInput); ++ bufInput.num_of_buffers_in_list = 1; ++ bufInput.session = m_xvbaConfig.xvbaSession; ++ ++ for (unsigned int i=0; isurface) ++ { ++ g_XVBA_vtable.DestroySurface(render->surface); ++ render->surface = 0; ++ render->state = 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(); ++ ++ 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; ++ ++ 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_NO_POSTPROC); ++ } ++ ++ 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::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_UNCONFIGURED; ++ m_extTimeout = 10000; ++ Flush(); ++ ReleaseBufferPool(true); ++ 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; ++ m_fence = None; ++ ++ 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; ++} ++ ++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 (m_fence) ++// glDeleteSync(m_fence); ++// m_fence = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0); ++ ++ // 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; ++ } ++ } ++ ++ // 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; ++ } ++ ++ xvba_render_state *render = m_bufferPool.glSurfaces[pic->sourceIdx].render; ++ if (render) ++ { ++ // check if video surface is 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 = RENDER_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(bool precleanup /*= false*/) ++{ ++// if (m_fence) ++// { ++// uint64_t maxTimeout = 1000000000LL; ++// glClientWaitSync(m_fence, GL_SYNC_FLUSH_COMMANDS_BIT, maxTimeout); ++// glDeleteSync(m_fence); ++// m_fence = None; ++// } ++ ++ CSingleLock lock(m_bufferPool.renderPicSec); ++ ++ for (unsigned int i = 0; i < m_bufferPool.glSurfaces.size(); ++i) ++ { ++ if (m_bufferPool.glSurfaces[i].glSurface) ++ { ++ g_XVBA_vtable.DestroySurface(m_bufferPool.glSurfaces[i].glSurface); ++ m_bufferPool.glSurfaces[i].glSurface = 0; ++ } ++ if (m_bufferPool.glSurfaces[i].texture && !precleanup) ++ { ++ glDeleteTextures(1, &m_bufferPool.glSurfaces[i].texture); ++ m_bufferPool.glSurfaces[i].texture = 0; ++ } ++ m_bufferPool.glSurfaces[i].render = 0; ++ m_bufferPool.glSurfaces[i].used = true; ++ } ++ ++ if (!precleanup) ++ { ++ 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; ++ } ++ } ++} ++ ++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; ++ ++ m_Display = g_Windowing.GetDisplay(); ++ glContext = g_Windowing.GetGlxContext(); ++ m_Window = g_Windowing.GetWindow(); ++ ++ // 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, ++ m_Window, ++ 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 --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/XVBA.h b/xbmc/cores/dvdplayer/DVDCodecs/Video/XVBA.h +new file mode 100644 +index 0000000..f38444c +--- /dev/null ++++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/XVBA.h +@@ -0,0 +1,382 @@ ++/* ++ * 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 ++ ++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(); ++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(); ++ 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(bool precleanup = false); ++ 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; ++ GLsync m_fence; ++ 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 precleanup = false); ++ 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; ++ ++ COutput m_xvbaOutput; ++ CXvbaBufferStats m_bufferStats; ++ CEvent m_inMsgEvent; ++ CXvbaRenderPicture *m_presentPicture; ++ ++ int m_speed; ++ int m_codecControl; ++}; ++ ++} +diff --git a/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp b/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp +index 15a39fa..e5e71f3 100644 +--- a/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp ++++ b/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp +@@ -1162,6 +1162,9 @@ int CDVDPlayerVideo::OutputPicture(const DVDVideoPicture* src, double pts) + case RENDER_FMT_NONE: + formatstr = "NONE"; + break; ++ case RENDER_FMT_XVBA: ++ formatstr = "XVBA"; ++ break; + } + + if(m_bAllowFullscreen) +diff --git a/xbmc/settings/GUISettings.cpp b/xbmc/settings/GUISettings.cpp +index 0e320e1..10ef779 100644 +--- a/xbmc/settings/GUISettings.cpp ++++ b/xbmc/settings/GUISettings.cpp +@@ -696,6 +696,9 @@ void CGUISettings::Initialize() + #ifdef HAVE_LIBVA + AddBool(vp, "videoplayer.usevaapi", 13426, true); + #endif ++#ifdef HAVE_LIBXVBA ++ AddBool(vp, "videoplayer.usexvba", 13437, 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/VideoSettings.h b/xbmc/settings/VideoSettings.h +index f8093b2..f54a837 100644 +--- a/xbmc/settings/VideoSettings.h ++++ b/xbmc/settings/VideoSettings.h +@@ -65,6 +65,8 @@ enum EINTERLACEMETHOD + VS_INTERLACEMETHOD_SW_BLEND = 20, + VS_INTERLACEMETHOD_AUTO_ION = 21, + ++ VS_INTERLACEMETHOD_XVBA = 22, ++ + VS_INTERLACEMETHOD_MAX // do not use and keep as last enum value. + }; + +diff --git a/xbmc/video/dialogs/GUIDialogVideoSettings.cpp b/xbmc/video/dialogs/GUIDialogVideoSettings.cpp +index f25d10d..f6b1ea4 100644 +--- a/xbmc/video/dialogs/GUIDialogVideoSettings.cpp ++++ b/xbmc/video/dialogs/GUIDialogVideoSettings.cpp +@@ -110,6 +110,7 @@ void CGUIDialogVideoSettings::CreateSettings() + 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_AUTO_ION , 16325)); ++ entries.push_back(make_pair(VS_INTERLACEMETHOD_XVBA , 16326)); + + /* remove unsupported methods */ + for(vector >::iterator it = entries.begin(); it != entries.end();) +-- +1.7.10 + + +From 517eda0bf58a6376a82839ab92e51b97c143edf1 Mon Sep 17 00:00:00 2001 +From: xbmc +Date: Thu, 23 Aug 2012 19:39:49 +0200 +Subject: [PATCH 43/73] ffmpeg: add av_find_default_stream_index to interface + +--- + lib/DllAvFormat.h | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/lib/DllAvFormat.h b/lib/DllAvFormat.h +index 9bda3f3..bf31fcb 100644 +--- a/lib/DllAvFormat.h ++++ b/lib/DllAvFormat.h +@@ -98,6 +98,7 @@ class DllAvFormatInterface + virtual int avformat_write_header (AVFormatContext *s, AVDictionary **options)=0; + virtual int av_write_trailer(AVFormatContext *s)=0; + virtual int av_write_frame (AVFormatContext *s, AVPacket *pkt)=0; ++ virtual int av_find_default_stream_index(AVFormatContext *s)=0; + }; + + #if (defined USE_EXTERNAL_FFMPEG) || (defined TARGET_DARWIN) +@@ -153,6 +154,7 @@ class DllAvFormat : public DllDynamic, DllAvFormatInterface + virtual int avformat_write_header (AVFormatContext *s, AVDictionary **options) { return ::avformat_write_header (s, options); } + virtual int av_write_trailer(AVFormatContext *s) { return ::av_write_trailer(s); } + virtual int av_write_frame (AVFormatContext *s, AVPacket *pkt) { return ::av_write_frame(s, pkt); } ++ virtual int av_find_default_stream_index(AVFormatContext *s) { return ::av_find_default_stream_index(s); } + + // DLL faking. + virtual bool ResolveExports() { return true; } +@@ -209,6 +211,7 @@ class DllAvFormat : public DllDynamic, DllAvFormatInterface + DEFINE_METHOD2(int, avformat_write_header , (AVFormatContext *p1, AVDictionary **p2)) + DEFINE_METHOD1(int, av_write_trailer, (AVFormatContext *p1)) + DEFINE_METHOD2(int, av_write_frame , (AVFormatContext *p1, AVPacket *p2)) ++ DEFINE_METHOD1(int, av_find_default_stream_index, (AVFormatContext *p1)) + BEGIN_METHOD_RESOLVE() + RESOLVE_METHOD_RENAME(av_register_all, av_register_all_dont_call) + RESOLVE_METHOD(av_find_input_format) +@@ -243,6 +246,7 @@ class DllAvFormat : public DllDynamic, DllAvFormatInterface + RESOLVE_METHOD(avformat_write_header) + RESOLVE_METHOD(av_write_trailer) + RESOLVE_METHOD(av_write_frame) ++ RESOLVE_METHOD(av_find_default_stream_index) + END_METHOD_RESOLVE() + + /* dependencies of libavformat */ +-- +1.7.10 + + +From 23be471842ae9ea7bd62c18261a5e96a11045d04 Mon Sep 17 00:00:00 2001 +From: xbmc +Date: Mon, 20 Aug 2012 16:06:39 +0200 +Subject: [PATCH 44/73] dvdplayer: observe pts counter overflow + +--- + .../cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.cpp | 198 +++++++++++++++++++- + xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.h | 4 + + 2 files changed, 201 insertions(+), 1 deletion(-) + +diff --git a/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.cpp b/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.cpp +index 7c0ab03..f91be3c 100644 +--- a/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.cpp ++++ b/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.cpp +@@ -18,13 +18,13 @@ + * + */ + +-#include "system.h" + #ifndef __STDC_CONSTANT_MACROS + #define __STDC_CONSTANT_MACROS + #endif + #ifndef __STDC_LIMIT_MACROS + #define __STDC_LIMIT_MACROS + #endif ++#include "system.h" + #ifdef _LINUX + #include "stdint.h" + #endif +@@ -495,6 +495,9 @@ bool CDVDDemuxFFmpeg::Open(CDVDInputStream* pInput) + AddStream(i); + } + ++ m_bPtsWrapChecked = false; ++ m_bPtsWrap = false; ++ + return true; + } + +@@ -605,6 +608,12 @@ double CDVDDemuxFFmpeg::ConvertTimestamp(int64_t pts, int den, int num) + if (pts == (int64_t)AV_NOPTS_VALUE) + return DVD_NOPTS_VALUE; + ++ if (m_bPtsWrap) ++ { ++ if (pts < m_iStartTime && pts < m_iEndTime) ++ pts += m_iMaxTime; ++ } ++ + // do calculations in floats as they can easily overflow otherwise + // we don't care for having a completly exact timestamp anyway + double timestamp = (double)pts * num / den; +@@ -729,6 +738,24 @@ DemuxPacket* CDVDDemuxFFmpeg::Read() + pkt.pts = AV_NOPTS_VALUE; + } + ++ if (!m_bPtsWrapChecked && m_pFormatContext->iformat->flags & AVFMT_TS_DISCONT) ++ { ++ int defaultStream = m_dllAvFormat.av_find_default_stream_index(m_pFormatContext); ++ int64_t duration = m_pFormatContext->streams[defaultStream]->duration * 1.5; ++ m_iMaxTime = 1LL<streams[defaultStream]->pts_wrap_bits; ++ m_iStartTime = m_pFormatContext->streams[defaultStream]->start_time; ++ if (m_iStartTime != DVD_NOPTS_VALUE) ++ { ++ m_iEndTime = (m_iStartTime + duration) & ~m_iMaxTime; ++ if (m_iEndTime < m_iStartTime) ++ { ++ CLog::Log(LOGNOTICE,"CDVDDemuxFFmpeg::Read - file contains pts overflow"); ++ m_bPtsWrap = true; ++ } ++ } ++ m_bPtsWrapChecked = true; ++ } ++ + // copy contents into our own packet + pPacket->iSize = pkt.size; + +@@ -845,10 +872,20 @@ bool CDVDDemuxFFmpeg::SeekTime(int time, bool backwords, double *startpts) + int ret; + { + CSingleLock lock(m_critSection); ++ + ret = m_dllAvFormat.av_seek_frame(m_pFormatContext, -1, seek_pts, backwords ? AVSEEK_FLAG_BACKWARD : 0); + + if(ret >= 0) ++ { + UpdateCurrentPTS(); ++ ++ // seek may fail silently on streams which allow discontinuity ++ // if current timestamp is way off asume a pts overflow and try bisect seek ++ if (m_bPtsWrap && fabs(time - m_iCurrentPts/1000) > 10000) ++ { ++ ret = SeekTimeDiscont(seek_pts, backwords) ? 1 : -1; ++ } ++ } + } + + if(m_iCurrentPts == DVD_NOPTS_VALUE) +@@ -867,6 +904,165 @@ bool CDVDDemuxFFmpeg::SeekTime(int time, bool backwords, double *startpts) + return (ret >= 0); + } + ++bool CDVDDemuxFFmpeg::SeekTimeDiscont(int64_t pts, bool backwards) ++{ ++ // this code is taken from ffmpeg function ff_gen_search ++ // it is modified to assume a pts overflow if timestamp < start_time ++ if (!m_pFormatContext->iformat->read_timestamp) ++ return false; ++ ++ int defaultStream = m_dllAvFormat.av_find_default_stream_index(m_pFormatContext); ++ ++ if (defaultStream < 0) ++ { ++ return false; ++ } ++ ++ // timestamp for default must be expressed in AV_TIME_BASE units ++ pts = m_dllAvUtil.av_rescale_rnd(pts, m_pFormatContext->streams[defaultStream]->time_base.den, ++ AV_TIME_BASE * (int64_t)m_pFormatContext->streams[defaultStream]->time_base.num, ++ AV_ROUND_NEAR_INF); ++ ++ int64_t pos, pos_min, pos_max, pos_limit, ts, ts_min, ts_max; ++ int64_t start_pos, filesize; ++ int no_change; ++ ++ pos_min = m_pFormatContext->data_offset; ++ ts_min = m_pFormatContext->iformat->read_timestamp(m_pFormatContext, defaultStream, ++ &pos_min, INT64_MAX); ++ if (ts_min == AV_NOPTS_VALUE) ++ return false; ++ ++ if(ts_min >= pts) ++ { ++ pos = pos_min; ++ return true; ++ } ++ ++ int step= 1024; ++ filesize = m_pInput->GetLength(); ++ pos_max = filesize - 1; ++ do ++ { ++ pos_max -= step; ++ ts_max = m_pFormatContext->iformat->read_timestamp(m_pFormatContext, defaultStream, ++ &pos_max, pos_max + step); ++ step += step; ++ }while (ts_max == AV_NOPTS_VALUE && pos_max >= step); ++ ++ if (ts_max == AV_NOPTS_VALUE) ++ return false; ++ ++ if (ts_max < m_iStartTime && ts_max < m_iEndTime) ++ ts_max += m_iMaxTime; ++ ++ for(;;) ++ { ++ int64_t tmp_pos = pos_max + 1; ++ int64_t tmp_ts = m_pFormatContext->iformat->read_timestamp(m_pFormatContext, defaultStream, ++ &tmp_pos, INT64_MAX); ++ if(tmp_ts == AV_NOPTS_VALUE) ++ break; ++ ++ if (tmp_ts < m_iStartTime && tmp_ts < m_iEndTime) ++ tmp_ts += m_iMaxTime; ++ ++ ts_max = tmp_ts; ++ pos_max = tmp_pos; ++ if (tmp_pos >= filesize) ++ break; ++ } ++ pos_limit = pos_max; ++ ++ if(ts_max <= pts) ++ { ++ bool ret = SeekByte(pos_max); ++ if (ret) ++ { ++ m_iCurrentPts = ConvertTimestamp(ts_max, m_pFormatContext->streams[defaultStream]->time_base.den, ++ m_pFormatContext->streams[defaultStream]->time_base.num); ++ } ++ return ret; ++ } ++ ++ if(ts_min > ts_max) ++ { ++ return false; ++ } ++ else if (ts_min == ts_max) ++ { ++ pos_limit = pos_min; ++ } ++ ++ no_change=0; ++ while (pos_min < pos_limit) ++ { ++ if (no_change == 0) ++ { ++ int64_t approximate_keyframe_distance= pos_max - pos_limit; ++ // interpolate position (better than dichotomy) ++ pos = m_dllAvUtil.av_rescale_rnd(pts - ts_min, pos_max - pos_min, ++ ts_max - ts_min, AV_ROUND_NEAR_INF) ++ + pos_min - approximate_keyframe_distance; ++ } ++ else if (no_change == 1) ++ { ++ // bisection, if interpolation failed to change min or max pos last time ++ pos = (pos_min + pos_limit) >> 1; ++ } ++ else ++ { ++ /* linear search if bisection failed, can only happen if there ++ are very few or no keyframes between min/max */ ++ pos = pos_min; ++ } ++ if (pos <= pos_min) ++ pos= pos_min + 1; ++ else if (pos > pos_limit) ++ pos= pos_limit; ++ start_pos = pos; ++ ++ ts = m_pFormatContext->iformat->read_timestamp(m_pFormatContext, defaultStream, ++ &pos, INT64_MAX); ++ if (pos == pos_max) ++ no_change++; ++ else ++ no_change=0; ++ ++ if (ts == AV_NOPTS_VALUE) ++ { ++ return false; ++ } ++ ++ if (ts < m_iStartTime && ts < m_iEndTime) ++ ts += m_iMaxTime; ++ ++ if (pts <= ts) ++ { ++ pos_limit = start_pos - 1; ++ pos_max = pos; ++ ts_max = ts; ++ } ++ if (pts >= ts) ++ { ++ pos_min = pos; ++ ts_min = ts; ++ } ++ } ++ ++ pos = (backwards) ? pos_min : pos_max; ++ ts = (backwards) ? ts_min : ts_max; ++ ++ bool ret = SeekByte(pos); ++ if (ret) ++ { ++ m_iCurrentPts = ConvertTimestamp(ts, m_pFormatContext->streams[defaultStream]->time_base.den, ++ m_pFormatContext->streams[defaultStream]->time_base.num); ++ } ++ ++ return ret; ++} ++ + bool CDVDDemuxFFmpeg::SeekByte(int64_t pos) + { + g_demuxer.set(this); +diff --git a/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.h b/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.h +index 2b5f2e8..e0acf29 100644 +--- a/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.h ++++ b/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.h +@@ -97,6 +97,7 @@ class CDVDDemuxFFmpeg : public CDVDDemux + DemuxPacket* Read(); + + bool SeekTime(int time, bool backwords = false, double* startpts = NULL); ++ bool SeekTimeDiscont(int64_t pts, bool backwards); + bool SeekByte(int64_t pos); + int GetStreamLength(); + CDemuxStream* GetStream(int iStreamId); +@@ -141,5 +142,8 @@ class CDVDDemuxFFmpeg : public CDVDDemux + XbmcThreads::EndTime m_timeout; + + CDVDInputStream* m_pInput; ++ ++ bool m_bPtsWrap, m_bPtsWrapChecked; ++ int64_t m_iStartTime, m_iMaxTime, m_iEndTime; + }; + +-- +1.7.10 + + +From 66382788a903f99ba317e972ba0445fc68320750 Mon Sep 17 00:00:00 2001 +From: xbmc +Date: Tue, 2 Oct 2012 13:02:10 +0200 +Subject: [PATCH 45/73] dvdplayer: avoid short screen flicker caused by + unnecessary reconfigure of renderer + +--- + xbmc/cores/dvdplayer/DVDPlayerVideo.cpp | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp b/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp +index e5e71f3..8b02d81 100644 +--- a/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp ++++ b/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp +@@ -1033,7 +1033,7 @@ int CDVDPlayerVideo::OutputPicture(const DVDVideoPicture* src, double pts) + || m_output.height != pPicture->iHeight + || m_output.dwidth != pPicture->iDisplayWidth + || m_output.dheight != pPicture->iDisplayHeight +- || m_output.framerate != config_framerate ++ || (!m_bFpsInvalid && fmod(m_output.framerate, config_framerate) != 0.0 ) + || m_output.color_format != (unsigned int)pPicture->format + || m_output.extended_format != pPicture->extended_format + || ( m_output.color_matrix != pPicture->color_matrix && pPicture->color_matrix != 0 ) // don't reconfigure on unspecified +@@ -1184,7 +1184,7 @@ int CDVDPlayerVideo::OutputPicture(const DVDVideoPicture* src, double pts) + m_output.height = pPicture->iHeight; + m_output.dwidth = pPicture->iDisplayWidth; + m_output.dheight = pPicture->iDisplayHeight; +- m_output.framerate = config_framerate; ++ m_output.framerate = config_framerate == 0.0 ? g_graphicsContext.GetFPS() : config_framerate; + m_output.color_format = pPicture->format; + m_output.extended_format = pPicture->extended_format; + m_output.color_matrix = pPicture->color_matrix; +-- +1.7.10 + + +From 04f4521c1938a7ac17acd59f3bd6be59c7ba8184 Mon Sep 17 00:00:00 2001 +From: xbmc +Date: Sat, 16 Jun 2012 12:46:30 +0200 +Subject: [PATCH 46/73] xvba: do not use vaapi if xvba is present + +--- + xbmc/cores/dvdplayer/DVDCodecs/Video/VAAPI.cpp | 9 +++++++++ + 1 file changed, 9 insertions(+) + +diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/VAAPI.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/VAAPI.cpp +index a2b9195..43a05b3 100644 +--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/VAAPI.cpp ++++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/VAAPI.cpp +@@ -261,6 +261,15 @@ void CDecoder::Close() + + bool CDecoder::Open(AVCodecContext *avctx, enum PixelFormat fmt, unsigned int surfaces) + { ++#ifdef HAVE_LIBXVBA ++ std::string Vendor = g_Windowing.GetRenderVendor(); ++ std::transform(Vendor.begin(), Vendor.end(), Vendor.begin(), ::tolower); ++ if (Vendor.compare(0, 3, "ati") == 0) ++ { ++ return false; ++ } ++#endif ++ + VAEntrypoint entrypoint = VAEntrypointVLD; + VAProfile profile; + +-- +1.7.10 + + +From a133b7fa119e859ec50b9f05a33de984105234f3 Mon Sep 17 00:00:00 2001 +From: xbmc +Date: Thu, 11 Oct 2012 12:05:50 +0200 +Subject: [PATCH 47/73] vdpau: advanced settings for auto deinterlacing + +--- + xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp | 8 ++++---- + xbmc/settings/AdvancedSettings.cpp | 4 ++++ + xbmc/settings/AdvancedSettings.h | 2 ++ + 3 files changed, 10 insertions(+), 4 deletions(-) + +diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp +index 235f565..d95797b 100644 +--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp ++++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp +@@ -1770,10 +1770,10 @@ EINTERLACEMETHOD CMixer::GetDeinterlacingMethod(bool log /* = false */) + 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 (m_config.outHeight >= 720) ++ deint = g_advancedSettings.m_videoVDPAUdeintHD; ++ else ++ deint = g_advancedSettings.m_videoVDPAUdeintSD; + + if (deint != -1) + { +diff --git a/xbmc/settings/AdvancedSettings.cpp b/xbmc/settings/AdvancedSettings.cpp +index 844f8e8..d913924 100644 +--- a/xbmc/settings/AdvancedSettings.cpp ++++ b/xbmc/settings/AdvancedSettings.cpp +@@ -106,6 +106,8 @@ void CAdvancedSettings::Initialize() + m_videoAllowMpeg4VAAPI = false; + m_videoDisableBackgroundDeinterlace = false; + m_videoCaptureUseOcclusionQuery = -1; //-1 is auto detect ++ m_videoVDPAUdeintHD = -1; ++ m_videoVDPAUdeintSD = -1; + m_videoVDPAUtelecine = false; + m_videoVDPAUdeintSkipChromaHD = false; + m_DXVACheckCompatibility = false; +@@ -503,6 +505,8 @@ void CAdvancedSettings::ParseSettingsFile(const CStdString &file) + 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::GetBoolean(pElement,"vdpauInvTelecine",m_videoVDPAUtelecine); + XMLUtils::GetBoolean(pElement,"vdpauHDdeintSkipChroma",m_videoVDPAUdeintSkipChromaHD); + +diff --git a/xbmc/settings/AdvancedSettings.h b/xbmc/settings/AdvancedSettings.h +index 72718e5..aaa4702 100644 +--- a/xbmc/settings/AdvancedSettings.h ++++ b/xbmc/settings/AdvancedSettings.h +@@ -133,6 +133,8 @@ class CAdvancedSettings + int m_videoPercentSeekBackwardBig; + CStdString m_videoPPFFmpegDeint; + CStdString m_videoPPFFmpegPostProc; ++ int m_videoVDPAUdeintHD; ++ int m_videoVDPAUdeintSD; + bool m_videoVDPAUtelecine; + bool m_videoVDPAUdeintSkipChromaHD; + bool m_musicUseTimeSeeking; +-- +1.7.10 + + +From 62540aeaa356823bd34e9367ac39eef23a6e4ce4 Mon Sep 17 00:00:00 2001 +From: xbmc +Date: Thu, 11 Oct 2012 13:01:08 +0200 +Subject: [PATCH 48/73] dvdplayer: correct determination if video is playing + +--- + xbmc/cores/dvdplayer/DVDPlayer.cpp | 11 +++++++++-- + 1 file changed, 9 insertions(+), 2 deletions(-) + +diff --git a/xbmc/cores/dvdplayer/DVDPlayer.cpp b/xbmc/cores/dvdplayer/DVDPlayer.cpp +index 6fcb6b3..f76691d 100644 +--- a/xbmc/cores/dvdplayer/DVDPlayer.cpp ++++ b/xbmc/cores/dvdplayer/DVDPlayer.cpp +@@ -2382,9 +2382,16 @@ bool CDVDPlayer::IsPaused() const + + bool CDVDPlayer::HasVideo() const + { +- if (m_pInputStream && m_pInputStream->IsStreamType(DVDSTREAM_TYPE_DVD)) return true; ++ bool hasVideo(false); + +- return m_SelectionStreams.Count(STREAM_VIDEO) > 0 ? true : false; ++ if (m_pInputStream && m_pInputStream->IsStreamType(DVDSTREAM_TYPE_DVD)) ++ hasVideo = true; ++ else if (m_SelectionStreams.Count(STREAM_VIDEO) > 0) ++ hasVideo = true; ++ else if (g_renderManager.IsConfigured()) ++ hasVideo = true; ++ ++ return hasVideo; + } + + bool CDVDPlayer::HasAudio() const +-- +1.7.10 + + +From 5a093bbd60d1ca47ed7c5e4639f28dafc1b565c1 Mon Sep 17 00:00:00 2001 +From: xbmc +Date: Sun, 14 Oct 2012 13:46:54 +0200 +Subject: [PATCH 49/73] rendermanager: fix stuttering in non full-screen mode, + squash to add buffering + +--- + xbmc/cores/VideoRenderers/RenderManager.cpp | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/xbmc/cores/VideoRenderers/RenderManager.cpp b/xbmc/cores/VideoRenderers/RenderManager.cpp +index 0506823..b141c80 100644 +--- a/xbmc/cores/VideoRenderers/RenderManager.cpp ++++ b/xbmc/cores/VideoRenderers/RenderManager.cpp +@@ -1057,8 +1057,9 @@ void CXBMCRenderManager::PrepareNextRender() + presenttime = clocktime + MAXPRESENTDELAY; + + m_sleeptime = presenttime - clocktime; ++ double frametime = 1 / g_graphicsContext.GetFPS(); + +- if (g_graphicsContext.IsFullScreenVideo() || presenttime <= clocktime+0.01) ++ if (g_graphicsContext.IsFullScreenVideo() || presenttime <= clocktime + frametime) + { + m_presentPts = m_renderBuffers[idx].pts; + m_presenttime = presenttime; +-- +1.7.10 + + +From d0597caa2c922575efdf081d719d5665c626ffec Mon Sep 17 00:00:00 2001 +From: xbmc +Date: Sun, 14 Oct 2012 17:54:02 +0200 +Subject: [PATCH 50/73] rendermanager: forgot to set flip event if buffering + is not used + +--- + xbmc/cores/VideoRenderers/RenderManager.cpp | 20 ++++++++++---------- + 1 file changed, 10 insertions(+), 10 deletions(-) + +diff --git a/xbmc/cores/VideoRenderers/RenderManager.cpp b/xbmc/cores/VideoRenderers/RenderManager.cpp +index b141c80..9290f80 100644 +--- a/xbmc/cores/VideoRenderers/RenderManager.cpp ++++ b/xbmc/cores/VideoRenderers/RenderManager.cpp +@@ -1096,17 +1096,17 @@ void CXBMCRenderManager::NotifyDisplayFlip() + if (!m_pRenderer) + return; + +- if (m_iNumRenderBuffers < 3) +- return; +- +- int last = m_iDisplayedRenderBuffer; +- m_iDisplayedRenderBuffer = (m_iCurrentRenderBuffer + m_iNumRenderBuffers - 1) % m_iNumRenderBuffers; +- +- if (last != m_iDisplayedRenderBuffer +- && m_iDisplayedRenderBuffer != m_iCurrentRenderBuffer) ++ if (m_iNumRenderBuffers >= 3) + { +- m_pRenderer->ReleaseBuffer(m_iDisplayedRenderBuffer); +- m_overlays.ReleaseBuffer(m_iDisplayedRenderBuffer); ++ int last = m_iDisplayedRenderBuffer; ++ m_iDisplayedRenderBuffer = (m_iCurrentRenderBuffer + m_iNumRenderBuffers - 1) % m_iNumRenderBuffers; ++ ++ if (last != m_iDisplayedRenderBuffer ++ && m_iDisplayedRenderBuffer != m_iCurrentRenderBuffer) ++ { ++ m_pRenderer->ReleaseBuffer(m_iDisplayedRenderBuffer); ++ m_overlays.ReleaseBuffer(m_iDisplayedRenderBuffer); ++ } + } + + lock.Leave(); +-- +1.7.10 + + +From c485392afa608bfbcf903fa53a9dd824258c96dd Mon Sep 17 00:00:00 2001 +From: xbmc +Date: Fri, 26 Oct 2012 15:30:22 +0200 +Subject: [PATCH 51/73] vdpau: fix small mem leak + +--- + xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp +index d95797b..fec4b88 100644 +--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp ++++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp +@@ -2052,6 +2052,8 @@ void CMixer::Uninit() + m_outputSurfaces.pop(); + } + m_config.vdpProcs.vdp_video_mixer_destroy(m_videoMixer); ++ ++ delete [] m_BlackBar; + } + + void CMixer::Flush() +-- +1.7.10 + + +From 9d7228a84013e409149d7b05d34545d1bdf06e27 Mon Sep 17 00:00:00 2001 +From: xbmc +Date: Mon, 29 Oct 2012 18:25:56 +0100 +Subject: [PATCH 52/73] xvba: do not render if there is no valid texture + +--- + xbmc/cores/VideoRenderers/LinuxRendererGL.cpp | 8 +++----- + 1 file changed, 3 insertions(+), 5 deletions(-) + +diff --git a/xbmc/cores/VideoRenderers/LinuxRendererGL.cpp b/xbmc/cores/VideoRenderers/LinuxRendererGL.cpp +index ec3606a..7c3adcb 100644 +--- a/xbmc/cores/VideoRenderers/LinuxRendererGL.cpp ++++ b/xbmc/cores/VideoRenderers/LinuxRendererGL.cpp +@@ -2924,16 +2924,14 @@ void CLinuxRendererGL::UploadXVBATexture(int index) + YUVFIELDS &fields = m_buffers[index].fields; + YUVPLANE &plane = fields[0][1]; + +- if (!xvba) ++ if (!xvba || !xvba->valid) + { +- fields[0][1].id = fields[0][0].id; + m_eventTexturesDone[index]->Set(); +- CLog::Log(LOGWARNING,"CLinuxRendererGL::UploadXVBATexture no xvba texture, index: %d", index); ++ m_skipRender = true; + return; + } +-// xvba->Transfer(); + +- fields[0][1].id = xvba->texture; ++ plane.id = xvba->texture; + + im.height = xvba->texHeight; + im.width = xvba->texWidth; +-- +1.7.10 + + +From 85be082db41b27cdd3824b8360dc021e17a84c22 Mon Sep 17 00:00:00 2001 +From: xbmc +Date: Fri, 2 Nov 2012 13:20:03 +0100 +Subject: [PATCH 53/73] player: fix rewind + +--- + xbmc/cores/dvdplayer/DVDMessage.h | 5 ++++- + xbmc/cores/dvdplayer/DVDPlayer.cpp | 33 ++++++++++++++++++++----------- + xbmc/cores/dvdplayer/DVDPlayer.h | 7 ++++--- + xbmc/cores/dvdplayer/DVDPlayerVideo.cpp | 10 ++++++---- + xbmc/cores/dvdplayer/DVDPlayerVideo.h | 1 + + 5 files changed, 36 insertions(+), 20 deletions(-) + +diff --git a/xbmc/cores/dvdplayer/DVDMessage.h b/xbmc/cores/dvdplayer/DVDMessage.h +index 30b2f5c..b9831d4 100644 +--- a/xbmc/cores/dvdplayer/DVDMessage.h ++++ b/xbmc/cores/dvdplayer/DVDMessage.h +@@ -218,7 +218,7 @@ class CDVDMsgPlayerSetState : public CDVDMsg + class CDVDMsgPlayerSeek : public CDVDMsg + { + public: +- CDVDMsgPlayerSeek(int time, bool backward, bool flush = true, bool accurate = true, bool restore = true, bool trickplay = false) ++ CDVDMsgPlayerSeek(int time, bool backward, bool flush = true, bool accurate = true, bool restore = true, bool trickplay = false, bool sync = true) + : CDVDMsg(PLAYER_SEEK) + , m_time(time) + , m_backward(backward) +@@ -226,6 +226,7 @@ class CDVDMsgPlayerSeek : public CDVDMsg + , m_accurate(accurate) + , m_restore(restore) + , m_trickplay(trickplay) ++ , m_sync(sync) + {} + int GetTime() { return m_time; } + bool GetBackward() { return m_backward; } +@@ -233,6 +234,7 @@ class CDVDMsgPlayerSeek : public CDVDMsg + bool GetAccurate() { return m_accurate; } + bool GetRestore() { return m_restore; } + bool GetTrickPlay() { return m_trickplay; } ++ bool GetSync() { return m_sync; } + private: + int m_time; + bool m_backward; +@@ -240,6 +242,7 @@ class CDVDMsgPlayerSeek : public CDVDMsg + bool m_accurate; + bool m_restore; // whether to restore any EDL cut time + bool m_trickplay; ++ bool m_sync; + }; + + class CDVDMsgPlayerSeekChapter : public CDVDMsg +diff --git a/xbmc/cores/dvdplayer/DVDPlayer.cpp b/xbmc/cores/dvdplayer/DVDPlayer.cpp +index f76691d..07df0d8 100644 +--- a/xbmc/cores/dvdplayer/DVDPlayer.cpp ++++ b/xbmc/cores/dvdplayer/DVDPlayer.cpp +@@ -1543,11 +1543,13 @@ void CDVDPlayer::HandlePlaySpeed() + } + else if (m_CurrentVideo.id >= 0 + && (m_CurrentVideo.inited == true || GetPlaySpeed() < 0) // allow rewind at end of file +- && m_SpeedState.lastpts != m_dvdPlayerVideo.GetCurrentPts() ++ && (m_SpeedState.lastpts != m_dvdPlayerVideo.GetCurrentPts() || fabs(m_SpeedState.lastabstime - CDVDClock::GetAbsoluteClock()) > DVD_MSEC_TO_TIME(200)) ++ && (m_dvdPlayerVideo.GetCurrentPts() != DVD_NOPTS_VALUE) + && m_SpeedState.lasttime != GetTime()) + { + m_SpeedState.lastpts = m_dvdPlayerVideo.GetCurrentPts(); + m_SpeedState.lasttime = GetTime(); ++ m_SpeedState.lastabstime = CDVDClock::GetAbsoluteClock(); + // check how much off clock video is when ff/rw:ing + // a problem here is that seeking isn't very accurate + // and since the clock will be resynced after seek +@@ -1566,7 +1568,7 @@ void CDVDPlayer::HandlePlaySpeed() + { + CLog::Log(LOGDEBUG, "CDVDPlayer::Process - Seeking to catch up"); + int64_t iTime = (int64_t)DVD_TIME_TO_MSEC(m_clock.GetClock() + m_State.time_offset + 500000.0 * m_playSpeed / DVD_PLAYSPEED_NORMAL); +- m_messenger.Put(new CDVDMsgPlayerSeek(iTime, (GetPlaySpeed() < 0), true, false, false, true)); ++ m_messenger.Put(new CDVDMsgPlayerSeek(iTime, (GetPlaySpeed() < 0), true, false, false, true, false)); + } + } + } +@@ -2030,7 +2032,7 @@ void CDVDPlayer::HandleMessages() + if(!m_pSubtitleDemuxer->SeekTime(time, msg.GetBackward())) + CLog::Log(LOGDEBUG, "failed to seek subtitle demuxer: %d, success", time); + } +- FlushBuffers(!msg.GetFlush(), start, msg.GetAccurate()); ++ FlushBuffers(!msg.GetFlush(), start, msg.GetAccurate(), msg.GetSync()); + } + else + CLog::Log(LOGWARNING, "error while seeking"); +@@ -2168,9 +2170,10 @@ void CDVDPlayer::HandleMessages() + double offset; + offset = CDVDClock::GetAbsoluteClock() - m_State.timestamp; + offset *= m_playSpeed / DVD_PLAYSPEED_NORMAL; ++ offset = DVD_TIME_TO_MSEC(offset); + if(offset > 1000) offset = 1000; + if(offset < -1000) offset = -1000; +- m_State.time += DVD_TIME_TO_MSEC(offset); ++ m_State.time += offset; + m_State.timestamp = CDVDClock::GetAbsoluteClock(); + } + +@@ -2186,7 +2189,8 @@ void CDVDPlayer::HandleMessages() + // do a seek after rewind, clock is not in sync with current pts + if (m_playSpeed < 0 && speed >= 0) + { +- m_messenger.Put(new CDVDMsgPlayerSeek(GetTime(), true, true, true)); ++ int64_t iTime = (int64_t)DVD_TIME_TO_MSEC(m_clock.GetClock() + m_State.time_offset); ++ m_messenger.Put(new CDVDMsgPlayerSeek(iTime, true, true, false, false, true)); + } + + // if playspeed is different then DVD_PLAYSPEED_NORMAL or DVD_PLAYSPEED_PAUSE +@@ -2767,10 +2771,11 @@ int64_t CDVDPlayer::GetTime() + { + offset = CDVDClock::GetAbsoluteClock() - m_State.timestamp; + offset *= m_playSpeed / DVD_PLAYSPEED_NORMAL; ++ offset = DVD_TIME_TO_MSEC(offset); + if(offset > 1000) offset = 1000; + if(offset < -1000) offset = -1000; + } +- return llrint(m_State.time + DVD_TIME_TO_MSEC(offset)); ++ return llrint(m_State.time + offset); + } + + // return length in msec +@@ -3140,7 +3145,7 @@ bool CDVDPlayer::CloseTeletextStream(bool bWaitForBuffers) + return true; + } + +-void CDVDPlayer::FlushBuffers(bool queued, double pts, bool accurate) ++void CDVDPlayer::FlushBuffers(bool queued, double pts, bool accurate, bool sync) + { + double startpts; + if(accurate) +@@ -3152,19 +3157,23 @@ void CDVDPlayer::FlushBuffers(bool queued, double pts, bool accurate) + if(startpts != DVD_NOPTS_VALUE) + startpts -= m_offset_pts; + +- m_CurrentAudio.inited = false; ++ if (sync) ++ { ++ m_CurrentAudio.inited = false; ++ m_CurrentVideo.inited = false; ++ m_CurrentSubtitle.inited = false; ++ m_CurrentTeletext.inited = false; ++ } ++ + m_CurrentAudio.dts = DVD_NOPTS_VALUE; + m_CurrentAudio.startpts = startpts; + +- m_CurrentVideo.inited = false; + m_CurrentVideo.dts = DVD_NOPTS_VALUE; + m_CurrentVideo.startpts = startpts; + +- m_CurrentSubtitle.inited = false; + m_CurrentSubtitle.dts = DVD_NOPTS_VALUE; + m_CurrentSubtitle.startpts = startpts; + +- m_CurrentTeletext.inited = false; + m_CurrentTeletext.dts = DVD_NOPTS_VALUE; + m_CurrentTeletext.startpts = startpts; + +@@ -3208,7 +3217,7 @@ void CDVDPlayer::FlushBuffers(bool queued, double pts, bool accurate) + m_CurrentTeletext.started = false; + } + +- if(pts != DVD_NOPTS_VALUE) ++ if(pts != DVD_NOPTS_VALUE && sync) + m_clock.Discontinuity(pts); + UpdatePlayState(0); + } +diff --git a/xbmc/cores/dvdplayer/DVDPlayer.h b/xbmc/cores/dvdplayer/DVDPlayer.h +index d3c201e..70ecea9 100644 +--- a/xbmc/cores/dvdplayer/DVDPlayer.h ++++ b/xbmc/cores/dvdplayer/DVDPlayer.h +@@ -310,7 +310,7 @@ class CDVDPlayer : public IPlayer, public CThread, public IDVDPlayer + bool GetCachingTimes(double& play_left, double& cache_left, double& file_offset); + + +- void FlushBuffers(bool queued, double pts = DVD_NOPTS_VALUE, bool accurate = true); ++ void FlushBuffers(bool queued, double pts = DVD_NOPTS_VALUE, bool accurate = true, bool sync = true); + + void HandleMessages(); + void HandlePlaySpeed(); +@@ -359,8 +359,9 @@ class CDVDPlayer : public IPlayer, public CThread, public IDVDPlayer + int m_playSpeed; + struct SSpeedState + { +- double lastpts; // holds last display pts during ff/rw operations +- double lasttime; ++ double lastpts; // holds last display pts during ff/rw operations ++ int64_t lasttime; ++ double lastabstime; + } m_SpeedState; + + int m_errorCount; +diff --git a/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp b/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp +index 8b02d81..d26ab9c 100644 +--- a/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp ++++ b/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp +@@ -1268,13 +1268,13 @@ int CDVDPlayerVideo::OutputPicture(const DVDVideoPicture* src, double pts) + + if( m_speed < 0 ) + { +- double decoderPts = m_droppingStats.m_lastDecoderPts; ++ double inputPts = m_droppingStats.m_lastPts; + double renderPts = m_droppingStats.m_lastRenderPts; + if (pts > renderPts) + { +- if (decoderPts >= renderPts) ++ if (inputPts >= renderPts) + { +- Sleep(200); ++ Sleep(50); + } + return result | EOS_DROPPED; + } +@@ -1571,7 +1571,7 @@ double CDVDPlayerVideo::GetCurrentPts() + + if( m_stalled ) + iRenderPts = DVD_NOPTS_VALUE; +- else ++ else if ( m_speed == DVD_PLAYSPEED_NORMAL) + iRenderPts = iRenderPts - max(0.0, iSleepTime); + + return iRenderPts; +@@ -1671,6 +1671,8 @@ int CDVDPlayerVideo::CalcDropRequirement(double pts) + int iSkippedDeint = 0; + int iBufferLevel; + ++ m_droppingStats.m_lastPts = pts; ++ + // get decoder stats + if (!m_pVideoCodec->GetPts(iDecoderPts, iSkippedDeint, interlaced)) + iDecoderPts = pts; +diff --git a/xbmc/cores/dvdplayer/DVDPlayerVideo.h b/xbmc/cores/dvdplayer/DVDPlayerVideo.h +index 509d5f7..7cddda7 100644 +--- a/xbmc/cores/dvdplayer/DVDPlayerVideo.h ++++ b/xbmc/cores/dvdplayer/DVDPlayerVideo.h +@@ -51,6 +51,7 @@ class CDroppingStats + double m_totalGain; + double m_lastDecoderPts; + double m_lastRenderPts; ++ double m_lastPts; + unsigned int m_lateFrames; + unsigned int m_dropRequests; + bool m_requestOutputDrop; +-- +1.7.10 + + +From 024ecda241754f02ad985fab9116e33b06b8d174 Mon Sep 17 00:00:00 2001 +From: fritsch +Date: Fri, 2 Nov 2012 17:56:12 +0100 +Subject: [PATCH 54/73] xvba: do not create decoder for surfaces larger than + width 2048 or height 1536 + +--- + xbmc/cores/dvdplayer/DVDCodecs/Video/XVBA.cpp | 15 +++++++++++++++ + 1 file changed, 15 insertions(+) + +diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/XVBA.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/XVBA.cpp +index e8e376a..b73c48a 100644 +--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/XVBA.cpp ++++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/XVBA.cpp +@@ -335,6 +335,21 @@ bool CDecoder::Open(AVCodecContext* avctx, const enum PixelFormat fmt, unsigned + return false; + } + ++ // Fixme: Revisit with new SDK ++ // Workaround for 0.74.01-AES-2 that does not signal if surfaces are too large ++ // it seems that xvba does not support anything > 2k ++ // return false, for files that are larger ++ // if you are unlucky, this would kill your decoder ++ // we limit to 2048x1536(+8) now - as this was tested working ++ int surfaceWidth = (avctx->coded_width+15) & ~15; ++ int surfaceHeight = (avctx->coded_height+15) & ~15; ++ if(surfaceHeight > 1544 || surfaceWidth > 2048) ++ { ++ CLog::Log(LOGERROR, "Surface too large, decoder skipped: surfaceWidth %u, surfaceHeight %u", ++ surfaceWidth, surfaceHeight); ++ return false; ++ } ++ + if (!m_dllAvUtil.Load()) + return false; + +-- +1.7.10 + + +From 98ebb0d0232cf4a7ea2082f9f16e210a39e983e8 Mon Sep 17 00:00:00 2001 +From: fritsch +Date: Sun, 4 Nov 2012 16:24:10 +0100 +Subject: [PATCH 55/73] xvba: add string for available decoders - we are + important so make sure we are there + +--- + xbmc/cores/dvdplayer/DVDCodecs/DVDFactoryCodec.cpp | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/xbmc/cores/dvdplayer/DVDCodecs/DVDFactoryCodec.cpp b/xbmc/cores/dvdplayer/DVDCodecs/DVDFactoryCodec.cpp +index 0cea7a9..6fb74b7 100644 +--- a/xbmc/cores/dvdplayer/DVDCodecs/DVDFactoryCodec.cpp ++++ b/xbmc/cores/dvdplayer/DVDCodecs/DVDFactoryCodec.cpp +@@ -169,6 +169,11 @@ CDVDVideoCodec* CDVDFactoryCodec::CreateVideoCodec(CDVDStreamInfo &hint, unsigne + #elif defined(_LINUX) && !defined(TARGET_DARWIN) + hwSupport += "VAAPI:no "; + #endif ++#if defined(HAVE_LIBXVBA) && defined(TARGET_LINUX) ++ hwSupport += "XVBA:yes "; ++#elif defined(TARGET_LINUX) ++ hwSupport += "XVBA:no "; ++#endif + + CLog::Log(LOGDEBUG, "CDVDFactoryCodec: compiled in hardware support: %s", hwSupport.c_str()); + +-- +1.7.10 + + +From 84e701f7db6603a2942611d5c74ba645c625ec0d Mon Sep 17 00:00:00 2001 +From: fritsch +Date: Thu, 22 Nov 2012 21:32:21 +0100 +Subject: [PATCH 56/73] xvba: revisit Artefacts. There are more broken video + files out there + +--- + lib/ffmpeg/libavcodec/xvba_h264.c | 10 ++++++++-- + 1 file changed, 8 insertions(+), 2 deletions(-) + +diff --git a/lib/ffmpeg/libavcodec/xvba_h264.c b/lib/ffmpeg/libavcodec/xvba_h264.c +index a077442..87af687 100644 +--- a/lib/ffmpeg/libavcodec/xvba_h264.c ++++ b/lib/ffmpeg/libavcodec/xvba_h264.c +@@ -102,10 +102,16 @@ static int end_frame(AVCodecContext *avctx) + pic_descriptor->avc_num_ref_frames = h->sps.ref_frame_count; + pic_descriptor->avc_reserved_8bit = 0; + +- /* Set correct level */ +- if (pic_descriptor->level == 41) { ++ /* Set a level that can decode stuff in every case without a lookup table ++ xvba seems to have problems only when the number of Reframes goes beyond ++ the max support number of Level4.1@High. So in praxis decoding a Level 3.0 ++ file that in deed has level4.1@High specs does not matter. We use this fact ++ and check if the ref_frames stay in the range Level4.1@high can decode if ++ not, we set Level5.1 */ ++ if (pic_descriptor->avc_num_ref_frames > 4) { + const unsigned int mbw = pic_descriptor->width_in_mb; + const unsigned int mbh = pic_descriptor->height_in_mb; ++ // this matches Level4.1@High stats to differ between <= 4.1 and 5.1 + const unsigned int max_ref_frames = 12288 * 1024 / (mbw * mbh * 384); + const unsigned int num_ref_frames = pic_descriptor->avc_num_ref_frames; + if (max_ref_frames < num_ref_frames) +-- +1.7.10 + + +From afd776e3e90a1787ce4c3392266d70368de4e164 Mon Sep 17 00:00:00 2001 +From: xbmc +Date: Fri, 23 Nov 2012 09:42:02 +0100 +Subject: [PATCH 57/73] xvba: reactivate accidently disabled + IsDecodingFinished + +--- + xbmc/cores/dvdplayer/DVDCodecs/Video/XVBA.cpp | 2 -- + 1 file changed, 2 deletions(-) + +diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/XVBA.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/XVBA.cpp +index b73c48a..47ff25f 100644 +--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/XVBA.cpp ++++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/XVBA.cpp +@@ -1949,8 +1949,6 @@ void COutput::Flush() + + bool COutput::IsDecodingFinished() + { +- return true; +- + // check for decoding to be finished + CXvbaDecodedPicture decodedPic = m_decodedPics.front(); + +-- +1.7.10 + + +From 37576c15f9e3a0c2dce593e9d9cb5a7863845de7 Mon Sep 17 00:00:00 2001 +From: xbmc +Date: Fri, 23 Nov 2012 17:41:12 +0100 +Subject: [PATCH 58/73] xrandr: fix query for multiple screens + +--- + xbmc/windowing/X11/XRandR.cpp | 10 ++++++---- + 1 file changed, 6 insertions(+), 4 deletions(-) + +diff --git a/xbmc/windowing/X11/XRandR.cpp b/xbmc/windowing/X11/XRandR.cpp +index cc933b9..533e03d 100644 +--- a/xbmc/windowing/X11/XRandR.cpp ++++ b/xbmc/windowing/X11/XRandR.cpp +@@ -57,12 +57,14 @@ bool CXRandR::Query(bool force) + + m_outputs.clear(); + // query all screens ++ // we are happy if at least one screen returns results ++ bool success = false; + for(unsigned int screennum=0; screennum +Date: Sun, 2 Dec 2012 15:46:55 +0100 +Subject: [PATCH 59/73] X11: add debug log to print out refresh after xrr + event + +--- + xbmc/windowing/X11/WinSystemX11.cpp | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/xbmc/windowing/X11/WinSystemX11.cpp b/xbmc/windowing/X11/WinSystemX11.cpp +index ef83133..76c6362 100644 +--- a/xbmc/windowing/X11/WinSystemX11.cpp ++++ b/xbmc/windowing/X11/WinSystemX11.cpp +@@ -685,6 +685,12 @@ void CWinSystemX11::NotifyXRREvent() + XOutput *out = g_xrandr.GetOutput(currentOutput); + XMode mode = g_xrandr.GetCurrentMode(currentOutput); + ++ if (out) ++ CLog::Log(LOGDEBUG, "%s - current output: %s, mode: %s, refresh: %.3f", __FUNCTION__ ++ , out->name.c_str(), mode.id.c_str(), mode.hz); ++ else ++ CLog::Log(LOGWARNING, "%s - output name not set", __FUNCTION__); ++ + RESOLUTION_INFO res; + unsigned int i; + bool found(false); +-- +1.7.10 + + +From d418ae1053a3842eb3e6a3bbd84666a5ee3defe2 Mon Sep 17 00:00:00 2001 +From: xbmc +Date: Tue, 11 Dec 2012 11:08:13 +0100 +Subject: [PATCH 60/73] X11: dont call XCloseDisplay on shutdown, it crashes + when powered doen by cec on ATI + +--- + xbmc/windowing/X11/WinSystemX11.cpp | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/xbmc/windowing/X11/WinSystemX11.cpp b/xbmc/windowing/X11/WinSystemX11.cpp +index 76c6362..e4e25b2 100644 +--- a/xbmc/windowing/X11/WinSystemX11.cpp ++++ b/xbmc/windowing/X11/WinSystemX11.cpp +@@ -108,7 +108,8 @@ bool CWinSystemX11::DestroyWindowSystem() + //we don't call XCloseDisplay() here, since ati keeps a pointer to our m_dpy + //so instead we just let m_dpy die on exit + // i have seen core dumps on ATI if the display is not closed here +- XCloseDisplay(m_dpy); ++ // crashes when shutting down via cec ++// XCloseDisplay(m_dpy); + } + + // m_SDLSurface is free()'d by SDL_Quit(). +-- +1.7.10 + + +From 3b700401e9aace50b5ce6c5d7ba2a2e33bb5217f Mon Sep 17 00:00:00 2001 +From: xbmc +Date: Wed, 12 Dec 2012 09:52:17 +0100 +Subject: [PATCH 61/73] vdpau: make interop gl default and remove setting, + rename and intvert interop yuv + +--- + language/English/strings.po | 2 +- + xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp | 17 ++++++++++------- + xbmc/settings/GUISettings.cpp | 3 +-- + xbmc/settings/GUIWindowSettingsCategory.cpp | 23 +++-------------------- + 4 files changed, 15 insertions(+), 30 deletions(-) + +diff --git a/language/English/strings.po b/language/English/strings.po +index ede18b3..281a8a1 100644 +--- a/language/English/strings.po ++++ b/language/English/strings.po +@@ -5121,7 +5121,7 @@ msgid "Allow Vdpau OpenGL interop" + msgstr "" + + msgctxt "#13436" +-msgid "Allow Vdpau OpenGL interop YUV" ++msgid "Prefer VDPAU Video Mixer" + msgstr "" + + msgctxt "#13437" +diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp +index fec4b88..ad140fb 100644 +--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp ++++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp +@@ -365,12 +365,15 @@ bool CDecoder::Supports(EINTERLACEMETHOD method) + || method == VS_INTERLACEMETHOD_AUTO) + return true; + +- if (g_guiSettings.GetBool("videoplayer.usevdpauinteropyuv")) ++ if (!m_vdpauConfig.usePixmaps) + { + if (method == VS_INTERLACEMETHOD_RENDER_BOB) + return true; + } + ++ if (method == VS_INTERLACEMETHOD_VDPAU_INVERSE_TELECINE) ++ return false; ++ + for(SInterlaceMapping* p = g_interlace_mapping; p->method != VS_INTERLACEMETHOD_NONE; p++) + { + if(p->method == method) +@@ -1847,7 +1850,7 @@ void CMixer::SetDeinterlacing() + + SetDeintSkipChroma(); + +- m_config.useInteropYuv = g_guiSettings.GetBool("videoplayer.usevdpauinteropyuv"); ++ m_config.useInteropYuv = !g_guiSettings.GetBool("videoplayer.usevdpaumixer"); + } + + void CMixer::SetDeintSkipChroma() +@@ -2039,7 +2042,7 @@ void CMixer::Init() + m_vdpError = false; + + m_config.upscale = g_advancedSettings.m_videoVDPAUScaling; +- m_config.useInteropYuv = g_guiSettings.GetBool("videoplayer.usevdpauinteropyuv"); ++ m_config.useInteropYuv = !g_guiSettings.GetBool("videoplayer.usevdpaumixer"); + + CreateVdpauMixer(); + } +@@ -2149,11 +2152,12 @@ void CMixer::InitCycle() + DVP_FLAG_INTERLACED); + m_config.useInteropYuv = false; + } +- else if (method == VS_INTERLACEMETHOD_RENDER_BOB && m_config.useInteropYuv) ++ else if (method == VS_INTERLACEMETHOD_RENDER_BOB) + { + m_mixersteps = 1; + m_mixerfield = VDP_VIDEO_MIXER_PICTURE_STRUCTURE_FRAME; + m_mixerInput[1].DVDPic.format = RENDER_FMT_VDPAU_420; ++ m_config.useInteropYuv = true; + } + else + { +@@ -3185,7 +3189,7 @@ bool COutput::GLInit() + glVDPAUGetSurfaceivNV = NULL; + #endif + +- m_config.usePixmaps = !g_guiSettings.GetBool("videoplayer.usevdpauinterop"); ++ m_config.usePixmaps = false; + + #ifdef GL_NV_vdpau_interop + if (glewIsSupported("GL_NV_vdpau_interop")) +@@ -3217,8 +3221,7 @@ bool COutput::GLInit() + #endif + { + m_config.usePixmaps = true; +- g_guiSettings.SetBool("videoplayer.usevdpauinterop",false); +- g_guiSettings.SetBool("videoplayer.usevdpauinteropyuv",false); ++ g_guiSettings.SetBool("videoplayer.usevdpaumixer",true); + } + if (!glXBindTexImageEXT) + glXBindTexImageEXT = (PFNGLXBINDTEXIMAGEEXTPROC)glXGetProcAddress((GLubyte *) "glXBindTexImageEXT"); +diff --git a/xbmc/settings/GUISettings.cpp b/xbmc/settings/GUISettings.cpp +index 10ef779..a4bd524 100644 +--- a/xbmc/settings/GUISettings.cpp ++++ b/xbmc/settings/GUISettings.cpp +@@ -690,8 +690,7 @@ void CGUISettings::Initialize() + + #ifdef HAVE_LIBVDPAU + AddBool(vp, "videoplayer.usevdpau", 13425, true); +- AddBool(vp, "videoplayer.usevdpauinterop", 13435, true); +- AddBool(vp, "videoplayer.usevdpauinteropyuv", 13436, false); ++ AddBool(vp, "videoplayer.usevdpaumixer", 13436, true); + #endif + #ifdef HAVE_LIBVA + AddBool(vp, "videoplayer.usevaapi", 13426, true); +diff --git a/xbmc/settings/GUIWindowSettingsCategory.cpp b/xbmc/settings/GUIWindowSettingsCategory.cpp +index 3c19a06..b9f18e4 100644 +--- a/xbmc/settings/GUIWindowSettingsCategory.cpp ++++ b/xbmc/settings/GUIWindowSettingsCategory.cpp +@@ -602,9 +602,9 @@ void CGUIWindowSettingsCategory::UpdateSettings() + pControl->SetEnabled(true); + } + } +- else if (strSetting.Equals("videoplayer.usevdpauinteropyuv")) ++ else if (strSetting.Equals("videoplayer.usevdpaumixer")) + { +- bool hasInterop = g_guiSettings.GetBool("videoplayer.usevdpauinterop"); ++ bool hasInterop = true; + #ifndef GL_NV_vdpau_interop + hasInterop = false; + #endif +@@ -616,24 +616,7 @@ void CGUIWindowSettingsCategory::UpdateSettings() + else + { + pControl->SetEnabled(false); +- g_guiSettings.SetBool("videoplayer.usevdpauinteropyuv",false); +- } +- } +- else if (strSetting.Equals("videoplayer.usevdpauinterop")) +- { +- bool hasInterop = g_guiSettings.GetBool("videoplayer.usevdpau"); +-#ifndef GL_NV_vdpau_interop +- hasInterop = false; +-#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.usevdpauinterop",false); ++ g_guiSettings.SetBool("videoplayer.usevdpaumixer",true); + } + } + else +-- +1.7.10 + + +From a060312a4e236858bf3c9a97d663c5643796b649 Mon Sep 17 00:00:00 2001 +From: xbmc +Date: Wed, 12 Dec 2012 18:34:47 +0100 +Subject: [PATCH 62/73] vdpau: drop studio level conversion + +--- + language/English/strings.po | 6 +- + xbmc/cores/VideoRenderers/LinuxRendererGL.cpp | 4 +- + xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp | 94 +----------------------- + xbmc/settings/GUISettings.cpp | 1 - + 4 files changed, 7 insertions(+), 98 deletions(-) + +diff --git a/language/English/strings.po b/language/English/strings.po +index 281a8a1..fc896b3 100644 +--- a/language/English/strings.po ++++ b/language/English/strings.po +@@ -4371,11 +4371,7 @@ msgctxt "#13121" + msgid "VDPAU HQ Upscaling level" + msgstr "" + +-msgctxt "#13122" +-msgid "VDPAU Studio level color conversion" +-msgstr "" +- +-#empty strings from id 13123 to 13129 ++#empty strings from id 13122 to 13129 + + msgctxt "#13130" + msgid "Blank other displays" +diff --git a/xbmc/cores/VideoRenderers/LinuxRendererGL.cpp b/xbmc/cores/VideoRenderers/LinuxRendererGL.cpp +index 7c3adcb..0bb924b 100644 +--- a/xbmc/cores/VideoRenderers/LinuxRendererGL.cpp ++++ b/xbmc/cores/VideoRenderers/LinuxRendererGL.cpp +@@ -3545,7 +3545,7 @@ bool CLinuxRendererGL::Supports(ERENDERFEATURE feature) + { + if(feature == RENDERFEATURE_BRIGHTNESS) + { +- if ((m_renderMethod & RENDER_VDPAU) && !g_guiSettings.GetBool("videoplayer.vdpaustudiolevel")) ++ if (m_renderMethod & RENDER_VDPAU) + return true; + + if (m_renderMethod & RENDER_VAAPI) +@@ -3561,7 +3561,7 @@ bool CLinuxRendererGL::Supports(ERENDERFEATURE feature) + + if(feature == RENDERFEATURE_CONTRAST) + { +- if ((m_renderMethod & RENDER_VDPAU) && !g_guiSettings.GetBool("videoplayer.vdpaustudiolevel")) ++ if (m_renderMethod & RENDER_VDPAU) + return true; + + if (m_renderMethod & RENDER_VAAPI) +diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp +index ad140fb..5851e1a 100644 +--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp ++++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp +@@ -57,15 +57,6 @@ + }; + 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 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 + { + const EINTERLACEMETHOD method; +@@ -1614,74 +1605,6 @@ void CMixer::PostProcOff() + 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; +@@ -1701,19 +1624,10 @@ void CMixer::SetColor() + //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); +- } ++ 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__); + } + +diff --git a/xbmc/settings/GUISettings.cpp b/xbmc/settings/GUISettings.cpp +index a4bd524..67aeec9 100644 +--- a/xbmc/settings/GUISettings.cpp ++++ b/xbmc/settings/GUISettings.cpp +@@ -772,7 +772,6 @@ void CGUISettings::Initialize() + AddSeparator(vp, "videoplayer.sep1.5"); + #ifdef HAVE_LIBVDPAU + AddBool(NULL, "videoplayer.vdpauUpscalingLevel", 13121, false); +- AddBool(vp, "videoplayer.vdpaustudiolevel", 13122, false); + #endif + #endif + AddSeparator(vp, "videoplayer.sep5"); +-- +1.7.10 + + +From 6d03704ce1cbc7d09d684da1ced478b2b59c0b35 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Gr=C3=A9gory=20Coutant?= +Date: Wed, 12 Dec 2012 19:49:47 +0100 +Subject: [PATCH 63/73] x11: support for multiple x screens + +--- + xbmc/windowing/X11/XRandR.cpp | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/xbmc/windowing/X11/XRandR.cpp b/xbmc/windowing/X11/XRandR.cpp +index 533e03d..7a16488 100644 +--- a/xbmc/windowing/X11/XRandR.cpp ++++ b/xbmc/windowing/X11/XRandR.cpp +@@ -92,7 +92,7 @@ bool CXRandR::Query(bool force, int screennum) + pclose(file); + + TiXmlElement *pRootElement = xmlDoc.RootElement(); +- if (strcasecmp(pRootElement->Value(), "screen") != screennum) ++ if (atoi(pRootElement->Attribute("id")) != screennum) + { + // TODO ERROR + return false; +-- +1.7.10 + + +From 597c8449084e1e5ebfebfb31db570f7826d06517 Mon Sep 17 00:00:00 2001 +From: xbmc +Date: Wed, 12 Dec 2012 20:28:49 +0100 +Subject: [PATCH 64/73] vdpau: observe ffmpeg tags for color space + +--- + xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp | 38 ++++++++++++++++-------- + xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.h | 1 + + 2 files changed, 27 insertions(+), 12 deletions(-) + +diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp +index 5851e1a..8858614 100644 +--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp ++++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp +@@ -907,6 +907,7 @@ int CDecoder::Decode(AVCodecContext *avctx, AVFrame *pFrame) + memset(&pic.DVDPic, 0, sizeof(pic.DVDPic)); + ((CDVDVideoCodecFFmpeg*)avctx->opaque)->GetPictureCommon(&pic.DVDPic); + pic.render = render; ++ pic.DVDPic.color_matrix = avctx->colorspace; + m_bufferStats.IncDecoded(); + m_vdpauOutput.m_dataPort.SendOutMessage(COutputDataProtocol::NEWFRAME, &pic, sizeof(pic)); + +@@ -1513,10 +1514,6 @@ void CMixer::InitCSCMatrix(int Width) + 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() +@@ -1527,11 +1524,13 @@ void CMixer::CheckFeatures() + m_Upscale = m_config.upscale; + } + if (m_Brightness != g_settings.m_currentVideoSettings.m_Brightness || +- m_Contrast != g_settings.m_currentVideoSettings.m_Contrast) ++ m_Contrast != g_settings.m_currentVideoSettings.m_Contrast || ++ m_ColorMatrix != m_mixerInput[1].DVDPic.color_matrix) + { + SetColor(); + m_Brightness = g_settings.m_currentVideoSettings.m_Brightness; + m_Contrast = g_settings.m_currentVideoSettings.m_Contrast; ++ m_ColorMatrix = m_mixerInput[1].DVDPic.color_matrix; + } + if (m_NoiseReduction != g_settings.m_currentVideoSettings.m_NoiseReduction) + { +@@ -1615,13 +1614,27 @@ void CMixer::SetColor() + 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); ++ switch(m_mixerInput[1].DVDPic.color_matrix) ++ { ++ case AVCOL_SPC_BT709: ++ colorStandard = VDP_COLOR_STANDARD_ITUR_BT_709; ++ break; ++ case AVCOL_SPC_BT470BG: ++ case AVCOL_SPC_SMPTE170M: ++ colorStandard = VDP_COLOR_STANDARD_ITUR_BT_601; ++ break; ++ case AVCOL_SPC_SMPTE240M: ++ colorStandard = VDP_COLOR_STANDARD_SMPTE_240M; ++ break; ++ case AVCOL_SPC_FCC: ++ case AVCOL_SPC_UNSPECIFIED: ++ case AVCOL_SPC_RGB: ++ default: ++ if(m_config.surfaceWidth > 1000) ++ colorStandard = VDP_COLOR_STANDARD_ITUR_BT_709; ++ else ++ colorStandard = VDP_COLOR_STANDARD_ITUR_BT_601; ++ } + + VdpVideoMixerAttribute attributes[] = { VDP_VIDEO_MIXER_ATTRIBUTE_CSC_MATRIX }; + vdp_st = m_config.vdpProcs.vdp_generate_csc_matrix(&m_Procamp, colorStandard, &m_CSCMatrix); +@@ -1952,6 +1965,7 @@ void CMixer::Init() + m_Sharpness = 0.0; + m_DeintMode = 0; + m_Deint = 0; ++ m_ColorMatrix = 0; + m_PostProc = false; + m_vdpError = false; + +diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.h b/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.h +index 4d1559c..471ad68 100644 +--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.h ++++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.h +@@ -334,6 +334,7 @@ class CMixer : private CThread + int m_DeintMode; + int m_Deint; + int m_Upscale; ++ unsigned int m_ColorMatrix : 4; + uint32_t *m_BlackBar; + VdpVideoMixerPictureStructure m_mixerfield; + int m_mixerstep; +-- +1.7.10 + + +From 3f9308d76025ef1e31923fa9a06587f75c00f870 Mon Sep 17 00:00:00 2001 +From: xbmc +Date: Thu, 20 Dec 2012 19:35:38 +0100 +Subject: [PATCH 65/73] fix compile error after recent change + +--- + xbmc/settings/GUIWindowSettingsCategory.cpp | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/xbmc/settings/GUIWindowSettingsCategory.cpp b/xbmc/settings/GUIWindowSettingsCategory.cpp +index b9f18e4..cacb32a 100644 +--- a/xbmc/settings/GUIWindowSettingsCategory.cpp ++++ b/xbmc/settings/GUIWindowSettingsCategory.cpp +@@ -2453,7 +2453,7 @@ void CGUIWindowSettingsCategory::FillInMonitors(CStdString strSetting) + { + // we expect "videoscreen.monitor" but it might be hidden on some platforms, + // so check that we actually have a visable control. +- CBaseSettingControl *control = GetSetting(strSetting); ++ BaseSettingControlPtr control = GetSetting(strSetting); + if (control) + { + control->SetDelayed(); +-- +1.7.10 + + +From 213792b2678760d42740d581a1ee71e186a31c4d Mon Sep 17 00:00:00 2001 +From: xbmc +Date: Mon, 24 Dec 2012 16:02:42 +0100 +Subject: [PATCH 66/73] pvr: increase changes counter of stream on stream + change, cosmetics after + dd307930d39d92f145a01a16600cd00e01ec39be + +--- + xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxPVRClient.cpp | 5 ++--- + 1 file changed, 2 insertions(+), 3 deletions(-) + +diff --git a/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxPVRClient.cpp b/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxPVRClient.cpp +index 8c984f6..034e545 100644 +--- a/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxPVRClient.cpp ++++ b/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxPVRClient.cpp +@@ -348,9 +348,7 @@ void CDVDDemuxPVRClient::RequestStreams() + if (stm) + { + st = dynamic_cast(stm); +- if (!st +- || (st->codec != (CodecID)props.stream[i].iCodecId) +- || (st->iChannels != props.stream[i].iChannels)) ++ if (!st || (st->codec != (CodecID)props.stream[i].iCodecId)) + DisposeStream(i); + } + if (!m_streams[i]) +@@ -367,6 +365,7 @@ void CDVDDemuxPVRClient::RequestStreams() + st->iBitsPerSample = props.stream[i].iBitsPerSample; + m_streams[i] = st; + st->m_parser_split = true; ++ st->changes++; + } + else if (props.stream[i].iCodecType == AVMEDIA_TYPE_VIDEO) + { +-- +1.7.10 + + +From e810d3bd68e89e800fba217e88184c2df0fe4040 Mon Sep 17 00:00:00 2001 +From: xbmc +Date: Thu, 17 Jan 2013 16:03:22 +0100 +Subject: [PATCH 67/73] X11: add keymapping for XF86XK_Sleep + +--- + xbmc/windowing/WinEventsX11.cpp | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/xbmc/windowing/WinEventsX11.cpp b/xbmc/windowing/WinEventsX11.cpp +index c31877e..ed31c04 100644 +--- a/xbmc/windowing/WinEventsX11.cpp ++++ b/xbmc/windowing/WinEventsX11.cpp +@@ -143,6 +143,7 @@ + , {XK_Break, XBMCK_BREAK} + , {XK_Menu, XBMCK_MENU} + , {XF86XK_PowerOff, XBMCK_POWER} ++, {XF86XK_Sleep, XBMCK_SLEEP} + , {XK_EcuSign, XBMCK_EURO} + , {XK_Undo, XBMCK_UNDO} + /* Media keys */ +-- +1.7.10 + + +From 2cb807b2f801f06723cde1bdd636550c08fc08ab Mon Sep 17 00:00:00 2001 +From: fritsch +Date: Sat, 12 Jan 2013 13:03:50 +0100 +Subject: [PATCH 68/73] dvdplayer: Allow multithread decoding for hi10p + content by default + +This allows decoding of some hi10p material on e.g. AMD Fusion with +both cores at the max. This introduces a new advancedsetting named +disablehi10pmultithreading to disable hi10p decoded multithreaded. +--- + .../DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp | 18 ++++++++++++++++-- + .../dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.h | 1 + + xbmc/settings/AdvancedSettings.cpp | 2 ++ + xbmc/settings/AdvancedSettings.h | 1 + + 4 files changed, 20 insertions(+), 2 deletions(-) + +diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp +index b3252ec..3f8a6e8 100644 +--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp ++++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp +@@ -154,6 +154,7 @@ enum PixelFormat CDVDVideoCodecFFmpeg::GetFormat( struct AVCodecContext * avctx + m_iScreenHeight = 0; + m_iOrientation = 0; + m_bSoftware = false; ++ m_isHi10p = false; + m_pHardware = NULL; + m_iLastKeyframe = 0; + m_dts = DVD_NOPTS_VALUE; +@@ -204,7 +205,10 @@ bool CDVDVideoCodecFFmpeg::Open(CDVDStreamInfo &hints, CDVDCodecOptions &options + case FF_PROFILE_H264_HIGH_444_PREDICTIVE: + case FF_PROFILE_H264_HIGH_444_INTRA: + case FF_PROFILE_H264_CAVLC_444: ++ // this is needed to not open the decoders + m_bSoftware = true; ++ // this we need to enable multithreading for hi10p via advancedsettings ++ m_isHi10p = true; + break; + } + } +@@ -277,8 +281,18 @@ bool CDVDVideoCodecFFmpeg::Open(CDVDStreamInfo &hints, CDVDCodecOptions &options + m_pCodecContext->codec_tag = hints.codec_tag; + /* Only allow slice threading, since frame threading is more + * sensitive to changes in frame sizes, and it causes crashes +- * during HW accell */ +- m_pCodecContext->thread_type = FF_THREAD_SLICE; ++ * during HW accell - so we unset it in this case. ++ * ++ * When we detect Hi10p and user did not disable hi10pmultithreading ++ * via advancedsettings.xml we keep the ffmpeg default thread type. ++ * */ ++ if(m_isHi10p && !g_advancedSettings.m_videoDisableHi10pMultithreading) ++ { ++ CLog::Log(LOGDEBUG,"CDVDVideoCodecFFmpeg::Open() Keep default threading for Hi10p: %d", ++ m_pCodecContext->thread_type); ++ } ++ else ++ m_pCodecContext->thread_type = FF_THREAD_SLICE; + + #if defined(TARGET_DARWIN_IOS) + // ffmpeg with enabled neon will crash and burn if this is enabled +diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.h b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.h +index bf4367c..db1d2b2 100644 +--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.h ++++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.h +@@ -116,6 +116,7 @@ class CDVDVideoCodecFFmpeg : public CDVDVideoCodec + + std::string m_name; + bool m_bSoftware; ++ bool m_isHi10p; + IHardwareDecoder *m_pHardware; + int m_iLastKeyframe; + double m_dts; +diff --git a/xbmc/settings/AdvancedSettings.cpp b/xbmc/settings/AdvancedSettings.cpp +index d913924..6a48309 100644 +--- a/xbmc/settings/AdvancedSettings.cpp ++++ b/xbmc/settings/AdvancedSettings.cpp +@@ -116,6 +116,7 @@ void CAdvancedSettings::Initialize() + m_DXVANoDeintProcForProgressive = false; + m_videoFpsDetect = 1; + m_videoDefaultLatency = 0.0; ++ m_videoDisableHi10pMultithreading = false; + + m_musicUseTimeSeeking = true; + m_musicTimeSeekForward = 10; +@@ -502,6 +503,7 @@ void CAdvancedSettings::ParseSettingsFile(const CStdString &file) + XMLUtils::GetBoolean(pElement,"enablehighqualityhwscalers", m_videoEnableHighQualityHwScalers); + XMLUtils::GetFloat(pElement,"autoscalemaxfps",m_videoAutoScaleMaxFps, 0.0f, 1000.0f); + XMLUtils::GetBoolean(pElement,"allowmpeg4vdpau",m_videoAllowMpeg4VDPAU); ++ XMLUtils::GetBoolean(pElement,"disablehi10pmultithreading",m_videoDisableHi10pMultithreading); + XMLUtils::GetBoolean(pElement,"allowmpeg4vaapi",m_videoAllowMpeg4VAAPI); + XMLUtils::GetBoolean(pElement, "disablebackgrounddeinterlace", m_videoDisableBackgroundDeinterlace); + XMLUtils::GetInt(pElement, "useocclusionquery", m_videoCaptureUseOcclusionQuery, -1, 1); +diff --git a/xbmc/settings/AdvancedSettings.h b/xbmc/settings/AdvancedSettings.h +index aaa4702..863e4f3 100644 +--- a/xbmc/settings/AdvancedSettings.h ++++ b/xbmc/settings/AdvancedSettings.h +@@ -168,6 +168,7 @@ class CAdvancedSettings + bool m_DXVAForceProcessorRenderer; + bool m_DXVANoDeintProcForProgressive; + int m_videoFpsDetect; ++ bool m_videoDisableHi10pMultithreading; + + CStdString m_videoDefaultPlayer; + CStdString m_videoDefaultDVDPlayer; +-- +1.7.10 + + +From 5e52fa15742e1300ac394738ead4ca2792c4812c Mon Sep 17 00:00:00 2001 +From: xbmc +Date: Mon, 21 Jan 2013 09:00:19 +0100 +Subject: [PATCH 69/73] X11: remove toggle full screen after resume + +--- + xbmc/powermanagement/PowerManager.cpp | 5 ----- + 1 file changed, 5 deletions(-) + +diff --git a/xbmc/powermanagement/PowerManager.cpp b/xbmc/powermanagement/PowerManager.cpp +index a5534c9..7e2ddc6 100644 +--- a/xbmc/powermanagement/PowerManager.cpp ++++ b/xbmc/powermanagement/PowerManager.cpp +@@ -223,11 +223,6 @@ void CPowerManager::OnWake() + #if defined(_WIN32) + ShowWindow(g_hWnd,SW_RESTORE); + SetForegroundWindow(g_hWnd); +-#elif !defined(TARGET_DARWIN_OSX) +- // Hack to reclaim focus, thus rehiding system mouse pointer. +- // Surely there's a better way? +- g_graphicsContext.ToggleFullScreenRoot(); +- g_graphicsContext.ToggleFullScreenRoot(); + #endif + } + g_application.ResetScreenSaver(); +-- +1.7.10 + + +From e8f3e20dfb3bde4434e2aea69b34e22ba1859a31 Mon Sep 17 00:00:00 2001 +From: xbmc +Date: Wed, 23 Jan 2013 17:03:02 +0100 +Subject: [PATCH 70/73] xrandr: set screen on mode change command + +--- + xbmc/windowing/X11/XRandR.cpp | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/xbmc/windowing/X11/XRandR.cpp b/xbmc/windowing/X11/XRandR.cpp +index 7a16488..6531ba3 100644 +--- a/xbmc/windowing/X11/XRandR.cpp ++++ b/xbmc/windowing/X11/XRandR.cpp +@@ -246,7 +246,7 @@ bool CXRandR::SetMode(XOutput output, XMode mode) + m_currentMode = modeFound.id; + char cmd[255]; + if (getenv("XBMC_BIN_HOME")) +- snprintf(cmd, sizeof(cmd), "%s/xbmc-xrandr --output %s --mode %s", getenv("XBMC_BIN_HOME"), outputFound.name.c_str(), modeFound.id.c_str()); ++ snprintf(cmd, sizeof(cmd), "%s/xbmc-xrandr --screen %d --output %s --mode %s", getenv("XBMC_BIN_HOME"), outputFound.screen, outputFound.name.c_str(), modeFound.id.c_str()); + else + return false; + CLog::Log(LOGINFO, "XRANDR: %s", cmd); +-- +1.7.10 + + +From f229dba603070e1f0528d395c9d5d63f9044ae6e Mon Sep 17 00:00:00 2001 +From: xbmc +Date: Wed, 23 Jan 2013 17:03:39 +0100 +Subject: [PATCH 71/73] X11: recreate glx context when output changes + +--- + xbmc/windowing/X11/WinSystemX11.cpp | 6 +++--- + xbmc/windowing/X11/WinSystemX11.h | 2 +- + 2 files changed, 4 insertions(+), 4 deletions(-) + +diff --git a/xbmc/windowing/X11/WinSystemX11.cpp b/xbmc/windowing/X11/WinSystemX11.cpp +index e4e25b2..b87e264 100644 +--- a/xbmc/windowing/X11/WinSystemX11.cpp ++++ b/xbmc/windowing/X11/WinSystemX11.cpp +@@ -409,11 +409,11 @@ bool CWinSystemX11::IsSuitableVisual(XVisualInfo *vInfo) + return true; + } + +-bool CWinSystemX11::RefreshGlxContext() ++bool CWinSystemX11::RefreshGlxContext(bool force) + { + bool retVal = false; + +- if (m_glContext) ++ if (m_glContext && !force) + { + CLog::Log(LOGDEBUG, "CWinSystemX11::RefreshGlxContext: refreshing context"); + glXMakeCurrent(m_dpy, None, NULL); +@@ -930,7 +930,7 @@ bool CWinSystemX11::SetWindow(int width, int height, bool fullscreen, const CStd + } + + CDirtyRegionList dr; +- RefreshGlxContext(); ++ RefreshGlxContext(!m_currentOutput.Equals(output)); + XSync(m_dpy, FALSE); + g_graphicsContext.Clear(0); + g_graphicsContext.Flip(dr); +diff --git a/xbmc/windowing/X11/WinSystemX11.h b/xbmc/windowing/X11/WinSystemX11.h +index 0b7c10a..33b1739 100644 +--- a/xbmc/windowing/X11/WinSystemX11.h ++++ b/xbmc/windowing/X11/WinSystemX11.h +@@ -74,7 +74,7 @@ class CWinSystemX11 : public CWinSystemBase + void NotifyMouseCoverage(bool covered); + + protected: +- bool RefreshGlxContext(); ++ bool RefreshGlxContext(bool force); + void CheckDisplayEvents(); + void OnLostDevice(); + bool SetWindow(int width, int height, bool fullscreen, const CStdString &output); +-- +1.7.10 + + +From ae08a23a2f4fd78139e2ebca8a4a87ab619feb0b Mon Sep 17 00:00:00 2001 +From: xbmc +Date: Sun, 27 Jan 2013 12:10:19 +0100 +Subject: [PATCH 72/73] vdpau: switch off de-interlacing on ff + +--- + xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp +index 8858614..3e21d9d 100644 +--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp ++++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp +@@ -2043,8 +2043,9 @@ void CMixer::InitCycle() + EINTERLACEMETHOD method = GetDeinterlacingMethod(); + bool interlaced = m_mixerInput[1].DVDPic.iFlags & DVP_FLAG_INTERLACED; + +- if (mode == VS_DEINTERLACEMODE_FORCE || +- (mode == VS_DEINTERLACEMODE_AUTO && interlaced)) ++ if (!(flags & DVP_FLAG_NO_POSTPROC) && ++ (mode == VS_DEINTERLACEMODE_FORCE || ++ (mode == VS_DEINTERLACEMODE_AUTO && interlaced))) + { + if((method == VS_INTERLACEMETHOD_AUTO && interlaced) + || method == VS_INTERLACEMETHOD_VDPAU_BOB +-- +1.7.10 + + +From 1ea917e026e8c5df15de6ce6276cba9e58d09d3d Mon Sep 17 00:00:00 2001 +From: xbmc +Date: Sat, 2 Feb 2013 13:17:09 +0100 +Subject: [PATCH 73/73] vdpau: fix mp4 part2 decoding, activate by default + +--- + xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp | 8 ++------ + xbmc/settings/AdvancedSettings.cpp | 2 +- + 2 files changed, 3 insertions(+), 7 deletions(-) + +diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp +index 3e21d9d..524efae 100644 +--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp ++++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp +@@ -127,10 +127,9 @@ bool CDecoder::Open(AVCodecContext* avctx, const enum PixelFormat, unsigned int + VdpDecoderProfile profile = 0; + if(avctx->codec_id == CODEC_ID_H264) + profile = VDP_DECODER_PROFILE_H264_HIGH; +-#ifdef VDP_DECODER_PROFILE_MPEG4_PART2_ASP + else if(avctx->codec_id == CODEC_ID_MPEG4) + profile = VDP_DECODER_PROFILE_MPEG4_PART2_ASP; +-#endif ++ + if(profile) + { + if (!CDVDCodecUtils::IsVP3CompatibleWidth(avctx->coded_width)) +@@ -530,13 +529,10 @@ void CDecoder::ReadFormatOf( PixelFormat fmt + vdp_decoder_profile = VDP_DECODER_PROFILE_VC1_ADVANCED; + vdp_chroma_type = VDP_CHROMA_TYPE_420; + break; +-#if (defined PIX_FMT_VDPAU_MPEG4_IN_AVUTIL) && \ +- (defined VDP_DECODER_PROFILE_MP) + case PIX_FMT_VDPAU_MPEG4: +- vdp_decoder_profile = VDP_DECOPEG4_PART2_ASP; ++ vdp_decoder_profile = VDP_DECODER_PROFILE_MPEG4_PART2_ASP; + vdp_chroma_type = VDP_CHROMA_TYPE_420; + break; +-#endif + default: + vdp_decoder_profile = 0; + vdp_chroma_type = 0; +diff --git a/xbmc/settings/AdvancedSettings.cpp b/xbmc/settings/AdvancedSettings.cpp +index 6a48309..d390ec7 100644 +--- a/xbmc/settings/AdvancedSettings.cpp ++++ b/xbmc/settings/AdvancedSettings.cpp +@@ -102,7 +102,7 @@ void CAdvancedSettings::Initialize() + m_videoNonLinStretchRatio = 0.5f; + m_videoEnableHighQualityHwScalers = false; + m_videoAutoScaleMaxFps = 30.0f; +- m_videoAllowMpeg4VDPAU = false; ++ m_videoAllowMpeg4VDPAU = true; + m_videoAllowMpeg4VAAPI = false; + m_videoDisableBackgroundDeinterlace = false; + m_videoCaptureUseOcclusionQuery = -1; //-1 is auto detect +-- +1.7.10 + diff --git a/packages/mediacenter/xbmc/patches/xbmc-995.09-revert-rpi-fixes.patch b/packages/mediacenter/xbmc/patches/xbmc-995.09-revert-rpi-fixes.patch new file mode 100644 index 0000000000..b7d03823ff --- /dev/null +++ b/packages/mediacenter/xbmc/patches/xbmc-995.09-revert-rpi-fixes.patch @@ -0,0 +1,64 @@ +diff -Naur xbmc-12.0.2/xbmc/cores/omxplayer/OMXPlayerVideo.cpp xbmc-12.0.2.patch/xbmc/cores/omxplayer/OMXPlayerVideo.cpp +--- xbmc-12.0.2/xbmc/cores/omxplayer/OMXPlayerVideo.cpp 2013-02-19 19:04:39.000000000 +0100 ++++ xbmc-12.0.2.patch/xbmc/cores/omxplayer/OMXPlayerVideo.cpp 2013-02-22 18:18:47.298296862 +0100 +@@ -124,7 +124,6 @@ + m_started = false; + m_stalled = m_messageQueue.GetPacketCount(CDVDMsg::DEMUXER_PACKET) == 0; + m_autosync = 1; +- m_iSleepEndTime = DVD_NOPTS_VALUE; + + m_audio_count = m_av_clock->HasAudio(); + +@@ -453,23 +452,13 @@ + m_dropbase = 0.0f; + #endif + +- // DVDPlayer sleeps until m_iSleepEndTime here before calling FlipPage. +- // Video playback in asynchronous in OMXPlayer, so we don't want to do that here, as it prevents the video fifo from being kept full. +- // So, we keep track of when FlipPage would have been called on DVDPlayer and return early if it is not time. +- // m_iSleepEndTime == DVD_NOPTS_VALUE means we are not waiting to call FlipPage, otherwise it is the time we want to call FlipPage +- if (m_iSleepEndTime == DVD_NOPTS_VALUE) { +- m_iSleepEndTime = iCurrentClock + iSleepTime; +- } +- +- if (!CThread::m_bStop && m_av_clock->GetAbsoluteClock(false) < m_iSleepEndTime + DVD_MSEC_TO_TIME(500)) +- return; +- + double pts_media = m_av_clock->OMXMediaTime(false, false); + ProcessOverlays(iGroupId, pts_media); + +- g_renderManager.FlipPage(CThread::m_bStop, m_iSleepEndTime / DVD_TIME_BASE, -1, FS_NONE); ++ while(!CThread::m_bStop && m_av_clock->GetAbsoluteClock(false) < (iCurrentClock + iSleepTime + DVD_MSEC_TO_TIME(500)) ) ++ Sleep(1); + +- m_iSleepEndTime = DVD_NOPTS_VALUE; ++ g_renderManager.FlipPage(CThread::m_bStop, (iCurrentClock + iSleepTime) / DVD_TIME_BASE, -1, FS_NONE); + + //m_av_clock->WaitAbsoluteClock((iCurrentClock + iSleepTime)); + } +@@ -580,14 +569,12 @@ + m_av_clock->OMXReset(false); + m_av_clock->UnLock(); + m_started = false; +- m_iSleepEndTime = DVD_NOPTS_VALUE; + } + else if (pMsg->IsType(CDVDMsg::GENERAL_FLUSH)) // private message sent by (COMXPlayerVideo::Flush()) + { + CLog::Log(LOGDEBUG, "COMXPlayerVideo - CDVDMsg::GENERAL_FLUSH"); + m_stalled = true; + m_started = false; +- m_iSleepEndTime = DVD_NOPTS_VALUE; + m_av_clock->Lock(); + m_av_clock->OMXStop(false); + m_omxVideo.Reset(); +diff -Naur xbmc-12.0.2/xbmc/cores/omxplayer/OMXPlayerVideo.h xbmc-12.0.2.patch/xbmc/cores/omxplayer/OMXPlayerVideo.h +--- xbmc-12.0.2/xbmc/cores/omxplayer/OMXPlayerVideo.h 2013-02-19 19:04:39.000000000 +0100 ++++ xbmc-12.0.2.patch/xbmc/cores/omxplayer/OMXPlayerVideo.h 2013-02-22 18:18:44.166310881 +0100 +@@ -49,7 +49,6 @@ + bool m_open; + CDVDStreamInfo m_hints; + double m_iCurrentPts; +- double m_iSleepEndTime; + OMXClock *m_av_clock; + COMXVideo m_omxVideo; + float m_fFrameRate; diff --git a/packages/mediacenter/xbmc/patches/xbmc-995.10-xvba_rpi_fixes-059b89b.patch b/packages/mediacenter/xbmc/patches/xbmc-995.10-xvba_rpi_fixes-059b89b.patch new file mode 100644 index 0000000000..a93becfe17 --- /dev/null +++ b/packages/mediacenter/xbmc/patches/xbmc-995.10-xvba_rpi_fixes-059b89b.patch @@ -0,0 +1,1148 @@ +From bc4a2f53976c71c403b91ab1aa6138f966a90480 Mon Sep 17 00:00:00 2001 +From: unknown +Date: Fri, 18 Jan 2013 15:16:38 +0100 +Subject: [PATCH 1/7] multi-screen: fix compilation on windows + +--- + xbmc/settings/GUIWindowSettingsCategory.cpp | 11 ++++++++++- + 1 file changed, 10 insertions(+), 1 deletion(-) + +diff --git a/xbmc/settings/GUIWindowSettingsCategory.cpp b/xbmc/settings/GUIWindowSettingsCategory.cpp +index cacb32a..cbf0acb 100644 +--- a/xbmc/settings/GUIWindowSettingsCategory.cpp ++++ b/xbmc/settings/GUIWindowSettingsCategory.cpp +@@ -528,12 +528,14 @@ void CGUIWindowSettingsCategory::CreateSettings() + FillInRefreshRates(strSetting, g_guiSettings.GetResolution(), false); + continue; + } ++#if defined(HAS_GLX) + else if (strSetting.Equals("videoscreen.monitor")) + { + AddSetting(pSetting, group->GetWidth(), iControlID); + FillInMonitors(strSetting); + continue; + } ++#endif + else if (strSetting.Equals("lookandfeel.skintheme")) + { + AddSetting(pSetting, group->GetWidth(), iControlID); +@@ -1483,6 +1485,7 @@ void CGUIWindowSettingsCategory::OnSettingChanged(BaseSettingControlPtr pSetting + // Cascade + FillInResolutions("videoscreen.resolution", mode, RES_DESKTOP, true); + } ++#if defined(HAS_GLX) + else if (strSetting.Equals("videoscreen.monitor")) + { + CSettingString *pSettingString = (CSettingString *)pSettingControl->GetSetting(); +@@ -1497,6 +1500,7 @@ void CGUIWindowSettingsCategory::OnSettingChanged(BaseSettingControlPtr pSetting + FillInResolutions("videoscreen.resolution", mode, RES_DESKTOP, true); + } + } ++#endif + else if (strSetting.Equals("videoscreen.resolution")) + { + RESOLUTION nextRes = (RESOLUTION) g_guiSettings.GetInt("videoscreen.resolution"); +@@ -2451,6 +2455,7 @@ DisplayMode CGUIWindowSettingsCategory::FillInScreens(CStdString strSetting, RES + + void CGUIWindowSettingsCategory::FillInMonitors(CStdString strSetting) + { ++#if defined(HAS_GLX) + // we expect "videoscreen.monitor" but it might be hidden on some platforms, + // so check that we actually have a visable control. + BaseSettingControlPtr control = GetSetting(strSetting); +@@ -2476,6 +2481,7 @@ void CGUIWindowSettingsCategory::FillInMonitors(CStdString strSetting) + pControl->SetValue(currentMonitor); + g_guiSettings.SetString("videoscreen.monitor", g_settings.m_ResInfo[RES_DESKTOP].strOutput); + } ++#endif + } + + +@@ -2607,7 +2613,10 @@ void CGUIWindowSettingsCategory::OnRefreshRateChanged(RESOLUTION nextRes) + RESOLUTION lastRes = g_graphicsContext.GetVideoResolution(); + bool cancelled = false; + +- bool outputChanged = !g_Windowing.IsCurrentOutput(g_guiSettings.GetString("videoscreen.monitor")); ++ bool outputChanged = true; ++#if defined(HAS_GLX) ++ outputChanged = !g_Windowing.IsCurrentOutput(g_guiSettings.GetString("videoscreen.monitor")); ++#endif + + g_guiSettings.SetResolution(nextRes); + g_graphicsContext.SetVideoResolution(nextRes, outputChanged); +-- +1.7.10 + + +From 3724a6e137d00f92b5eb4e419883ae239f0562f8 Mon Sep 17 00:00:00 2001 +From: xbmc +Date: Fri, 22 Feb 2013 09:57:17 +0100 +Subject: [PATCH 2/7] buffering back ports + +--- + xbmc/cores/IPlayer.h | 5 ++ + xbmc/cores/VideoRenderers/BaseRenderer.h | 7 ++- + xbmc/cores/VideoRenderers/LinuxRendererGL.h | 6 +- + xbmc/cores/VideoRenderers/OverlayRenderer.cpp | 17 +++--- + xbmc/cores/VideoRenderers/OverlayRenderer.h | 8 +-- + xbmc/cores/VideoRenderers/RenderManager.cpp | 64 +++++++++++++--------- + xbmc/cores/VideoRenderers/RenderManager.h | 73 ++++++++++++++++++++++--- + xbmc/cores/dvdplayer/DVDPlayer.cpp | 7 ++- + xbmc/cores/dvdplayer/DVDPlayer.h | 2 + + xbmc/cores/dvdplayer/DVDPlayerVideo.cpp | 18 +++++- + 10 files changed, 150 insertions(+), 57 deletions(-) + +diff --git a/xbmc/cores/IPlayer.h b/xbmc/cores/IPlayer.h +index f2aa227..cbf2faa 100644 +--- a/xbmc/cores/IPlayer.h ++++ b/xbmc/cores/IPlayer.h +@@ -229,6 +229,11 @@ class IPlayer + */ + virtual void GetSubtitleCapabilities(std::vector &subCaps) { subCaps.assign(1,IPC_SUBS_ALL); }; + ++ /*! ++ \brief called by RenderManager in order to schedule frames ++ */ ++ virtual double GetClock(double& absolute, bool interpolated = true) {return 0; }; ++ + protected: + IPlayerCallback& m_callback; + }; +diff --git a/xbmc/cores/VideoRenderers/BaseRenderer.h b/xbmc/cores/VideoRenderers/BaseRenderer.h +index b02d536..60b7197 100644 +--- a/xbmc/cores/VideoRenderers/BaseRenderer.h ++++ b/xbmc/cores/VideoRenderers/BaseRenderer.h +@@ -26,10 +26,11 @@ + + #define MAX_PLANES 3 + #define MAX_FIELDS 3 ++#define NUM_BUFFERS 10 + + typedef struct YV12Image + { +- BYTE * plane[MAX_PLANES]; ++ uint8_t* plane[MAX_PLANES]; + int planesize[MAX_PLANES]; + unsigned stride[MAX_PLANES]; + unsigned width; +@@ -84,8 +85,8 @@ class CBaseRenderer + virtual void Flush() {}; + + virtual unsigned int GetProcessorSize() { return 0; } +- virtual unsigned int GetMaxProcessorSize() { return 0; } +- virtual void SetProcessorSize(int numBuffers) { } ++ virtual unsigned int GetMaxBufferSize() { return 0; } ++ virtual void SetBufferSize(int numBuffers) { } + virtual void ReleaseBuffer(int idx) { } + + virtual bool Supports(ERENDERFEATURE feature) { return false; } +diff --git a/xbmc/cores/VideoRenderers/LinuxRendererGL.h b/xbmc/cores/VideoRenderers/LinuxRendererGL.h +index e76624b..a189892 100644 +--- a/xbmc/cores/VideoRenderers/LinuxRendererGL.h ++++ b/xbmc/cores/VideoRenderers/LinuxRendererGL.h +@@ -46,8 +46,6 @@ + namespace XVBA { class CXvbaRenderPicture; } + + +-#define NUM_BUFFERS 10 +- + #undef ALIGN + #define ALIGN(value, alignment) (((value)+((alignment)-1))&~((alignment)-1)) + #define CLAMP(a, min, max) ((a) > (max) ? (max) : ( (a) < (min) ? (min) : a )) +@@ -141,8 +139,8 @@ class CLinuxRendererGL : public CBaseRenderer + 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 GetMaxProcessorSize() { return NUM_BUFFERS; } ++ virtual void SetBufferSize(int numBuffers) { m_NumYV12Buffers = numBuffers; } ++ virtual unsigned int GetMaxBufferSize() { return NUM_BUFFERS; } + virtual unsigned int GetProcessorSize() { return m_NumYV12Buffers; } + + #ifdef HAVE_LIBVDPAU +diff --git a/xbmc/cores/VideoRenderers/OverlayRenderer.cpp b/xbmc/cores/VideoRenderers/OverlayRenderer.cpp +index 94aaaf5..5236390 100644 +--- a/xbmc/cores/VideoRenderers/OverlayRenderer.cpp ++++ b/xbmc/cores/VideoRenderers/OverlayRenderer.cpp +@@ -93,24 +93,28 @@ long COverlayMainThread::Release() + + CRenderer::~CRenderer() + { +- for(int i = 0; i < 2; i++) ++ for(int i = 0; i < NUM_BUFFERS; i++) + Release(m_buffers[i]); + } + +-void CRenderer::AddOverlay(CDVDOverlay* o, double pts) ++void CRenderer::AddOverlay(CDVDOverlay* o, double pts, int index) + { + CSingleLock lock(m_section); + ++ m_decode = index; ++ + SElement e; + e.pts = pts; + e.overlay_dvd = o->Acquire(); + m_buffers[m_decode].push_back(e); + } + +-void CRenderer::AddOverlay(COverlay* o, double pts) ++void CRenderer::AddOverlay(COverlay* o, double pts, int index) + { + CSingleLock lock(m_section); + ++ m_decode = index; ++ + SElement e; + e.pts = pts; + e.overlay = o->Acquire(); +@@ -163,13 +167,6 @@ void CRenderer::Flip() + m_render = (m_render + 1) % m_iNumBuffers; + } + +-void CRenderer::SetBuffer(int idx) +-{ +- CSingleLock lock(m_section); +- Release(m_buffers[idx]); +- m_decode = idx; +-} +- + void CRenderer::ReleaseBuffer(int idx) + { + CSingleLock lock(m_section); +diff --git a/xbmc/cores/VideoRenderers/OverlayRenderer.h b/xbmc/cores/VideoRenderers/OverlayRenderer.h +index c6740a5..66c592a 100644 +--- a/xbmc/cores/VideoRenderers/OverlayRenderer.h ++++ b/xbmc/cores/VideoRenderers/OverlayRenderer.h +@@ -23,6 +23,7 @@ + #pragma once + + #include "threads/CriticalSection.h" ++#include "BaseRenderer.h" + + #include + +@@ -92,14 +93,13 @@ + CRenderer(); + ~CRenderer(); + +- void AddOverlay(CDVDOverlay* o, double pts); +- void AddOverlay(COverlay* o, double pts); ++ void AddOverlay(CDVDOverlay* o, double pts, int index); ++ void AddOverlay(COverlay* o, double pts, int index); + void AddCleanup(COverlay* o); + void Flip(); + void Render(); + void Flush(); + void SetNumBuffers(int numBuffers) { m_iNumBuffers = numBuffers; } +- void SetBuffer(int idx); + void ReleaseBuffer(int idx); + + protected: +@@ -127,7 +127,7 @@ + void Release(SElementV& list); + + CCriticalSection m_section; +- SElementV m_buffers[10]; ++ SElementV m_buffers[NUM_BUFFERS]; + int m_iNumBuffers; + int m_decode; + int m_render; +diff --git a/xbmc/cores/VideoRenderers/RenderManager.cpp b/xbmc/cores/VideoRenderers/RenderManager.cpp +index 9290f80..ca454eb 100644 +--- a/xbmc/cores/VideoRenderers/RenderManager.cpp ++++ b/xbmc/cores/VideoRenderers/RenderManager.cpp +@@ -228,7 +228,7 @@ CStdString CXBMCRenderManager::GetVSyncState() + return state; + } + +-bool CXBMCRenderManager::Configure(unsigned int width, unsigned int height, unsigned int d_width, unsigned int d_height, float fps, unsigned flags, ERenderFormat format, unsigned extended_format, unsigned int orientation) ++bool CXBMCRenderManager::Configure(unsigned int width, unsigned int height, unsigned int d_width, unsigned int d_height, float fps, unsigned flags, ERenderFormat format, unsigned extended_format, unsigned int orientation, bool buffering) + { + /* make sure any queued frame was fully presented */ + double timeout = m_presenttime + 0.1; +@@ -248,12 +248,8 @@ bool CXBMCRenderManager::Configure(unsigned int width, unsigned int height, unsi + return false; + } + +- // check if decoder supports buffering +- m_bCodecSupportsBuffering = false; +- if (format == RENDER_FMT_VDPAU +- || format == RENDER_FMT_VDPAU_420 +- || format == RENDER_FMT_XVBA) +- m_bCodecSupportsBuffering = true; ++ // set buffering ++ m_bCodecSupportsBuffering = buffering; + + bool result = m_pRenderer->Configure(width, height, d_width, d_height, fps, flags, format, extended_format, orientation); + if(result) +@@ -325,7 +321,7 @@ void CXBMCRenderManager::RenderUpdate(bool clear, DWORD flags, DWORD alpha) + m_presentevent.Set(); + } + +-unsigned int CXBMCRenderManager::PreInit(CDVDClock *pClock) ++unsigned int CXBMCRenderManager::PreInit() + { + CRetakeLock lock(m_sharedSection); + +@@ -333,7 +329,6 @@ unsigned int CXBMCRenderManager::PreInit(CDVDClock *pClock) + m_presenterr = 0.0; + m_errorindex = 0; + memset(m_errorbuff, 0, sizeof(m_errorbuff)); +- m_pClock = pClock; + + m_bIsStarted = false; + m_bPauseDrawing = false; +@@ -617,10 +612,12 @@ void CXBMCRenderManager::FlipPage(volatile bool& bStop, double timestamp /* = 0L + } + } + +- FlipFreeBuffer(); +- m_renderBuffers[m_iOutputRenderBuffer].pts = timestamp; +- m_renderBuffers[m_iOutputRenderBuffer].presentfield = presentfield; +- m_renderBuffers[m_iOutputRenderBuffer].presentmethod = presentmethod; ++ if (FlipFreeBuffer() >= 0) ++ { ++ m_renderBuffers[m_iOutputRenderBuffer].pts = timestamp; ++ m_renderBuffers[m_iOutputRenderBuffer].presentfield = presentfield; ++ m_renderBuffers[m_iOutputRenderBuffer].presentmethod = presentmethod; ++ } + m_speed = speed; + } + +@@ -880,9 +877,17 @@ int CXBMCRenderManager::AddVideoPicture(DVDVideoPicture& pic) + #endif + m_pRenderer->ReleaseImage(index, false); + ++ m_bRenderBufferUsed = true; + return index; + } + ++void CXBMCRenderManager::AddOverlay(CDVDOverlay* o, double pts) ++{ ++ CSharedLock lock(m_sharedSection); ++ m_overlays.AddOverlay(o, pts, (m_iOutputRenderBuffer + 1) % m_iNumRenderBuffers); ++ m_bRenderBufferUsed = true; ++} ++ + bool CXBMCRenderManager::Supports(ERENDERFEATURE feature) + { + CSharedLock lock(m_sharedSection); +@@ -939,31 +944,28 @@ EINTERLACEMETHOD CXBMCRenderManager::AutoInterlaceMethodInternal(EINTERLACEMETHO + return mInt; + } + +-int CXBMCRenderManager::WaitForBuffer(volatile bool& bStop) ++int CXBMCRenderManager::WaitForBuffer(volatile bool& bStop, int timeout) + { + 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; ++ double maxwait = GetPresentTime() + (float)timeout/1000; + while(!HasFreeBuffer() && !bStop) + { + lock.Leave(); +- m_flipEvent.WaitMSec(50); +- if(GetPresentTime() > timeout && !bStop) ++ m_flipEvent.WaitMSec(std::min(50, timeout)); ++ if(GetPresentTime() > maxwait && !bStop) + { +- CLog::Log(LOGWARNING, "CRenderManager::WaitForBuffer - timeout waiting for buffer"); ++ if (timeout != 0) ++ 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; + +@@ -987,10 +989,17 @@ int CXBMCRenderManager::FlipFreeBuffer() + // See "Render Buffer State Description" in header for information. + if (HasFreeBuffer()) + { ++ if (!m_bRenderBufferUsed) ++ { ++ return -1; ++ } ++ m_bRenderBufferUsed = false; + m_bAllRenderBuffersDisplayed = false; + m_iOutputRenderBuffer = (m_iOutputRenderBuffer + 1) % m_iNumRenderBuffers; + return m_iOutputRenderBuffer; + } ++ else ++ return -1; + } + + bool CXBMCRenderManager::HasFreeBuffer() +@@ -1013,7 +1022,7 @@ bool CXBMCRenderManager::HasFreeBuffer() + + void CXBMCRenderManager::ResetRenderBuffer() + { +- m_iNumRenderBuffers = m_pRenderer->GetMaxProcessorSize(); ++ m_iNumRenderBuffers = m_pRenderer->GetMaxBufferSize(); + m_iNumRenderBuffers = std::min(5, m_iNumRenderBuffers); + m_iNumRenderBuffers = std::max(2, m_iNumRenderBuffers); + +@@ -1022,7 +1031,7 @@ void CXBMCRenderManager::ResetRenderBuffer() + + CLog::Log(LOGNOTICE,"CXBMCRenderManager::ResetRenderBuffer - using %d render buffers", m_iNumRenderBuffers); + m_overlays.SetNumBuffers(m_iNumRenderBuffers); +- m_pRenderer->SetProcessorSize(m_iNumRenderBuffers); ++ m_pRenderer->SetBufferSize(m_iNumRenderBuffers); + + m_iCurrentRenderBuffer = 0; + m_iOutputRenderBuffer = 0; +@@ -1031,6 +1040,7 @@ void CXBMCRenderManager::ResetRenderBuffer() + m_sleeptime = 1.0; + m_presentPts = DVD_NOPTS_VALUE; + m_speed = 0; ++ m_bRenderBufferUsed = false; + } + + void CXBMCRenderManager::PrepareNextRender() +@@ -1045,7 +1055,11 @@ void CXBMCRenderManager::PrepareNextRender() + } + + double iClockSleep, iPlayingClock, iCurrentClock; +- iPlayingClock = m_pClock->GetClock(iCurrentClock, false); ++ if (g_application.m_pPlayer) ++ iPlayingClock = g_application.m_pPlayer->GetClock(iCurrentClock, false); ++ else ++ iPlayingClock = iCurrentClock = 0; ++ + iClockSleep = m_renderBuffers[idx].pts - iPlayingClock; + + if (m_speed) +diff --git a/xbmc/cores/VideoRenderers/RenderManager.h b/xbmc/cores/VideoRenderers/RenderManager.h +index 6746957..1a460c7 100644 +--- a/xbmc/cores/VideoRenderers/RenderManager.h ++++ b/xbmc/cores/VideoRenderers/RenderManager.h +@@ -66,21 +66,44 @@ class CXBMCRenderManager + void SetViewMode(int iViewMode); + + // Functions called from mplayer +- bool Configure(unsigned int width, unsigned int height, unsigned int d_width, unsigned int d_height, float fps, unsigned flags, ERenderFormat format, unsigned extended_format, unsigned int orientation); ++ /** ++ * Called by video player to configure renderer ++ * @param width width of decoded frame ++ * @param height height of decoded frame ++ * @param d_width displayed width of frame (aspect ratio) ++ * @param d_height displayed height of frame ++ * @param fps frames per second of video ++ * @param flags see RenderFlags.h ++ * @param format see RenderFormats.h ++ * @param extended_format used by DXVA ++ * @param orientation ++ * @param buffering enable buffering in renderer, defaults to false ++ */ ++ bool Configure(unsigned int width, unsigned int height, unsigned int d_width, unsigned int d_height, float fps, unsigned flags, ERenderFormat format, unsigned extended_format, unsigned int orientation, bool buffering = false); + bool IsConfigured(); + + int AddVideoPicture(DVDVideoPicture& picture); + ++ /** ++ * Called by video player to flip render buffers ++ * If buffering is enabled this method does not block. In case of disabled buffering ++ * this method blocks waiting for the render thread to pass by. ++ * When buffering is used there might be no free buffer available after the call to ++ * this method. Player has to call WaitForBuffer. A free buffer will become ++ * available after the main thread has flipped front / back buffers. ++ * ++ * @param bStop reference to stop flag of calling thread ++ * @param timestamp pts of frame delivered with AddVideoPicture ++ * @param source depreciated ++ * @param sync signals frame, top, or bottom field ++ * @param speed current speed of player, needed to calculate presenttime when buffering is avtive ++ */ + void FlipPage(volatile bool& bStop, double timestamp = 0.0, int source = -1, EFIELDSYNC sync = FS_NONE, int speed = 0); +- unsigned int PreInit(CDVDClock *pClock); ++ unsigned int PreInit(); + void UnInit(); + bool Flush(); + +- void AddOverlay(CDVDOverlay* o, double pts) +- { +- CSharedLock lock(m_sharedSection); +- m_overlays.AddOverlay(o, pts); +- } ++ void AddOverlay(CDVDOverlay* o, double pts); + + void AddCleanup(OVERLAY::COverlay* o) + { +@@ -132,11 +155,43 @@ class CXBMCRenderManager + CSharedSection& GetSection() { return m_sharedSection; }; + + void RegisterRenderUpdateCallBack(const void *ctx, RenderUpdateCallBackFn fn); +- int WaitForBuffer(volatile bool& bStop); ++ ++ /** ++ * If player uses buffering it has to wait for a buffer before it calls ++ * AddVideoPicture and AddOverlay. It waits for max 50 ms before it returns -1 ++ * in case no buffer is available. Player may call this in a loop and decides ++ * by itself when it wants to drop a frame. ++ * If no buffering is requested in Configure, player does not need to call this, ++ * because FlipPage will block. ++ */ ++ int WaitForBuffer(volatile bool& bStop, int timeout = 100); ++ ++ /** ++ * Called by application right after flip. The buffer which has been rendered to ++ * display becomes available for player to deliver a new frame. ++ */ + void NotifyDisplayFlip(); ++ ++ /** ++ * Can be called by player for lateness detection. This is done best by ++ * looking at the end of the queue. ++ */ + bool GetStats(double &sleeptime, double &pts, int &bufferLevel); ++ ++ /** ++ * Called by application (main thread) to query if there is any frame to render ++ */ + bool HasFrame(); ++ ++ /** ++ * Video player can dynamically enable/disable buffering. In situations like ++ * rewind buffering is not ideal. ++ */ + void EnableBuffering(bool enable); ++ ++ /** ++ * Video player call this on flush in oder to discard any queued frames ++ */ + void DiscardBuffer(); + + protected: +@@ -202,6 +257,7 @@ class CXBMCRenderManager + bool m_bUseBuffering; + bool m_bCodecSupportsBuffering; + int m_speed; ++ bool m_bRenderBufferUsed; + CEvent m_flipEvent; + + struct +@@ -225,7 +281,6 @@ class CXBMCRenderManager + int m_presentsource; + CEvent m_presentevent; + CEvent m_flushEvent; +- CDVDClock *m_pClock; + + + OVERLAY::CRenderer m_overlays; +diff --git a/xbmc/cores/dvdplayer/DVDPlayer.cpp b/xbmc/cores/dvdplayer/DVDPlayer.cpp +index 07df0d8..18fae70 100644 +--- a/xbmc/cores/dvdplayer/DVDPlayer.cpp ++++ b/xbmc/cores/dvdplayer/DVDPlayer.cpp +@@ -463,7 +463,7 @@ bool CDVDPlayer::OpenFile(const CFileItem& file, const CPlayerOptions &options) + m_ready.Reset(); + + #if defined(HAS_VIDEO_PLAYBACK) +- g_renderManager.PreInit(&m_clock); ++ g_renderManager.PreInit(); + #endif + + Create(); +@@ -4097,3 +4097,8 @@ bool CDVDPlayer::CachePVRStream(void) const + !g_PVRManager.IsPlayingRecording() && + g_advancedSettings.m_bPVRCacheInDvdPlayer; + } ++ ++double CDVDPlayer::GetClock(double& absolute, bool interpolated) ++{ ++ return m_clock.GetClock(absolute, interpolated); ++} +diff --git a/xbmc/cores/dvdplayer/DVDPlayer.h b/xbmc/cores/dvdplayer/DVDPlayer.h +index 70ecea9..2b67d4c 100644 +--- a/xbmc/cores/dvdplayer/DVDPlayer.h ++++ b/xbmc/cores/dvdplayer/DVDPlayer.h +@@ -252,6 +252,8 @@ class CDVDPlayer : public IPlayer, public CThread, public IDVDPlayer + virtual bool SwitchChannel(const PVR::CPVRChannel &channel); + virtual bool CachePVRStream(void) const; + ++ virtual double GetClock(double& absolute, bool interpolated = true); ++ + enum ECacheState + { CACHESTATE_DONE = 0 + , CACHESTATE_FULL // player is filling up the demux queue +diff --git a/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp b/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp +index d26ab9c..19ba35d 100644 +--- a/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp ++++ b/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp +@@ -1117,53 +1117,69 @@ int CDVDPlayerVideo::OutputPicture(const DVDVideoPicture* src, double pts) + } + + CStdString formatstr; ++ bool buffering; + + switch(pPicture->format) + { + case RENDER_FMT_YUV420P: + formatstr = "YV12"; ++ buffering = true; + break; + case RENDER_FMT_YUV420P16: + formatstr = "YV12P16"; ++ buffering = true; + break; + case RENDER_FMT_YUV420P10: + formatstr = "YV12P10"; ++ buffering = true; + break; + case RENDER_FMT_NV12: + formatstr = "NV12"; ++ buffering = true; + break; + case RENDER_FMT_UYVY422: + formatstr = "UYVY"; ++ buffering = true; + break; + case RENDER_FMT_YUYV422: + formatstr = "YUY2"; ++ buffering = true; + break; + case RENDER_FMT_VDPAU: + formatstr = "VDPAU"; ++ buffering = true; + break; + case RENDER_FMT_VDPAU_420: + formatstr = "VDPAU_420"; ++ buffering = true; + break; + case RENDER_FMT_DXVA: + formatstr = "DXVA"; ++ buffering = true; + break; + case RENDER_FMT_VAAPI: + formatstr = "VAAPI"; ++ buffering = false; + break; + case RENDER_FMT_OMXEGL: + formatstr = "OMXEGL"; ++ buffering = false; + break; + case RENDER_FMT_CVBREF: + formatstr = "BGRA"; ++ buffering = false; + break; + case RENDER_FMT_BYPASS: + formatstr = "BYPASS"; ++ buffering = false; + break; + case RENDER_FMT_NONE: + formatstr = "NONE"; ++ buffering = false; + break; + case RENDER_FMT_XVBA: + formatstr = "XVBA"; ++ buffering = true; + break; + } + +@@ -1174,7 +1190,7 @@ int CDVDPlayerVideo::OutputPicture(const DVDVideoPicture* src, double pts) + } + + CLog::Log(LOGDEBUG,"%s - change configuration. %dx%d. framerate: %4.2f. format: %s",__FUNCTION__,pPicture->iWidth, pPicture->iHeight, config_framerate, formatstr.c_str()); +- if(!g_renderManager.Configure(pPicture->iWidth, pPicture->iHeight, pPicture->iDisplayWidth, pPicture->iDisplayHeight, config_framerate, flags, pPicture->format, pPicture->extended_format, m_hints.orientation)) ++ if(!g_renderManager.Configure(pPicture->iWidth, pPicture->iHeight, pPicture->iDisplayWidth, pPicture->iDisplayHeight, config_framerate, flags, pPicture->format, pPicture->extended_format, m_hints.orientation, buffering)) + { + CLog::Log(LOGERROR, "%s - failed to configure renderer", __FUNCTION__); + return EOS_ABORT; +-- +1.7.10 + + +From 1cfeec2846a58b7e2ad44471bb085cef9d2c687d Mon Sep 17 00:00:00 2001 +From: xbmc +Date: Sat, 16 Feb 2013 08:32:18 +0100 +Subject: [PATCH 3/7] add buffering for GLES + +--- + xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp | 10 ---------- + xbmc/cores/VideoRenderers/LinuxRendererGLES.h | 6 ++++-- + 2 files changed, 4 insertions(+), 12 deletions(-) + +diff --git a/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp b/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp +index 2a59e2b..1bf2f3b 100644 +--- a/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp ++++ b/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp +@@ -135,13 +135,6 @@ + delete m_dllSwScale; + } + +-void CLinuxRendererGLES::ManageTextures() +-{ +- m_NumYV12Buffers = 2; +- //m_iYV12RenderBuffer = 0; +- return; +-} +- + bool CLinuxRendererGLES::ValidateRenderTarget() + { + if (!m_bValidated) +@@ -395,7 +388,6 @@ void CLinuxRendererGLES::Update(bool bPauseDrawing) + { + if (!m_bConfigured) return; + ManageDisplay(); +- ManageTextures(); + } + + void CLinuxRendererGLES::RenderUpdate(bool clear, DWORD flags, DWORD alpha) +@@ -409,7 +401,6 @@ void CLinuxRendererGLES::RenderUpdate(bool clear, DWORD flags, DWORD alpha) + if (m_renderMethod & RENDER_BYPASS) + { + ManageDisplay(); +- ManageTextures(); + // if running bypass, then the player might need the src/dst rects + // for sizing video playback on a layer other than the gles layer. + if (m_RenderUpdateCallBackFn) +@@ -449,7 +440,6 @@ void CLinuxRendererGLES::RenderUpdate(bool clear, DWORD flags, DWORD alpha) + return; + + ManageDisplay(); +- ManageTextures(); + + g_graphicsContext.BeginPaint(); + +diff --git a/xbmc/cores/VideoRenderers/LinuxRendererGLES.h b/xbmc/cores/VideoRenderers/LinuxRendererGLES.h +index c6b69db..5bae10d 100644 +--- a/xbmc/cores/VideoRenderers/LinuxRendererGLES.h ++++ b/xbmc/cores/VideoRenderers/LinuxRendererGLES.h +@@ -41,7 +41,7 @@ + class COpenMaxVideo; + typedef std::vector Features; + +-#define NUM_BUFFERS 3 ++#define NUM_BUFFERS 10 + + + #undef ALIGN +@@ -138,6 +138,9 @@ class CLinuxRendererGLES : public CBaseRenderer + virtual void UnInit(); + virtual void Reset(); /* resets renderer after seek for example */ + virtual void ReorderDrawPoints(); ++ virtual void SetBufferSize(int numBuffers) { m_NumYV12Buffers = numBuffers; } ++ virtual unsigned int GetMaxBufferSize() { return NUM_BUFFERS; } ++ virtual unsigned int GetProcessorSize() { return m_NumYV12Buffers; } + + virtual void RenderUpdate(bool clear, DWORD flags = 0, DWORD alpha = 255); + +@@ -162,7 +165,6 @@ class CLinuxRendererGLES : public CBaseRenderer + protected: + virtual void Render(DWORD flags, int index); + +- virtual void ManageTextures(); + int NextYV12Texture(); + virtual bool ValidateRenderTarget(); + virtual void LoadShaders(int field=FIELD_FULL); +-- +1.7.10 + + +From 20fe728e43350442747c05adde545103516f377b Mon Sep 17 00:00:00 2001 +From: xbmc +Date: Sun, 10 Feb 2013 18:40:30 +0100 +Subject: [PATCH 4/7] OMXPlayer: adapt to buffering + +--- + xbmc/cores/omxplayer/OMXPlayer.cpp | 6 ++++++ + xbmc/cores/omxplayer/OMXPlayer.h | 2 ++ + xbmc/cores/omxplayer/OMXPlayerVideo.cpp | 21 +++++++++++++-------- + 3 files changed, 21 insertions(+), 8 deletions(-) + +diff --git a/xbmc/cores/omxplayer/OMXPlayer.cpp b/xbmc/cores/omxplayer/OMXPlayer.cpp +index 60aa9ab..b4eda41 100644 +--- a/xbmc/cores/omxplayer/OMXPlayer.cpp ++++ b/xbmc/cores/omxplayer/OMXPlayer.cpp +@@ -4210,4 +4210,10 @@ void COMXPlayer::GetSubtitleCapabilities(std::vector &subCaps) + subCaps.push_back(IPC_SUBS_ALL); + } + ++double COMXPlayer::GetClock(double& absolute, bool interpolated) ++{ ++ m_av_clock.GetClock(absolute, interpolated); ++ return m_av_clock.OMXMediaTime(false, false); ++} ++ + #endif +diff --git a/xbmc/cores/omxplayer/OMXPlayer.h b/xbmc/cores/omxplayer/OMXPlayer.h +index d606e84..ad9d1e6 100644 +--- a/xbmc/cores/omxplayer/OMXPlayer.h ++++ b/xbmc/cores/omxplayer/OMXPlayer.h +@@ -332,6 +332,8 @@ class COMXPlayer : public IPlayer, public CThread, public IDVDPlayer + virtual void GetScalingMethods(std::vector &scalingMethods); + virtual void GetAudioCapabilities(std::vector &audioCaps); + virtual void GetSubtitleCapabilities(std::vector &subCaps); ++ ++ virtual double GetClock(double& absolute, bool interpolated = true); + protected: + friend class COMXSelectionStreams; + +diff --git a/xbmc/cores/omxplayer/OMXPlayerVideo.cpp b/xbmc/cores/omxplayer/OMXPlayerVideo.cpp +index 90f94aa..ecf4c9a 100644 +--- a/xbmc/cores/omxplayer/OMXPlayerVideo.cpp ++++ b/xbmc/cores/omxplayer/OMXPlayerVideo.cpp +@@ -158,6 +158,8 @@ bool OMXPlayerVideo::OpenStream(CDVDStreamInfo &hints) + m_open = true; + m_send_eos = false; + ++ g_renderManager.EnableBuffering(false); ++ + return true; + } + +@@ -358,7 +360,7 @@ void OMXPlayerVideo::Output(int iGroupId, double pts, bool bDropPacket) + + if(!g_renderManager.Configure(m_hints.width, m_hints.height, + iDisplayWidth, iDisplayHeight, m_fps, flags, format, 0, +- m_hints.orientation)) ++ m_hints.orientation, true)) + { + CLog::Log(LOGERROR, "%s - failed to configure renderer", __FUNCTION__); + return; +@@ -452,15 +454,15 @@ void OMXPlayerVideo::Output(int iGroupId, double pts, bool bDropPacket) + m_dropbase = 0.0f; + #endif + +- double pts_media = m_av_clock->OMXMediaTime(false, false); +- ProcessOverlays(iGroupId, pts_media); +- +- while(!CThread::m_bStop && m_av_clock->GetAbsoluteClock(false) < (iCurrentClock + iSleepTime + DVD_MSEC_TO_TIME(500)) ) +- Sleep(1); ++ int buffer = g_renderManager.WaitForBuffer(m_bStop, 0); ++ if (buffer < 0) ++ return; + +- g_renderManager.FlipPage(CThread::m_bStop, (iCurrentClock + iSleepTime) / DVD_TIME_BASE, -1, FS_NONE); ++ double pts_overlay = m_av_clock->OMXMediaTime(false, false) ++ + 2* (double)DVD_TIME_BASE / g_graphicsContext.GetFPS(); ++ ProcessOverlays(iGroupId, pts_overlay); + +- //m_av_clock->WaitAbsoluteClock((iCurrentClock + iSleepTime)); ++ g_renderManager.FlipPage(CThread::m_bStop, pts_overlay, -1, FS_NONE, m_speed); + } + + void OMXPlayerVideo::Process() +@@ -569,6 +571,7 @@ void OMXPlayerVideo::Process() + m_av_clock->OMXReset(false); + m_av_clock->UnLock(); + m_started = false; ++ g_renderManager.EnableBuffering(false); + } + else if (pMsg->IsType(CDVDMsg::GENERAL_FLUSH)) // private message sent by (COMXPlayerVideo::Flush()) + { +@@ -580,6 +583,7 @@ void OMXPlayerVideo::Process() + m_omxVideo.Reset(); + m_av_clock->OMXReset(false); + m_av_clock->UnLock(); ++ g_renderManager.EnableBuffering(false); + } + else if (pMsg->IsType(CDVDMsg::PLAYER_SETSPEED)) + { +@@ -664,6 +668,7 @@ void OMXPlayerVideo::Process() + m_codecname = m_omxVideo.GetDecoderName(); + 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 +-- +1.7.10 + + +From 192e1b003ddbda567342c42fb20ce5c7dee28ab1 Mon Sep 17 00:00:00 2001 +From: xbmc +Date: Thu, 21 Feb 2013 18:09:07 +0100 +Subject: [PATCH 5/7] fix ass subs for GLES + +--- + xbmc/cores/VideoRenderers/OverlayRendererGL.cpp | 33 +++++++++++++++-------- + 1 file changed, 22 insertions(+), 11 deletions(-) + +diff --git a/xbmc/cores/VideoRenderers/OverlayRendererGL.cpp b/xbmc/cores/VideoRenderers/OverlayRendererGL.cpp +index 4375d19..ed8e48d 100644 +--- a/xbmc/cores/VideoRenderers/OverlayRendererGL.cpp ++++ b/xbmc/cores/VideoRenderers/OverlayRendererGL.cpp +@@ -359,7 +359,7 @@ static void LoadTexture(GLenum target + + void COverlayGlyphGL::Render(SRenderState& state) + { +- if (m_texture == 0) ++ if ((m_texture == 0) || (m_count == 0)) + return; + + glEnable(GL_TEXTURE_2D); +@@ -418,21 +418,32 @@ void COverlayGlyphGL::Render(SRenderState& state) + GLint colLoc = g_Windowing.GUIShaderGetCol(); + GLint tex0Loc = g_Windowing.GUIShaderGetCoord0(); + +- glVertexAttribPointer(posLoc, 3, GL_FLOAT, GL_FALSE, sizeof(VERTEX), (char*)m_vertex + offsetof(VERTEX, x)); +- glVertexAttribPointer(colLoc, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(VERTEX), (char*)m_vertex + offsetof(VERTEX, r)); +- glVertexAttribPointer(tex0Loc, 2, GL_FLOAT, GL_FALSE, sizeof(VERTEX), (char*)m_vertex + offsetof(VERTEX, u)); ++ // stack object until VBOs will be used ++ std::vector vecVertices( 6 * m_count); ++ VERTEX *vertices = &vecVertices[0]; ++ ++ for (int i=0; i +Date: Sun, 24 Feb 2013 09:55:00 +0100 +Subject: [PATCH 6/7] flip free buffer after overlay has been released + +--- + xbmc/cores/VideoRenderers/OverlayRenderer.cpp | 19 ++++++++++++------- + xbmc/cores/VideoRenderers/OverlayRenderer.h | 6 +++--- + xbmc/cores/VideoRenderers/RenderManager.cpp | 6 ++++-- + xbmc/cores/VideoRenderers/RenderManager.h | 1 + + 4 files changed, 20 insertions(+), 12 deletions(-) + +diff --git a/xbmc/cores/VideoRenderers/OverlayRenderer.cpp b/xbmc/cores/VideoRenderers/OverlayRenderer.cpp +index 5236390..3039751 100644 +--- a/xbmc/cores/VideoRenderers/OverlayRenderer.cpp ++++ b/xbmc/cores/VideoRenderers/OverlayRenderer.cpp +@@ -127,27 +127,32 @@ void CRenderer::AddCleanup(COverlay* o) + m_cleanup.push_back(o->Acquire()); + } + +-void CRenderer::Release(SElementV& list) ++long CRenderer::Release(SElementV& list) + { + SElementV l = list; + list.clear(); + ++ long count = 0; + for(SElementV::iterator it = l.begin(); it != l.end(); it++) + { + if(it->overlay) +- it->overlay->Release(); ++ count += it->overlay->Release(); + if(it->overlay_dvd) +- it->overlay_dvd->Release(); ++ count += it->overlay_dvd->Release(); + } ++ return count; + } + +-void CRenderer::Release(COverlayV& list) ++long CRenderer::Release(COverlayV& list) + { + COverlayV l = list; + list.clear(); + ++ long count = 0; + for(COverlayV::iterator it = l.begin(); it != l.end(); it++) +- (*it)->Release(); ++ count += (*it)->Release(); ++ ++ return count; + } + + void CRenderer::Flush() +@@ -167,10 +172,10 @@ void CRenderer::Flip() + m_render = (m_render + 1) % m_iNumBuffers; + } + +-void CRenderer::ReleaseBuffer(int idx) ++long CRenderer::ReleaseBuffer(int idx) + { + CSingleLock lock(m_section); +- Release(m_buffers[idx]); ++ return Release(m_buffers[idx]); + } + + void CRenderer::Render() +diff --git a/xbmc/cores/VideoRenderers/OverlayRenderer.h b/xbmc/cores/VideoRenderers/OverlayRenderer.h +index 66c592a..2fcac4a 100644 +--- a/xbmc/cores/VideoRenderers/OverlayRenderer.h ++++ b/xbmc/cores/VideoRenderers/OverlayRenderer.h +@@ -100,7 +100,7 @@ + void Render(); + void Flush(); + void SetNumBuffers(int numBuffers) { m_iNumBuffers = numBuffers; } +- void ReleaseBuffer(int idx); ++ long ReleaseBuffer(int idx); + + protected: + +@@ -123,8 +123,8 @@ + COverlay* Convert(CDVDOverlay* o, double pts); + COverlay* Convert(CDVDOverlaySSA* o, double pts); + +- void Release(COverlayV& list); +- void Release(SElementV& list); ++ long Release(COverlayV& list); ++ long Release(SElementV& list); + + CCriticalSection m_section; + SElementV m_buffers[NUM_BUFFERS]; +diff --git a/xbmc/cores/VideoRenderers/RenderManager.cpp b/xbmc/cores/VideoRenderers/RenderManager.cpp +index ca454eb..bc2e403 100644 +--- a/xbmc/cores/VideoRenderers/RenderManager.cpp ++++ b/xbmc/cores/VideoRenderers/RenderManager.cpp +@@ -989,7 +989,7 @@ int CXBMCRenderManager::FlipFreeBuffer() + // See "Render Buffer State Description" in header for information. + if (HasFreeBuffer()) + { +- if (!m_bRenderBufferUsed) ++ if (!m_bRenderBufferUsed && !m_bOverlayReleased) + { + return -1; + } +@@ -1041,6 +1041,7 @@ void CXBMCRenderManager::ResetRenderBuffer() + m_presentPts = DVD_NOPTS_VALUE; + m_speed = 0; + m_bRenderBufferUsed = false; ++ m_bOverlayReleased = false; + } + + void CXBMCRenderManager::PrepareNextRender() +@@ -1119,7 +1120,8 @@ void CXBMCRenderManager::NotifyDisplayFlip() + && m_iDisplayedRenderBuffer != m_iCurrentRenderBuffer) + { + m_pRenderer->ReleaseBuffer(m_iDisplayedRenderBuffer); +- m_overlays.ReleaseBuffer(m_iDisplayedRenderBuffer); ++ if (m_overlays.ReleaseBuffer(m_iDisplayedRenderBuffer) > 0) ++ m_bOverlayReleased = true; + } + } + +diff --git a/xbmc/cores/VideoRenderers/RenderManager.h b/xbmc/cores/VideoRenderers/RenderManager.h +index 1a460c7..fd85882 100644 +--- a/xbmc/cores/VideoRenderers/RenderManager.h ++++ b/xbmc/cores/VideoRenderers/RenderManager.h +@@ -258,6 +258,7 @@ class CXBMCRenderManager + bool m_bCodecSupportsBuffering; + int m_speed; + bool m_bRenderBufferUsed; ++ bool m_bOverlayReleased; + CEvent m_flipEvent; + + struct +-- +1.7.10 + + +From 059b89b5e0b50af7560783a4e6a0638ab9f2680c Mon Sep 17 00:00:00 2001 +From: xbmc +Date: Sun, 24 Feb 2013 17:38:25 +0100 +Subject: [PATCH 7/7] RverlayRenderer: align buffers with index in + renderManager + +--- + xbmc/cores/VideoRenderers/OverlayRenderer.cpp | 7 +++++-- + xbmc/cores/VideoRenderers/OverlayRenderer.h | 2 +- + xbmc/cores/VideoRenderers/RenderManager.cpp | 5 +++-- + 3 files changed, 9 insertions(+), 5 deletions(-) + +diff --git a/xbmc/cores/VideoRenderers/OverlayRenderer.cpp b/xbmc/cores/VideoRenderers/OverlayRenderer.cpp +index 3039751..5592eca 100644 +--- a/xbmc/cores/VideoRenderers/OverlayRenderer.cpp ++++ b/xbmc/cores/VideoRenderers/OverlayRenderer.cpp +@@ -166,10 +166,13 @@ void CRenderer::Flush() + Release(m_cleanup); + } + +-void CRenderer::Flip() ++void CRenderer::Flip(int source) + { + CSingleLock lock(m_section); +- m_render = (m_render + 1) % m_iNumBuffers; ++ if( source >= 0 && source < m_iNumBuffers ) ++ m_render = source; ++ else ++ m_render = (m_render + 1) % m_iNumBuffers; + } + + long CRenderer::ReleaseBuffer(int idx) +diff --git a/xbmc/cores/VideoRenderers/OverlayRenderer.h b/xbmc/cores/VideoRenderers/OverlayRenderer.h +index 2fcac4a..627dd9f 100644 +--- a/xbmc/cores/VideoRenderers/OverlayRenderer.h ++++ b/xbmc/cores/VideoRenderers/OverlayRenderer.h +@@ -96,7 +96,7 @@ + void AddOverlay(CDVDOverlay* o, double pts, int index); + void AddOverlay(COverlay* o, double pts, int index); + void AddCleanup(COverlay* o); +- void Flip(); ++ void Flip(int source); + void Render(); + void Flush(); + void SetNumBuffers(int numBuffers) { m_iNumBuffers = numBuffers; } +diff --git a/xbmc/cores/VideoRenderers/RenderManager.cpp b/xbmc/cores/VideoRenderers/RenderManager.cpp +index bc2e403..099eb4d 100644 +--- a/xbmc/cores/VideoRenderers/RenderManager.cpp ++++ b/xbmc/cores/VideoRenderers/RenderManager.cpp +@@ -303,7 +303,7 @@ void CXBMCRenderManager::RenderUpdate(bool clear, DWORD flags, DWORD alpha) + if(m_presentstep == PRESENT_FLIP) + { + FlipRenderBuffer(); +- m_overlays.Flip(); ++ m_overlays.Flip(m_presentsource); + m_pRenderer->FlipPage(m_presentsource); + m_presentstep = PRESENT_FRAME; + m_presentevent.Set(); +@@ -703,7 +703,7 @@ void CXBMCRenderManager::Present() + if(m_presentstep == PRESENT_FLIP) + { + FlipRenderBuffer(); +- m_overlays.Flip(); ++ m_overlays.Flip(m_presentsource); + m_pRenderer->FlipPage(m_presentsource); + m_presentstep = PRESENT_FRAME; + m_presentevent.Set(); +@@ -994,6 +994,7 @@ int CXBMCRenderManager::FlipFreeBuffer() + return -1; + } + m_bRenderBufferUsed = false; ++ m_bOverlayReleased = false; + m_bAllRenderBuffersDisplayed = false; + m_iOutputRenderBuffer = (m_iOutputRenderBuffer + 1) % m_iNumRenderBuffers; + return m_iOutputRenderBuffer; +-- +1.7.10 + From 82399ef04c529299b0350f227cb68a4a5fb69699 Mon Sep 17 00:00:00 2001 From: Stephan Raue Date: Sun, 24 Feb 2013 23:36:27 +0100 Subject: [PATCH 12/13] xbmc: update XVBA/VDPAU/OMX patches - take 2 Signed-off-by: Stephan Raue --- .../xbmc-995.01-xvba_support-1ea917e.patch | 19295 ---------------- packages/mediacenter/xbmc/unpack | 32 - 2 files changed, 19327 deletions(-) delete mode 100644 packages/mediacenter/xbmc/patches.x86/xbmc-995.01-xvba_support-1ea917e.patch delete mode 100755 packages/mediacenter/xbmc/unpack diff --git a/packages/mediacenter/xbmc/patches.x86/xbmc-995.01-xvba_support-1ea917e.patch b/packages/mediacenter/xbmc/patches.x86/xbmc-995.01-xvba_support-1ea917e.patch deleted file mode 100644 index ac7780f5c2..0000000000 --- a/packages/mediacenter/xbmc/patches.x86/xbmc-995.01-xvba_support-1ea917e.patch +++ /dev/null @@ -1,19295 +0,0 @@ -From bfd49543c49747236d401df4351767d584f756ac Mon Sep 17 00:00:00 2001 -From: wsnipex -Date: Sun, 4 Nov 2012 14:05:52 +0100 -Subject: [PATCH 01/73] configure: add --enable-pvraddons-with-dependencies - switch for intree building of PVR Addons - ---- - configure.in | 12 ++++++++++++ - 1 file changed, 12 insertions(+) - -diff --git a/configure.in b/configure.in -index 4769315..350d960 100644 ---- a/configure.in -+++ b/configure.in -@@ -521,6 +521,14 @@ AC_ARG_ENABLE([external-ffmpeg], - [use_external_ffmpeg=$use_external_libraries]) - - ### End of external library options -+### PVR addons specific -+AC_ARG_ENABLE([pvraddons-with-dependencies], -+ [AS_HELP_STRING([--enable-pvraddons-with-dependencies], -+ [enable build of pvr addons with dependencies (default is no) 'Linux only'])], -+ [use_pvraddons_with_deps=$enableval], -+ [use_pvraddons_with_deps=no]) -+ -+### End PVR addons specific - - if test "x$host_vendor" != "xapple"; then - DEFAULT_COMPILE_FLAGS="-fPIC -DPIC -D_REENTRANT" -@@ -2770,12 +2778,16 @@ XB_CONFIG_MODULE([pvr-addons], [ - if test "$USE_EXTERNAL_FFMPEG" = 1; then - PVR_EXT_FFMPEG="--enable-external-ffmpeg" - fi -+ if test "$use_pvraddons_with_deps" = "yes"; then -+ ADDONS_WITH_DEPS="--enable-addons-with-dependencies" -+ fi - ./configure \ - --prefix="${prefix}" \ - --host=$host_alias \ - --build=$build_alias \ - --target=$target_alias \ - $PVR_EXT_FFMPEG \ -+ $ADDONS_WITH_DEPS \ - CC="$CC" \ - CXX="$CXX" \ - CFLAGS="$CFLAGS" \ --- -1.7.10 - - -From dc83e2351e8bf8e904102782ea489d2c8caa2802 Mon Sep 17 00:00:00 2001 -From: xbmc -Date: Mon, 28 May 2012 10:03:31 +0200 -Subject: [PATCH 02/73] VideoRenerers: add buffering - ---- - xbmc/Application.cpp | 3 + - xbmc/cores/VideoRenderers/BaseRenderer.h | 5 +- - xbmc/cores/VideoRenderers/LinuxRendererGL.cpp | 41 ++-- - xbmc/cores/VideoRenderers/LinuxRendererGL.h | 13 +- - xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp | 8 +- - xbmc/cores/VideoRenderers/LinuxRendererGLES.h | 4 +- - xbmc/cores/VideoRenderers/OverlayRenderer.cpp | 19 +- - xbmc/cores/VideoRenderers/OverlayRenderer.h | 6 +- - xbmc/cores/VideoRenderers/RenderManager.cpp | 296 +++++++++++++++++++---- - xbmc/cores/VideoRenderers/RenderManager.h | 48 +++- - xbmc/cores/VideoRenderers/WinRenderer.cpp | 8 +- - xbmc/cores/VideoRenderers/WinRenderer.h | 2 +- - xbmc/cores/dvdplayer/DVDPlayer.cpp | 2 +- - xbmc/cores/dvdplayer/DVDPlayerVideo.cpp | 18 +- - 14 files changed, 380 insertions(+), 93 deletions(-) - -diff --git a/xbmc/Application.cpp b/xbmc/Application.cpp -index c6f0a14..18e6310 100644 ---- a/xbmc/Application.cpp -+++ b/xbmc/Application.cpp -@@ -2367,7 +2367,10 @@ void CApplication::Render() - m_lastFrameTime = XbmcThreads::SystemClockMillis(); - - if (flip) -+ { - g_graphicsContext.Flip(dirtyRegions); -+ g_renderManager.NotifyDisplayFlip(); -+ } - CTimeUtils::UpdateFrameTime(flip); - - g_TextureManager.FreeUnusedTextures(); -diff --git a/xbmc/cores/VideoRenderers/BaseRenderer.h b/xbmc/cores/VideoRenderers/BaseRenderer.h -index 81d21d8..b02d536 100644 ---- a/xbmc/cores/VideoRenderers/BaseRenderer.h -+++ b/xbmc/cores/VideoRenderers/BaseRenderer.h -@@ -80,10 +80,13 @@ class CBaseRenderer - void GetVideoRect(CRect &source, CRect &dest); - float GetAspectRatio() const; - -- virtual bool AddVideoPicture(DVDVideoPicture* picture) { return false; } -+ virtual bool AddVideoPicture(DVDVideoPicture* picture, int index) { return false; } - virtual void Flush() {}; - - virtual unsigned int GetProcessorSize() { return 0; } -+ virtual unsigned int GetMaxProcessorSize() { return 0; } -+ virtual void SetProcessorSize(int numBuffers) { } -+ virtual void ReleaseBuffer(int idx) { } - - virtual bool Supports(ERENDERFEATURE feature) { return false; } - -diff --git a/xbmc/cores/VideoRenderers/LinuxRendererGL.cpp b/xbmc/cores/VideoRenderers/LinuxRendererGL.cpp -index 1cf52d3..b32a7ea 100644 ---- a/xbmc/cores/VideoRenderers/LinuxRendererGL.cpp -+++ b/xbmc/cores/VideoRenderers/LinuxRendererGL.cpp -@@ -235,14 +235,6 @@ bool CLinuxRendererGL::ValidateRenderer() - return true; - } - -- --void CLinuxRendererGL::ManageTextures() --{ -- m_NumYV12Buffers = 2; -- //m_iYV12RenderBuffer = 0; -- return; --} -- - bool CLinuxRendererGL::ValidateRenderTarget() - { - if (!m_bValidated) -@@ -603,13 +595,28 @@ void CLinuxRendererGL::Flush() - glFinish(); - m_bValidated = false; - m_fbo.fbo.Cleanup(); -+ m_iYV12RenderBuffer = 0; -+} -+ -+void CLinuxRendererGL::ReleaseBuffer(int idx) -+{ -+ YUVBUFFER &buf = m_buffers[idx]; -+#ifdef HAVE_LIBVDPAU -+ SAFE_RELEASE(buf.vdpau); -+#endif -+#ifdef HAVE_LIBVA -+ buf.vaapi.surface.reset(); -+#endif -+#ifdef TARGET_DARWIN -+ if (buf.cvBufferRef) -+ CVBufferRelease(buf.cvBufferRef); -+#endif - } - - void CLinuxRendererGL::Update(bool bPauseDrawing) - { - if (!m_bConfigured) return; - ManageDisplay(); -- ManageTextures(); - } - - void CLinuxRendererGL::RenderUpdate(bool clear, DWORD flags, DWORD alpha) -@@ -625,7 +632,6 @@ void CLinuxRendererGL::RenderUpdate(bool clear, DWORD flags, DWORD alpha) - } - - ManageDisplay(); -- ManageTextures(); - - g_graphicsContext.BeginPaint(); - -@@ -782,7 +788,6 @@ unsigned int CLinuxRendererGL::PreInit() - m_resolution = RES_DESKTOP; - - m_iYV12RenderBuffer = 0; -- m_NumYV12Buffers = 2; - - m_formats.push_back(RENDER_FMT_YUV420P); - GLint size; -@@ -2465,7 +2470,7 @@ void CLinuxRendererGL::UploadVAAPITexture(int index) - || status == VA_STATUS_ERROR_INVALID_DISPLAY) - { - va.display->lost(true); -- for(int i = 0; i < NUM_BUFFERS; i++) -+ for(int i = 0; i < m_NumYV12Buffers; i++) - { - m_buffers[i].vaapi.display.reset(); - m_buffers[i].vaapi.surface.reset(); -@@ -3412,26 +3417,26 @@ void CLinuxRendererGL::UnBindPbo(YUVBUFFER& buff) - } - - #ifdef HAVE_LIBVDPAU --void CLinuxRendererGL::AddProcessor(CVDPAU* vdpau) -+void CLinuxRendererGL::AddProcessor(CVDPAU* vdpau, int index) - { -- YUVBUFFER &buf = m_buffers[NextYV12Texture()]; -+ YUVBUFFER &buf = m_buffers[index]; - SAFE_RELEASE(buf.vdpau); - buf.vdpau = (CVDPAU*)vdpau->Acquire(); - } - #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 TARGET_DARWIN --void CLinuxRendererGL::AddProcessor(struct __CVBuffer *cvBufferRef) -+void CLinuxRendererGL::AddProcessor(struct __CVBuffer *cvBufferRef, int index) - { -- YUVBUFFER &buf = m_buffers[NextYV12Texture()]; -+ YUVBUFFER &buf = m_buffers[index]; - if (buf.cvBufferRef) - CVBufferRelease(buf.cvBufferRef); - buf.cvBufferRef = cvBufferRef; -diff --git a/xbmc/cores/VideoRenderers/LinuxRendererGL.h b/xbmc/cores/VideoRenderers/LinuxRendererGL.h -index acebfe0..9f55fcb 100644 ---- a/xbmc/cores/VideoRenderers/LinuxRendererGL.h -+++ b/xbmc/cores/VideoRenderers/LinuxRendererGL.h -@@ -44,7 +44,7 @@ - namespace Shaders { class BaseVideoFilterShader; } - namespace VAAPI { struct CHolder; } - --#define NUM_BUFFERS 3 -+#define NUM_BUFFERS 10 - - - #undef ALIGN -@@ -138,15 +138,19 @@ class CLinuxRendererGL : public CBaseRenderer - 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 GetMaxProcessorSize() { return NUM_BUFFERS; } -+ virtual unsigned int GetProcessorSize() { return m_NumYV12Buffers; } - - #ifdef HAVE_LIBVDPAU -- virtual void AddProcessor(CVDPAU* vdpau); -+ virtual void AddProcessor(CVDPAU* vdpau, int index); - #endif - #ifdef HAVE_LIBVA -- virtual void AddProcessor(VAAPI::CHolder& holder); -+ virtual void AddProcessor(VAAPI::CHolder& holder, int index); - #endif - #ifdef TARGET_DARWIN -- virtual void AddProcessor(struct __CVBuffer *cvBufferRef); -+ virtual void AddProcessor(struct __CVBuffer *cvBufferRef, int index); - #endif - - virtual void RenderUpdate(bool clear, DWORD flags = 0, DWORD alpha = 255); -@@ -168,7 +172,6 @@ class CLinuxRendererGL : public CBaseRenderer - void DrawBlackBars(); - - bool ValidateRenderer(); -- virtual void ManageTextures(); - int NextYV12Texture(); - virtual bool ValidateRenderTarget(); - virtual void LoadShaders(int field=FIELD_FULL); -diff --git a/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp b/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp -index cb0939f..2a59e2b 100644 ---- a/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp -+++ b/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp -@@ -1982,16 +1982,16 @@ EINTERLACEMETHOD CLinuxRendererGLES::AutoInterlaceMethod() - } - - #ifdef HAVE_LIBOPENMAX --void CLinuxRendererGLES::AddProcessor(COpenMax* openMax, DVDVideoPicture *picture) -+void CLinuxRendererGLES::AddProcessor(COpenMax* openMax, DVDVideoPicture *picture, int index) - { -- YUVBUFFER &buf = m_buffers[NextYV12Texture()]; -+ YUVBUFFER &buf = m_buffers[index]; - buf.openMaxBuffer = picture->openMaxBuffer; - } - #endif - #ifdef HAVE_VIDEOTOOLBOXDECODER --void CLinuxRendererGLES::AddProcessor(struct __CVBuffer *cvBufferRef) -+void CLinuxRendererGLES::AddProcessor(struct __CVBuffer *cvBufferRef, int index) - { -- YUVBUFFER &buf = m_buffers[NextYV12Texture()]; -+ YUVBUFFER &buf = m_buffers[index]; - if (buf.cvBufferRef) - CVBufferRelease(buf.cvBufferRef); - buf.cvBufferRef = cvBufferRef; -diff --git a/xbmc/cores/VideoRenderers/LinuxRendererGLES.h b/xbmc/cores/VideoRenderers/LinuxRendererGLES.h -index 76b5437..c6b69db 100644 ---- a/xbmc/cores/VideoRenderers/LinuxRendererGLES.h -+++ b/xbmc/cores/VideoRenderers/LinuxRendererGLES.h -@@ -153,10 +153,10 @@ class CLinuxRendererGLES : public CBaseRenderer - virtual std::vector SupportedFormats() { return m_formats; } - - #ifdef HAVE_LIBOPENMAX -- virtual void AddProcessor(COpenMax* openMax, DVDVideoPicture *picture); -+ virtual void AddProcessor(COpenMax* openMax, DVDVideoPicture *picture, int index); - #endif - #ifdef HAVE_VIDEOTOOLBOXDECODER -- virtual void AddProcessor(struct __CVBuffer *cvBufferRef); -+ virtual void AddProcessor(struct __CVBuffer *cvBufferRef, int index); - #endif - - protected: -diff --git a/xbmc/cores/VideoRenderers/OverlayRenderer.cpp b/xbmc/cores/VideoRenderers/OverlayRenderer.cpp -index 19d2d7d..94aaaf5 100644 ---- a/xbmc/cores/VideoRenderers/OverlayRenderer.cpp -+++ b/xbmc/cores/VideoRenderers/OverlayRenderer.cpp -@@ -89,7 +89,6 @@ long COverlayMainThread::Release() - CRenderer::CRenderer() - { - m_render = 0; -- m_decode = (m_render + 1) % 2; - } - - CRenderer::~CRenderer() -@@ -151,20 +150,30 @@ void CRenderer::Flush() - { - 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); - } - - void CRenderer::Flip() - { - CSingleLock lock(m_section); -+ m_render = (m_render + 1) % m_iNumBuffers; -+} - -- m_render = m_decode; -- m_decode =(m_decode + 1) % 2; -+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 --git a/xbmc/cores/VideoRenderers/OverlayRenderer.h b/xbmc/cores/VideoRenderers/OverlayRenderer.h -index d2175d8..c6740a5 100644 ---- a/xbmc/cores/VideoRenderers/OverlayRenderer.h -+++ b/xbmc/cores/VideoRenderers/OverlayRenderer.h -@@ -98,6 +98,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 --git a/xbmc/cores/VideoRenderers/RenderManager.cpp b/xbmc/cores/VideoRenderers/RenderManager.cpp -index d22287d..eeb6c6f 100644 ---- a/xbmc/cores/VideoRenderers/RenderManager.cpp -+++ b/xbmc/cores/VideoRenderers/RenderManager.cpp -@@ -28,6 +28,7 @@ - #include "utils/MathUtils.h" - #include "threads/SingleLock.h" - #include "utils/log.h" -+#include "utils/TimeUtils.h" - - #include "Application.h" - #include "ApplicationMessenger.h" -@@ -247,6 +248,11 @@ bool CXBMCRenderManager::Configure(unsigned int width, unsigned int height, unsi - return false; - } - -+ // check if decoder supports buffering -+ m_bCodecSupportsBuffering = false; -+// if (format == RENDER_FMT_VDPAU) -+// m_bCodecSupportsBuffering = true; -+ - bool result = m_pRenderer->Configure(width, height, d_width, d_height, fps, flags, format, extended_format, orientation); - if(result) - { -@@ -261,6 +267,7 @@ bool CXBMCRenderManager::Configure(unsigned int width, unsigned int height, unsi - m_bReconfigured = true; - m_presentstep = PRESENT_IDLE; - m_presentevent.Set(); -+ ResetRenderBuffer(); - } - - return result; -@@ -292,8 +299,12 @@ void CXBMCRenderManager::RenderUpdate(bool clear, DWORD flags, DWORD alpha) - 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; -@@ -312,7 +323,7 @@ void CXBMCRenderManager::RenderUpdate(bool clear, DWORD flags, DWORD alpha) - m_presentevent.Set(); - } - --unsigned int CXBMCRenderManager::PreInit() -+unsigned int CXBMCRenderManager::PreInit(CDVDClock *pClock) - { - CRetakeLock lock(m_sharedSection); - -@@ -320,6 +331,7 @@ unsigned int CXBMCRenderManager::PreInit() - m_presenterr = 0.0; - m_errorindex = 0; - memset(m_errorbuff, 0, sizeof(m_errorbuff)); -+ m_pClock = pClock; - - m_bIsStarted = false; - m_bPauseDrawing = false; -@@ -338,6 +350,10 @@ unsigned int CXBMCRenderManager::PreInit() - - UpdateDisplayLatency(); - -+ m_bUseBuffering = false; -+ m_bCodecSupportsBuffering = true; -+ ResetRenderBuffer(); -+ - return m_pRenderer->PreInit(); - } - -@@ -366,7 +382,9 @@ bool CXBMCRenderManager::Flush() - - CRetakeLock lock(m_sharedSection); - m_pRenderer->Flush(); -+ m_overlays.Flush(); - m_flushEvent.Set(); -+ ResetRenderBuffer(); - } - else - { -@@ -534,25 +552,21 @@ void CXBMCRenderManager::SetViewMode(int iViewMode) - m_pRenderer->SetViewMode(iViewMode); - } - --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; -@@ -560,58 +574,67 @@ void CXBMCRenderManager::FlipPage(volatile bool& bStop, double timestamp /* = 0L - { 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; -+ } - } - } - } -@@ -675,8 +698,12 @@ void CXBMCRenderManager::Present() - 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; -@@ -800,11 +827,11 @@ int CXBMCRenderManager::AddVideoPicture(DVDVideoPicture& pic) - if (!m_pRenderer) - return -1; - -- if(m_pRenderer->AddVideoPicture(&pic)) -+ if(m_pRenderer->AddVideoPicture(&pic, (m_iOutputRenderBuffer + 1) % m_iNumRenderBuffers)) - 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; -@@ -830,19 +857,19 @@ int CXBMCRenderManager::AddVideoPicture(DVDVideoPicture& pic) - } - #ifdef HAVE_LIBVDPAU - else if(pic.format == RENDER_FMT_VDPAU) -- m_pRenderer->AddProcessor(pic.vdpau); -+ m_pRenderer->AddProcessor(pic.vdpau, index); - #endif - #ifdef HAVE_LIBOPENMAX - else if(pic.format == RENDER_FMT_OMXEGL) -- m_pRenderer->AddProcessor(pic.openMax, &pic); -+ m_pRenderer->AddProcessor(pic.openMax, &pic, index); - #endif - #ifdef TARGET_DARWIN - else if(pic.format == RENDER_FMT_CVBREF) -- m_pRenderer->AddProcessor(pic.cvBufferRef); -+ m_pRenderer->AddProcessor(pic.cvBufferRef, index); - #endif - #ifdef HAVE_LIBVA - else if(pic.format == RENDER_FMT_VAAPI) -- m_pRenderer->AddProcessor(*pic.vaapi); -+ m_pRenderer->AddProcessor(*pic.vaapi, index); - #endif - m_pRenderer->ReleaseImage(index, false); - -@@ -904,3 +931,176 @@ EINTERLACEMETHOD CXBMCRenderManager::AutoInterlaceMethodInternal(EINTERLACEMETHO - - 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(); -+} -+ -+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 outputPlus1 = (m_iOutputRenderBuffer + 1) % m_iNumRenderBuffers; -+ if ((m_iOutputRenderBuffer == m_iDisplayedRenderBuffer && !m_bAllRenderBuffersDisplayed) -+ || outputPlus1 == m_iCurrentRenderBuffer) -+ return false; -+ else -+ return true; -+} -+ -+void CXBMCRenderManager::ResetRenderBuffer() -+{ -+ m_iNumRenderBuffers = m_pRenderer->GetMaxProcessorSize(); -+ m_iNumRenderBuffers = std::min(5, m_iNumRenderBuffers); -+ m_iNumRenderBuffers = std::max(2, m_iNumRenderBuffers); -+ -+ if (!m_bCodecSupportsBuffering) -+ m_iNumRenderBuffers = 2; -+ -+ CLog::Log(LOGNOTICE,"CXBMCRenderManager::ResetRenderBuffer - using %d render buffers", m_iNumRenderBuffers); -+ m_overlays.SetNumBuffers(m_iNumRenderBuffers); -+ m_pRenderer->SetProcessorSize(m_iNumRenderBuffers); -+ -+ m_iCurrentRenderBuffer = 0; -+ m_iOutputRenderBuffer = 0; -+ m_iDisplayedRenderBuffer = 0; -+ m_bAllRenderBuffersDisplayed = true; -+ m_sleeptime = 1.0; -+ m_presentPts = DVD_NOPTS_VALUE; -+ m_speed = 0; -+} -+ -+void CXBMCRenderManager::PrepareNextRender() -+{ -+ int idx = GetNextRenderBufferIndex(); -+ if (idx < 0) -+ { -+ if (m_speed >= DVD_PLAYSPEED_NORMAL && g_graphicsContext.IsFullScreenVideo()) -+ CLog::Log(LOGDEBUG,"%s no buffer, out: %d, current: %d, display: %d", -+ __FUNCTION__, 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; -+ -+ 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); -+ -+ if (m_iNumRenderBuffers < 3) -+ return; -+ -+ 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 (m_iNumRenderBuffers < 3) -+ return; -+ -+ int last = m_iDisplayedRenderBuffer; -+ m_iDisplayedRenderBuffer = (m_iCurrentRenderBuffer + m_iNumRenderBuffers - 1) % m_iNumRenderBuffers; -+ -+ if (last != m_iDisplayedRenderBuffer -+ && m_iDisplayedRenderBuffer != m_iCurrentRenderBuffer) -+ { -+ m_pRenderer->ReleaseBuffer(m_iDisplayedRenderBuffer); -+ m_overlays.ReleaseBuffer(m_iDisplayedRenderBuffer); -+ } -+ -+ lock.Leave(); -+ m_flipEvent.Set(); -+} -diff --git a/xbmc/cores/VideoRenderers/RenderManager.h b/xbmc/cores/VideoRenderers/RenderManager.h -index 7fe6bb2..34ff8d0 100644 ---- a/xbmc/cores/VideoRenderers/RenderManager.h -+++ b/xbmc/cores/VideoRenderers/RenderManager.h -@@ -31,6 +31,7 @@ - #include "OverlayRenderer.h" - - class CRenderCapture; -+class CDVDClock; - - namespace DXVA { class CProcessor; } - namespace VAAPI { class CSurfaceHolder; } -@@ -70,8 +71,8 @@ class CXBMCRenderManager - - 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(); - -@@ -131,6 +132,10 @@ class CXBMCRenderManager - CSharedSection& GetSection() { return m_sharedSection; }; - - void RegisterRenderUpdateCallBack(const void *ctx, RenderUpdateCallBackFn fn); -+ int WaitForBuffer(volatile bool& bStop); -+ void NotifyDisplayFlip(); -+ void EnableBuffering(bool enable); -+ void DiscardBuffer(); - - protected: - void Render(bool clear, DWORD flags, DWORD alpha); -@@ -139,6 +144,13 @@ class CXBMCRenderManager - void PresentFields(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 -@@ -169,6 +181,37 @@ class CXBMCRenderManager - 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). -+ // 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). -+ -+ int m_iCurrentRenderBuffer; -+ int m_iNumRenderBuffers; -+ int m_iOutputRenderBuffer; -+ int m_iDisplayedRenderBuffer; -+ bool m_bAllRenderBuffersDisplayed; -+ bool m_bUseBuffering; -+ bool m_bCodecSupportsBuffering; -+ 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; -@@ -180,6 +223,7 @@ class CXBMCRenderManager - int m_presentsource; - CEvent m_presentevent; - CEvent m_flushEvent; -+ CDVDClock *m_pClock; - - - OVERLAY::CRenderer m_overlays; -diff --git a/xbmc/cores/VideoRenderers/WinRenderer.cpp b/xbmc/cores/VideoRenderers/WinRenderer.cpp -index 7842089..6e4433c 100644 ---- a/xbmc/cores/VideoRenderers/WinRenderer.cpp -+++ b/xbmc/cores/VideoRenderers/WinRenderer.cpp -@@ -253,12 +253,12 @@ int CWinRenderer::NextYV12Texture() - return -1; - } - --bool CWinRenderer::AddVideoPicture(DVDVideoPicture* picture) -+bool CWinRenderer::AddVideoPicture(DVDVideoPicture* picture, int index) - { - if (m_renderMethod == RENDER_DXVA) - { -- int source = NextYV12Texture(); -- if(source < 0) -+ int source = index; -+ if(source < 0 || NextYV12Texture() < 0) - return false; - - DXVABuffer *buf = (DXVABuffer*)m_VideoBuffers[source]; -@@ -274,7 +274,7 @@ int CWinRenderer::GetImage(YV12Image *image, int source, bool readonly) - if( source == AUTOSOURCE ) - source = NextYV12Texture(); - -- if( source < 0 ) -+ if( source < 0 || NextYV12Texture() < 0) - return -1; - - YUVBuffer *buf = (YUVBuffer*)m_VideoBuffers[source]; -diff --git a/xbmc/cores/VideoRenderers/WinRenderer.h b/xbmc/cores/VideoRenderers/WinRenderer.h -index 2ab5684..f493ba7 100644 ---- a/xbmc/cores/VideoRenderers/WinRenderer.h -+++ b/xbmc/cores/VideoRenderers/WinRenderer.h -@@ -157,7 +157,7 @@ class CWinRenderer : public CBaseRenderer - virtual bool Configure(unsigned int width, unsigned int height, unsigned int d_width, unsigned int d_height, float fps, unsigned flags, ERenderFormat format, unsigned extended_format, unsigned int orientation); - virtual int GetImage(YV12Image *image, int source = AUTOSOURCE, bool readonly = false); - virtual void ReleaseImage(int source, bool preserve = false); -- virtual bool AddVideoPicture(DVDVideoPicture* picture); -+ virtual bool AddVideoPicture(DVDVideoPicture* picture, int index); - virtual void FlipPage(int source); - virtual unsigned int PreInit(); - virtual void UnInit(); -diff --git a/xbmc/cores/dvdplayer/DVDPlayer.cpp b/xbmc/cores/dvdplayer/DVDPlayer.cpp -index 0cd2510..315d64a 100644 ---- a/xbmc/cores/dvdplayer/DVDPlayer.cpp -+++ b/xbmc/cores/dvdplayer/DVDPlayer.cpp -@@ -463,7 +463,7 @@ bool CDVDPlayer::OpenFile(const CFileItem& file, const CPlayerOptions &options) - m_ready.Reset(); - - #if defined(HAS_VIDEO_PLAYBACK) -- g_renderManager.PreInit(); -+ g_renderManager.PreInit(&m_clock); - #endif - - Create(); -diff --git a/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp b/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp -index 3008c25..a4bb1ba 100644 ---- a/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp -+++ b/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp -@@ -261,6 +261,7 @@ void CDVDPlayerVideo::OpenStream(CDVDStreamInfo &hint, CDVDVideoCodec* codec) - 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) -@@ -436,6 +437,7 @@ void CDVDPlayerVideo::Process() - picture.iFlags &= ~DVP_FLAG_ALLOCATED; - m_packets.clear(); - m_started = false; -+ g_renderManager.EnableBuffering(false); - } - else if (pMsg->IsType(CDVDMsg::GENERAL_FLUSH)) // private message sent by (CDVDPlayerVideo::Flush()) - { -@@ -448,6 +450,7 @@ void CDVDPlayerVideo::Process() - //we need to recalculate the framerate - //TODO: this needs to be set on a streamchange instead - ResetFrameRateCalc(); -+ g_renderManager.EnableBuffering(false); - - m_stalled = true; - m_started = false; -@@ -586,6 +589,8 @@ void CDVDPlayerVideo::Process() - - m_pVideoCodec->Reset(); - m_packets.clear(); -+ picture.iFlags &= ~DVP_FLAG_ALLOCATED; -+ g_renderManager.DiscardBuffer(); - break; - } - -@@ -700,6 +705,7 @@ void CDVDPlayerVideo::Process() - 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 -@@ -1317,6 +1323,16 @@ int CDVDPlayerVideo::OutputPicture(const DVDVideoPicture* src, double pts) - 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); - -@@ -1333,7 +1349,7 @@ int CDVDPlayerVideo::OutputPicture(const DVDVideoPicture* src, double pts) - 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 --- -1.7.10 - - -From dacc0167c993efa6ac884fd3c439fc5f0c823934 Mon Sep 17 00:00:00 2001 -From: xbmc -Date: Tue, 2 Oct 2012 10:49:09 +0200 -Subject: [PATCH 03/73] linuxrenderer: delete all textures on reconfigure - ---- - xbmc/cores/VideoRenderers/LinuxRendererGL.cpp | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/xbmc/cores/VideoRenderers/LinuxRendererGL.cpp b/xbmc/cores/VideoRenderers/LinuxRendererGL.cpp -index b32a7ea..a2dc2be 100644 ---- a/xbmc/cores/VideoRenderers/LinuxRendererGL.cpp -+++ b/xbmc/cores/VideoRenderers/LinuxRendererGL.cpp -@@ -251,7 +251,7 @@ bool CLinuxRendererGL::ValidateRenderTarget() - // function pointer for texture might change in - // call to LoadShaders - glFinish(); -- for (int i = 0 ; i < m_NumYV12Buffers ; i++) -+ for (int i = 0 ; i < NUM_BUFFERS ; i++) - (this->*m_textureDelete)(i); - - // trigger update of video filters --- -1.7.10 - - -From 226539d21ba940ea8add89417df7102302c7ba79 Mon Sep 17 00:00:00 2001 -From: xbmc -Date: Mon, 28 May 2012 10:17:33 +0200 -Subject: [PATCH 04/73] drop frame counter in application, ask render manager - instead - ---- - xbmc/Application.cpp | 50 +++++---------------------- - xbmc/Application.h | 6 ++-- - xbmc/cores/VideoRenderers/RenderManager.cpp | 11 ++++++ - xbmc/cores/VideoRenderers/RenderManager.h | 1 + - 4 files changed, 23 insertions(+), 45 deletions(-) - -diff --git a/xbmc/Application.cpp b/xbmc/Application.cpp -index 18e6310..9a7b900 100644 ---- a/xbmc/Application.cpp -+++ b/xbmc/Application.cpp -@@ -415,8 +415,6 @@ - #endif - m_currentStack = new CFileItemList; - -- m_frameCount = 0; -- - m_bPresentFrame = false; - m_bPlatformDirectories = true; - -@@ -2227,28 +2225,18 @@ float CApplication::GetDimScreenSaverLevel() const - - 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() -@@ -2268,7 +2256,6 @@ void CApplication::Render() - - int vsync_mode = g_guiSettings.GetInt("videoscreen.vsync"); - -- bool decrement = false; - bool hasRendered = false; - bool limitFrames = false; - unsigned int singleFrameTime = 10; // default limit 100 fps -@@ -2282,13 +2269,10 @@ void CApplication::Render() - m_bPresentFrame = false; - if (!extPlayerActive && g_graphicsContext.IsFullScreenVideo() && !IsPaused()) - { -- CSingleLock lock(m_frameMutex); -- -- TightConditionVariable cv(m_frameCond,m_frameCount); -- cv.wait(lock,100); -- -- m_bPresentFrame = m_frameCount > 0; -- decrement = m_bPresentFrame; -+ m_frameEvent.Reset(); -+ m_bPresentFrame = g_renderManager.HasFrame(); -+ if (!m_bPresentFrame && m_frameEvent.WaitMSec(100)) -+ m_bPresentFrame = g_renderManager.HasFrame(); - hasRendered = true; - } - else -@@ -2312,8 +2296,6 @@ void CApplication::Render() - else if (lowfps) - singleFrameTime = 200; // 5 fps, <=200 ms latency to wake up - } -- -- decrement = true; - } - } - -@@ -2377,13 +2359,6 @@ void CApplication::Render() - - 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) -@@ -5638,12 +5613,6 @@ bool CApplication::SwitchToFullScreen() - // 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; -@@ -5876,7 +5845,6 @@ bool CApplication::IsCurrentThread() const - - bool CApplication::IsPresentFrame() - { -- CSingleLock lock(m_frameMutex); - bool ret = m_bPresentFrame; - - return ret; -diff --git a/xbmc/Application.h b/xbmc/Application.h -index 69609fa..6764a60 100644 ---- a/xbmc/Application.h -+++ b/xbmc/Application.h -@@ -422,10 +422,8 @@ class CApplication : public CXBApplicationEx, public IPlayerCallback, public IMs - bool m_bEnableLegacyRes; - bool m_bTestMode; - bool m_bSystemScreenSaverEnable; -- -- int m_frameCount; -- CCriticalSection m_frameMutex; -- XbmcThreads::ConditionVariable m_frameCond; -+ -+ CEvent m_frameEvent; - - VIDEO::CVideoInfoScanner *m_videoInfoScanner; - MUSIC_INFO::CMusicInfoScanner *m_musicInfoScanner; -diff --git a/xbmc/cores/VideoRenderers/RenderManager.cpp b/xbmc/cores/VideoRenderers/RenderManager.cpp -index eeb6c6f..4b897da 100644 ---- a/xbmc/cores/VideoRenderers/RenderManager.cpp -+++ b/xbmc/cores/VideoRenderers/RenderManager.cpp -@@ -1104,3 +1104,14 @@ void CXBMCRenderManager::NotifyDisplayFlip() - lock.Leave(); - m_flipEvent.Set(); - } -+ -+bool CXBMCRenderManager::HasFrame() -+{ -+ CSharedLock lock(m_sharedSection); -+ if (m_presentstep == PRESENT_IDLE && -+ GetNextRenderBufferIndex() < 0 && -+ m_speed > 0) -+ return false; -+ else -+ return true; -+} -diff --git a/xbmc/cores/VideoRenderers/RenderManager.h b/xbmc/cores/VideoRenderers/RenderManager.h -index 34ff8d0..288175e 100644 ---- a/xbmc/cores/VideoRenderers/RenderManager.h -+++ b/xbmc/cores/VideoRenderers/RenderManager.h -@@ -134,6 +134,7 @@ class CXBMCRenderManager - void RegisterRenderUpdateCallBack(const void *ctx, RenderUpdateCallBackFn fn); - int WaitForBuffer(volatile bool& bStop); - void NotifyDisplayFlip(); -+ bool HasFrame(); - void EnableBuffering(bool enable); - void DiscardBuffer(); - --- -1.7.10 - - -From 0f81843cb7279f3b99607551967354ff30e15e4d Mon Sep 17 00:00:00 2001 -From: xbmc -Date: Mon, 28 May 2012 10:34:39 +0200 -Subject: [PATCH 05/73] videoplayer: adopt lateness detection and dropping to - buffering - ---- - xbmc/cores/VideoRenderers/RenderManager.cpp | 12 ++ - xbmc/cores/VideoRenderers/RenderManager.h | 1 + - .../dvdplayer/DVDCodecs/Video/DVDVideoCodec.h | 14 ++ - .../DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp | 31 +++ - .../DVDCodecs/Video/DVDVideoCodecFFmpeg.h | 7 + - xbmc/cores/dvdplayer/DVDPlayerVideo.cpp | 224 ++++++++++++++++---- - xbmc/cores/dvdplayer/DVDPlayerVideo.h | 24 +++ - 7 files changed, 268 insertions(+), 45 deletions(-) - -diff --git a/xbmc/cores/VideoRenderers/RenderManager.cpp b/xbmc/cores/VideoRenderers/RenderManager.cpp -index 4b897da..f19797c 100644 ---- a/xbmc/cores/VideoRenderers/RenderManager.cpp -+++ b/xbmc/cores/VideoRenderers/RenderManager.cpp -@@ -1105,6 +1105,18 @@ void CXBMCRenderManager::NotifyDisplayFlip() - m_flipEvent.Set(); - } - -+bool CXBMCRenderManager::GetStats(double &sleeptime, double &pts, int &bufferLevel) -+{ -+ CSharedLock lock(m_sharedSection); -+ sleeptime = m_sleeptime; -+ pts = m_presentPts; -+ if (m_iNumRenderBuffers < 3) -+ bufferLevel = -1; -+ else -+ bufferLevel = (m_iOutputRenderBuffer - m_iCurrentRenderBuffer + m_iNumRenderBuffers) % m_iNumRenderBuffers; -+ return true; -+} -+ - bool CXBMCRenderManager::HasFrame() - { - CSharedLock lock(m_sharedSection); -diff --git a/xbmc/cores/VideoRenderers/RenderManager.h b/xbmc/cores/VideoRenderers/RenderManager.h -index 288175e..9342586 100644 ---- a/xbmc/cores/VideoRenderers/RenderManager.h -+++ b/xbmc/cores/VideoRenderers/RenderManager.h -@@ -134,6 +134,7 @@ class CXBMCRenderManager - void RegisterRenderUpdateCallBack(const void *ctx, RenderUpdateCallBackFn fn); - int WaitForBuffer(volatile bool& bStop); - void NotifyDisplayFlip(); -+ bool GetStats(double &sleeptime, double &pts, int &bufferLevel); - bool HasFrame(); - void EnableBuffering(bool enable); - void DiscardBuffer(); -diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodec.h b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodec.h -index 1d8bad3..5001aac 100644 ---- a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodec.h -+++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodec.h -@@ -110,6 +110,10 @@ struct DVDVideoUserData - #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_NO_POSTPROC 0x00000100 -+#define DVP_FLAG_DRAIN 0x00000200 -+ - // DVP_FLAG 0x00000100 - 0x00000f00 is in use by libmpeg2! - - #define DVP_QSCALE_UNKNOWN 0 -@@ -127,6 +131,9 @@ struct DVDVideoUserData - #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 -+ - class CDVDVideoCodec - { - public: -@@ -237,4 +244,11 @@ class CDVDVideoCodec - { - return 0; - } -+ -+ virtual bool GetPts(double &pts, int &skippedDeint, int &interlaced) -+ { -+ return false; -+ } -+ -+ virtual void SetCodecControl(int flags) {} - }; -diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp -index 8f81637..af706bd 100644 ---- a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp -+++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp -@@ -142,6 +142,7 @@ enum PixelFormat CDVDVideoCodecFFmpeg::GetFormat( struct AVCodecContext * avctx - m_iLastKeyframe = 0; - m_dts = DVD_NOPTS_VALUE; - m_started = false; -+ m_decoderPts = DVD_NOPTS_VALUE; - } - - CDVDVideoCodecFFmpeg::~CDVDVideoCodecFFmpeg() -@@ -340,6 +341,14 @@ void CDVDVideoCodecFFmpeg::SetDropState(bool bDrop) - { - 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 -@@ -541,6 +550,7 @@ int CDVDVideoCodecFFmpeg::Decode(BYTE* pData, int iSize, double dts, double pts) - 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); - -@@ -639,6 +649,22 @@ bool CDVDVideoCodecFFmpeg::GetPictureCommon(DVDVideoPicture* pDvdVideoPicture) - 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_codecControlFlags; -+ - if(!m_started) - pDvdVideoPicture->iFlags |= DVP_FLAG_DROPPED; - -@@ -861,3 +887,8 @@ unsigned CDVDVideoCodecFFmpeg::GetConvergeCount() - else - return 0; - } -+ -+void CDVDVideoCodecFFmpeg::SetCodecControl(int flags) -+{ -+ m_codecControlFlags = flags; -+} -diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.h b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.h -index 61d0305..52e1113 100644 ---- a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.h -+++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.h -@@ -44,6 +44,7 @@ class CDVDVideoCodecFFmpeg : public CDVDVideoCodec - 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 const std::string Name() = 0; - virtual CCriticalSection* Section() { return NULL; } - }; -@@ -60,6 +61,8 @@ class CDVDVideoCodecFFmpeg : public CDVDVideoCodec - 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 SetCodecControl(int flags); - - bool IsHardwareAllowed() { return !m_bSoftware; } - IHardwareDecoder * GetHardware() { return m_pHardware; }; -@@ -119,4 +122,8 @@ class CDVDVideoCodecFFmpeg : public CDVDVideoCodec - double m_dts; - bool m_started; - std::vector m_formats; -+ double m_decoderPts, m_decoderInterval; -+ int m_skippedDeint; -+ bool m_requestSkipDeint; -+ int m_codecControlFlags; - }; -diff --git a/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp b/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp -index a4bb1ba..93908a7 100644 ---- a/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp -+++ b/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp -@@ -326,8 +326,10 @@ void CDVDPlayerVideo::Process() - - int iDropped = 0; //frames dropped in a row - bool bRequestDrop = false; -+ int iDropDirective; - - m_videoStats.Start(); -+ m_droppingStats.Reset(); - - while (!m_bStop) - { -@@ -437,6 +439,7 @@ void CDVDPlayerVideo::Process() - picture.iFlags &= ~DVP_FLAG_ALLOCATED; - m_packets.clear(); - m_started = false; -+ m_droppingStats.Reset(); - g_renderManager.EnableBuffering(false); - } - else if (pMsg->IsType(CDVDMsg::GENERAL_FLUSH)) // private message sent by (CDVDPlayerVideo::Flush()) -@@ -450,6 +453,7 @@ void CDVDPlayerVideo::Process() - //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; -@@ -468,6 +472,7 @@ void CDVDPlayerVideo::Process() - m_speed = static_cast(pMsg)->m_value; - if(m_speed == DVD_PLAYSPEED_PAUSE) - m_iNrOfPicturesNotToSkip = 0; -+ m_droppingStats.Reset(); - } - else if (pMsg->IsType(CDVDMsg::PLAYER_STARTED)) - { -@@ -502,6 +507,28 @@ void CDVDPlayerVideo::Process() - 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) -+ codecControl |= DVP_FLAG_DRAIN; -+ if (m_speed > DVD_PLAYSPEED_NORMAL) -+ codecControl |= DVP_FLAG_NO_POSTPROC; -+ m_pVideoCodec->SetCodecControl(codecControl); -+ if (iDropDirective & EOS_DROPPED) -+ { -+ m_iDroppedFrames++; -+ iDropped++; -+ } -+ - #ifdef PROFILE - bRequestDrop = false; - #else -@@ -511,6 +538,7 @@ void CDVDPlayerVideo::Process() - bRequestDrop = false; - m_iDroppedRequest = 0; - m_iLateFrames = 0; -+ m_droppingStats.m_requestOutputDrop = false; - } - #endif - -@@ -558,15 +586,8 @@ void CDVDPlayerVideo::Process() - } - - m_videoStats.AddSampleBytes(pPacket->iSize); -- // assume decoder dropped a picture if it didn't give us any -- // 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++; -- } -+ -+ bRequestDrop = false; - - // loop while no error - while (!m_bStop) -@@ -1244,50 +1265,30 @@ int CDVDPlayerVideo::OutputPicture(const DVDVideoPicture* src, double pts) - m_FlipTimeStamp += max(0.0, iSleepTime); - m_FlipTimeStamp += iFrameDuration; - -- 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 -+ if ((m_droppingStats.m_requestOutputDrop && !(pPicture->iFlags & DVP_FLAG_NOSKIP)) -+ || (pPicture->iFlags & DVP_FLAG_DROPPED)) - { -- m_iDroppedRequest = 0; -+ m_droppingStats.AddOutputDropGain(pts, 1/m_fFrameRate); -+ m_droppingStats.m_requestOutputDrop = false; -+ CLog::Log(LOGDEBUG,"%s - dropped in output", __FUNCTION__); -+ return result | EOS_DROPPED; - } - - if( m_speed < 0 ) - { -- if( iClockSleep < -DVD_MSEC_TO_TIME(200) -- && !(pPicture->iFlags & DVP_FLAG_NOSKIP) ) -+ double decoderPts = m_droppingStats.m_lastDecoderPts; -+ double renderPts = m_droppingStats.m_lastRenderPts; -+ if (pts > renderPts) -+ { -+ if (decoderPts >= renderPts) -+ { -+ Sleep(200); -+ } - 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 -@@ -1648,3 +1649,136 @@ void CDVDPlayerVideo::CalcFrameRate() - 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; -+ if (iDecoderPts == DVD_NOPTS_VALUE) -+ iDecoderPts = pts; -+ -+ // get render stats -+ g_renderManager.GetStats(iSleepTime, iRenderPts, iBufferLevel); -+ -+ if (iBufferLevel < 0) -+ result |= EOS_BUFFER_LEVEL; -+ else if (iBufferLevel < 2) -+ { -+ result |= EOS_BUFFER_LEVEL; -+ CLog::Log(LOGDEBUG,"CDVDPlayerVideo::CalcDropRequirement - 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; -+ -+ 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(); -+ } -+ -+ // 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; -+ } -+ 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 --git a/xbmc/cores/dvdplayer/DVDPlayerVideo.h b/xbmc/cores/dvdplayer/DVDPlayerVideo.h -index fe7e12c..4913712 100644 ---- a/xbmc/cores/dvdplayer/DVDPlayerVideo.h -+++ b/xbmc/cores/dvdplayer/DVDPlayerVideo.h -@@ -37,6 +37,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: -@@ -110,6 +130,7 @@ class CDVDPlayerVideo : public CThread - #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); -@@ -135,6 +156,7 @@ class CDVDPlayerVideo : public CThread - - 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 -@@ -195,5 +217,7 @@ class CDVDPlayerVideo : public CThread - CPullupCorrection m_pullupCorrection; - - std::list m_packets; -+ -+ CDroppingStats m_droppingStats; - }; - --- -1.7.10 - - -From 4bc6ff77b121468020578f9d393e8aaae1a419f6 Mon Sep 17 00:00:00 2001 -From: xbmc -Date: Mon, 28 May 2012 10:41:31 +0200 -Subject: [PATCH 06/73] videoplayer: update frametime, it might change due to - fps detection - ---- - xbmc/cores/dvdplayer/DVDPlayerVideo.cpp | 2 ++ - 1 file changed, 2 insertions(+) - -diff --git a/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp b/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp -index 93908a7..4675556 100644 ---- a/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp -+++ b/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp -@@ -721,6 +721,8 @@ void CDVDPlayerVideo::Process() - CDVDCodecUtils::FreePicture(pTempYUVPackedPicture); - #endif - -+ frametime = (double)DVD_TIME_BASE/m_fFrameRate; -+ - if(m_started == false) - { - m_codecname = m_pVideoCodec->GetName(); --- -1.7.10 - - -From 723a731d68b9360f9804e8711255afa62c4ce34d Mon Sep 17 00:00:00 2001 -From: xbmc -Date: Mon, 28 May 2012 10:43:06 +0200 -Subject: [PATCH 07/73] videoplayer: give streams with invalid fps a chance - for fps detection - ---- - xbmc/cores/dvdplayer/DVDPlayerVideo.cpp | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp b/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp -index 4675556..2ef6358 100644 ---- a/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp -+++ b/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp -@@ -1595,7 +1595,7 @@ void CDVDPlayerVideo::CalcFrameRate() - 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; --- -1.7.10 - - -From 60c955c30cdfcf361396e47fc92a1e1883b085fe Mon Sep 17 00:00:00 2001 -From: xbmc -Date: Mon, 28 May 2012 10:49:05 +0200 -Subject: [PATCH 08/73] dvdplayer: allow rewinding at end of stream, do a seek - after rewind - ---- - xbmc/cores/dvdplayer/DVDPlayer.cpp | 8 +++++++- - 1 file changed, 7 insertions(+), 1 deletion(-) - -diff --git a/xbmc/cores/dvdplayer/DVDPlayer.cpp b/xbmc/cores/dvdplayer/DVDPlayer.cpp -index 315d64a..6fcb6b3 100644 ---- a/xbmc/cores/dvdplayer/DVDPlayer.cpp -+++ b/xbmc/cores/dvdplayer/DVDPlayer.cpp -@@ -1542,7 +1542,7 @@ void CDVDPlayer::HandlePlaySpeed() - - } - else if (m_CurrentVideo.id >= 0 -- && m_CurrentVideo.inited == true -+ && (m_CurrentVideo.inited == true || GetPlaySpeed() < 0) // allow rewind at end of file - && m_SpeedState.lastpts != m_dvdPlayerVideo.GetCurrentPts() - && m_SpeedState.lasttime != GetTime()) - { -@@ -2183,6 +2183,12 @@ void CDVDPlayer::HandleMessages() - pvrinputstream->Pause( speed == 0 ); - } - -+ // do a seek after rewind, clock is not in sync with current pts -+ 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 --- -1.7.10 - - -From 8d237cf023501560fc394679819463034a209413 Mon Sep 17 00:00:00 2001 -From: xbmc -Date: Sun, 2 Sep 2012 16:05:21 +0200 -Subject: [PATCH 09/73] video player: present correct pts to user for a/v sync - (after buffering in renderer) - ---- - xbmc/cores/dvdplayer/DVDPlayerVideo.cpp | 41 +++++++++++++++++++------------ - xbmc/cores/dvdplayer/DVDPlayerVideo.h | 2 +- - 2 files changed, 26 insertions(+), 17 deletions(-) - -diff --git a/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp b/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp -index 2ef6358..10e2225 100644 ---- a/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp -+++ b/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp -@@ -1251,22 +1251,6 @@ int CDVDPlayerVideo::OutputPicture(const DVDVideoPicture* src, double pts) - else - iSleepTime = iFrameSleep + (iClockSleep - iFrameSleep) / m_autosync; - --#ifdef PROFILE /* during profiling, try to play as fast as possible */ -- iSleepTime = 0; --#endif -- -- // present the current pts of this frame to user, and include the actual -- // presentation delay, to allow him to adjust for it -- if( m_stalled ) -- m_iCurrentPts = DVD_NOPTS_VALUE; -- else -- m_iCurrentPts = pts - max(0.0, iSleepTime); -- -- // timestamp when we think next picture should be displayed based on current duration -- m_FlipTimeStamp = iCurrentClock; -- m_FlipTimeStamp += max(0.0, iSleepTime); -- m_FlipTimeStamp += iFrameDuration; -- - if ((m_droppingStats.m_requestOutputDrop && !(pPicture->iFlags & DVP_FLAG_NOSKIP)) - || (pPicture->iFlags & DVP_FLAG_DROPPED)) - { -@@ -1571,6 +1555,22 @@ void CDVDPlayerVideo::ResetFrameRateCalc() - g_advancedSettings.m_videoFpsDetect == 0; - } - -+double CDVDPlayerVideo::GetCurrentPts() -+{ -+ double iSleepTime, iRenderPts; -+ int iBufferLevel; -+ -+ // get render stats -+ g_renderManager.GetStats(iSleepTime, iRenderPts, iBufferLevel); -+ -+ if( m_stalled ) -+ iRenderPts = DVD_NOPTS_VALUE; -+ else -+ iRenderPts = iRenderPts - max(0.0, iSleepTime); -+ -+ return iRenderPts; -+} -+ - #define MAXFRAMERATEDIFF 0.01 - #define MAXFRAMESERR 1000 - -@@ -1689,6 +1689,15 @@ int CDVDPlayerVideo::CalcDropRequirement(double pts) - else - iInterval = 1/m_fFrameRate*(double)DVD_TIME_BASE; - -+ -+ m_FlipTimeStamp = m_pClock->GetAbsoluteClock() + max(0.0, iSleepTime) + iInterval; -+ -+ if( m_stalled ) -+ m_iCurrentPts = DVD_NOPTS_VALUE; -+ else -+ m_iCurrentPts = iRenderPts - max(0.0, iSleepTime); -+ -+ - if (m_droppingStats.m_lastDecoderPts > 0 - && bNewFrame - && m_bAllowDrop -diff --git a/xbmc/cores/dvdplayer/DVDPlayerVideo.h b/xbmc/cores/dvdplayer/DVDPlayerVideo.h -index 4913712..509d5f7 100644 ---- a/xbmc/cores/dvdplayer/DVDPlayerVideo.h -+++ b/xbmc/cores/dvdplayer/DVDPlayerVideo.h -@@ -108,7 +108,7 @@ class CDVDPlayerVideo : public CThread - - bool InitializedOutputDevice(); - -- double GetCurrentPts() { return m_iCurrentPts; } -+ double GetCurrentPts(); - int GetPullupCorrection() { return m_pullupCorrection.GetPatternLength(); } - - double GetOutputDelay(); /* returns the expected delay, from that a packet is put in queue */ --- -1.7.10 - - -From 04a6a8b4ca29c17da6bbb9591685922b2f6f1442 Mon Sep 17 00:00:00 2001 -From: xbmc -Date: Mon, 28 May 2012 11:02:29 +0200 -Subject: [PATCH 10/73] vaapi: adopt to buffering in renderer - ---- - xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp | 2 +- - xbmc/cores/dvdplayer/DVDCodecs/Video/VAAPI.cpp | 3 ++- - xbmc/cores/dvdplayer/DVDCodecs/Video/VAAPI.h | 1 + - 3 files changed, 4 insertions(+), 2 deletions(-) - -diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp -index af706bd..dae3b8e 100644 ---- a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp -+++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp -@@ -106,7 +106,7 @@ enum PixelFormat CDVDVideoCodecFFmpeg::GetFormat( struct AVCodecContext * avctx - && (avctx->codec_id != CODEC_ID_MPEG4 || g_advancedSettings.m_videoAllowMpeg4VAAPI)) - { - VAAPI::CDecoder* dec = new VAAPI::CDecoder(); -- if(dec->Open(avctx, *cur)) -+ if(dec->Open(avctx, *cur, ctx->m_uSurfacesCount)) - { - ctx->SetHardware(dec); - return *cur; -diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/VAAPI.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/VAAPI.cpp -index 9f5a960..a2b9195 100644 ---- a/xbmc/cores/dvdplayer/DVDCodecs/Video/VAAPI.cpp -+++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/VAAPI.cpp -@@ -357,6 +357,7 @@ bool CDecoder::Open(AVCodecContext *avctx, enum PixelFormat fmt, unsigned int su - CHECK(vaCreateConfig(m_display->get(), profile, entrypoint, &attrib, 1, &m_hwaccel->config_id)) - m_config = m_hwaccel->config_id; - -+ m_renderbuffers_count = surfaces; - if (!EnsureContext(avctx)) - return false; - -@@ -388,7 +389,7 @@ bool CDecoder::EnsureContext(AVCodecContext *avctx) - else - m_refs = 2; - } -- return EnsureSurfaces(avctx, m_refs + 3); -+ return EnsureSurfaces(avctx, m_refs + m_renderbuffers_count + 1); - } - - bool CDecoder::EnsureSurfaces(AVCodecContext *avctx, unsigned n_surfaces_count) -diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/VAAPI.h b/xbmc/cores/dvdplayer/DVDCodecs/Video/VAAPI.h -index 863edc4..417cbc0 100644 ---- a/xbmc/cores/dvdplayer/DVDCodecs/Video/VAAPI.h -+++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/VAAPI.h -@@ -122,6 +122,7 @@ class CDecoder - static const unsigned m_surfaces_max = 32; - unsigned m_surfaces_count; - VASurfaceID m_surfaces[m_surfaces_max]; -+ unsigned m_renderbuffers_count; - - int m_refs; - std::list m_surfaces_used; --- -1.7.10 - - -From 4d237410264bbff9c4ac373de498f80ecb15f7a3 Mon Sep 17 00:00:00 2001 -From: xbmc -Date: Sat, 7 Apr 2012 09:19:00 +0200 -Subject: [PATCH 11/73] vdpau: redesign - ---- - language/English/strings.po | 12 +- - system/shaders/yuv2rgb_basic.glsl | 12 + - xbmc/cores/VideoRenderers/LinuxRendererGL.cpp | 203 +- - xbmc/cores/VideoRenderers/LinuxRendererGL.h | 13 +- - xbmc/cores/VideoRenderers/RenderFormats.h | 1 + - xbmc/cores/VideoRenderers/RenderManager.cpp | 8 +- - xbmc/cores/VideoRenderers/RenderManager.h | 2 +- - .../VideoRenderers/VideoShaders/YUV2RGBShader.cpp | 2 + - .../dvdplayer/DVDCodecs/Video/DVDVideoCodec.h | 4 +- - .../DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp | 23 +- - .../DVDCodecs/Video/DVDVideoCodecFFmpeg.h | 1 - - xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp | 3798 +++++++++++++++----- - xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.h | 662 +++- - xbmc/cores/dvdplayer/DVDPlayerVideo.cpp | 3 + - xbmc/settings/AdvancedSettings.cpp | 8 +- - xbmc/settings/AdvancedSettings.h | 4 +- - xbmc/settings/GUISettings.cpp | 2 + - xbmc/settings/GUIWindowSettingsCategory.cpp | 34 + - xbmc/utils/ActorProtocol.cpp | 253 ++ - xbmc/utils/ActorProtocol.h | 87 + - xbmc/utils/Makefile | 1 + - xbmc/video/dialogs/GUIDialogVideoSettings.cpp | 2 +- - xbmc/windowing/X11/WinSystemX11.h | 1 + - 23 files changed, 3942 insertions(+), 1194 deletions(-) - create mode 100644 xbmc/utils/ActorProtocol.cpp - create mode 100644 xbmc/utils/ActorProtocol.h - -diff --git a/language/English/strings.po b/language/English/strings.po -index dff2978..88292d3 100644 ---- a/language/English/strings.po -+++ b/language/English/strings.po -@@ -5114,7 +5114,15 @@ msgctxt "#13434" - msgid "Play only this" - msgstr "" - --#empty strings from id 13435 to 13499 -+msgctxt "#13435" -+msgid "Allow Vdpau OpenGL interop" -+msgstr "" -+ -+msgctxt "#13436" -+msgid "Allow Vdpau OpenGL interop YUV" -+msgstr "" -+ -+#empty strings from id 13437 to 13499 - - msgctxt "#13500" - msgid "A/V sync method" -@@ -6333,7 +6341,7 @@ msgid "Software Blend" - msgstr "" - - msgctxt "#16325" --msgid "Auto - ION Optimized" -+msgid "VDPAU - Bob" - msgstr "" - - #empty strings from id 16326 to 16399 -diff --git a/system/shaders/yuv2rgb_basic.glsl b/system/shaders/yuv2rgb_basic.glsl -index 88c33b2..aa26174 100644 ---- a/system/shaders/yuv2rgb_basic.glsl -+++ b/system/shaders/yuv2rgb_basic.glsl -@@ -70,6 +70,18 @@ void main() - 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 --git a/xbmc/cores/VideoRenderers/LinuxRendererGL.cpp b/xbmc/cores/VideoRenderers/LinuxRendererGL.cpp -index a2dc2be..4ee50c1 100644 ---- a/xbmc/cores/VideoRenderers/LinuxRendererGL.cpp -+++ b/xbmc/cores/VideoRenderers/LinuxRendererGL.cpp -@@ -689,6 +689,18 @@ void CLinuxRendererGL::RenderUpdate(bool clear, DWORD flags, DWORD alpha) - glDisable(GL_POLYGON_STIPPLE); - - } -+ else if(m_format == RENDER_FMT_VDPAU_420 -+ && !(flags & RENDER_FLAG_BOTH)) -+ { -+ 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); - -@@ -769,11 +781,6 @@ void CLinuxRendererGL::FlipPage(int source) - - 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; - } - -@@ -1100,6 +1107,12 @@ void CLinuxRendererGL::LoadShaders(int field) - m_textureCreate = &CLinuxRendererGL::CreateVDPAUTexture; - m_textureDelete = &CLinuxRendererGL::DeleteVDPAUTexture; - } -+ else if (m_format == RENDER_FMT_VDPAU_420) -+ { -+ m_textureUpload = &CLinuxRendererGL::UploadVDPAUTexture420; -+ m_textureCreate = &CLinuxRendererGL::CreateVDPAUTexture420; -+ m_textureDelete = &CLinuxRendererGL::DeleteVDPAUTexture420; -+ } - else if (m_format == RENDER_FMT_VAAPI) - { - m_textureUpload = &CLinuxRendererGL::UploadVAAPITexture; -@@ -1175,7 +1188,10 @@ void CLinuxRendererGL::Render(DWORD flags, int renderBuffer) - m_currentField = FIELD_FULL; - - // call texture load function -+ m_skipRender = false; - (this->*m_textureUpload)(renderBuffer); -+ if (m_skipRender) -+ return; - - if (m_renderMethod & RENDER_GLSL) - { -@@ -1541,17 +1557,12 @@ void CLinuxRendererGL::RenderFromFBO() - 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); -@@ -1609,8 +1620,6 @@ void CLinuxRendererGL::RenderVDPAU(int index, int field) - if (m_pVideoFilterShader) - m_pVideoFilterShader->Disable(); - -- vdpau->ReleasePixmap(); -- - glBindTexture (m_textureTarget, 0); - glDisable(m_textureTarget); - #endif -@@ -2295,12 +2304,14 @@ void CLinuxRendererGL::DeleteVDPAUTexture(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[0][1].id = 0; - #endif - } - -@@ -2334,11 +2345,152 @@ bool CLinuxRendererGL::CreateVDPAUTexture(int index) - 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 || !vdpau->valid) -+ { -+ m_eventTexturesDone[index]->Set(); -+ m_skipRender = true; -+ return; -+ } -+ -+ 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(); -- glPixelStorei(GL_UNPACK_ALIGNMENT,1); //what's this for? - #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 || !vdpau->valid) -+ { -+ m_eventTexturesDone[index]->Set(); -+ m_skipRender = true; -+ 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(); -+#endif -+} - - void CLinuxRendererGL::DeleteVAAPITexture(int index) - { -@@ -3276,12 +3428,13 @@ bool CLinuxRendererGL::Supports(EINTERLACEMETHOD method) - if(method == VS_INTERLACEMETHOD_AUTO) - return true; - -- if(m_renderMethod & RENDER_VDPAU) -+ if(m_renderMethod & RENDER_VDPAU || -+ m_format == RENDER_FMT_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; - } -@@ -3367,14 +3520,7 @@ EINTERLACEMETHOD CLinuxRendererGL::AutoInterlaceMethod() - return VS_INTERLACEMETHOD_NONE; - - if(m_renderMethod & RENDER_VDPAU) -- { --#ifdef HAVE_LIBVDPAU -- CVDPAU *vdpau = m_buffers[m_iYV12RenderBuffer].vdpau; -- if(vdpau) -- return vdpau->AutoInterlaceMethod(); --#endif - return VS_INTERLACEMETHOD_NONE; -- } - - if(Supports(VS_INTERLACEMETHOD_RENDER_BOB)) - return VS_INTERLACEMETHOD_RENDER_BOB; -@@ -3417,11 +3563,12 @@ void CLinuxRendererGL::UnBindPbo(YUVBUFFER& buff) - } - - #ifdef HAVE_LIBVDPAU --void CLinuxRendererGL::AddProcessor(CVDPAU* vdpau, int index) -+void CLinuxRendererGL::AddProcessor(VDPAU::CVdpauRenderPicture *vdpau, int index) - { - YUVBUFFER &buf = m_buffers[index]; -+ VDPAU::CVdpauRenderPicture *pic = vdpau->Acquire(); - SAFE_RELEASE(buf.vdpau); -- buf.vdpau = (CVDPAU*)vdpau->Acquire(); -+ buf.vdpau = pic; - } - #endif - -diff --git a/xbmc/cores/VideoRenderers/LinuxRendererGL.h b/xbmc/cores/VideoRenderers/LinuxRendererGL.h -index 9f55fcb..3218cd5 100644 ---- a/xbmc/cores/VideoRenderers/LinuxRendererGL.h -+++ b/xbmc/cores/VideoRenderers/LinuxRendererGL.h -@@ -38,15 +38,14 @@ - - class CRenderCapture; - --class CVDPAU; - class CBaseTexture; - namespace Shaders { class BaseYUV2RGBShader; } - namespace Shaders { class BaseVideoFilterShader; } - namespace VAAPI { struct CHolder; } -+namespace VDPAU { class CVdpauRenderPicture; } - - #define NUM_BUFFERS 10 - -- - #undef ALIGN - #define ALIGN(value, alignment) (((value)+((alignment)-1))&~((alignment)-1)) - #define CLAMP(a, min, max) ((a) > (max) ? (max) : ( (a) < (min) ? (min) : a )) -@@ -144,7 +143,7 @@ class CLinuxRendererGL : public CBaseRenderer - virtual unsigned int GetProcessorSize() { return m_NumYV12Buffers; } - - #ifdef HAVE_LIBVDPAU -- virtual void AddProcessor(CVDPAU* vdpau, int index); -+ virtual void AddProcessor(VDPAU::CVdpauRenderPicture* vdpau, int index); - #endif - #ifdef HAVE_LIBVA - virtual void AddProcessor(VAAPI::CHolder& holder, int index); -@@ -195,6 +194,10 @@ class CLinuxRendererGL : public CBaseRenderer - 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); -@@ -221,6 +224,7 @@ class CLinuxRendererGL : public CBaseRenderer - 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 - - struct -@@ -281,7 +285,7 @@ class CLinuxRendererGL : public CBaseRenderer - GLuint pbo[MAX_PLANES]; - - #ifdef HAVE_LIBVDPAU -- CVDPAU* vdpau; -+ VDPAU::CVdpauRenderPicture *vdpau; - #endif - #ifdef HAVE_LIBVA - VAAPI::CHolder& vaapi; -@@ -327,6 +331,7 @@ class CLinuxRendererGL : public CBaseRenderer - bool m_nonLinStretch; - bool m_nonLinStretchGui; - float m_pixelRatio; -+ bool m_skipRender; - }; - - -diff --git a/xbmc/cores/VideoRenderers/RenderFormats.h b/xbmc/cores/VideoRenderers/RenderFormats.h -index 09f8f5d..0262c60 100644 ---- a/xbmc/cores/VideoRenderers/RenderFormats.h -+++ b/xbmc/cores/VideoRenderers/RenderFormats.h -@@ -26,6 +26,7 @@ enum ERenderFormat { - RENDER_FMT_YUV420P10, - RENDER_FMT_YUV420P16, - RENDER_FMT_VDPAU, -+ RENDER_FMT_VDPAU_420, - RENDER_FMT_NV12, - RENDER_FMT_UYVY422, - RENDER_FMT_YUYV422, -diff --git a/xbmc/cores/VideoRenderers/RenderManager.cpp b/xbmc/cores/VideoRenderers/RenderManager.cpp -index f19797c..a521680 100644 ---- a/xbmc/cores/VideoRenderers/RenderManager.cpp -+++ b/xbmc/cores/VideoRenderers/RenderManager.cpp -@@ -250,8 +250,9 @@ bool CXBMCRenderManager::Configure(unsigned int width, unsigned int height, unsi - - // check if decoder supports buffering - m_bCodecSupportsBuffering = false; --// if (format == RENDER_FMT_VDPAU) --// m_bCodecSupportsBuffering = true; -+ if (format == RENDER_FMT_VDPAU || -+ format == RENDER_FMT_VDPAU_420) -+ m_bCodecSupportsBuffering = true; - - bool result = m_pRenderer->Configure(width, height, d_width, d_height, fps, flags, format, extended_format, orientation); - if(result) -@@ -856,7 +857,8 @@ int CXBMCRenderManager::AddVideoPicture(DVDVideoPicture& pic) - CDVDCodecUtils::CopyDXVA2Picture(&image, &pic); - } - #ifdef HAVE_LIBVDPAU -- else if(pic.format == RENDER_FMT_VDPAU) -+ else if(pic.format == RENDER_FMT_VDPAU -+ || pic.format == RENDER_FMT_VDPAU_420) - m_pRenderer->AddProcessor(pic.vdpau, index); - #endif - #ifdef HAVE_LIBOPENMAX -diff --git a/xbmc/cores/VideoRenderers/RenderManager.h b/xbmc/cores/VideoRenderers/RenderManager.h -index 9342586..6746957 100644 ---- a/xbmc/cores/VideoRenderers/RenderManager.h -+++ b/xbmc/cores/VideoRenderers/RenderManager.h -@@ -35,7 +35,7 @@ - - namespace DXVA { class CProcessor; } - namespace VAAPI { class CSurfaceHolder; } --class CVDPAU; -+namespace VDPAU { class CVdpauRenderPicture; } - struct DVDVideoPicture; - - #define ERRORBUFFSIZE 30 -diff --git a/xbmc/cores/VideoRenderers/VideoShaders/YUV2RGBShader.cpp b/xbmc/cores/VideoRenderers/VideoShaders/YUV2RGBShader.cpp -index 58f26b0..50606eb 100644 ---- a/xbmc/cores/VideoRenderers/VideoShaders/YUV2RGBShader.cpp -+++ b/xbmc/cores/VideoRenderers/VideoShaders/YUV2RGBShader.cpp -@@ -201,6 +201,8 @@ static void CalculateYUVMatrixGL(GLfloat res[4][4] - m_defines += "#define XBMC_YUY2\n"; - else if (m_format == RENDER_FMT_UYVY422) - m_defines += "#define XBMC_UYVY\n"; -+ else if (RENDER_FMT_VDPAU_420) -+ m_defines += "#define XBMC_VDPAU_NV12\n"; - else - CLog::Log(LOGERROR, "GL: BaseYUV2RGBGLSLShader - unsupported format %d", m_format); - -diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodec.h b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodec.h -index 5001aac..98d8f89 100644 ---- a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodec.h -+++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodec.h -@@ -34,7 +34,7 @@ - - namespace DXVA { class CSurfaceContext; } - namespace VAAPI { struct CHolder; } --class CVDPAU; -+namespace VDPAU { class CVdpauRenderPicture; } - class COpenMax; - class COpenMaxVideo; - struct OpenMaxVideoBuffer; -@@ -55,7 +55,7 @@ struct DVDVideoPicture - DXVA::CSurfaceContext* context; - }; - struct { -- CVDPAU* vdpau; -+ VDPAU::CVdpauRenderPicture* vdpau; - }; - struct { - VAAPI::CHolder* vaapi; -diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp -index dae3b8e..a6e42e5 100644 ---- a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp -+++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp -@@ -71,14 +71,14 @@ enum PixelFormat CDVDVideoCodecFFmpeg::GetFormat( struct AVCodecContext * avctx - 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; -@@ -205,14 +205,27 @@ bool CDVDVideoCodecFFmpeg::Open(CDVDStreamInfo &hints, CDVDCodecOptions &options - 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 = m_dllAvCodec.avcodec_alloc_context3(pCodec); - 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(std::vector::iterator it = options.m_keys.begin(); it != options.m_keys.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 -diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.h b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.h -index 52e1113..bf4367c 100644 ---- a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.h -+++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.h -@@ -28,7 +28,6 @@ - #include "DllSwScale.h" - #include "DllAvFilter.h" - --class CVDPAU; - class CCriticalSection; - - class CDVDVideoCodecFFmpeg : public CDVDVideoCodec -diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp -index f70a4f9..235f565 100644 ---- a/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp -+++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp -@@ -32,11 +32,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}, -@@ -50,14 +55,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 - { -@@ -68,88 +75,30 @@ - , {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; -+void* CDecoder::dl_handle; -+ -+//----------------------------------------------------------------------------- -+// CVDPAU -+//----------------------------------------------------------------------------- - --CVDPAU::CVDPAU() -+CDecoder::CDecoder() : m_vdpauOutput(&m_inMsgEvent) - { -- 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; -+ m_vdpauConfig.vdpDevice = VDP_INVALID_HANDLE; -+ m_vdpauConfig.videoSurfaces = &m_videoSurfaces; -+ m_vdpauConfig.videoSurfaceSec = &m_videoSurfaceSec; - -- m_glPixmap = 0; -- m_Pixmap = 0; -- if (!glXBindTexImageEXT) -- glXBindTexImageEXT = (PFNGLXBINDTEXIMAGEEXTPROC)glXGetProcAddress((GLubyte *) "glXBindTexImageEXT"); -- if (!glXReleaseTexImageEXT) -- glXReleaseTexImageEXT = (PFNGLXRELEASETEXIMAGEEXTPROC)glXGetProcAddress((GLubyte *) "glXReleaseTexImageEXT"); -+ m_vdpauConfigured = false; -+ m_DisplayState = VDPAU_OPEN; -+} - -- 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; -- surface_width = surface_height = 0; -- -- memset(&decoder, 0, sizeof(decoder)); -- memset(&outRect, 0, sizeof(outRect)); -- memset(&outRectVid, 0, sizeof(outRectVid)); -- -- m_Display = NULL; -- -- 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; -- -- videoMixer = VDP_INVALID_HANDLE; -- m_BlackBar = NULL; -- -- memset(m_features, 0, sizeof(m_features)); -- m_feature_count = 0; -- m_vdpauOutputMethod = OUTPUT_NONE; -- -- upScale = g_advancedSettings.m_videoVDPAUScaling; -- -- vdp_video_mixer_set_attribute_values = NULL; -- vdp_generate_csc_matrix = NULL; -- vdp_presentation_queue_target_destroy = NULL; -- vdp_presentation_queue_create = NULL; -- vdp_presentation_queue_destroy = NULL; -- vdp_presentation_queue_display = NULL; -- vdp_presentation_queue_block_until_surface_idle = NULL; -- vdp_presentation_queue_target_create_x11 = NULL; -- vdp_presentation_queue_query_surface_status = NULL; -- vdp_presentation_queue_get_time = NULL; -- vdp_get_error_string = NULL; -- vdp_decoder_create = NULL; -- vdp_decoder_destroy = NULL; -- vdp_decoder_render = NULL; -- vdp_decoder_query_caps = NULL; -- vdp_preemption_callback_register = NULL; -- dl_vdp_device_create_x11 = NULL; -- dl_vdp_get_proc_address = NULL; -- dl_vdp_preemption_callback_register = NULL; --} -- --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) -@@ -157,6 +106,8 @@ bool CVDPAU::Open(AVCodecContext* avctx, const enum PixelFormat, unsigned int su - CLog::Log(LOGWARNING,"(VDPAU) no width/height available, can't init"); - return false; - } -+ m_vdpauConfig.numRenderBuffers = surfaces; -+ m_decoderThread = CThread::GetCurrentThreadId(); - - if (!dl_handle) - { -@@ -168,8 +119,6 @@ bool CVDPAU::Open(AVCodecContext* avctx, const enum PixelFormat, unsigned int su - 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; - } - } -@@ -178,8 +127,9 @@ bool CVDPAU::Open(AVCodecContext* avctx, const enum PixelFormat, unsigned int su - return false; - - InitVDPAUProcs(); -+ m_presentPicture = 0; - -- if (vdp_device != VDP_INVALID_HANDLE) -+ if (m_vdpauConfig.vdpDevice != VDP_INVALID_HANDLE) - { - SpewHardwareAvailable(); - -@@ -197,25 +147,23 @@ bool CVDPAU::Open(AVCodecContext* avctx, const enum PixelFormat, unsigned int su - - /* 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); -@@ -224,17 +172,20 @@ bool CVDPAU::Open(AVCodecContext* avctx, const enum PixelFormat, unsigned int su - 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()) - { -@@ -250,188 +201,111 @@ void CVDPAU::Close() - 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 -- }; -- -- GLXFBConfig *fbConfigs; -- fbConfigs = glXChooseFBConfig(m_Display, DefaultScreen(m_Display), doubleVisAttributes, &num); -- if (fbConfigs==NULL) -+ // check if we should do some pre-cleanup here -+ // a second decoder might need resources -+ if (m_vdpauConfigured == true) - { -- CLog::Log(LOGERROR, "GLX Error: MakePixmap: No compatible framebuffers found"); -- return false; -- } -- CLog::Log(LOGDEBUG, "Found %d fbconfigs.", num); -- fbConfigIndex = 0; -- CLog::Log(LOGDEBUG, "Using fbconfig index %d.", fbConfigIndex); -+ CSingleLock lock(m_DecoderSection); -+ CLog::Log(LOGNOTICE,"CVDPAU::Release pre-cleanup"); - -- m_glPixmap = glXCreatePixmap(m_Display, fbConfigs[fbConfigIndex], m_Pixmap, pixmapAttribs); -+ 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; -+ } - -- if (!m_glPixmap) -- { -- CLog::Log(LOGINFO, "GLX Error: Could not create Pixmap"); -- XFree(fbConfigs); -- 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; -+ } -+ } - } -- XFree(fbConfigs); -+ IHardwareDecoder::Release(); -+} - -- return true; -+long CDecoder::ReleasePicReference() -+{ -+ return IHardwareDecoder::Release(); - } - --bool CVDPAU::MakePixmap(int width, int height) -+void CDecoder::SetWidthHeight(int width, int height) - { -+ m_vdpauConfig.upscale = g_advancedSettings.m_videoVDPAUScaling; -+ - //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", m_vdpauConfig.outWidth, m_vdpauConfig.outHeight); - } - --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; - } - -@@ -445,16 +319,13 @@ int CVDPAU::Check(AVCodecContext* avctx) - } - 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(); -@@ -469,7 +340,7 @@ int CVDPAU::Check(AVCodecContext* avctx) - 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) -@@ -478,91 +349,28 @@ bool CVDPAU::IsVDPAUFormat(PixelFormat format) - 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 -- || method == VS_INTERLACEMETHOD_AUTO_ION) -+ || 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) -@@ -571,162 +379,12 @@ bool CVDPAU::Supports(EINTERLACEMETHOD method) - 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_AUTO_ION) -- { -- if (vid_height <= 576) -- { -- VdpBool enabled[]={1,1,0}; -- vdp_st = vdp_video_mixer_set_feature_enables(videoMixer, ARSIZE(feature), feature, enabled); -- } -- else if (vid_height > 576) -- { -- 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 -- || 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; - -@@ -736,151 +394,115 @@ void CVDPAU::InitVDPAUProcs() - 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(); -- } -- else -- { -- CLog::Log(LOGERROR,"(VDPAU) - Unable to get dl_vdp_device_create_x11 in %s", __FUNCTION__); -- vdp_device = VDP_INVALID_HANDLE; -- return; -+ m_Display = XOpenDisplay(NULL); - } - -- int mScreen = DefaultScreen(m_Display); -+ int mScreen = g_Windowing.GetCurrentScreen(); - 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; - } - - #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; -+ -+ 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) -+ 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__)) -@@ -888,8 +510,7 @@ void CVDPAU::FiniVDPAUOutput() - } - } - -- --void CVDPAU::ReadFormatOf( PixelFormat fmt -+void CDecoder::ReadFormatOf( PixelFormat fmt - , VdpDecoderProfile &vdp_decoder_profile - , VdpChromaType &vdp_chroma_type) - { -@@ -916,9 +537,9 @@ void CVDPAU::ReadFormatOf( PixelFormat fmt - vdp_chroma_type = VDP_CHROMA_TYPE_420; - break; - #if (defined PIX_FMT_VDPAU_MPEG4_IN_AVUTIL) && \ -- (defined VDP_DECODER_PROFILE_MPEG4_PART2_ASP) -+ (defined VDP_DECODER_PROFILE_MP) - case PIX_FMT_VDPAU_MPEG4: -- vdp_decoder_profile = VDP_DECODER_PROFILE_MPEG4_PART2_ASP; -+ vdp_decoder_profile = VDP_DECOPEG4_PART2_ASP; - vdp_chroma_type = VDP_CHROMA_TYPE_420; - break; - #endif -@@ -929,170 +550,78 @@ void CVDPAU::ReadFormatOf( PixelFormat fmt - } - } - -- --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; -- 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:"); -@@ -1102,7 +631,7 @@ void CVDPAU::SpewHardwareAvailable() //Copyright (c) 2008 Wladimir J. van der L - { - 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) - { -@@ -1111,13 +640,13 @@ void CVDPAU::SpewHardwareAvailable() //Copyright (c) 2008 Wladimir J. van der L - } - } - 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) - -@@ -1141,7 +670,7 @@ void CVDPAU::SpewHardwareAvailable() //Copyright (c) 2008 Wladimir J. van der L - - } - --bool CVDPAU::IsSurfaceValid(vdpau_render_state *render) -+bool CDecoder::IsSurfaceValid(vdpau_render_state *render) - { - // find render state in queue - bool found(false); -@@ -1168,34 +697,33 @@ bool CVDPAU::IsSurfaceValid(vdpau_render_state *render) - 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(); - - // 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; -+ } - } - } - -@@ -1204,21 +732,22 @@ int CVDPAU::FFGetBuffer(AVCodecContext *avctx, AVFrame *pic) - { - // 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); -@@ -1239,18 +768,6 @@ int CVDPAU::FFGetBuffer(AVCodecContext *avctx, AVFrame *pic) - - pic->linesize[0] = pic->linesize[1] = pic->linesize[2] = 0; - -- if(pic->reference) -- { -- pA->ip_age[0]= pA->ip_age[1]+1; -- pA->ip_age[1]= 1; -- pA->b_age++; -- } -- else -- { -- pA->ip_age[0]++; -- pA->ip_age[1]++; -- pA->b_age = 1; -- } - pic->type= FF_BUFFER_TYPE_USER; - - render->state |= FF_VDPAU_STATE_USED_FOR_REFERENCE; -@@ -1258,15 +775,16 @@ int CVDPAU::FFGetBuffer(AVCodecContext *avctx, AVFrame *pic) - 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) -@@ -1275,6 +793,8 @@ void CVDPAU::FFReleaseBuffer(AVCodecContext *avctx, AVFrame *pic) - return; - } - -+ CSingleLock vLock(vdp->m_videoSurfaceSec); -+ render->state &= ~FF_VDPAU_STATE_USED_FOR_REFERENCE; - for(i=0; i<4; i++) - pic->data[i]= NULL; - -@@ -1289,21 +809,18 @@ void CVDPAU::FFReleaseBuffer(AVCodecContext *avctx, AVFrame *pic) - } - - --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]) -@@ -1333,59 +850,41 @@ void CVDPAU::FFDrawSlice(struct AVCodecContext *s, - 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) -+{ - 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 - -@@ -1393,7 +892,10 @@ int CVDPAU::Decode(AVCodecContext *avctx, AVFrame *pFrame) - 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)) -@@ -1402,258 +904,166 @@ int CVDPAU::Decode(AVCodecContext *avctx, AVFrame *pFrame) - return VC_BUFFER; - } - -+ CSingleLock lock(m_videoSurfaceSec); - render->state |= FF_VDPAU_STATE_USED_FOR_RENDER; -+ lock.Leave(); - -- ClearUsedForRender(&past[0]); -- past[0] = past[1]; -- past[1] = current; -- current = future; -- future = render; -+ // 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)); - -- DVDVideoPicture DVDPic; -- memset(&DVDPic, 0, sizeof(DVDVideoPicture)); -- ((CDVDVideoCodecFFmpeg*)avctx->opaque)->GetPictureCommon(&DVDPic); -- m_DVDVideoPics.push(DVDPic); -+ m_codecControl = pic.DVDPic.iFlags & (DVP_FLAG_DRAIN | DVP_FLAG_NO_POSTPROC); -+ } - -- int pics = m_DVDVideoPics.size(); -- if (pics < 2) -- return VC_BUFFER; -- else if (pics > 2) -+ int retval = 0; -+ uint16_t decoded, processed, render; -+ Message *msg; -+ while (m_vdpauOutput.m_controlPort.ReceiveInMessage(&msg)) -+ { -+ if (msg->signal == COutputControlProtocol::ERROR) - { -- // this should not normally happen -- CLog::Log(LOGERROR, "CVDPAU::Decode - invalid number of pictures in queue"); -- while (pics-- != 2) -- m_DVDVideoPics.pop(); -+ m_DisplayState = VDPAU_ERROR; -+ retval |= VC_ERROR; - } -+ msg->Release(); -+ } - -- if (mode == VS_DEINTERLACEMODE_FORCE -- || (mode == VS_DEINTERLACEMODE_AUTO && m_DVDVideoPics.front().iFlags & DVP_FLAG_INTERLACED)) -+ m_bufferStats.Get(decoded, processed, render); -+ -+ uint64_t startTime = CurrentHostCounter(); -+ while (!retval) -+ { -+ if (m_vdpauOutput.m_dataPort.ReceiveInMessage(&msg)) - { -- if((method == VS_INTERLACEMETHOD_AUTO_ION -- || 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 (msg->signal == COutputDataProtocol::PICTURE) - { -- if((method == VS_INTERLACEMETHOD_AUTO_ION && vid_height > 576) -- || 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_codecControl); - } -+ 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 (!retval) - { -- if (past[0]) -- past_surfaces[1] = past[0]->surface; -- if (past[1]) -- past_surfaces[0] = past[1]->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; - } -- else -- { -- 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; -- } -- } -- -- 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; -- } -- -- *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(); -+ CSingleLock lock(m_DecoderSection); - -- picture->format = RENDER_FMT_VDPAU; -- picture->iFlags &= DVP_FLAG_DROPPED; -- picture->iWidth = OutWidth; -- picture->iHeight = OutHeight; -- picture->vdpau = this; -+ if (!m_vdpauConfigured) -+ return; - -- if(m_mixerstep) -+ Message *reply; -+ if (m_vdpauOutput.m_controlPort.SendOutMessageSync(COutputControlProtocol::FLUSH, -+ &reply, -+ 2000)) - { -- picture->iRepeatPicture = -0.5; -- if(m_mixerstep > 1) -+ 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::ReturnRenderPicture(CVdpauRenderPicture *renderPic) - { -- //CLog::Log(LOGNOTICE,"%s",__FUNCTION__); -- VdpStatus vdp_st; -- -- CSharedLock lock(m_DecoderSection); -- -- { CSharedLock dLock(m_DisplaySection); -- if (m_DisplayState != VDPAU_OPEN) -- return; -- } -- -- presentSurface = outputSurface; -- -- vdp_st = vdp_presentation_queue_display(vdp_flip_queue, -- presentSurface, -- 0, -- 0, -- 0); -- CheckStatus(vdp_st, __LINE__); -+ 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) - { -@@ -1671,4 +1081,2422 @@ bool CVDPAU::CheckStatus(VdpStatus vdp_st, int line) - 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 != RENDER_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 != RENDER_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,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 -+ || 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 flags; -+ m_config.stats->GetParams(latency, flags); -+ latency = (latency*1000)/CurrentHostFrequency(); -+ if (flags & DVP_FLAG_NO_POSTPROC) -+ 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 = RENDER_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 = RENDER_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 = RENDER_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 = RENDER_FMT_VDPAU_420; -+ else -+ { -+ m_mixerInput[1].DVDPic.format = RENDER_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 == RENDER_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 != RENDER_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 == RENDER_FMT_VDPAU_420) -+ 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 == RENDER_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 == RENDER_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 == RENDER_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 == RENDER_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 == RENDER_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, g_Windowing.GetWindow(), &wndattribs); -+ -+ pixmap.pixmap = XCreatePixmap(m_Display, -+ g_Windowing.GetWindow(), -+ 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, g_Windowing.GetCurrentScreen(), 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.usevdpauinterop"); -+ -+#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.usevdpauinterop",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.GetWindow(); -+ -+ // 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, -+ m_Window, -+ 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 --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.h b/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.h -index 2f53edf..4d1559c 100644 ---- a/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.h -+++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.h -@@ -1,5 +1,3 @@ -- --#pragma once - /* - * Copyright (C) 2005-2012 Team XBMC - * http://www.xbmc.org -@@ -20,9 +18,32 @@ - * - */ - -+/** -+ * 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. -+ */ -+ -+#pragma once -+ - #include "system_gl.h" - --#include -+#include "DllAvUtil.h" -+#include "DVDVideoCodec.h" -+#include "DVDVideoCodecFFmpeg.h" -+#include "libavcodec/vdpau.h" - #include - #include - #define GLX_GLXEXT_PROTOTYPES -@@ -37,118 +58,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... */ -- }; -- -- 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; -- -- 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); -+#include "threads/Thread.h" -+#include "utils/ActorProtocol.h" - -- void CheckFeatures(); -- void SetColor(); -- void SetNoiseReduction(); -- void SetSharpness(); -- void SetDeinterlacing(); -- void SetHWUpscaling(); -+using namespace Actor; - -- 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; -- } -- } -- -- VdpProcamp m_Procamp; -- VdpCSCMatrix m_CSCMatrix; -- VdpDevice HasDevice() { return vdp_device != VDP_INVALID_HANDLE; }; -- VdpChromaType vdp_chroma_type; -+#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 - -+namespace VDPAU -+{ - -- // protected: -- void InitVDPAUProcs(); -- void FiniVDPAUProcs(); -- void FiniVDPAUOutput(); -- bool ConfigOutputMethod(AVCodecContext *avctx, AVFrame *pFrame); -- bool FiniOutputMethod(); -+/** -+ * VDPAU interface to driver -+ */ - -- VdpDevice vdp_device; -- VdpGetProcAddress * vdp_get_proc_address; -- VdpPresentationQueueTarget vdp_flip_target; -- VdpPresentationQueue vdp_flip_queue; -- VdpDeviceDestroy * vdp_device_destroy; -+struct VDPAU_procs -+{ -+ VdpGetProcAddress * vdp_get_proc_address; -+ 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 +92,15 @@ class CVDPAU - 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 +113,459 @@ class CVDPAU - - 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; -+//----------------------------------------------------------------------------- -+// VDPAU data structs -+//----------------------------------------------------------------------------- - -- 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); -+class CDecoder; - -- 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; -+/** -+ * 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[14]; -+ 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 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); -+ virtual bool GetPicture(AVCodecContext* avctx, AVFrame* frame, DVDVideoPicture* picture); -+ virtual void Reset(); -+ virtual void Close(); -+ virtual long Release(); -+ virtual bool CanSkipDeint(); -+ -+ 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[14]; -- 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 +576,24 @@ class CVDPAU - , 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; -+ -+ COutput m_vdpauOutput; -+ CVdpauBufferStats m_bufferStats; -+ CEvent m_inMsgEvent; -+ CVdpauRenderPicture *m_presentPicture; -+ -+ int m_codecControl; - }; -+ -+} -diff --git a/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp b/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp -index 10e2225..15a39fa 100644 ---- a/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp -+++ b/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp -@@ -1141,6 +1141,9 @@ int CDVDPlayerVideo::OutputPicture(const DVDVideoPicture* src, double pts) - case RENDER_FMT_VDPAU: - formatstr = "VDPAU"; - break; -+ case RENDER_FMT_VDPAU_420: -+ formatstr = "VDPAU_420"; -+ break; - case RENDER_FMT_DXVA: - formatstr = "DXVA"; - break; -diff --git a/xbmc/settings/AdvancedSettings.cpp b/xbmc/settings/AdvancedSettings.cpp -index 16800b7..844f8e8 100644 ---- a/xbmc/settings/AdvancedSettings.cpp -+++ b/xbmc/settings/AdvancedSettings.cpp -@@ -98,7 +98,7 @@ void CAdvancedSettings::Initialize() - m_videoIgnoreSecondsAtStart = 3*60; - m_videoIgnorePercentAtEnd = 8.0f; - m_videoPlayCountMinimumPercent = 90.0f; -- m_videoVDPAUScaling = false; -+ m_videoVDPAUScaling = -1; - m_videoNonLinStretchRatio = 0.5f; - m_videoEnableHighQualityHwScalers = false; - m_videoAutoScaleMaxFps = 30.0f; -@@ -106,6 +106,8 @@ void CAdvancedSettings::Initialize() - m_videoAllowMpeg4VAAPI = false; - m_videoDisableBackgroundDeinterlace = false; - m_videoCaptureUseOcclusionQuery = -1; //-1 is auto detect -+ m_videoVDPAUtelecine = false; -+ m_videoVDPAUdeintSkipChromaHD = false; - m_DXVACheckCompatibility = false; - m_DXVACheckCompatibilityPresent = false; - m_DXVAForceProcessorRenderer = true; -@@ -493,7 +495,7 @@ void CAdvancedSettings::ParseSettingsFile(const CStdString &file) - XMLUtils::GetString(pElement,"cleandatetime", m_videoCleanDateTimeRegExp); - XMLUtils::GetString(pElement,"ppffmpegdeinterlacing",m_videoPPFFmpegDeint); - XMLUtils::GetString(pElement,"ppffmpegpostprocessing",m_videoPPFFmpegPostProc); -- XMLUtils::GetBoolean(pElement,"vdpauscaling",m_videoVDPAUScaling); -+ XMLUtils::GetInt(pElement,"vdpauscaling",m_videoVDPAUScaling); - XMLUtils::GetFloat(pElement, "nonlinearstretchratio", m_videoNonLinStretchRatio, 0.01f, 1.0f); - XMLUtils::GetBoolean(pElement,"enablehighqualityhwscalers", m_videoEnableHighQualityHwScalers); - XMLUtils::GetFloat(pElement,"autoscalemaxfps",m_videoAutoScaleMaxFps, 0.0f, 1000.0f); -@@ -501,6 +503,8 @@ void CAdvancedSettings::ParseSettingsFile(const CStdString &file) - XMLUtils::GetBoolean(pElement,"allowmpeg4vaapi",m_videoAllowMpeg4VAAPI); - XMLUtils::GetBoolean(pElement, "disablebackgrounddeinterlace", m_videoDisableBackgroundDeinterlace); - XMLUtils::GetInt(pElement, "useocclusionquery", m_videoCaptureUseOcclusionQuery, -1, 1); -+ XMLUtils::GetBoolean(pElement,"vdpauInvTelecine",m_videoVDPAUtelecine); -+ XMLUtils::GetBoolean(pElement,"vdpauHDdeintSkipChroma",m_videoVDPAUdeintSkipChromaHD); - - TiXmlElement* pAdjustRefreshrate = pElement->FirstChildElement("adjustrefreshrate"); - if (pAdjustRefreshrate) -diff --git a/xbmc/settings/AdvancedSettings.h b/xbmc/settings/AdvancedSettings.h -index 27887d4..72718e5 100644 ---- a/xbmc/settings/AdvancedSettings.h -+++ b/xbmc/settings/AdvancedSettings.h -@@ -133,6 +133,8 @@ class CAdvancedSettings - int m_videoPercentSeekBackwardBig; - CStdString m_videoPPFFmpegDeint; - CStdString m_videoPPFFmpegPostProc; -+ bool m_videoVDPAUtelecine; -+ bool m_videoVDPAUdeintSkipChromaHD; - bool m_musicUseTimeSeeking; - int m_musicTimeSeekForward; - int m_musicTimeSeekBackward; -@@ -148,7 +150,7 @@ class CAdvancedSettings - CStdString m_audioHost; - bool m_audioApplyDrc; - -- bool m_videoVDPAUScaling; -+ int m_videoVDPAUScaling; - float m_videoNonLinStretchRatio; - bool m_videoEnableHighQualityHwScalers; - float m_videoAutoScaleMaxFps; -diff --git a/xbmc/settings/GUISettings.cpp b/xbmc/settings/GUISettings.cpp -index 76ec0cc..4cdb093 100644 ---- a/xbmc/settings/GUISettings.cpp -+++ b/xbmc/settings/GUISettings.cpp -@@ -685,6 +685,8 @@ void CGUISettings::Initialize() - - #ifdef HAVE_LIBVDPAU - AddBool(vp, "videoplayer.usevdpau", 13425, true); -+ AddBool(vp, "videoplayer.usevdpauinterop", 13435, true); -+ AddBool(vp, "videoplayer.usevdpauinteropyuv", 13436, false); - #endif - #ifdef HAVE_LIBVA - AddBool(vp, "videoplayer.usevaapi", 13426, true); -diff --git a/xbmc/settings/GUIWindowSettingsCategory.cpp b/xbmc/settings/GUIWindowSettingsCategory.cpp -index 4ac2663..d988598 100644 ---- a/xbmc/settings/GUIWindowSettingsCategory.cpp -+++ b/xbmc/settings/GUIWindowSettingsCategory.cpp -@@ -596,6 +596,40 @@ void CGUIWindowSettingsCategory::UpdateSettings() - pControl->SetEnabled(true); - } - } -+ else if (strSetting.Equals("videoplayer.usevdpauinteropyuv")) -+ { -+ bool hasInterop = g_guiSettings.GetBool("videoplayer.usevdpauinterop"); -+#ifndef GL_NV_vdpau_interop -+ hasInterop = false; -+#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.usevdpauinterop")) -+ { -+ bool hasInterop = g_guiSettings.GetBool("videoplayer.usevdpau"); -+#ifndef GL_NV_vdpau_interop -+ hasInterop = false; -+#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.usevdpauinterop",false); -+ } -+ } - else - #endif - if (strSetting.Equals("videoscreen.resolution")) -diff --git a/xbmc/utils/ActorProtocol.cpp b/xbmc/utils/ActorProtocol.cpp -new file mode 100644 -index 0000000..e0cfd0e ---- /dev/null -+++ b/xbmc/utils/ActorProtocol.cpp -@@ -0,0 +1,253 @@ -+/* -+ * Copyright (C) 2005-2012 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, see -+ * . -+ * -+ */ -+ -+#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 --git a/xbmc/utils/ActorProtocol.h b/xbmc/utils/ActorProtocol.h -new file mode 100644 -index 0000000..e7108ac ---- /dev/null -+++ b/xbmc/utils/ActorProtocol.h -@@ -0,0 +1,87 @@ -+/* -+ * Copyright (C) 2005-2012 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, see -+ * . -+ * -+ */ -+ -+#pragma once -+ -+#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) -+ : portName(name), inDefered(false), outDefered(false) {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 --git a/xbmc/utils/Makefile b/xbmc/utils/Makefile -index d201884..7d1f9f0 100644 ---- a/xbmc/utils/Makefile -+++ b/xbmc/utils/Makefile -@@ -70,6 +70,7 @@ SRCS=AlarmClock.cpp \ - Weather.cpp \ - XBMCTinyXML.cpp \ - XMLUtils.cpp \ -+ ActorProtocol.cpp \ - - LIB=utils.a - -diff --git a/xbmc/video/dialogs/GUIDialogVideoSettings.cpp b/xbmc/video/dialogs/GUIDialogVideoSettings.cpp -index ac5f007..f25d10d 100644 ---- a/xbmc/video/dialogs/GUIDialogVideoSettings.cpp -+++ b/xbmc/video/dialogs/GUIDialogVideoSettings.cpp -@@ -103,7 +103,7 @@ void CGUIDialogVideoSettings::CreateSettings() - 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 , 16325)); - 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)); -diff --git a/xbmc/windowing/X11/WinSystemX11.h b/xbmc/windowing/X11/WinSystemX11.h -index e7af3cb..2dd8a9f 100644 ---- a/xbmc/windowing/X11/WinSystemX11.h -+++ b/xbmc/windowing/X11/WinSystemX11.h -@@ -63,6 +63,7 @@ class CWinSystemX11 : public CWinSystemBase - // Local to WinSystemX11 only - Display* GetDisplay() { return m_dpy; } - GLXWindow GetWindow() { return m_glWindow; } -+ GLXContext GetGlxContext() { return m_glContext; } - - protected: - bool RefreshGlxContext(); --- -1.7.10 - - -From c088467d9d0955051a510dadbddb270ddc3e3c20 Mon Sep 17 00:00:00 2001 -From: xbmc -Date: Tue, 25 Sep 2012 12:14:15 +0200 -Subject: [PATCH 12/73] linuxrenderer: drop method RenderMultiPass - ---- - xbmc/cores/VideoRenderers/LinuxRendererGL.cpp | 9 ++------- - xbmc/cores/VideoRenderers/LinuxRendererGL.h | 1 - - 2 files changed, 2 insertions(+), 8 deletions(-) - -diff --git a/xbmc/cores/VideoRenderers/LinuxRendererGL.cpp b/xbmc/cores/VideoRenderers/LinuxRendererGL.cpp -index 4ee50c1..ea58c85 100644 ---- a/xbmc/cores/VideoRenderers/LinuxRendererGL.cpp -+++ b/xbmc/cores/VideoRenderers/LinuxRendererGL.cpp -@@ -1205,7 +1205,8 @@ void CLinuxRendererGL::Render(DWORD flags, int renderBuffer) - break; - - case RQ_MULTIPASS: -- RenderMultiPass(renderBuffer, m_currentField); -+ RenderToFBO(renderBuffer, m_currentField); -+ RenderFromFBO(); - VerifyGLState(); - break; - } -@@ -1328,12 +1329,6 @@ void CLinuxRendererGL::RenderSinglePass(int index, int field) - VerifyGLState(); - } - --void CLinuxRendererGL::RenderMultiPass(int index, int field) --{ -- RenderToFBO(index, field); -- RenderFromFBO(); --} -- - void CLinuxRendererGL::RenderToFBO(int index, int field) - { - YUVPLANES &planes = m_buffers[index].fields[field]; -diff --git a/xbmc/cores/VideoRenderers/LinuxRendererGL.h b/xbmc/cores/VideoRenderers/LinuxRendererGL.h -index 3218cd5..afc78c2 100644 ---- a/xbmc/cores/VideoRenderers/LinuxRendererGL.h -+++ b/xbmc/cores/VideoRenderers/LinuxRendererGL.h -@@ -218,7 +218,6 @@ class CLinuxRendererGL : public CBaseRenderer - void CalculateTextureSourceRects(int source, int num_planes); - - // renderers -- void RenderMultiPass(int renderBuffer, int field); // multi pass glsl renderer - void RenderToFBO(int renderBuffer, int field); - void RenderFromFBO(); - void RenderSinglePass(int renderBuffer, int field); // single pass glsl renderer --- -1.7.10 - - -From 0de3939247a63509e6bfab2e77c298eaa28aa29c Mon Sep 17 00:00:00 2001 -From: xbmc -Date: Tue, 25 Sep 2012 13:20:47 +0200 -Subject: [PATCH 13/73] linuxrenderer: implement progressive weave for vdpau - ---- - xbmc/cores/VideoRenderers/LinuxRendererGL.cpp | 55 ++++++++++++++++++------- - xbmc/cores/VideoRenderers/LinuxRendererGL.h | 4 +- - 2 files changed, 41 insertions(+), 18 deletions(-) - -diff --git a/xbmc/cores/VideoRenderers/LinuxRendererGL.cpp b/xbmc/cores/VideoRenderers/LinuxRendererGL.cpp -index ea58c85..b281ca7 100644 ---- a/xbmc/cores/VideoRenderers/LinuxRendererGL.cpp -+++ b/xbmc/cores/VideoRenderers/LinuxRendererGL.cpp -@@ -689,18 +689,6 @@ void CLinuxRendererGL::RenderUpdate(bool clear, DWORD flags, DWORD alpha) - glDisable(GL_POLYGON_STIPPLE); - - } -- else if(m_format == RENDER_FMT_VDPAU_420 -- && !(flags & RENDER_FLAG_BOTH)) -- { -- 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); - -@@ -1200,13 +1188,21 @@ void CLinuxRendererGL::Render(DWORD flags, int renderBuffer) - { - case RQ_LOW: - case RQ_SINGLEPASS: -- RenderSinglePass(renderBuffer, m_currentField); -+ if (m_format == RENDER_FMT_VDPAU_420 && m_currentField == FIELD_FULL) -+ RenderProgressiveWeave(renderBuffer, m_currentField); -+ else -+ RenderSinglePass(renderBuffer, m_currentField); - VerifyGLState(); - break; - - case RQ_MULTIPASS: -- RenderToFBO(renderBuffer, m_currentField); -- RenderFromFBO(); -+ if (m_format == RENDER_FMT_VDPAU_420 && m_currentField == FIELD_FULL) -+ RenderProgressiveWeave(renderBuffer, m_currentField); -+ else -+ { -+ RenderToFBO(renderBuffer, m_currentField); -+ RenderFromFBO(); -+ } - VerifyGLState(); - break; - } -@@ -1329,7 +1325,7 @@ void CLinuxRendererGL::RenderSinglePass(int index, int field) - VerifyGLState(); - } - --void CLinuxRendererGL::RenderToFBO(int index, int field) -+void CLinuxRendererGL::RenderToFBO(int index, int field, bool weave /*= false*/) - { - YUVPLANES &planes = m_buffers[index].fields[field]; - -@@ -1431,6 +1427,8 @@ void CLinuxRendererGL::RenderToFBO(int index, int field) - } - m_fbo.width *= planes[0].pixpertex_x; - m_fbo.height *= planes[0].pixpertex_y; -+ if (weave) -+ m_fbo.height *= 2; - - // 1st Pass to video frame size - glBegin(GL_QUADS); -@@ -1549,6 +1547,31 @@ void CLinuxRendererGL::RenderFromFBO() - VerifyGLState(); - } - -+void CLinuxRendererGL::RenderProgressiveWeave(int index, int field) -+{ -+ bool scaleUp = (int)m_sourceHeight < g_graphicsContext.GetHeight() || (int)m_sourceWidth < g_graphicsContext.GetWidth(); -+ -+ if (m_fbo.fbo.IsSupported() && (scaleUp || m_renderQuality == RQ_MULTIPASS)) -+ { -+ glEnable(GL_POLYGON_STIPPLE); -+ glPolygonStipple(stipple_weave); -+ RenderToFBO(index, FIELD_TOP, true); -+ glPolygonStipple(stipple_weave+4); -+ RenderToFBO(index, FIELD_BOT, true); -+ glDisable(GL_POLYGON_STIPPLE); -+ RenderFromFBO(); -+ } -+ else -+ { -+ glEnable(GL_POLYGON_STIPPLE); -+ glPolygonStipple(stipple_weave); -+ RenderSinglePass(index, FIELD_TOP); -+ glPolygonStipple(stipple_weave+4); -+ RenderSinglePass(index, FIELD_BOT); -+ glDisable(GL_POLYGON_STIPPLE); -+ } -+} -+ - void CLinuxRendererGL::RenderVDPAU(int index, int field) - { - #ifdef HAVE_LIBVDPAU -diff --git a/xbmc/cores/VideoRenderers/LinuxRendererGL.h b/xbmc/cores/VideoRenderers/LinuxRendererGL.h -index afc78c2..2fc34ae 100644 ---- a/xbmc/cores/VideoRenderers/LinuxRendererGL.h -+++ b/xbmc/cores/VideoRenderers/LinuxRendererGL.h -@@ -218,12 +218,12 @@ class CLinuxRendererGL : public CBaseRenderer - void CalculateTextureSourceRects(int source, int num_planes); - - // renderers -- void RenderToFBO(int renderBuffer, int field); -+ void RenderToFBO(int renderBuffer, int field, bool weave = false); - void RenderFromFBO(); - 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 RenderProgressiveWeave(int renderBuffer, int field); // render using vdpau hardware - void RenderVAAPI(int renderBuffer, int field); // render using vdpau hardware - - struct --- -1.7.10 - - -From c12380f4b9c9c2671bfd1ebd3e29ba7cd83ac95e Mon Sep 17 00:00:00 2001 -From: FernetMenta -Date: Thu, 5 Jul 2012 15:22:05 +0200 -Subject: [PATCH 14/73] X11: ditch SDL for video and window events - ---- - xbmc/Application.cpp | 2 +- - xbmc/system.h | 5 + - xbmc/windowing/Makefile | 1 + - xbmc/windowing/WinEvents.h | 4 + - xbmc/windowing/WinEventsX11.cpp | 765 +++++++++++++++++++++++++++++++++++ - xbmc/windowing/WinEventsX11.h | 57 +++ - xbmc/windowing/X11/WinSystemX11.cpp | 370 ++++++++++++----- - xbmc/windowing/X11/WinSystemX11.h | 9 +- - 8 files changed, 1112 insertions(+), 101 deletions(-) - create mode 100644 xbmc/windowing/WinEventsX11.cpp - create mode 100644 xbmc/windowing/WinEventsX11.h - -diff --git a/xbmc/Application.cpp b/xbmc/Application.cpp -index 9a7b900..fc8e721 100644 ---- a/xbmc/Application.cpp -+++ b/xbmc/Application.cpp -@@ -790,7 +790,7 @@ bool CApplication::CreateGUI() - - uint32_t sdlFlags = 0; - --#if defined(HAS_SDL_OPENGL) || (HAS_GLES == 2) -+#if (defined(HAS_SDL_OPENGL) || (HAS_GLES == 2)) && !defined(HAS_GLX) - sdlFlags |= SDL_INIT_VIDEO; - #endif - -diff --git a/xbmc/system.h b/xbmc/system.h -index 4165c01..32584b1 100644 ---- a/xbmc/system.h -+++ b/xbmc/system.h -@@ -162,16 +162,21 @@ - #define HAS_GL - #ifdef HAVE_X11 - #define HAS_GLX -+#define HAS_X11_WIN_EVENTS - #endif - #ifdef HAVE_SDL - #define HAS_SDL - #ifndef HAS_SDL_OPENGL - #define HAS_SDL_OPENGL - #endif -+#ifndef HAVE_X11 - #define HAS_SDL_WIN_EVENTS -+#endif - #else -+#ifndef HAVE_X11 - #define HAS_LINUX_EVENTS - #endif -+#endif - #define HAS_LINUX_NETWORK - #define HAS_LIRC - #ifdef HAVE_LIBPULSE -diff --git a/xbmc/windowing/Makefile b/xbmc/windowing/Makefile -index f109bec..f981642 100644 ---- a/xbmc/windowing/Makefile -+++ b/xbmc/windowing/Makefile -@@ -1,6 +1,7 @@ - SRCS=WinEventsSDL.cpp \ - WinEventsLinux.cpp \ - WinSystem.cpp \ -+ WinEventsX11.cpp \ - - LIB=windowing.a - -diff --git a/xbmc/windowing/WinEvents.h b/xbmc/windowing/WinEvents.h -index 6d322a9..5a671cc 100644 ---- a/xbmc/windowing/WinEvents.h -+++ b/xbmc/windowing/WinEvents.h -@@ -58,6 +58,10 @@ class CWinEventsBase - #include "WinEventsSDL.h" - #define CWinEvents CWinEventsSDL - -+#elif defined(TARGET_LINUX) && defined(HAS_X11_WIN_EVENTS) -+#include "WinEventsX11.h" -+#define CWinEvents CWinEventsX11 -+ - #elif defined(TARGET_LINUX) && defined(HAS_LINUX_EVENTS) - #include "WinEventsLinux.h" - #define CWinEvents CWinEventsLinux -diff --git a/xbmc/windowing/WinEventsX11.cpp b/xbmc/windowing/WinEventsX11.cpp -new file mode 100644 -index 0000000..24477ae ---- /dev/null -+++ b/xbmc/windowing/WinEventsX11.cpp -@@ -0,0 +1,765 @@ -+/* -+* Copyright (C) 2005-2012 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 HAS_X11_WIN_EVENTS -+ -+#include "WinEvents.h" -+#include "WinEventsX11.h" -+#include "Application.h" -+#include "ApplicationMessenger.h" -+#include -+#include "X11/WinSystemX11GL.h" -+#include "X11/keysymdef.h" -+#include "X11/XF86keysym.h" -+#include "utils/log.h" -+#include "guilib/GUIWindowManager.h" -+#include "input/MouseStat.h" -+ -+CWinEventsX11* CWinEventsX11::WinEvents = 0; -+ -+static uint32_t SymMappingsX11[][2] = -+{ -+ {XK_BackSpace, XBMCK_BACKSPACE} -+, {XK_Tab, XBMCK_TAB} -+, {XK_Clear, XBMCK_CLEAR} -+, {XK_Return, XBMCK_RETURN} -+, {XK_Pause, XBMCK_PAUSE} -+, {XK_Escape, XBMCK_ESCAPE} -+, {XK_Delete, XBMCK_DELETE} -+// multi-media keys -+, {XF86XK_Back, XBMCK_BROWSER_BACK} -+, {XF86XK_Forward, XBMCK_BROWSER_FORWARD} -+, {XF86XK_Refresh, XBMCK_BROWSER_REFRESH} -+, {XF86XK_Stop, XBMCK_BROWSER_STOP} -+, {XF86XK_Search, XBMCK_BROWSER_SEARCH} -+, {XF86XK_Favorites, XBMCK_BROWSER_FAVORITES} -+, {XF86XK_HomePage, XBMCK_BROWSER_HOME} -+, {XF86XK_AudioMute, XBMCK_VOLUME_MUTE} -+, {XF86XK_AudioLowerVolume, XBMCK_VOLUME_DOWN} -+, {XF86XK_AudioRaiseVolume, XBMCK_VOLUME_UP} -+, {XF86XK_AudioNext, XBMCK_MEDIA_NEXT_TRACK} -+, {XF86XK_AudioPrev, XBMCK_MEDIA_PREV_TRACK} -+, {XF86XK_AudioStop, XBMCK_MEDIA_STOP} -+, {XF86XK_AudioPause, XBMCK_MEDIA_PLAY_PAUSE} -+, {XF86XK_Mail, XBMCK_LAUNCH_MAIL} -+, {XF86XK_Select, XBMCK_LAUNCH_MEDIA_SELECT} -+, {XF86XK_Launch0, XBMCK_LAUNCH_APP1} -+, {XF86XK_Launch1, XBMCK_LAUNCH_APP2} -+, {XF86XK_WWW, XBMCK_LAUNCH_FILE_BROWSER} -+, {XF86XK_AudioMedia, XBMCK_LAUNCH_MEDIA_CENTER } -+ // Numeric keypad -+, {XK_KP_0, XBMCK_KP0} -+, {XK_KP_1, XBMCK_KP1} -+, {XK_KP_2, XBMCK_KP2} -+, {XK_KP_3, XBMCK_KP3} -+, {XK_KP_4, XBMCK_KP4} -+, {XK_KP_5, XBMCK_KP5} -+, {XK_KP_6, XBMCK_KP6} -+, {XK_KP_7, XBMCK_KP7} -+, {XK_KP_8, XBMCK_KP8} -+, {XK_KP_9, XBMCK_KP9} -+, {XK_KP_Separator, XBMCK_KP_PERIOD} -+, {XK_KP_Divide, XBMCK_KP_DIVIDE} -+, {XK_KP_Multiply, XBMCK_KP_MULTIPLY} -+, {XK_KP_Subtract, XBMCK_KP_MINUS} -+, {XK_KP_Add, XBMCK_KP_PLUS} -+, {XK_KP_Enter, XBMCK_KP_ENTER} -+, {XK_KP_Equal, XBMCK_KP_EQUALS} -+ // Arrows + Home/End pad -+, {XK_Up, XBMCK_UP} -+, {XK_Down, XBMCK_DOWN} -+, {XK_Right, XBMCK_RIGHT} -+, {XK_Left, XBMCK_LEFT} -+, {XK_Insert, XBMCK_INSERT} -+, {XK_Home, XBMCK_HOME} -+, {XK_End, XBMCK_END} -+, {XK_Page_Up, XBMCK_PAGEUP} -+, {XK_Page_Down, XBMCK_PAGEDOWN} -+ // Function keys -+, {XK_F1, XBMCK_F1} -+, {XK_F2, XBMCK_F2} -+, {XK_F3, XBMCK_F3} -+, {XK_F4, XBMCK_F4} -+, {XK_F5, XBMCK_F5} -+, {XK_F6, XBMCK_F6} -+, {XK_F7, XBMCK_F7} -+, {XK_F8, XBMCK_F8} -+, {XK_F9, XBMCK_F9} -+, {XK_F10, XBMCK_F10} -+, {XK_F11, XBMCK_F11} -+, {XK_F12, XBMCK_F12} -+, {XK_F13, XBMCK_F13} -+, {XK_F14, XBMCK_F14} -+, {XK_F15, XBMCK_F15} -+ // Key state modifier keys -+, {XK_Num_Lock, XBMCK_NUMLOCK} -+, {XK_Caps_Lock, XBMCK_CAPSLOCK} -+, {XK_Scroll_Lock, XBMCK_SCROLLOCK} -+, {XK_Shift_R, XBMCK_RSHIFT} -+, {XK_Shift_L, XBMCK_LSHIFT} -+, {XK_Control_R, XBMCK_RCTRL} -+, {XK_Control_L, XBMCK_LCTRL} -+, {XK_Alt_R, XBMCK_RALT} -+, {XK_Alt_L, XBMCK_LALT} -+, {XK_Meta_R, XBMCK_RMETA} -+, {XK_Meta_L, XBMCK_LMETA} -+, {XK_Super_L, XBMCK_LSUPER} -+, {XK_Super_R, XBMCK_RSUPER} -+, {XK_Mode_switch, XBMCK_MODE} -+, {XK_Multi_key, XBMCK_COMPOSE} -+ // Miscellaneous function keys -+, {XK_Help, XBMCK_HELP} -+, {XK_Print, XBMCK_PRINT} -+//, {0, XBMCK_SYSREQ} -+, {XK_Break, XBMCK_BREAK} -+, {XK_Menu, XBMCK_MENU} -+, {XF86XK_PowerOff, XBMCK_POWER} -+, {XK_EcuSign, XBMCK_EURO} -+, {XK_Undo, XBMCK_UNDO} -+ /* Media keys */ -+, {XF86XK_Eject, XBMCK_EJECT} -+, {XF86XK_Stop, XBMCK_STOP} -+, {XF86XK_AudioRecord, XBMCK_RECORD} -+, {XF86XK_AudioRewind, XBMCK_REWIND} -+, {XF86XK_Phone, XBMCK_PHONE} -+, {XF86XK_AudioPlay, XBMCK_PLAY} -+, {XF86XK_AudioRandomPlay, XBMCK_SHUFFLE} -+, {XF86XK_AudioForward, XBMCK_FASTFORWARD} -+}; -+ -+ -+CWinEventsX11::CWinEventsX11() -+{ -+ m_display = 0; -+ m_window = 0; -+ m_keybuf = 0; -+ m_utf16buf = 0; -+} -+ -+CWinEventsX11::~CWinEventsX11() -+{ -+ if (m_keybuf); -+ { -+ free(m_keybuf); -+ m_keybuf = 0; -+ } -+ -+ if (m_utf16buf) -+ { -+ free(m_utf16buf); -+ m_utf16buf = 0; -+ } -+ -+ if (m_xic) -+ { -+ XUnsetICFocus(m_xic); -+ XDestroyIC(m_xic); -+ m_xic = 0; -+ } -+ -+ if (m_xim) -+ { -+ XCloseIM(m_xim); -+ m_xim = 0; -+ } -+ -+ m_symLookupTable.clear(); -+} -+ -+bool CWinEventsX11::Init(Display *dpy, Window win) -+{ -+ if (WinEvents) -+ return true; -+ -+ WinEvents = new CWinEventsX11(); -+ WinEvents->m_display = dpy; -+ WinEvents->m_window = win; -+ WinEvents->m_keybuf = (char*)malloc(32*sizeof(char)); -+ WinEvents->m_utf16buf = (uint16_t*)malloc(32*sizeof(uint16_t)); -+ WinEvents->m_keymodState = 0; -+ WinEvents->m_wmDeleteMessage = XInternAtom(dpy, "WM_DELETE_WINDOW", False); -+ WinEvents->m_structureChanged = false; -+ memset(&(WinEvents->m_lastKey), 0, sizeof(XBMC_Event)); -+ -+ // open input method -+ char *old_locale = NULL, *old_modifiers = NULL; -+ char res_name[8]; -+ const char *p; -+ size_t n; -+ -+ // set resource name to xbmc, not used -+ strcpy(res_name, "xbmc"); -+ -+ // save current locale, this should be "C" -+ p = setlocale(LC_ALL, NULL); -+ if (p) -+ { -+ old_locale = (char*)malloc(strlen(p) +1); -+ strcpy(old_locale, p); -+ } -+ p = XSetLocaleModifiers(NULL); -+ if (p) -+ { -+ old_modifiers = (char*)malloc(strlen(p) +1); -+ strcpy(old_modifiers, p); -+ } -+ -+ // set users preferences and open input method -+ p = setlocale(LC_ALL, ""); -+ XSetLocaleModifiers(""); -+ WinEvents->m_xim = XOpenIM(WinEvents->m_display, NULL, res_name, res_name); -+ -+ // restore old locale -+ if (old_locale) -+ { -+ setlocale(LC_ALL, old_locale); -+ free(old_locale); -+ } -+ if (old_modifiers) -+ { -+ XSetLocaleModifiers(old_modifiers); -+ free(old_modifiers); -+ } -+ -+ WinEvents->m_xic = NULL; -+ if (WinEvents->m_xim) -+ { -+ WinEvents->m_xic = XCreateIC(WinEvents->m_xim, -+ XNClientWindow, WinEvents->m_window, -+ XNFocusWindow, WinEvents->m_window, -+ XNInputStyle, XIMPreeditNothing | XIMStatusNothing, -+ XNResourceName, res_name, -+ XNResourceClass, res_name, -+ NULL); -+ } -+ -+ if (!WinEvents->m_xic) -+ CLog::Log(LOGWARNING,"CWinEventsX11::Init - no input method found"); -+ -+ // build Keysym lookup table -+ for (unsigned int i = 0; i < sizeof(SymMappingsX11)/(2*sizeof(uint32_t)); ++i) -+ { -+ WinEvents->m_symLookupTable[SymMappingsX11[i][0]] = SymMappingsX11[i][1]; -+ } -+ -+ return true; -+} -+ -+void CWinEventsX11::Quit() -+{ -+ if (!WinEvents) -+ return; -+ -+ delete WinEvents; -+ WinEvents = 0; -+} -+ -+bool CWinEventsX11::HasStructureChanged() -+{ -+ if (!WinEvents) -+ return false; -+ -+ bool ret = WinEvents->m_structureChanged; -+ WinEvents->m_structureChanged = false; -+ return ret; -+} -+ -+bool CWinEventsX11::MessagePump() -+{ -+ if (!WinEvents) -+ return false; -+ -+ bool ret = false; -+ XEvent xevent; -+ unsigned long serial = 0; -+ -+ while (WinEvents && XPending(WinEvents->m_display)) -+ { -+ memset(&xevent, 0, sizeof (XEvent)); -+ XNextEvent(WinEvents->m_display, &xevent); -+ -+ // ignore events generated by auto-repeat -+ if (xevent.type == KeyRelease && XPending(WinEvents->m_display)) -+ { -+ XEvent peekevent; -+ XPeekEvent(WinEvents->m_display, &peekevent); -+ if ((peekevent.type == KeyPress) && -+ (peekevent.xkey.keycode == xevent.xkey.keycode) && -+ ((peekevent.xkey.time - xevent.xkey.time) < 2)) -+ { -+ XNextEvent(WinEvents->m_display, &peekevent); -+ continue; -+ } -+ } -+ -+ if (XFilterEvent(&xevent, None)) -+ continue; -+ -+ switch (xevent.type) -+ { -+ case MapNotify: -+ { -+ g_application.m_AppActive = true; -+ break; -+ } -+ -+ case UnmapNotify: -+ { -+ g_application.m_AppActive = false; -+ break; -+ } -+ -+ case FocusIn: -+ { -+ if (WinEvents->m_xic) -+ XSetICFocus(WinEvents->m_xic); -+ g_application.m_AppFocused = true; -+ if (serial == xevent.xfocus.serial) -+ break; -+ g_Windowing.NotifyAppFocusChange(g_application.m_AppFocused); -+ break; -+ } -+ -+ case FocusOut: -+ { -+ if (WinEvents->m_xic) -+ XUnsetICFocus(WinEvents->m_xic); -+ g_application.m_AppFocused = false; -+ g_Windowing.NotifyAppFocusChange(g_application.m_AppFocused); -+ serial = xevent.xfocus.serial; -+ break; -+ } -+ -+ case Expose: -+ { -+ g_windowManager.MarkDirty(); -+ break; -+ } -+ -+ case ConfigureNotify: -+ { -+ if (xevent.xconfigure.window != WinEvents->m_window) -+ break; -+ -+ WinEvents->m_structureChanged = true; -+ XBMC_Event newEvent; -+ memset(&newEvent, 0, sizeof(newEvent)); -+ newEvent.type = XBMC_VIDEORESIZE; -+ newEvent.resize.w = xevent.xconfigure.width; -+ newEvent.resize.h = xevent.xconfigure.height; -+ ret |= g_application.OnEvent(newEvent); -+ g_windowManager.MarkDirty(); -+ break; -+ } -+ -+ case ClientMessage: -+ { -+ if (xevent.xclient.data.l[0] == WinEvents->m_wmDeleteMessage) -+ if (!g_application.m_bStop) CApplicationMessenger::Get().Quit(); -+ break; -+ } -+ -+ case KeyPress: -+ { -+ XBMC_Event newEvent; -+ memset(&newEvent, 0, sizeof(newEvent)); -+ newEvent.type = XBMC_KEYDOWN; -+ KeySym xkeysym; -+ -+ // fallback if we have no IM -+ if (!WinEvents->m_xic) -+ { -+ static XComposeStatus state; -+ char keybuf[32]; -+ xkeysym = XLookupKeysym(&xevent.xkey, 0); -+ newEvent.key.keysym.sym = LookupXbmcKeySym(xkeysym); -+ newEvent.key.keysym.scancode = xevent.xkey.keycode; -+ newEvent.key.state = xevent.xkey.state; -+ newEvent.key.type = xevent.xkey.type; -+ if (XLookupString(&xevent.xkey, keybuf, sizeof(keybuf), NULL, &state)) -+ { -+ newEvent.key.keysym.unicode = keybuf[0]; -+ } -+ ret |= ProcessKey(newEvent, 500); -+ break; -+ } -+ -+ Status status; -+ int utf16size; -+ int utf16length; -+ int len; -+ len = Xutf8LookupString(WinEvents->m_xic, &xevent.xkey, -+ WinEvents->m_keybuf, sizeof(WinEvents->m_keybuf), -+ &xkeysym, &status); -+ if (status == XBufferOverflow) -+ { -+ WinEvents->m_keybuf = (char*)realloc(WinEvents->m_keybuf, len*sizeof(char)); -+ len = Xutf8LookupString(WinEvents->m_xic, &xevent.xkey, -+ WinEvents->m_keybuf, sizeof(WinEvents->m_keybuf), -+ &xkeysym, &status); -+ } -+ switch (status) -+ { -+ case XLookupNone: -+ break; -+ case XLookupChars: -+ case XLookupBoth: -+ { -+ if (len == 0) -+ break; -+ utf16size = len * sizeof(uint16_t); -+ if (utf16size > sizeof(WinEvents->m_utf16buf)) -+ { -+ WinEvents->m_utf16buf = (uint16_t *)realloc(WinEvents->m_utf16buf,utf16size); -+ if (WinEvents->m_utf16buf == NULL) -+ { -+ break; -+ } -+ } -+ utf16length = Utf8ToUnicode(WinEvents->m_keybuf, len, WinEvents->m_utf16buf, utf16size); -+ if (utf16length < 0) -+ { -+ break; -+ } -+ for (unsigned int i = 0; i < utf16length - 1; i++) -+ { -+ newEvent.key.keysym.sym = XBMCK_UNKNOWN; -+ newEvent.key.keysym.unicode = WinEvents->m_utf16buf[i]; -+ newEvent.key.state = xevent.xkey.state; -+ newEvent.key.type = xevent.xkey.type; -+ ret |= ProcessKey(newEvent, 500); -+ } -+ if (utf16length > 0) -+ { -+ newEvent.key.keysym.scancode = xevent.xkey.keycode; -+ xkeysym = XLookupKeysym(&xevent.xkey, 0); -+ newEvent.key.keysym.sym = LookupXbmcKeySym(xkeysym); -+ newEvent.key.keysym.unicode = WinEvents->m_utf16buf[utf16length - 1]; -+ newEvent.key.state = xevent.xkey.state; -+ newEvent.key.type = xevent.xkey.type; -+ -+ ret |= ProcessKey(newEvent, 500); -+ } -+ break; -+ } -+ -+ case XLookupKeySym: -+ { -+ newEvent.key.keysym.scancode = xevent.xkey.keycode; -+ newEvent.key.keysym.sym = LookupXbmcKeySym(xkeysym); -+ newEvent.key.state = xevent.xkey.state; -+ newEvent.key.type = xevent.xkey.type; -+ ret |= ProcessKey(newEvent, 500); -+ break; -+ } -+ -+ }// switch status -+ break; -+ } //KeyPress -+ -+ case KeyRelease: -+ { -+ XBMC_Event newEvent; -+ KeySym xkeysym; -+ memset(&newEvent, 0, sizeof(newEvent)); -+ newEvent.type = XBMC_KEYUP; -+ xkeysym = XLookupKeysym(&xevent.xkey, 0); -+ newEvent.key.keysym.scancode = xevent.xkey.keycode; -+ newEvent.key.keysym.sym = LookupXbmcKeySym(xkeysym); -+ newEvent.key.state = xevent.xkey.state; -+ newEvent.key.type = xevent.xkey.type; -+ ret |= ProcessKey(newEvent, 0); -+ break; -+ } -+ -+ // lose mouse coverage -+ case LeaveNotify: -+ { -+ g_Mouse.SetActive(false); -+ break; -+ } -+ -+ case MotionNotify: -+ { -+ XBMC_Event newEvent; -+ memset(&newEvent, 0, sizeof(newEvent)); -+ newEvent.type = XBMC_MOUSEMOTION; -+ newEvent.motion.xrel = (int16_t)xevent.xmotion.x_root; -+ newEvent.motion.yrel = (int16_t)xevent.xmotion.y_root; -+ newEvent.motion.x = (int16_t)xevent.xmotion.x; -+ newEvent.motion.y = (int16_t)xevent.xmotion.y; -+ ret |= g_application.OnEvent(newEvent); -+ break; -+ } -+ -+ case ButtonPress: -+ { -+ XBMC_Event newEvent; -+ memset(&newEvent, 0, sizeof(newEvent)); -+ newEvent.type = XBMC_MOUSEBUTTONDOWN; -+ newEvent.button.button = (unsigned char)xevent.xbutton.button; -+ newEvent.button.state = XBMC_PRESSED; -+ newEvent.button.x = (int16_t)xevent.xbutton.x; -+ newEvent.button.y = (int16_t)xevent.xbutton.y; -+ ret |= g_application.OnEvent(newEvent); -+ break; -+ } -+ -+ case ButtonRelease: -+ { -+ XBMC_Event newEvent; -+ memset(&newEvent, 0, sizeof(newEvent)); -+ newEvent.type = XBMC_MOUSEBUTTONUP; -+ newEvent.button.button = (unsigned char)xevent.xbutton.button; -+ newEvent.button.state = XBMC_RELEASED; -+ newEvent.button.x = (int16_t)xevent.xbutton.x; -+ newEvent.button.y = (int16_t)xevent.xbutton.y; -+ ret |= g_application.OnEvent(newEvent); -+ break; -+ } -+ -+ default: -+ { -+ break; -+ } -+ }// switch event.type -+ }// while -+ -+ ret |= ProcessKeyRepeat(); -+ -+ return ret; -+} -+ -+bool CWinEventsX11::ProcessKey(XBMC_Event &event, int repeatDelay) -+{ -+ if (event.type == XBMC_KEYDOWN) -+ { -+ // check key modifiers -+ switch(event.key.keysym.sym) -+ { -+ case XBMCK_LSHIFT: -+ WinEvents->m_keymodState |= XBMCKMOD_LSHIFT; -+ break; -+ case XBMCK_RSHIFT: -+ WinEvents->m_keymodState |= XBMCKMOD_RSHIFT; -+ break; -+ case XBMCK_LCTRL: -+ WinEvents->m_keymodState |= XBMCKMOD_LCTRL; -+ break; -+ case XBMCK_RCTRL: -+ WinEvents->m_keymodState |= XBMCKMOD_RCTRL; -+ break; -+ case XBMCK_LALT: -+ WinEvents->m_keymodState |= XBMCKMOD_LALT; -+ break; -+ case XBMCK_RALT: -+ WinEvents->m_keymodState |= XBMCKMOD_RCTRL; -+ break; -+ case XBMCK_LMETA: -+ WinEvents->m_keymodState |= XBMCKMOD_LMETA; -+ break; -+ case XBMCK_RMETA: -+ WinEvents->m_keymodState |= XBMCKMOD_RMETA; -+ break; -+ case XBMCK_MODE: -+ WinEvents->m_keymodState |= XBMCKMOD_MODE; -+ break; -+ default: -+ break; -+ } -+ event.key.keysym.mod = (XBMCMod)WinEvents->m_keymodState; -+ memcpy(&(WinEvents->m_lastKey), &event, sizeof(event)); -+ WinEvents->m_repeatKeyTimeout.Set(repeatDelay); -+ -+ bool ret = ProcessShortcuts(event); -+ if (ret) -+ return ret; -+ } -+ else if (event.type == XBMC_KEYUP) -+ { -+ switch(event.key.keysym.sym) -+ { -+ case XBMCK_LSHIFT: -+ WinEvents->m_keymodState &= ~XBMCKMOD_LSHIFT; -+ break; -+ case XBMCK_RSHIFT: -+ WinEvents->m_keymodState &= ~XBMCKMOD_RSHIFT; -+ break; -+ case XBMCK_LCTRL: -+ WinEvents->m_keymodState &= ~XBMCKMOD_LCTRL; -+ break; -+ case XBMCK_RCTRL: -+ WinEvents->m_keymodState &= ~XBMCKMOD_RCTRL; -+ break; -+ case XBMCK_LALT: -+ WinEvents->m_keymodState &= ~XBMCKMOD_LALT; -+ break; -+ case XBMCK_RALT: -+ WinEvents->m_keymodState &= ~XBMCKMOD_RCTRL; -+ break; -+ case XBMCK_LMETA: -+ WinEvents->m_keymodState &= ~XBMCKMOD_LMETA; -+ break; -+ case XBMCK_RMETA: -+ WinEvents->m_keymodState &= ~XBMCKMOD_RMETA; -+ break; -+ case XBMCK_MODE: -+ WinEvents->m_keymodState &= ~XBMCKMOD_MODE; -+ break; -+ default: -+ break; -+ } -+ event.key.keysym.mod = (XBMCMod)WinEvents->m_keymodState; -+ memset(&(WinEvents->m_lastKey), 0, sizeof(event)); -+ } -+ -+ return g_application.OnEvent(event); -+} -+ -+bool CWinEventsX11::ProcessShortcuts(XBMC_Event& event) -+{ -+ if (event.key.keysym.mod & XBMCKMOD_ALT) -+ { -+ switch(event.key.keysym.sym) -+ { -+ case XBMCK_TAB: // ALT+TAB to minimize/hide -+ g_application.Minimize(); -+ return true; -+ -+ default: -+ return false; -+ } -+ } -+ return false; -+} -+ -+bool CWinEventsX11::ProcessKeyRepeat() -+{ -+ if (WinEvents && (WinEvents->m_lastKey.type == XBMC_KEYDOWN)) -+ { -+ if (WinEvents->m_repeatKeyTimeout.IsTimePast()) -+ { -+ return ProcessKey(WinEvents->m_lastKey, 10); -+ } -+ } -+ return false; -+} -+ -+int CWinEventsX11::Utf8ToUnicode(const char *utf8, const int utf8Length, uint16_t *utf16, const int utf16MaxLength) -+{ -+ // p moves over the output buffer. max_ptr points to the next to the last slot of the buffer. -+ uint16_t *p = utf16; -+ uint16_t const *const maxPtr = utf16 + utf16MaxLength; -+ -+ // end_of_input points to the last byte of input as opposed to the next to the last byte. -+ char const *const endOfInput = utf8 + utf8Length - 1; -+ -+ while (utf8 <= endOfInput) -+ { -+ unsigned char const c = *utf8; -+ if (p >= maxPtr) -+ { -+ //No more output space. -+ return -1; -+ } -+ if (c < 0x80) -+ { -+ //One byte ASCII. -+ *p++ = c; -+ utf8 += 1; -+ } -+ else if (c < 0xC0) -+ { -+ // Follower byte without preceding leader bytes. -+ return -1; -+ } -+ // 11 bits -+ else if (c < 0xE0) -+ { -+ // Two byte sequence. We need one follower byte. -+ if (endOfInput - utf8 < 1 || (((utf8[1] ^ 0x80)) & 0xC0)) -+ { -+ return -1; -+ } -+ *p++ = (uint16_t)(((c & 0x1F) << 6) + (utf8[1] & 0x3F)); -+ utf8 += 2; -+ } -+ // 16 bis -+ else if (c < 0xF0) -+ { -+ // Three byte sequence. We need two follower byte. -+ if (endOfInput - utf8 < 2 || ((utf8[1] ^ 0x80) & 0xC0) || ((utf8[2] ^ 0x80) & 0xC0)) -+ { -+ return -1; -+ } -+ *p++ = (uint16_t)(((c & 0xF) << 12) + ((utf8[1] & 0x3F) << 6) + (utf8[2] & 0x3F)); -+ utf8 += 3; -+ } -+ // 21 bits -+ else if (c < 0xF8) -+ { -+ int plane; -+ // Four byte sequence. We need three follower bytes. -+ if (endOfInput - utf8 < 3 || ((utf8[1] ^ 0x80) & 0xC0) || -+ ((utf8[2] ^ 0x80) & 0xC0) || ((utf8[3] ^ 0x80) & 0xC0)) -+ { -+ return -1; -+ } -+ uint32_t unicode = ((c & 0x7) << 18) + ((utf8[1] & 0x3F) << 12) + -+ ((utf8[2] & 0x3F) << 6) + (utf8[3] & 0x3F); -+ utf8 += 4; -+ CLog::Log(LOGERROR, "CWinEventsX11::Utf8ToUnicode: 4 byte unicode not supported"); -+ } -+ // 26 bits -+ else if (c < 0xFC) -+ { -+ CLog::Log(LOGERROR, "CWinEventsX11::Utf8ToUnicode: 4 byte unicode not supported"); -+ utf8 += 5; -+ } -+ // 31 bit -+ else -+ { -+ CLog::Log(LOGERROR, "CWinEventsX11::Utf8ToUnicode: 4 byte unicode not supported"); -+ utf8 += 6; -+ } -+ } -+ return p - utf16; -+} -+ -+XBMCKey CWinEventsX11::LookupXbmcKeySym(KeySym keysym) -+{ -+ // try direct mapping first -+ std::map::iterator it; -+ it = WinEvents->m_symLookupTable.find(keysym); -+ if (it != WinEvents->m_symLookupTable.end()) -+ { -+ return (XBMCKey)(it->second); -+ } -+ -+ // try ascii mappings -+ if (keysym>>8 == 0x00) -+ return (XBMCKey)(keysym & 0xFF); -+ -+ return (XBMCKey)keysym; -+} -+#endif -diff --git a/xbmc/windowing/WinEventsX11.h b/xbmc/windowing/WinEventsX11.h -new file mode 100644 -index 0000000..e9b7553 ---- /dev/null -+++ b/xbmc/windowing/WinEventsX11.h -@@ -0,0 +1,57 @@ -+/* -+* Copyright (C) 2005-2012 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 "WinEvents.h" -+#include -+#include "threads/SystemClock.h" -+#include -+ -+class CWinEventsX11 : public CWinEventsBase -+{ -+public: -+ CWinEventsX11(); -+ virtual ~CWinEventsX11(); -+ static bool Init(Display *dpy, Window win); -+ static void Quit(); -+ static bool HasStructureChanged(); -+ static bool MessagePump(); -+ -+protected: -+ static int Utf8ToUnicode(const char *utf8, const int utf8Length, uint16_t *utf16, const int utf16MaxLength); -+ static XBMCKey LookupXbmcKeySym(KeySym keysym); -+ static bool ProcessKey(XBMC_Event &event, int repeatDelay); -+ static bool ProcessKeyRepeat(); -+ static bool ProcessShortcuts(XBMC_Event& event); -+ static CWinEventsX11 *WinEvents; -+ Display *m_display; -+ Window m_window; -+ Atom m_wmDeleteMessage; -+ char *m_keybuf; -+ uint16_t *m_utf16buf; -+ XIM m_xim; -+ XIC m_xic; -+ XBMC_Event m_lastKey; -+ XbmcThreads::EndTime m_repeatKeyTimeout; -+ std::map m_symLookupTable; -+ int m_keymodState; -+ bool m_structureChanged; -+}; -diff --git a/xbmc/windowing/X11/WinSystemX11.cpp b/xbmc/windowing/X11/WinSystemX11.cpp -index a839709..76ef462 100644 ---- a/xbmc/windowing/X11/WinSystemX11.cpp -+++ b/xbmc/windowing/X11/WinSystemX11.cpp -@@ -22,7 +22,6 @@ - - #ifdef HAS_GLX - --#include - #include "WinSystemX11.h" - #include "settings/Settings.h" - #include "guilib/Texture.h" -@@ -31,27 +30,30 @@ - #include "XRandR.h" - #include - #include "threads/SingleLock.h" --#include - #include "cores/VideoRenderers/RenderManager.h" - #include "utils/TimeUtils.h" -+#include "settings/GUISettings.h" - - #if defined(HAS_XRANDR) - #include - #endif - -+#include "../WinEvents.h" -+#include "input/MouseStat.h" -+ - using namespace std; - - CWinSystemX11::CWinSystemX11() : CWinSystemBase() - { - m_eWindowSystem = WINDOW_SYSTEM_X11; - m_glContext = NULL; -- m_SDLSurface = NULL; - m_dpy = NULL; - m_glWindow = 0; -- m_wmWindow = 0; - m_bWasFullScreenBeforeMinimize = false; - m_minimized = false; -+ m_bIgnoreNextFocusMessage = false; - m_dpyLostTime = 0; -+ m_invisibleCursor = 0; - - XSetErrorHandler(XErrorHandler); - } -@@ -64,18 +66,6 @@ bool CWinSystemX11::InitWindowSystem() - { - if ((m_dpy = XOpenDisplay(NULL))) - { -- -- SDL_EnableUNICODE(1); -- // set repeat to 10ms to ensure repeat time < frame time -- // so that hold times can be reliably detected -- SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, 10); -- -- SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8); -- SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8); -- SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8); -- SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 8); -- SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); -- - return CWinSystemBase::InitWindowSystem(); - } - else -@@ -113,45 +103,37 @@ bool CWinSystemX11::DestroyWindowSystem() - - bool CWinSystemX11::CreateNewWindow(const CStdString& name, bool fullScreen, RESOLUTION_INFO& res, PHANDLE_EVENT_FUNC userFunction) - { -- RESOLUTION_INFO& desktop = g_settings.m_ResInfo[RES_DESKTOP]; -- -- if (fullScreen && -- (res.iWidth != desktop.iWidth || res.iHeight != desktop.iHeight || -- res.fRefreshRate != desktop.fRefreshRate || res.iScreen != desktop.iScreen)) -- { -- //on the first call to SDL_SetVideoMode, SDL stores the current displaymode -- //SDL restores the displaymode on SDL_QUIT(), if we change the displaymode -- //before the first call to SDL_SetVideoMode, SDL changes the displaymode back -- //to the wrong mode on exit -- -- CLog::Log(LOGINFO, "CWinSystemX11::CreateNewWindow initializing to desktop resolution first"); -- if (!SetFullScreen(true, desktop, false)) -- return false; -- } -- - if(!SetFullScreen(fullScreen, res, false)) - return false; - -- CBaseTexture* iconTexture = CTexture::LoadFromFile("special://xbmc/media/icon.png"); -- -- if (iconTexture) -- SDL_WM_SetIcon(SDL_CreateRGBSurfaceFrom(iconTexture->GetPixels(), iconTexture->GetWidth(), iconTexture->GetHeight(), 32, iconTexture->GetPitch(), 0xff0000, 0x00ff00, 0x0000ff, 0xff000000L), NULL); -- SDL_WM_SetCaption("XBMC Media Center", NULL); -- delete iconTexture; -- -- // register XRandR Events --#if defined(HAS_XRANDR) -- int iReturn; -- XRRQueryExtension(m_dpy, &m_RREventBase, &iReturn); -- XRRSelectInput(m_dpy, m_wmWindow, RRScreenChangeNotifyMask); --#endif -- - m_bWindowCreated = true; - return true; - } - - bool CWinSystemX11::DestroyWindow() - { -+ if (!m_glWindow) -+ return true; -+ -+ if (m_glContext) -+ glXMakeCurrent(m_dpy, None, NULL); -+ -+ if (m_invisibleCursor) -+ { -+ XUndefineCursor(m_dpy, m_glWindow); -+ XFreeCursor(m_dpy, m_invisibleCursor); -+ m_invisibleCursor = 0; -+ } -+ -+ CWinEvents::Quit(); -+ -+ XUnmapWindow(m_dpy, m_glWindow); -+ XSync(m_dpy,TRUE); -+ XUngrabKeyboard(m_dpy, CurrentTime); -+ XUngrabPointer(m_dpy, CurrentTime); -+ XDestroyWindow(m_dpy, m_glWindow); -+ m_glWindow = 0; -+ - return true; - } - -@@ -161,65 +143,105 @@ bool CWinSystemX11::ResizeWindow(int newWidth, int newHeight, int newLeft, int n - && m_nHeight == newHeight) - return true; - -+ if (!SetWindow(newWidth, newHeight, false)) -+ { -+ return false; -+ } -+ -+ RefreshGlxContext(); - m_nWidth = newWidth; - m_nHeight = newHeight; -+ m_bFullScreen = false; - -- int options = SDL_OPENGL; -- if (m_bFullScreen) -- options |= SDL_FULLSCREEN; -- else -- options |= SDL_RESIZABLE; -+ return false; -+} -+ -+void CWinSystemX11::RefreshWindow() -+{ -+ g_xrandr.Query(true); -+ XOutput out = g_xrandr.GetCurrentOutput(); -+ XMode mode = g_xrandr.GetCurrentMode(out.name); - -- if ((m_SDLSurface = SDL_SetVideoMode(m_nWidth, m_nHeight, 0, options))) -+ // only overwrite desktop resolution, if we are not in fullscreen mode -+ if (!g_graphicsContext.IsFullScreenVideo()) - { -- RefreshGlxContext(); -- return true; -+ CLog::Log(LOGDEBUG, "CWinSystemX11::RefreshWindow - store desktop resolution, width: %d, height: %d, hz: %2.2f", mode.w, mode.h, mode.hz); -+ UpdateDesktopResolution(g_settings.m_ResInfo[RES_DESKTOP], 0, mode.w, mode.h, mode.hz); -+ g_settings.m_ResInfo[RES_DESKTOP].strId = mode.id; -+ g_settings.m_ResInfo[RES_DESKTOP].strOutput = out.name; - } - -- return false; -+ 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; -+ } -+ -+ if (g_graphicsContext.IsFullScreenRoot()) -+ g_graphicsContext.SetVideoResolution((RESOLUTION)i, true); -+ else -+ g_graphicsContext.SetVideoResolution(RES_WINDOW, true); - } - - bool CWinSystemX11::SetFullScreen(bool fullScreen, RESOLUTION_INFO& res, bool blankOtherDisplays) - { -- m_nWidth = res.iWidth; -- m_nHeight = res.iHeight; -- m_bFullScreen = fullScreen; - - #if defined(HAS_XRANDR) - XOutput out; - XMode mode; -- out.name = res.strOutput; -- mode.w = res.iWidth; -- mode.h = res.iHeight; -- mode.hz = res.fRefreshRate; -- mode.id = res.strId; -+ -+ if (fullScreen) -+ { -+ out.name = res.strOutput; -+ mode.w = res.iWidth; -+ mode.h = res.iHeight; -+ mode.hz = res.fRefreshRate; -+ mode.id = res.strId; -+ } -+ else -+ { -+ out.name = g_settings.m_ResInfo[RES_DESKTOP].strOutput; -+ mode.w = g_settings.m_ResInfo[RES_DESKTOP].iWidth; -+ mode.h = g_settings.m_ResInfo[RES_DESKTOP].iHeight; -+ mode.hz = g_settings.m_ResInfo[RES_DESKTOP].fRefreshRate; -+ mode.id = g_settings.m_ResInfo[RES_DESKTOP].strId; -+ } - -- if(m_bFullScreen) -+ XOutput currout = g_xrandr.GetCurrentOutput(); -+ XMode currmode = g_xrandr.GetCurrentMode(currout.name); -+ -+ // 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(); - g_xrandr.SetMode(out, mode); - } -- else -- g_xrandr.RestoreState(); - #endif - -- int options = SDL_OPENGL; -- if (m_bFullScreen) -- options |= SDL_FULLSCREEN; -- else -- options |= SDL_RESIZABLE; -- -- if ((m_SDLSurface = SDL_SetVideoMode(m_nWidth, m_nHeight, 0, options))) -- { -- if ((m_SDLSurface->flags & SDL_OPENGL) != SDL_OPENGL) -- CLog::Log(LOGERROR, "CWinSystemX11::SetFullScreen SDL_OPENGL not set, SDL_GetError:%s", SDL_GetError()); -+ if (!SetWindow(res.iWidth, res.iHeight, fullScreen)) -+ return false; - -- RefreshGlxContext(); -+ RefreshGlxContext(); - -- return true; -- } -+ m_nWidth = res.iWidth; -+ m_nHeight = res.iHeight; -+ m_bFullScreen = fullScreen; - -- return false; -+ return true; - } - - void CWinSystemX11::UpdateResolutions() -@@ -321,17 +343,10 @@ bool CWinSystemX11::IsSuitableVisual(XVisualInfo *vInfo) - bool CWinSystemX11::RefreshGlxContext() - { - bool retVal = false; -- SDL_SysWMinfo info; -- SDL_VERSION(&info.version); -- if (SDL_GetWMInfo(&info) <= 0) -- { -- CLog::Log(LOGERROR, "Failed to get window manager info from SDL"); -- return false; -- } - -- if(m_glWindow == info.info.x11.window && m_glContext) -+ if (m_glContext) - { -- CLog::Log(LOGERROR, "GLX: Same window as before, refreshing context"); -+ CLog::Log(LOGDEBUG, "CWinSystemX11::RefreshGlxContext: refreshing context"); - glXMakeCurrent(m_dpy, None, NULL); - glXMakeCurrent(m_dpy, m_glWindow, m_glContext); - return true; -@@ -343,8 +358,6 @@ bool CWinSystemX11::RefreshGlxContext() - int availableVisuals = 0; - vMask.screen = DefaultScreen(m_dpy); - XWindowAttributes winAttr; -- m_glWindow = info.info.x11.window; -- m_wmWindow = info.info.x11.wmwindow; - - /* Assume a depth of 24 in case the below calls to XGetWindowAttributes() - or XGetVisualInfo() fail. That shouldn't happen unless something is -@@ -415,7 +428,10 @@ bool CWinSystemX11::RefreshGlxContext() - - void CWinSystemX11::ShowOSMouse(bool show) - { -- SDL_ShowCursor(show ? 1 : 0); -+ if (show) -+ XUndefineCursor(m_dpy,m_glWindow); -+ else if (m_invisibleCursor) -+ XDefineCursor(m_dpy,m_glWindow, m_invisibleCursor); - } - - void CWinSystemX11::ResetOSScreensaver() -@@ -429,8 +445,6 @@ void CWinSystemX11::ResetOSScreensaver() - { - m_screensaverReset.StartZero(); - XResetScreenSaver(m_dpy); -- //need to flush the output buffer, since we don't check for events on m_dpy -- XFlush(m_dpy); - } - } - else -@@ -446,13 +460,27 @@ void CWinSystemX11::NotifyAppActiveChange(bool bActivated) - - m_minimized = !bActivated; - } -+ -+void CWinSystemX11::NotifyAppFocusChange(bool bGaining) -+{ -+ if (bGaining && m_bWasFullScreenBeforeMinimize && !m_bIgnoreNextFocusMessage && -+ !g_graphicsContext.IsFullScreenRoot()) -+ g_graphicsContext.ToggleFullScreenRoot(); -+ if (!bGaining) -+ m_bIgnoreNextFocusMessage = false; -+} -+ - bool CWinSystemX11::Minimize() - { - m_bWasFullScreenBeforeMinimize = g_graphicsContext.IsFullScreenRoot(); - if (m_bWasFullScreenBeforeMinimize) -+ { -+ m_bIgnoreNextFocusMessage = true; - g_graphicsContext.ToggleFullScreenRoot(); -+ } -+ -+ XIconifyWindow(m_dpy, m_glWindow, DefaultScreen(m_dpy)); - -- SDL_WM_IconifyWindow(); - m_minimized = true; - return true; - } -@@ -462,13 +490,13 @@ bool CWinSystemX11::Restore() - } - bool CWinSystemX11::Hide() - { -- XUnmapWindow(m_dpy, m_wmWindow); -+ XUnmapWindow(m_dpy, m_glWindow); - XSync(m_dpy, False); - return true; - } - bool CWinSystemX11::Show(bool raise) - { -- XMapWindow(m_dpy, m_wmWindow); -+ XMapWindow(m_dpy, m_glWindow); - XSync(m_dpy, False); - m_minimized = false; - return true; -@@ -500,6 +528,7 @@ void CWinSystemX11::CheckDisplayEvents() - if (bGotEvent || bTimeout) - { - CLog::Log(LOGDEBUG, "%s - notify display reset event", __FUNCTION__); -+ RefreshWindow(); - - CSingleLock lock(m_resourceSection); - -@@ -558,4 +587,151 @@ bool CWinSystemX11::EnableFrameLimiter() - return m_minimized; - } - -+bool CWinSystemX11::SetWindow(int width, int height, bool fullscreen) -+{ -+ bool changeWindow = false; -+ bool changeSize = false; -+ bool mouseActive = false; -+ float mouseX, mouseY; -+ -+ if (m_glWindow && (m_bFullScreen != fullscreen)) -+ { -+ mouseActive = g_Mouse.IsActive(); -+ if (mouseActive) -+ { -+ Window root_return, child_return; -+ int root_x_return, root_y_return; -+ int win_x_return, win_y_return; -+ unsigned int mask_return; -+ bool isInWin = XQueryPointer(m_dpy, m_glWindow, &root_return, &child_return, -+ &root_x_return, &root_y_return, -+ &win_x_return, &win_y_return, -+ &mask_return); -+ if (isInWin) -+ { -+ mouseX = (float)win_x_return/m_nWidth; -+ mouseY = (float)win_y_return/m_nHeight; -+ g_Mouse.SetActive(false); -+ } -+ else -+ mouseActive = false; -+ } -+ DestroyWindow(); -+ } -+ -+ // create main window -+ if (!m_glWindow) -+ { -+ GLint att[] = -+ { -+ GLX_RGBA, -+ GLX_RED_SIZE, 8, -+ GLX_GREEN_SIZE, 8, -+ GLX_BLUE_SIZE, 8, -+ GLX_ALPHA_SIZE, 8, -+ GLX_DEPTH_SIZE, 24, -+ GLX_DOUBLEBUFFER, -+ None -+ }; -+ Colormap cmap; -+ XSetWindowAttributes swa; -+ XVisualInfo *vi; -+ -+ vi = glXChooseVisual(m_dpy, DefaultScreen(m_dpy), att); -+ cmap = XCreateColormap(m_dpy, RootWindow(m_dpy, vi->screen), vi->visual, AllocNone); -+ -+ int def_vis = (vi->visual == DefaultVisual(m_dpy, vi->screen)); -+ swa.override_redirect = fullscreen ? True : False; -+ swa.border_pixel = fullscreen ? 0 : 5; -+ swa.background_pixel = def_vis ? BlackPixel(m_dpy, vi->screen) : 0; -+ swa.colormap = cmap; -+ swa.background_pixel = def_vis ? BlackPixel(m_dpy, vi->screen) : 0; -+ swa.event_mask = FocusChangeMask | KeyPressMask | KeyReleaseMask | -+ ButtonPressMask | ButtonReleaseMask | PointerMotionMask | -+ PropertyChangeMask | StructureNotifyMask | KeymapStateMask | -+ EnterWindowMask | LeaveWindowMask | ExposureMask; -+ unsigned long mask = CWBackPixel | CWBorderPixel | CWColormap | CWOverrideRedirect | CWEventMask; -+ -+ m_glWindow = XCreateWindow(m_dpy, RootWindow(m_dpy, vi->screen), -+ 0, 0, width, height, 0, vi->depth, -+ InputOutput, vi->visual, -+ mask, &swa); -+ -+ // define invisible cursor -+ Pixmap bitmapNoData; -+ XColor black; -+ static char noData[] = { 0,0,0,0,0,0,0,0 }; -+ black.red = black.green = black.blue = 0; -+ -+ bitmapNoData = XCreateBitmapFromData(m_dpy, m_glWindow, noData, 8, 8); -+ m_invisibleCursor = XCreatePixmapCursor(m_dpy, bitmapNoData, bitmapNoData, -+ &black, &black, 0, 0); -+ XFreePixmap(m_dpy, bitmapNoData); -+ XDefineCursor(m_dpy,m_glWindow, m_invisibleCursor); -+ -+ //init X11 events -+ CWinEvents::Init(m_dpy, m_glWindow); -+ -+ changeWindow = true; -+ changeSize = true; -+ } -+ -+ if (!CWinEvents::HasStructureChanged() && ((width != m_nWidth) || (height != m_nHeight))) -+ { -+ changeSize = true; -+ } -+ -+ if (changeSize || changeWindow) -+ { -+ XResizeWindow(m_dpy, m_glWindow, width, height); -+ } -+ -+ if (changeWindow) -+ { -+ if (!fullscreen) -+ { -+ XWMHints wm_hints; -+ XClassHint class_hints; -+ XTextProperty windowName, iconName; -+ std::string titleString = "XBMC Media Center"; -+ char *title = (char*)titleString.c_str(); -+ -+ XStringListToTextProperty(&title, 1, &windowName); -+ XStringListToTextProperty(&title, 1, &iconName); -+ wm_hints.initial_state = NormalState; -+ wm_hints.input = True; -+ wm_hints.icon_pixmap = None; -+ wm_hints.flags = StateHint | IconPixmapHint | InputHint; -+ -+ XSetWMProperties(m_dpy, m_glWindow, &windowName, &iconName, -+ NULL, 0, NULL, &wm_hints, -+ NULL); -+ -+ // register interest in the delete window message -+ Atom wmDeleteMessage = XInternAtom(m_dpy, "WM_DELETE_WINDOW", False); -+ XSetWMProtocols(m_dpy, m_glWindow, &wmDeleteMessage, 1); -+ } -+ XMapRaised(m_dpy, m_glWindow); -+ XSync(m_dpy,TRUE); -+ -+ if (changeWindow && mouseActive) -+ { -+ XWarpPointer(m_dpy, None, m_glWindow, 0, 0, 0, 0, mouseX*width, mouseY*height); -+ } -+ -+ if (fullscreen) -+ { -+ int result = -1; -+ while (result != GrabSuccess) -+ { -+ result = XGrabPointer(m_dpy, m_glWindow, True, ButtonPressMask, GrabModeAsync, GrabModeAsync, m_glWindow, None, CurrentTime); -+ XbmcThreads::ThreadSleep(100); -+ } -+ XGrabKeyboard(m_dpy, m_glWindow, True, GrabModeAsync, GrabModeAsync, CurrentTime); -+ -+ } -+ } -+ return true; -+} -+ - #endif -diff --git a/xbmc/windowing/X11/WinSystemX11.h b/xbmc/windowing/X11/WinSystemX11.h -index 2dd8a9f..9616d17 100644 ---- a/xbmc/windowing/X11/WinSystemX11.h -+++ b/xbmc/windowing/X11/WinSystemX11.h -@@ -52,6 +52,7 @@ class CWinSystemX11 : public CWinSystemBase - virtual bool EnableFrameLimiter(); - - virtual void NotifyAppActiveChange(bool bActivated); -+ virtual void NotifyAppFocusChange(bool bGaining); - - virtual bool Minimize(); - virtual bool Restore() ; -@@ -64,19 +65,21 @@ class CWinSystemX11 : public CWinSystemBase - Display* GetDisplay() { return m_dpy; } - GLXWindow GetWindow() { return m_glWindow; } - GLXContext GetGlxContext() { return m_glContext; } -+ void RefreshWindow(); - - protected: - bool RefreshGlxContext(); - void CheckDisplayEvents(); - void OnLostDevice(); -+ bool SetWindow(int width, int height, bool fullscreen); - -- SDL_Surface* m_SDLSurface; -+ Window m_glWindow; - GLXContext m_glContext; -- GLXWindow m_glWindow; -- Window m_wmWindow; - Display* m_dpy; -+ Cursor m_invisibleCursor; - bool m_bWasFullScreenBeforeMinimize; - bool m_minimized; -+ bool m_bIgnoreNextFocusMessage; - int m_RREventBase; - CCriticalSection m_resourceSection; - std::vector m_resources; --- -1.7.10 - - -From 58fa894afaffbc990ee1ab87ff55db30e36ab2c2 Mon Sep 17 00:00:00 2001 -From: FernetMenta -Date: Thu, 5 Jul 2012 15:24:22 +0200 -Subject: [PATCH 15/73] X11: Add xbmc icon - ---- - xbmc/windowing/X11/WinSystemX11.cpp | 126 ++++++++++++++++++++++++++++++++++- - xbmc/windowing/X11/WinSystemX11.h | 2 + - 2 files changed, 127 insertions(+), 1 deletion(-) - -diff --git a/xbmc/windowing/X11/WinSystemX11.cpp b/xbmc/windowing/X11/WinSystemX11.cpp -index 76ef462..c854598 100644 ---- a/xbmc/windowing/X11/WinSystemX11.cpp -+++ b/xbmc/windowing/X11/WinSystemX11.cpp -@@ -134,6 +134,9 @@ bool CWinSystemX11::DestroyWindow() - XDestroyWindow(m_dpy, m_glWindow); - m_glWindow = 0; - -+ if (m_icon) -+ XFreePixmap(m_dpy, m_icon); -+ - return true; - } - -@@ -688,8 +691,10 @@ bool CWinSystemX11::SetWindow(int width, int height, bool fullscreen) - - if (changeWindow) - { -+ m_icon = None; - if (!fullscreen) - { -+ CreateIconPixmap(); - XWMHints wm_hints; - XClassHint class_hints; - XTextProperty windowName, iconName; -@@ -700,7 +705,7 @@ bool CWinSystemX11::SetWindow(int width, int height, bool fullscreen) - XStringListToTextProperty(&title, 1, &iconName); - wm_hints.initial_state = NormalState; - wm_hints.input = True; -- wm_hints.icon_pixmap = None; -+ wm_hints.icon_pixmap = m_icon; - wm_hints.flags = StateHint | IconPixmapHint | InputHint; - - XSetWMProperties(m_dpy, m_glWindow, &windowName, &iconName, -@@ -734,4 +739,123 @@ bool CWinSystemX11::SetWindow(int width, int height, bool fullscreen) - return true; - } - -+bool CWinSystemX11::CreateIconPixmap() -+{ -+ int depth; -+ XImage *img = NULL; -+ Visual *vis; -+ XWindowAttributes wndattribs; -+ XVisualInfo visInfo; -+ double rRatio; -+ double gRatio; -+ double bRatio; -+ int outIndex = 0; -+ int i,j; -+ int numBufBytes; -+ unsigned char *buf; -+ uint32_t *newBuf = 0; -+ size_t numNewBufBytes; -+ -+ // Get visual Info -+ XGetWindowAttributes(m_dpy, m_glWindow, &wndattribs); -+ visInfo.visualid = wndattribs.visual->visualid; -+ int nvisuals = 0; -+ XVisualInfo* visuals = XGetVisualInfo(m_dpy, VisualIDMask, &visInfo, &nvisuals); -+ if (nvisuals != 1) -+ { -+ CLog::Log(LOGERROR, "CWinSystemX11::CreateIconPixmap - could not find visual"); -+ return false; -+ } -+ visInfo = visuals[0]; -+ XFree(visuals); -+ -+ depth = visInfo.depth; -+ vis = visInfo.visual; -+ -+ if (depth < 15) -+ { -+ CLog::Log(LOGERROR, "CWinSystemX11::CreateIconPixmap - no suitable depth"); -+ return false; -+ } -+ -+ rRatio = vis->red_mask / 255.0; -+ gRatio = vis->green_mask / 255.0; -+ bRatio = vis->blue_mask / 255.0; -+ -+ CTexture iconTexture; -+ iconTexture.LoadFromFile("special://xbmc/media/icon.png"); -+ buf = iconTexture.GetPixels(); -+ -+ numBufBytes = iconTexture.GetWidth() * iconTexture.GetHeight() * 4; -+ -+ if (depth>=24) -+ numNewBufBytes = (4 * (iconTexture.GetWidth() * iconTexture.GetHeight())); -+ else -+ numNewBufBytes = (2 * (iconTexture.GetWidth() * iconTexture.GetHeight())); -+ -+ newBuf = (uint32_t*)malloc(numNewBufBytes); -+ if (!newBuf) -+ { -+ CLog::Log(LOGERROR, "CWinSystemX11::CreateIconPixmap - malloc failed"); -+ return false; -+ } -+ -+ for (i=0; ired_mask; -+ g &= vis->green_mask; -+ b &= vis->blue_mask; -+ newBuf[outIndex] = r | g | b; -+ ++outIndex; -+ } -+ } -+ img = XCreateImage(m_dpy, vis, depth,ZPixmap, 0, (char *)newBuf, -+ iconTexture.GetWidth(), iconTexture.GetHeight(), -+ (depth>=24)?32:16, 0); -+ if (!img) -+ { -+ CLog::Log(LOGERROR, "CWinSystemX11::CreateIconPixmap - could not create image"); -+ free(newBuf); -+ return false; -+ } -+ if (!XInitImage(img)) -+ { -+ CLog::Log(LOGERROR, "CWinSystemX11::CreateIconPixmap - init image failed"); -+ XDestroyImage(img); -+ return false; -+ } -+ -+ // set byte order -+ union -+ { -+ char c[sizeof(short)]; -+ short s; -+ } order; -+ order.s = 1; -+ if ((1 == order.c[0])) -+ { -+ img->byte_order = LSBFirst; -+ } -+ else -+ { -+ img->byte_order = MSBFirst; -+ } -+ -+ // create icon pixmap from image -+ m_icon = XCreatePixmap(m_dpy, m_glWindow, img->width, img->height, depth); -+ GC gc = XCreateGC(m_dpy, m_glWindow, 0, NULL); -+ XPutImage(m_dpy, m_icon, gc, img, 0, 0, 0, 0, img->width, img->height); -+ XFreeGC(m_dpy, gc); -+ XDestroyImage(img); // this also frees newBuf -+ -+ return true; -+} -+ - #endif -diff --git a/xbmc/windowing/X11/WinSystemX11.h b/xbmc/windowing/X11/WinSystemX11.h -index 9616d17..debf714 100644 ---- a/xbmc/windowing/X11/WinSystemX11.h -+++ b/xbmc/windowing/X11/WinSystemX11.h -@@ -77,6 +77,7 @@ class CWinSystemX11 : public CWinSystemBase - GLXContext m_glContext; - Display* m_dpy; - Cursor m_invisibleCursor; -+ Pixmap m_icon; - bool m_bWasFullScreenBeforeMinimize; - bool m_minimized; - bool m_bIgnoreNextFocusMessage; -@@ -88,6 +89,7 @@ class CWinSystemX11 : public CWinSystemBase - private: - bool IsSuitableVisual(XVisualInfo *vInfo); - static int XErrorHandler(Display* dpy, XErrorEvent* error); -+ bool CreateIconPixmap(); - - CStopWatch m_screensaverReset; - }; --- -1.7.10 - - -From cad2ac7f357906f10f100a038ff28e83a69c68e8 Mon Sep 17 00:00:00 2001 -From: xbmc -Date: Sun, 20 May 2012 14:11:26 +0200 -Subject: [PATCH 16/73] X11: add SDL joystick until we have a better solution - ---- - xbmc/windowing/WinEventsX11.cpp | 26 ++++++++++++++++++++++++++ - 1 file changed, 26 insertions(+) - -diff --git a/xbmc/windowing/WinEventsX11.cpp b/xbmc/windowing/WinEventsX11.cpp -index 24477ae..2ec86a8 100644 ---- a/xbmc/windowing/WinEventsX11.cpp -+++ b/xbmc/windowing/WinEventsX11.cpp -@@ -35,6 +35,10 @@ - #include "guilib/GUIWindowManager.h" - #include "input/MouseStat.h" - -+#ifdef HAS_SDL_JOYSTICK -+#include "input/SDLJoystick.h" -+#endif -+ - CWinEventsX11* CWinEventsX11::WinEvents = 0; - - static uint32_t SymMappingsX11[][2] = -@@ -547,6 +551,28 @@ bool CWinEventsX11::MessagePump() - - ret |= ProcessKeyRepeat(); - -+#ifdef HAS_SDL_JOYSTICK -+ SDL_Event event; -+ while (SDL_PollEvent(&event)) -+ { -+ switch(event.type) -+ { -+ case SDL_JOYBUTTONUP: -+ case SDL_JOYBUTTONDOWN: -+ case SDL_JOYAXISMOTION: -+ case SDL_JOYBALLMOTION: -+ case SDL_JOYHATMOTION: -+ g_Joystick.Update(event); -+ ret = true; -+ break; -+ -+ default: -+ break; -+ } -+ memset(&event, 0, sizeof(SDL_Event)); -+ } -+#endif -+ - return ret; - } - --- -1.7.10 - - -From fdefd4cf296518f31ad1165268fccd651e08dd3c Mon Sep 17 00:00:00 2001 -From: Joakim Plate -Date: Thu, 5 Jul 2012 12:35:55 +0200 -Subject: [PATCH 17/73] X11: factor out code handling device reset - notification - ---- - xbmc/windowing/X11/WinSystemX11.cpp | 22 ++++++++++++++-------- - xbmc/windowing/X11/WinSystemX11.h | 1 + - 2 files changed, 15 insertions(+), 8 deletions(-) - -diff --git a/xbmc/windowing/X11/WinSystemX11.cpp b/xbmc/windowing/X11/WinSystemX11.cpp -index c854598..70557d0 100644 ---- a/xbmc/windowing/X11/WinSystemX11.cpp -+++ b/xbmc/windowing/X11/WinSystemX11.cpp -@@ -530,14 +530,7 @@ void CWinSystemX11::CheckDisplayEvents() - - if (bGotEvent || bTimeout) - { -- CLog::Log(LOGDEBUG, "%s - notify display reset event", __FUNCTION__); -- RefreshWindow(); -- -- CSingleLock lock(m_resourceSection); -- -- // tell any shared resources -- for (vector::iterator i = m_resources.begin(); i != m_resources.end(); i++) -- (*i)->OnResetDevice(); -+ NotifyXRREvent(); - - // reset fail safe timer - m_dpyLostTime = 0; -@@ -545,6 +538,19 @@ void CWinSystemX11::CheckDisplayEvents() - #endif - } - -+void CWinSystemX11::NotifyXRREvent() -+{ -+ CLog::Log(LOGDEBUG, "%s - notify display reset event", __FUNCTION__); -+ RefreshWindow(); -+ -+ CSingleLock lock(m_resourceSection); -+ -+ // tell any shared resources -+ for (vector::iterator i = m_resources.begin(); i != m_resources.end(); i++) -+ (*i)->OnResetDevice(); -+ -+} -+ - void CWinSystemX11::OnLostDevice() - { - CLog::Log(LOGDEBUG, "%s - notify display change event", __FUNCTION__); -diff --git a/xbmc/windowing/X11/WinSystemX11.h b/xbmc/windowing/X11/WinSystemX11.h -index debf714..8c28e3f 100644 ---- a/xbmc/windowing/X11/WinSystemX11.h -+++ b/xbmc/windowing/X11/WinSystemX11.h -@@ -66,6 +66,7 @@ class CWinSystemX11 : public CWinSystemBase - GLXWindow GetWindow() { return m_glWindow; } - GLXContext GetGlxContext() { return m_glContext; } - void RefreshWindow(); -+ void NotifyXRREvent(); - - protected: - bool RefreshGlxContext(); --- -1.7.10 - - -From 9a409794d1eb8ee0c4b0b1124dea7dd30af32c06 Mon Sep 17 00:00:00 2001 -From: FernetMenta -Date: Thu, 5 Jul 2012 15:02:00 +0200 -Subject: [PATCH 18/73] X11: move xrandr events to WinEventsX11 - ---- - xbmc/windowing/WinEventsX11.cpp | 42 +++++++++++++++++++++++++++++++++++ - xbmc/windowing/WinEventsX11.h | 5 +++++ - xbmc/windowing/X11/WinSystemX11.cpp | 6 ++++- - 3 files changed, 52 insertions(+), 1 deletion(-) - -diff --git a/xbmc/windowing/WinEventsX11.cpp b/xbmc/windowing/WinEventsX11.cpp -index 2ec86a8..5946a33 100644 ---- a/xbmc/windowing/WinEventsX11.cpp -+++ b/xbmc/windowing/WinEventsX11.cpp -@@ -35,6 +35,10 @@ - #include "guilib/GUIWindowManager.h" - #include "input/MouseStat.h" - -+#if defined(HAS_XRANDR) -+#include -+#endif -+ - #ifdef HAS_SDL_JOYSTICK - #include "input/SDLJoystick.h" - #endif -@@ -203,6 +207,7 @@ bool CWinEventsX11::Init(Display *dpy, Window win) - WinEvents->m_keymodState = 0; - WinEvents->m_wmDeleteMessage = XInternAtom(dpy, "WM_DELETE_WINDOW", False); - WinEvents->m_structureChanged = false; -+ WinEvents->m_xrrEventPending = false; - memset(&(WinEvents->m_lastKey), 0, sizeof(XBMC_Event)); - - // open input method -@@ -266,6 +271,13 @@ bool CWinEventsX11::Init(Display *dpy, Window win) - WinEvents->m_symLookupTable[SymMappingsX11[i][0]] = SymMappingsX11[i][1]; - } - -+ // register for xrandr events -+#if defined(HAS_XRANDR) -+ int iReturn; -+ XRRQueryExtension(WinEvents->m_display, &WinEvents->m_RREventBase, &iReturn); -+ XRRSelectInput(WinEvents->m_display, WinEvents->m_window, RRScreenChangeNotifyMask); -+#endif -+ - return true; - } - -@@ -288,6 +300,15 @@ bool CWinEventsX11::HasStructureChanged() - return ret; - } - -+void CWinEventsX11::SetXRRFailSafeTimer(int millis) -+{ -+ if (!WinEvents) -+ return; -+ -+ WinEvents->m_xrrFailSafeTimer.Set(millis); -+ WinEvents->m_xrrEventPending = true; -+} -+ - bool CWinEventsX11::MessagePump() - { - if (!WinEvents) -@@ -547,10 +568,31 @@ bool CWinEventsX11::MessagePump() - break; - } - }// switch event.type -+ -+#if defined(HAS_XRANDR) -+ if (WinEvents && (xevent.type == WinEvents->m_RREventBase + RRScreenChangeNotify)) -+ { -+ XRRUpdateConfiguration(&xevent); -+ if (xevent.xgeneric.serial != serial) -+ g_Windowing.NotifyXRREvent(); -+ WinEvents->m_xrrEventPending = false; -+ serial = xevent.xgeneric.serial; -+ } -+#endif -+ - }// while - - ret |= ProcessKeyRepeat(); - -+#if defined(HAS_XRANDR) -+ if (WinEvents && WinEvents->m_xrrEventPending && WinEvents->m_xrrFailSafeTimer.IsTimePast()) -+ { -+ CLog::Log(LOGERROR,"CWinEventsX11::MessagePump - missed XRR Events"); -+ g_Windowing.NotifyXRREvent(); -+ WinEvents->m_xrrEventPending = false; -+ } -+#endif -+ - #ifdef HAS_SDL_JOYSTICK - SDL_Event event; - while (SDL_PollEvent(&event)) -diff --git a/xbmc/windowing/WinEventsX11.h b/xbmc/windowing/WinEventsX11.h -index e9b7553..6100933 100644 ---- a/xbmc/windowing/WinEventsX11.h -+++ b/xbmc/windowing/WinEventsX11.h -@@ -33,6 +33,8 @@ class CWinEventsX11 : public CWinEventsBase - static bool Init(Display *dpy, Window win); - static void Quit(); - static bool HasStructureChanged(); -+ static void PendingResize(int width, int height); -+ static void SetXRRFailSafeTimer(int millis); - static bool MessagePump(); - - protected: -@@ -54,4 +56,7 @@ class CWinEventsX11 : public CWinEventsBase - std::map m_symLookupTable; - int m_keymodState; - bool m_structureChanged; -+ int m_RREventBase; -+ XbmcThreads::EndTime m_xrrFailSafeTimer; -+ bool m_xrrEventPending; - }; -diff --git a/xbmc/windowing/X11/WinSystemX11.cpp b/xbmc/windowing/X11/WinSystemX11.cpp -index 70557d0..1cce843 100644 ---- a/xbmc/windowing/X11/WinSystemX11.cpp -+++ b/xbmc/windowing/X11/WinSystemX11.cpp -@@ -507,7 +507,7 @@ bool CWinSystemX11::Show(bool raise) - - void CWinSystemX11::CheckDisplayEvents() - { --#if defined(HAS_XRANDR) -+#if defined(HAS_XRANDR) && defined(HAS_SDL_VIDEO_X11) - bool bGotEvent(false); - bool bTimeout(false); - XEvent Event; -@@ -563,8 +563,12 @@ void CWinSystemX11::OnLostDevice() - (*i)->OnLostDevice(); - } - -+#if defined(HAS_SDL_VIDEO_X11) - // fail safe timer - m_dpyLostTime = CurrentHostCounter(); -+#else -+ CWinEvents::SetXRRFailSafeTimer(3000); -+#endif - } - - void CWinSystemX11::Register(IDispResource *resource) --- -1.7.10 - - -From 1dc579a2d5c608cfd4f799971759d18cbd2957e5 Mon Sep 17 00:00:00 2001 -From: FernetMenta -Date: Thu, 12 Apr 2012 15:43:56 +0200 -Subject: [PATCH 19/73] xrandr: remove method RestoreState - ---- - xbmc/windowing/X11/WinSystemX11.cpp | 13 +++++++++++-- - xbmc/windowing/X11/XRandR.cpp | 19 ------------------- - xbmc/windowing/X11/XRandR.h | 1 - - 3 files changed, 11 insertions(+), 22 deletions(-) - -diff --git a/xbmc/windowing/X11/WinSystemX11.cpp b/xbmc/windowing/X11/WinSystemX11.cpp -index 1cce843..e13ffa4 100644 ---- a/xbmc/windowing/X11/WinSystemX11.cpp -+++ b/xbmc/windowing/X11/WinSystemX11.cpp -@@ -77,9 +77,18 @@ bool CWinSystemX11::InitWindowSystem() - bool CWinSystemX11::DestroyWindowSystem() - { - #if defined(HAS_XRANDR) -- //restore videomode on exit -+ //restore desktop resolution on exit - if (m_bFullScreen) -- g_xrandr.RestoreState(); -+ { -+ XOutput out; -+ XMode mode; -+ out.name = g_settings.m_ResInfo[RES_DESKTOP].strOutput; -+ mode.w = g_settings.m_ResInfo[RES_DESKTOP].iWidth; -+ mode.h = g_settings.m_ResInfo[RES_DESKTOP].iHeight; -+ mode.hz = g_settings.m_ResInfo[RES_DESKTOP].fRefreshRate; -+ mode.id = g_settings.m_ResInfo[RES_DESKTOP].strId; -+ g_xrandr.SetMode(out, mode); -+ } - #endif - - if (m_dpy) -diff --git a/xbmc/windowing/X11/XRandR.cpp b/xbmc/windowing/X11/XRandR.cpp -index d8e9161..59755a6 100644 ---- a/xbmc/windowing/X11/XRandR.cpp -+++ b/xbmc/windowing/X11/XRandR.cpp -@@ -139,25 +139,6 @@ void CXRandR::SaveState() - Query(true); - } - --void CXRandR::RestoreState() --{ -- vector::iterator outiter; -- for (outiter=m_current.begin() ; outiter!=m_current.end() ; outiter++) -- { -- vector modes = (*outiter).modes; -- vector::iterator modeiter; -- for (modeiter=modes.begin() ; modeiter!=modes.end() ; modeiter++) -- { -- XMode mode = *modeiter; -- if (mode.isCurrent) -- { -- SetMode(*outiter, mode); -- return; -- } -- } -- } --} -- - bool CXRandR::SetMode(XOutput output, XMode mode) - { - if ((output.name == m_currentOutput && mode.id == m_currentMode) || (output.name == "" && mode.id == "")) -diff --git a/xbmc/windowing/X11/XRandR.h b/xbmc/windowing/X11/XRandR.h -index 2a269d0..5b64633 100644 ---- a/xbmc/windowing/X11/XRandR.h -+++ b/xbmc/windowing/X11/XRandR.h -@@ -99,7 +99,6 @@ class CXRandR - bool SetMode(XOutput output, XMode mode); - void LoadCustomModeLinesToAllOutputs(void); - void SaveState(); -- void RestoreState(); - //bool Has1080i(); - //bool Has1080p(); - //bool Has720p(); --- -1.7.10 - - -From 4a6f0e986fc27b356041a4b1bb989e0e594c8aa7 Mon Sep 17 00:00:00 2001 -From: xbmc -Date: Sun, 20 May 2012 13:17:10 +0200 -Subject: [PATCH 20/73] xrandr: observe orientation - ---- - xbmc/windowing/X11/WinSystemX11.cpp | 61 +++++++++++++++++++++++++++++++++-- - xbmc/windowing/X11/WinSystemX11.h | 2 ++ - xbmc/windowing/X11/XRandR.cpp | 7 ++++ - xbmc/windowing/X11/XRandR.h | 1 + - 4 files changed, 68 insertions(+), 3 deletions(-) - -diff --git a/xbmc/windowing/X11/WinSystemX11.cpp b/xbmc/windowing/X11/WinSystemX11.cpp -index e13ffa4..6b0aa92 100644 ---- a/xbmc/windowing/X11/WinSystemX11.cpp -+++ b/xbmc/windowing/X11/WinSystemX11.cpp -@@ -170,15 +170,24 @@ bool CWinSystemX11::ResizeWindow(int newWidth, int newHeight, int newLeft, int n - - void CWinSystemX11::RefreshWindow() - { -- g_xrandr.Query(true); -+ if (!g_xrandr.Query(true)) -+ { -+ CLog::Log(LOGERROR, "WinSystemX11::RefreshWindow - failed to query xrandr"); -+ return; -+ } - XOutput out = g_xrandr.GetCurrentOutput(); - XMode mode = g_xrandr.GetCurrentMode(out.name); - -+ RotateResolutions(); -+ - // only overwrite desktop resolution, if we are not in fullscreen mode - if (!g_graphicsContext.IsFullScreenVideo()) - { - CLog::Log(LOGDEBUG, "CWinSystemX11::RefreshWindow - store desktop resolution, width: %d, height: %d, hz: %2.2f", mode.w, mode.h, mode.hz); -- UpdateDesktopResolution(g_settings.m_ResInfo[RES_DESKTOP], 0, mode.w, mode.h, mode.hz); -+ if (!out.isRotated) -+ UpdateDesktopResolution(g_settings.m_ResInfo[RES_DESKTOP], 0, mode.w, mode.h, mode.hz); -+ else -+ UpdateDesktopResolution(g_settings.m_ResInfo[RES_DESKTOP], 0, mode.h, mode.w, mode.hz); - g_settings.m_ResInfo[RES_DESKTOP].strId = mode.id; - g_settings.m_ResInfo[RES_DESKTOP].strOutput = out.name; - } -@@ -234,6 +243,14 @@ bool CWinSystemX11::SetFullScreen(bool fullScreen, RESOLUTION_INFO& res, bool bl - XOutput currout = g_xrandr.GetCurrentOutput(); - XMode currmode = g_xrandr.GetCurrentMode(currout.name); - -+ // flip h/w when rotated -+ if (m_bIsRotated) -+ { -+ int w = mode.w; -+ mode.w = mode.h; -+ mode.h = w; -+ } -+ - // 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) -@@ -266,7 +283,11 @@ void CWinSystemX11::UpdateResolutions() - { - XOutput out = g_xrandr.GetCurrentOutput(); - XMode mode = g_xrandr.GetCurrentMode(out.name); -- UpdateDesktopResolution(g_settings.m_ResInfo[RES_DESKTOP], 0, mode.w, mode.h, mode.hz); -+ m_bIsRotated = out.isRotated; -+ if (!m_bIsRotated) -+ UpdateDesktopResolution(g_settings.m_ResInfo[RES_DESKTOP], 0, mode.w, mode.h, mode.hz); -+ else -+ UpdateDesktopResolution(g_settings.m_ResInfo[RES_DESKTOP], 0, mode.h, mode.w, mode.hz); - g_settings.m_ResInfo[RES_DESKTOP].strId = mode.id; - g_settings.m_ResInfo[RES_DESKTOP].strOutput = out.name; - } -@@ -305,6 +326,16 @@ void CWinSystemX11::UpdateResolutions() - res.iHeight = mode.h; - res.iScreenWidth = mode.w; - res.iScreenHeight = mode.h; -+ if (!m_bIsRotated) -+ { -+ res.iWidth = mode.w; -+ res.iHeight = mode.h; -+ } -+ else -+ { -+ res.iWidth = mode.h; -+ res.iHeight = mode.w; -+ } - if (mode.h>0 && mode.w>0 && out.hmm>0 && out.wmm>0) - res.fPixelRatio = ((float)out.wmm/(float)mode.w) / (((float)out.hmm/(float)mode.h)); - else -@@ -332,6 +363,30 @@ void CWinSystemX11::UpdateResolutions() - - } - -+void CWinSystemX11::RotateResolutions() -+{ -+#if defined(HAS_XRANDR) -+ XOutput out = g_xrandr.GetCurrentOutput(); -+ if (out.isRotated == m_bIsRotated) -+ return; -+ -+ for (unsigned int i = 0; i < g_settings.m_ResInfo.size(); ++i) -+ { -+ int width = g_settings.m_ResInfo[i].iWidth; -+ g_settings.m_ResInfo[i].iWidth = g_settings.m_ResInfo[i].iHeight; -+ g_settings.m_ResInfo[i].iHeight = width; -+ } -+ // update desktop resolution -+// int h = g_settings.m_ResInfo[RES_DESKTOP].iHeight; -+// int w = g_settings.m_ResInfo[RES_DESKTOP].iWidth; -+// float hz = g_settings.m_ResInfo[RES_DESKTOP].fRefreshRate; -+// UpdateDesktopResolution(g_settings.m_ResInfo[RES_DESKTOP], 0, w, h, hz); -+ -+ m_bIsRotated = out.isRotated; -+ -+#endif -+} -+ - bool CWinSystemX11::IsSuitableVisual(XVisualInfo *vInfo) - { - int value; -diff --git a/xbmc/windowing/X11/WinSystemX11.h b/xbmc/windowing/X11/WinSystemX11.h -index 8c28e3f..93cf5db 100644 ---- a/xbmc/windowing/X11/WinSystemX11.h -+++ b/xbmc/windowing/X11/WinSystemX11.h -@@ -73,12 +73,14 @@ class CWinSystemX11 : public CWinSystemBase - void CheckDisplayEvents(); - void OnLostDevice(); - bool SetWindow(int width, int height, bool fullscreen); -+ void RotateResolutions(); - - Window m_glWindow; - GLXContext m_glContext; - Display* m_dpy; - Cursor m_invisibleCursor; - Pixmap m_icon; -+ bool m_bIsRotated; - bool m_bWasFullScreenBeforeMinimize; - bool m_minimized; - bool m_bIgnoreNextFocusMessage; -diff --git a/xbmc/windowing/X11/XRandR.cpp b/xbmc/windowing/X11/XRandR.cpp -index 59755a6..45aeb71 100644 ---- a/xbmc/windowing/X11/XRandR.cpp -+++ b/xbmc/windowing/X11/XRandR.cpp -@@ -98,6 +98,13 @@ bool CXRandR::Query(bool force) - xoutput.y = (output->Attribute("y") != NULL ? atoi(output->Attribute("y")) : 0); - xoutput.wmm = (output->Attribute("wmm") != NULL ? atoi(output->Attribute("wmm")) : 0); - xoutput.hmm = (output->Attribute("hmm") != NULL ? atoi(output->Attribute("hmm")) : 0); -+ if (output->Attribute("rotation") != NULL -+ && (strcasecmp(output->Attribute("rotation"), "left") == 0 || strcasecmp(output->Attribute("rotation"), "right") == 0)) -+ { -+ xoutput.isRotated = true; -+ } -+ else -+ xoutput.isRotated = false; - - if (!xoutput.isConnected) - continue; -diff --git a/xbmc/windowing/X11/XRandR.h b/xbmc/windowing/X11/XRandR.h -index 5b64633..618bd68 100644 ---- a/xbmc/windowing/X11/XRandR.h -+++ b/xbmc/windowing/X11/XRandR.h -@@ -86,6 +86,7 @@ class XOutput - int wmm; - int hmm; - std::vector modes; -+ bool isRotated; - }; - - class CXRandR --- -1.7.10 - - -From 97e5811e05a4ecde7249b2f76283729ff300fda9 Mon Sep 17 00:00:00 2001 -From: FernetMenta -Date: Thu, 5 Jul 2012 11:54:15 +0200 -Subject: [PATCH 21/73] xrandr: allow getting info for multiple screen's - -Refactored by: Joakim Plate ---- - xbmc/windowing/X11/XRandR.cpp | 65 ++++++++++++++++++++++++++++++++--------- - xbmc/windowing/X11/XRandR.h | 8 +++-- - 2 files changed, 57 insertions(+), 16 deletions(-) - -diff --git a/xbmc/windowing/X11/XRandR.cpp b/xbmc/windowing/X11/XRandR.cpp -index 45aeb71..cc933b9 100644 ---- a/xbmc/windowing/X11/XRandR.cpp -+++ b/xbmc/windowing/X11/XRandR.cpp -@@ -39,6 +39,7 @@ - CXRandR::CXRandR(bool query) - { - m_bInit = false; -+ m_numScreens = 1; - if (query) - Query(); - } -@@ -55,11 +56,21 @@ bool CXRandR::Query(bool force) - return false; - - m_outputs.clear(); -- m_current.clear(); -+ // query all screens -+ for(unsigned int screennum=0; screennumValue(), "screen") != 0) -+ if (strcasecmp(pRootElement->Value(), "screen") != screennum) - { - // TODO ERROR - return false; -@@ -92,6 +103,7 @@ bool CXRandR::Query(bool force) - xoutput.name.TrimLeft(" \n\r\t"); - xoutput.name.TrimRight(" \n\r\t"); - xoutput.isConnected = (strcasecmp(output->Attribute("connected"), "true") == 0); -+ xoutput.screen = screennum; - xoutput.w = (output->Attribute("w") != NULL ? atoi(output->Attribute("w")) : 0); - xoutput.h = (output->Attribute("h") != NULL ? atoi(output->Attribute("h")) : 0); - xoutput.x = (output->Attribute("x") != NULL ? atoi(output->Attribute("x")) : 0); -@@ -123,7 +135,6 @@ bool CXRandR::Query(bool force) - xoutput.modes.push_back(xmode); - if (xmode.isCurrent) - { -- m_current.push_back(xoutput); - hascurrent = true; - } - } -@@ -247,17 +258,6 @@ bool CXRandR::SetMode(XOutput output, XMode mode) - return true; - } - --XOutput CXRandR::GetCurrentOutput() --{ -- Query(); -- for (unsigned int j = 0; j < m_outputs.size(); j++) -- { -- if(m_outputs[j].isConnected) -- return m_outputs[j]; -- } -- XOutput empty; -- return empty; --} - XMode CXRandR::GetCurrentMode(CStdString outputName) - { - Query(); -@@ -331,6 +331,43 @@ void CXRandR::LoadCustomModeLinesToAllOutputs(void) - } - } - -+void CXRandR::SetNumScreens(unsigned int num) -+{ -+ m_numScreens = num; -+ m_bInit = false; -+} -+ -+bool CXRandR::IsOutputConnected(CStdString name) -+{ -+ bool result = false; -+ Query(); -+ -+ for (unsigned int i = 0; i < m_outputs.size(); ++i) -+ { -+ if (m_outputs[i].name == name) -+ { -+ result = true; -+ break; -+ } -+ } -+ return result; -+} -+ -+XOutput* CXRandR::GetOutput(CStdString outputName) -+{ -+ XOutput *result = 0; -+ Query(); -+ for (unsigned int i = 0; i < m_outputs.size(); ++i) -+ { -+ if (m_outputs[i].name == outputName) -+ { -+ result = &m_outputs[i]; -+ break; -+ } -+ } -+ return result; -+} -+ - CXRandR g_xrandr; - - #endif // HAS_XRANDR -diff --git a/xbmc/windowing/X11/XRandR.h b/xbmc/windowing/X11/XRandR.h -index 618bd68..0824af5 100644 ---- a/xbmc/windowing/X11/XRandR.h -+++ b/xbmc/windowing/X11/XRandR.h -@@ -79,6 +79,7 @@ class XOutput - } - CStdString name; - bool isConnected; -+ int screen; - int w; - int h; - int x; -@@ -94,12 +95,15 @@ class CXRandR - public: - CXRandR(bool query=false); - bool Query(bool force=false); -+ bool Query(bool force, int screennum); - std::vector GetModes(void); -- XOutput GetCurrentOutput(); - XMode GetCurrentMode(CStdString outputName); -+ XOutput *GetOutput(CStdString outputName); - bool SetMode(XOutput output, XMode mode); - void LoadCustomModeLinesToAllOutputs(void); - void SaveState(); -+ void SetNumScreens(unsigned int num); -+ bool IsOutputConnected(CStdString name); - //bool Has1080i(); - //bool Has1080p(); - //bool Has720p(); -@@ -107,10 +111,10 @@ class CXRandR - - private: - bool m_bInit; -- std::vector m_current; - std::vector m_outputs; - CStdString m_currentOutput; - CStdString m_currentMode; -+ unsigned int m_numScreens; - }; - - extern CXRandR g_xrandr; --- -1.7.10 - - -From 2b379b9ce21b6d61b44b647b79ef3587dbbcf0ec Mon Sep 17 00:00:00 2001 -From: FernetMenta -Date: Thu, 5 Jul 2012 11:44:00 +0200 -Subject: [PATCH 22/73] X11: fix multi-head setups - ---- - language/English/strings.po | 4 +- - xbmc/rendering/gl/RenderSystemGL.h | 1 + - xbmc/settings/GUISettings.cpp | 5 + - xbmc/settings/GUIWindowSettingsCategory.cpp | 60 +++++- - xbmc/settings/GUIWindowSettingsCategory.h | 1 + - xbmc/windowing/WinEventsX11.cpp | 7 + - xbmc/windowing/X11/WinSystemX11.cpp | 262 ++++++++++++++++----------- - xbmc/windowing/X11/WinSystemX11.h | 10 +- - 8 files changed, 235 insertions(+), 115 deletions(-) - -diff --git a/language/English/strings.po b/language/English/strings.po -index 88292d3..bba7284 100644 ---- a/language/English/strings.po -+++ b/language/English/strings.po -@@ -895,7 +895,9 @@ msgctxt "#245" - msgid "Sizing: (%i,%i)->(%i,%i) (Zoom x%2.2f) AR:%2.2f:1 (Pixels: %2.2f:1) (VShift: %2.2f)" - msgstr "" - --#empty string with id 246 -+msgctxt "#246" -+msgid "Monitor" -+msgstr "" - - msgctxt "#247" - msgid "Scripts" -diff --git a/xbmc/rendering/gl/RenderSystemGL.h b/xbmc/rendering/gl/RenderSystemGL.h -index efe5493..85d780d 100644 ---- a/xbmc/rendering/gl/RenderSystemGL.h -+++ b/xbmc/rendering/gl/RenderSystemGL.h -@@ -44,6 +44,7 @@ class CRenderSystemGL : public CRenderSystemBase - virtual bool IsExtSupported(const char* extension); - - virtual void SetVSync(bool vsync); -+ virtual void ResetVSync() { m_bVsyncInit = false; } - - virtual void SetViewPort(CRect& viewPort); - virtual void GetViewPort(CRect& viewPort); -diff --git a/xbmc/settings/GUISettings.cpp b/xbmc/settings/GUISettings.cpp -index 4cdb093..0e320e1 100644 ---- a/xbmc/settings/GUISettings.cpp -+++ b/xbmc/settings/GUISettings.cpp -@@ -392,11 +392,16 @@ void CGUISettings::Initialize() - AddGroup(SETTINGS_SYSTEM, 13000); - CSettingsCategory* vs = AddCategory(SETTINGS_SYSTEM, "videoscreen", 21373); - -+#if defined(HAS_GLX) -+ AddString(vs, "videoscreen.monitor", 246, "", SPIN_CONTROL_TEXT); -+#endif -+ - // this setting would ideally not be saved, as its value is systematically derived from videoscreen.screenmode. - // contains a DISPLAYMODE - #if !defined(TARGET_DARWIN_IOS_ATV2) && !defined(TARGET_RASPBERRY_PI) - AddInt(vs, "videoscreen.screen", 240, 0, -1, 1, 32, SPIN_CONTROL_TEXT); - #endif -+ - // this setting would ideally not be saved, as its value is systematically derived from videoscreen.screenmode. - // contains an index to the g_settings.m_ResInfo array. the only meaningful fields are iScreen, iWidth, iHeight. - #if defined(TARGET_DARWIN) -diff --git a/xbmc/settings/GUIWindowSettingsCategory.cpp b/xbmc/settings/GUIWindowSettingsCategory.cpp -index d988598..3c19a06 100644 ---- a/xbmc/settings/GUIWindowSettingsCategory.cpp -+++ b/xbmc/settings/GUIWindowSettingsCategory.cpp -@@ -528,6 +528,12 @@ void CGUIWindowSettingsCategory::CreateSettings() - FillInRefreshRates(strSetting, g_guiSettings.GetResolution(), false); - continue; - } -+ else if (strSetting.Equals("videoscreen.monitor")) -+ { -+ AddSetting(pSetting, group->GetWidth(), iControlID); -+ FillInMonitors(strSetting); -+ continue; -+ } - else if (strSetting.Equals("lookandfeel.skintheme")) - { - AddSetting(pSetting, group->GetWidth(), iControlID); -@@ -1494,6 +1500,20 @@ void CGUIWindowSettingsCategory::OnSettingChanged(BaseSettingControlPtr pSetting - // Cascade - FillInResolutions("videoscreen.resolution", mode, RES_DESKTOP, true); - } -+ else if (strSetting.Equals("videoscreen.monitor")) -+ { -+ CSettingString *pSettingString = (CSettingString *)pSettingControl->GetSetting(); -+ CGUISpinControlEx *pControl = (CGUISpinControlEx *)GetControl(pSettingControl->GetID()); -+ CStdString currentMonitor = pControl->GetCurrentLabel(); -+ if (!g_Windowing.IsCurrentOutput(currentMonitor)) -+ { -+ g_guiSettings.SetString("videoscreen.monitor", currentMonitor); -+ g_Windowing.UpdateResolutions(); -+ DisplayMode mode = g_guiSettings.GetInt("videoscreen.screen"); -+ // Cascade -+ FillInResolutions("videoscreen.resolution", mode, RES_DESKTOP, true); -+ } -+ } - else if (strSetting.Equals("videoscreen.resolution")) - { - RESOLUTION nextRes = (RESOLUTION) g_guiSettings.GetInt("videoscreen.resolution"); -@@ -2430,11 +2450,15 @@ DisplayMode CGUIWindowSettingsCategory::FillInScreens(CStdString strSetting, RES - if (g_advancedSettings.m_canWindowed) - pControl->AddLabel(g_localizeStrings.Get(242), -1); - -+#if !defined(HAS_GLX) - for (int idx = 0; idx < g_Windowing.GetNumScreens(); idx++) - { - strScreen.Format(g_localizeStrings.Get(241), g_settings.m_ResInfo[RES_DESKTOP + idx].iScreen + 1); - pControl->AddLabel(strScreen, g_settings.m_ResInfo[RES_DESKTOP + idx].iScreen); - } -+#else -+ pControl->AddLabel(g_localizeStrings.Get(244), 0); -+#endif - pControl->SetValue(mode); - g_guiSettings.SetInt("videoscreen.screen", mode); - } -@@ -2442,6 +2466,36 @@ DisplayMode CGUIWindowSettingsCategory::FillInScreens(CStdString strSetting, RES - return mode; - } - -+void CGUIWindowSettingsCategory::FillInMonitors(CStdString strSetting) -+{ -+ // we expect "videoscreen.monitor" but it might be hidden on some platforms, -+ // so check that we actually have a visable control. -+ CBaseSettingControl *control = GetSetting(strSetting); -+ if (control) -+ { -+ control->SetDelayed(); -+ CGUISpinControlEx *pControl = (CGUISpinControlEx *)GetControl(control->GetID()); -+ pControl->Clear(); -+ -+ std::vector monitors; -+ g_Windowing.GetConnectedOutputs(&monitors); -+ -+ int currentMonitor = 0; -+ for (unsigned int i=0; iAddLabel(monitors[i], i); -+ } -+ -+ pControl->SetValue(currentMonitor); -+ g_guiSettings.SetString("videoscreen.monitor", g_settings.m_ResInfo[RES_DESKTOP].strOutput); -+ } -+} -+ -+ - void CGUIWindowSettingsCategory::FillInResolutions(CStdString strSetting, DisplayMode mode, RESOLUTION res, bool UserChange) - { - BaseSettingControlPtr control = GetSetting(strSetting); -@@ -2570,13 +2624,15 @@ void CGUIWindowSettingsCategory::OnRefreshRateChanged(RESOLUTION nextRes) - RESOLUTION lastRes = g_graphicsContext.GetVideoResolution(); - bool cancelled = false; - -+ bool outputChanged = !g_Windowing.IsCurrentOutput(g_guiSettings.GetString("videoscreen.monitor")); -+ - g_guiSettings.SetResolution(nextRes); -- g_graphicsContext.SetVideoResolution(nextRes); -+ g_graphicsContext.SetVideoResolution(nextRes, outputChanged); - - if (!CGUIDialogYesNo::ShowAndGetInput(13110, 13111, 20022, 20022, -1, -1, cancelled, 10000)) - { - g_guiSettings.SetResolution(lastRes); -- g_graphicsContext.SetVideoResolution(lastRes); -+ g_graphicsContext.SetVideoResolution(lastRes, outputChanged); - - DisplayMode mode = FillInScreens("videoscreen.screen", lastRes); - FillInResolutions("videoscreen.resolution", mode, lastRes, false); -diff --git a/xbmc/settings/GUIWindowSettingsCategory.h b/xbmc/settings/GUIWindowSettingsCategory.h -index 5142c6e..0d4649d 100644 ---- a/xbmc/settings/GUIWindowSettingsCategory.h -+++ b/xbmc/settings/GUIWindowSettingsCategory.h -@@ -51,6 +51,7 @@ class CGUIWindowSettingsCategory : - void FillInSoundSkins(CSetting *pSetting); - void FillInLanguages(CSetting *pSetting, const std::vector &languages = std::vector(), const std::vector &languageKeys = std::vector()); - DisplayMode FillInScreens(CStdString strSetting, RESOLUTION res); -+ void FillInMonitors(CStdString strSetting); - void FillInResolutions(CStdString strSetting, DisplayMode mode, RESOLUTION res, bool UserChange); - void FillInRefreshRates(CStdString strSetting, RESOLUTION res, bool UserChange); - void OnRefreshRateChanged(RESOLUTION resolution); -diff --git a/xbmc/windowing/WinEventsX11.cpp b/xbmc/windowing/WinEventsX11.cpp -index 5946a33..6c22358 100644 ---- a/xbmc/windowing/WinEventsX11.cpp -+++ b/xbmc/windowing/WinEventsX11.cpp -@@ -517,9 +517,16 @@ bool CWinEventsX11::MessagePump() - break; - } - -+ case EnterNotify: -+ { -+ g_Windowing.NotifyMouseCoverage(true); -+ break; -+ } -+ - // lose mouse coverage - case LeaveNotify: - { -+ g_Windowing.NotifyMouseCoverage(false); - g_Mouse.SetActive(false); - break; - } -diff --git a/xbmc/windowing/X11/WinSystemX11.cpp b/xbmc/windowing/X11/WinSystemX11.cpp -index 6b0aa92..5f913f1 100644 ---- a/xbmc/windowing/X11/WinSystemX11.cpp -+++ b/xbmc/windowing/X11/WinSystemX11.cpp -@@ -33,6 +33,7 @@ - #include "cores/VideoRenderers/RenderManager.h" - #include "utils/TimeUtils.h" - #include "settings/GUISettings.h" -+#include "windowing/WindowingFactory.h" - - #if defined(HAS_XRANDR) - #include -@@ -54,6 +55,7 @@ - m_bIgnoreNextFocusMessage = false; - m_dpyLostTime = 0; - m_invisibleCursor = 0; -+ m_bIsInternalXrr = false; - - XSetErrorHandler(XErrorHandler); - } -@@ -66,7 +68,8 @@ bool CWinSystemX11::InitWindowSystem() - { - if ((m_dpy = XOpenDisplay(NULL))) - { -- return CWinSystemBase::InitWindowSystem(); -+ bool ret = CWinSystemBase::InitWindowSystem(); -+ return ret; - } - else - CLog::Log(LOGERROR, "GLX Error: No Display found"); -@@ -103,6 +106,8 @@ bool CWinSystemX11::DestroyWindowSystem() - - //we don't call XCloseDisplay() here, since ati keeps a pointer to our m_dpy - //so instead we just let m_dpy die on exit -+ // i have seen core dumps on ATI if the display is not closed here -+ XCloseDisplay(m_dpy); - } - - // m_SDLSurface is free()'d by SDL_Quit(). -@@ -125,7 +130,10 @@ bool CWinSystemX11::DestroyWindow() - return true; - - if (m_glContext) -+ { -+ glFinish(); - glXMakeCurrent(m_dpy, None, NULL); -+ } - - if (m_invisibleCursor) - { -@@ -155,7 +163,7 @@ bool CWinSystemX11::ResizeWindow(int newWidth, int newHeight, int newLeft, int n - && m_nHeight == newHeight) - return true; - -- if (!SetWindow(newWidth, newHeight, false)) -+ if (!SetWindow(newWidth, newHeight, false, g_guiSettings.GetString("videoscreen.monitor"))) - { - return false; - } -@@ -164,58 +172,11 @@ bool CWinSystemX11::ResizeWindow(int newWidth, int newHeight, int newLeft, int n - m_nWidth = newWidth; - m_nHeight = newHeight; - m_bFullScreen = false; -+ m_currentOutput = g_guiSettings.GetString("videoscreen.monitor"); - - return false; - } - --void CWinSystemX11::RefreshWindow() --{ -- if (!g_xrandr.Query(true)) -- { -- CLog::Log(LOGERROR, "WinSystemX11::RefreshWindow - failed to query xrandr"); -- return; -- } -- XOutput out = g_xrandr.GetCurrentOutput(); -- XMode mode = g_xrandr.GetCurrentMode(out.name); -- -- RotateResolutions(); -- -- // only overwrite desktop resolution, if we are not in fullscreen mode -- if (!g_graphicsContext.IsFullScreenVideo()) -- { -- CLog::Log(LOGDEBUG, "CWinSystemX11::RefreshWindow - store desktop resolution, width: %d, height: %d, hz: %2.2f", mode.w, mode.h, mode.hz); -- if (!out.isRotated) -- UpdateDesktopResolution(g_settings.m_ResInfo[RES_DESKTOP], 0, mode.w, mode.h, mode.hz); -- else -- UpdateDesktopResolution(g_settings.m_ResInfo[RES_DESKTOP], 0, mode.h, mode.w, mode.hz); -- g_settings.m_ResInfo[RES_DESKTOP].strId = mode.id; -- g_settings.m_ResInfo[RES_DESKTOP].strOutput = 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; -- } -- -- if (g_graphicsContext.IsFullScreenRoot()) -- g_graphicsContext.SetVideoResolution((RESOLUTION)i, true); -- else -- g_graphicsContext.SetVideoResolution(RES_WINDOW, true); --} -- - bool CWinSystemX11::SetFullScreen(bool fullScreen, RESOLUTION_INFO& res, bool blankOtherDisplays) - { - -@@ -240,8 +201,7 @@ bool CWinSystemX11::SetFullScreen(bool fullScreen, RESOLUTION_INFO& res, bool bl - mode.id = g_settings.m_ResInfo[RES_DESKTOP].strId; - } - -- XOutput currout = g_xrandr.GetCurrentOutput(); -- XMode currmode = g_xrandr.GetCurrentMode(currout.name); -+ XMode currmode = g_xrandr.GetCurrentMode(out.name); - - // flip h/w when rotated - if (m_bIsRotated) -@@ -252,16 +212,17 @@ bool CWinSystemX11::SetFullScreen(bool fullScreen, RESOLUTION_INFO& res, bool bl - } - - // only call xrandr if mode changes -- if (currout.name != out.name || currmode.w != mode.w || currmode.h != mode.h || -+ if (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_bIsInternalXrr = true; - g_xrandr.SetMode(out, mode); - } - #endif - -- if (!SetWindow(res.iWidth, res.iHeight, fullScreen)) -+ if (!SetWindow(res.iWidth, res.iHeight, fullScreen, g_guiSettings.GetString("videoscreen.monitor"))) - return false; - - RefreshGlxContext(); -@@ -269,6 +230,7 @@ bool CWinSystemX11::SetFullScreen(bool fullScreen, RESOLUTION_INFO& res, bool bl - m_nWidth = res.iWidth; - m_nHeight = res.iHeight; - m_bFullScreen = fullScreen; -+ m_currentOutput = g_guiSettings.GetString("videoscreen.monitor"); - - return true; - } -@@ -277,19 +239,30 @@ void CWinSystemX11::UpdateResolutions() - { - CWinSystemBase::UpdateResolutions(); - -- - #if defined(HAS_XRANDR) -- if(g_xrandr.Query()) -- { -- XOutput out = g_xrandr.GetCurrentOutput(); -- XMode mode = g_xrandr.GetCurrentMode(out.name); -- m_bIsRotated = out.isRotated; -+ CStdString currentMonitor; -+ int numScreens = XScreenCount(m_dpy); -+ g_xrandr.SetNumScreens(numScreens); -+ if(g_xrandr.Query(true)) -+ { -+ currentMonitor = g_guiSettings.GetString("videoscreen.monitor"); -+ // check if the monitor is connected -+ XOutput *out = g_xrandr.GetOutput(currentMonitor); -+ if (!out) -+ { -+ // choose first output -+ currentMonitor = g_xrandr.GetModes()[0].name; -+ out = g_xrandr.GetOutput(currentMonitor); -+ g_guiSettings.SetString("videoscreen.monitor", currentMonitor); -+ } -+ XMode mode = g_xrandr.GetCurrentMode(currentMonitor); -+ m_bIsRotated = out->isRotated; - if (!m_bIsRotated) -- UpdateDesktopResolution(g_settings.m_ResInfo[RES_DESKTOP], 0, mode.w, mode.h, mode.hz); -+ UpdateDesktopResolution(g_settings.m_ResInfo[RES_DESKTOP], out->screen, mode.w, mode.h, mode.hz); - else -- UpdateDesktopResolution(g_settings.m_ResInfo[RES_DESKTOP], 0, mode.h, mode.w, mode.hz); -+ UpdateDesktopResolution(g_settings.m_ResInfo[RES_DESKTOP], out->screen, mode.h, mode.w, mode.hz); - g_settings.m_ResInfo[RES_DESKTOP].strId = mode.id; -- g_settings.m_ResInfo[RES_DESKTOP].strOutput = out.name; -+ g_settings.m_ResInfo[RES_DESKTOP].strOutput = currentMonitor; - } - else - #endif -@@ -300,23 +273,26 @@ void CWinSystemX11::UpdateResolutions() - UpdateDesktopResolution(g_settings.m_ResInfo[RES_DESKTOP], 0, w, h, 0.0); - } - -- - #if defined(HAS_XRANDR) - -+ // erase previous stored modes -+ if (g_settings.m_ResInfo.size() > RES_CUSTOM) -+ { -+ std::vector::iterator firstCustom = g_settings.m_ResInfo.begin()+RES_CUSTOM; -+ g_settings.m_ResInfo.erase(firstCustom, g_settings.m_ResInfo.end()); -+ } -+ - CLog::Log(LOGINFO, "Available videomodes (xrandr):"); -- vector::iterator outiter; -- vector outs; -- outs = g_xrandr.GetModes(); -- CLog::Log(LOGINFO, "Number of connected outputs: %"PRIdS"", outs.size()); -+ -+ XOutput *out = g_xrandr.GetOutput(currentMonitor); - string modename = ""; - -- for (outiter = outs.begin() ; outiter != outs.end() ; outiter++) -+ if (out != NULL) - { -- XOutput out = *outiter; - vector::iterator modeiter; -- CLog::Log(LOGINFO, "Output '%s' has %"PRIdS" modes", out.name.c_str(), out.modes.size()); -+ CLog::Log(LOGINFO, "Output '%s' has %"PRIdS" modes", out->name.c_str(), out->modes.size()); - -- for (modeiter = out.modes.begin() ; modeiter!=out.modes.end() ; modeiter++) -+ for (modeiter = out->modes.begin() ; modeiter!=out->modes.end() ; modeiter++) - { - XMode mode = *modeiter; - CLog::Log(LOGINFO, "ID:%s Name:%s Refresh:%f Width:%d Height:%d", -@@ -336,15 +312,15 @@ void CWinSystemX11::UpdateResolutions() - res.iWidth = mode.h; - res.iHeight = mode.w; - } -- if (mode.h>0 && mode.w>0 && out.hmm>0 && out.wmm>0) -- res.fPixelRatio = ((float)out.wmm/(float)mode.w) / (((float)out.hmm/(float)mode.h)); -+ if (mode.h>0 && mode.w>0 && out->hmm>0 && out->wmm>0) -+ res.fPixelRatio = ((float)out->wmm/(float)mode.w) / (((float)out->hmm/(float)mode.h)); - else - res.fPixelRatio = 1.0f; - - CLog::Log(LOGINFO, "Pixel Ratio: %f", res.fPixelRatio); - -- res.strMode.Format("%s: %s @ %.2fHz", out.name.c_str(), mode.name.c_str(), mode.hz); -- res.strOutput = out.name; -+ res.strMode.Format("%s: %s @ %.2fHz", out->name.c_str(), mode.name.c_str(), mode.hz); -+ res.strOutput = out->name; - res.strId = mode.id; - res.iSubtitles = (int)(0.95*mode.h); - res.fRefreshRate = mode.hz; -@@ -363,28 +339,19 @@ void CWinSystemX11::UpdateResolutions() - - } - --void CWinSystemX11::RotateResolutions() -+void CWinSystemX11::GetConnectedOutputs(std::vector *outputs) - { --#if defined(HAS_XRANDR) -- XOutput out = g_xrandr.GetCurrentOutput(); -- if (out.isRotated == m_bIsRotated) -- return; -- -- for (unsigned int i = 0; i < g_settings.m_ResInfo.size(); ++i) -+ vector outs; -+ outs = g_xrandr.GetModes(); -+ for(unsigned int i=0; ipush_back(outs[i].name); - } -- // update desktop resolution --// int h = g_settings.m_ResInfo[RES_DESKTOP].iHeight; --// int w = g_settings.m_ResInfo[RES_DESKTOP].iWidth; --// float hz = g_settings.m_ResInfo[RES_DESKTOP].fRefreshRate; --// UpdateDesktopResolution(g_settings.m_ResInfo[RES_DESKTOP], 0, w, h, hz); -- -- m_bIsRotated = out.isRotated; -+} - --#endif -+bool CWinSystemX11::IsCurrentOutput(CStdString output) -+{ -+ return m_currentOutput.Equals(output); - } - - bool CWinSystemX11::IsSuitableVisual(XVisualInfo *vInfo) -@@ -414,8 +381,11 @@ bool CWinSystemX11::RefreshGlxContext() - if (m_glContext) - { - CLog::Log(LOGDEBUG, "CWinSystemX11::RefreshGlxContext: refreshing context"); -+ glFinish(); - glXMakeCurrent(m_dpy, None, NULL); - glXMakeCurrent(m_dpy, m_glWindow, m_glContext); -+ XSync(m_dpy, FALSE); -+ g_Windowing.ResetVSync(); - return true; - } - -@@ -481,6 +451,8 @@ bool CWinSystemX11::RefreshGlxContext() - { - // make this context current - glXMakeCurrent(m_dpy, m_glWindow, m_glContext); -+ g_Windowing.ResetVSync(); -+ XSync(m_dpy, False); - retVal = true; - } - else -@@ -522,24 +494,53 @@ void CWinSystemX11::ResetOSScreensaver() - - void CWinSystemX11::NotifyAppActiveChange(bool bActivated) - { -- if (bActivated && m_bWasFullScreenBeforeMinimize && !g_graphicsContext.IsFullScreenRoot()) -+ if (bActivated && m_bWasFullScreenBeforeMinimize && !m_bFullScreen) -+ { - g_graphicsContext.ToggleFullScreenRoot(); - -+ m_bWasFullScreenBeforeMinimize = false; -+ } - m_minimized = !bActivated; - } - - void CWinSystemX11::NotifyAppFocusChange(bool bGaining) - { - if (bGaining && m_bWasFullScreenBeforeMinimize && !m_bIgnoreNextFocusMessage && -- !g_graphicsContext.IsFullScreenRoot()) -+ !m_bFullScreen) -+ { -+ m_bWasFullScreenBeforeMinimize = false; - g_graphicsContext.ToggleFullScreenRoot(); -+ m_minimized = false; -+ } - if (!bGaining) - m_bIgnoreNextFocusMessage = false; - } - -+void CWinSystemX11::NotifyMouseCoverage(bool covered) -+{ -+ if (!m_bFullScreen) -+ return; -+ -+ if (covered) -+ { -+ int result = -1; -+ while (result != GrabSuccess && result != AlreadyGrabbed) -+ { -+ result = XGrabPointer(m_dpy, m_glWindow, True, ButtonPressMask, GrabModeAsync, GrabModeAsync, None, None, CurrentTime); -+ XbmcThreads::ThreadSleep(100); -+ } -+ XGrabKeyboard(m_dpy, m_glWindow, True, GrabModeAsync, GrabModeAsync, CurrentTime); -+ } -+ else -+ { -+ XUngrabKeyboard(m_dpy, CurrentTime); -+ XUngrabPointer(m_dpy, CurrentTime); -+ } -+} -+ - bool CWinSystemX11::Minimize() - { -- m_bWasFullScreenBeforeMinimize = g_graphicsContext.IsFullScreenRoot(); -+ m_bWasFullScreenBeforeMinimize = m_bFullScreen; - if (m_bWasFullScreenBeforeMinimize) - { - m_bIgnoreNextFocusMessage = true; -@@ -605,13 +606,46 @@ void CWinSystemX11::CheckDisplayEvents() - void CWinSystemX11::NotifyXRREvent() - { - CLog::Log(LOGDEBUG, "%s - notify display reset event", __FUNCTION__); -- RefreshWindow(); -+ m_windowDirty = true; - -- CSingleLock lock(m_resourceSection); -+ // if external event update resolutions -+ if (!m_bIsInternalXrr) -+ { -+ UpdateResolutions(); -+ } -+ else if (!g_xrandr.Query(true)) -+ { -+ CLog::Log(LOGERROR, "WinSystemX11::RefreshWindow - failed to query xrandr"); -+ return; -+ } -+ m_bIsInternalXrr = false; - -- // tell any shared resources -- for (vector::iterator i = m_resources.begin(); i != m_resources.end(); i++) -- (*i)->OnResetDevice(); -+ CStdString currentOutput = g_guiSettings.GetString("videoscreen.monitor"); -+ XOutput *out = g_xrandr.GetOutput(currentOutput); -+ XMode mode = g_xrandr.GetCurrentMode(currentOutput); -+ -+ 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"); -+ i = RES_DESKTOP; -+ } -+ -+ if (g_graphicsContext.IsFullScreenRoot()) -+ g_graphicsContext.SetVideoResolution((RESOLUTION)i, true); -+ else -+ g_graphicsContext.SetVideoResolution(RES_WINDOW, true); - - } - -@@ -664,14 +698,14 @@ bool CWinSystemX11::EnableFrameLimiter() - return m_minimized; - } - --bool CWinSystemX11::SetWindow(int width, int height, bool fullscreen) -+bool CWinSystemX11::SetWindow(int width, int height, bool fullscreen, const CStdString &output) - { - bool changeWindow = false; - bool changeSize = false; - bool mouseActive = false; - float mouseX, mouseY; - -- if (m_glWindow && (m_bFullScreen != fullscreen)) -+ if (m_glWindow && ((m_bFullScreen != fullscreen) || !m_currentOutput.Equals(output) || m_windowDirty)) - { - mouseActive = g_Mouse.IsActive(); - if (mouseActive) -@@ -693,6 +727,7 @@ bool CWinSystemX11::SetWindow(int width, int height, bool fullscreen) - else - mouseActive = false; - } -+ OnLostDevice(); - DestroyWindow(); - } - -@@ -714,7 +749,11 @@ bool CWinSystemX11::SetWindow(int width, int height, bool fullscreen) - XSetWindowAttributes swa; - XVisualInfo *vi; - -- vi = glXChooseVisual(m_dpy, DefaultScreen(m_dpy), att); -+ XOutput *out = g_xrandr.GetOutput(output); -+ if (!out) -+ out = g_xrandr.GetOutput(m_currentOutput); -+ m_nScreen = out->screen; -+ vi = glXChooseVisual(m_dpy, m_nScreen, att); - cmap = XCreateColormap(m_dpy, RootWindow(m_dpy, vi->screen), vi->visual, AllocNone); - - int def_vis = (vi->visual == DefaultVisual(m_dpy, vi->screen)); -@@ -730,7 +769,7 @@ bool CWinSystemX11::SetWindow(int width, int height, bool fullscreen) - unsigned long mask = CWBackPixel | CWBorderPixel | CWColormap | CWOverrideRedirect | CWEventMask; - - m_glWindow = XCreateWindow(m_dpy, RootWindow(m_dpy, vi->screen), -- 0, 0, width, height, 0, vi->depth, -+ out->x, out->y, width, height, 0, vi->depth, - InputOutput, vi->visual, - mask, &swa); - -@@ -801,14 +840,19 @@ bool CWinSystemX11::SetWindow(int width, int height, bool fullscreen) - if (fullscreen) - { - int result = -1; -- while (result != GrabSuccess) -+ while (result != GrabSuccess && result != AlreadyGrabbed) - { -- result = XGrabPointer(m_dpy, m_glWindow, True, ButtonPressMask, GrabModeAsync, GrabModeAsync, m_glWindow, None, CurrentTime); -+ result = XGrabPointer(m_dpy, m_glWindow, True, ButtonPressMask, GrabModeAsync, GrabModeAsync, None, None, CurrentTime); - XbmcThreads::ThreadSleep(100); - } - XGrabKeyboard(m_dpy, m_glWindow, True, GrabModeAsync, GrabModeAsync, CurrentTime); -- - } -+ CSingleLock lock(m_resourceSection); -+ // tell any shared resources -+ for (vector::iterator i = m_resources.begin(); i != m_resources.end(); i++) -+ (*i)->OnResetDevice(); -+ -+ m_windowDirty = false; - } - return true; - } -diff --git a/xbmc/windowing/X11/WinSystemX11.h b/xbmc/windowing/X11/WinSystemX11.h -index 93cf5db..71034fc 100644 ---- a/xbmc/windowing/X11/WinSystemX11.h -+++ b/xbmc/windowing/X11/WinSystemX11.h -@@ -65,15 +65,16 @@ class CWinSystemX11 : public CWinSystemBase - Display* GetDisplay() { return m_dpy; } - GLXWindow GetWindow() { return m_glWindow; } - GLXContext GetGlxContext() { return m_glContext; } -- void RefreshWindow(); - void NotifyXRREvent(); -+ void GetConnectedOutputs(std::vector *outputs); -+ bool IsCurrentOutput(CStdString output); -+ void NotifyMouseCoverage(bool covered); - - protected: - bool RefreshGlxContext(); - void CheckDisplayEvents(); - void OnLostDevice(); -- bool SetWindow(int width, int height, bool fullscreen); -- void RotateResolutions(); -+ bool SetWindow(int width, int height, bool fullscreen, const CStdString &output); - - Window m_glWindow; - GLXContext m_glContext; -@@ -88,6 +89,9 @@ class CWinSystemX11 : public CWinSystemBase - CCriticalSection m_resourceSection; - std::vector m_resources; - uint64_t m_dpyLostTime; -+ CStdString m_currentOutput; -+ bool m_windowDirty; -+ bool m_bIsInternalXrr; - - private: - bool IsSuitableVisual(XVisualInfo *vInfo); --- -1.7.10 - - -From 2a747f13a0a50dea0883d0d3c701ef290235a99b Mon Sep 17 00:00:00 2001 -From: FernetMenta -Date: Thu, 5 Jul 2012 11:36:32 +0200 -Subject: [PATCH 23/73] X11: remove all DefaultScreen and RootWindow macros - ---- - xbmc/windowing/X11/WinSystemX11.cpp | 6 +++--- - xbmc/windowing/X11/WinSystemX11.h | 1 + - xbmc/windowing/X11/WinSystemX11GL.cpp | 2 +- - 3 files changed, 5 insertions(+), 4 deletions(-) - -diff --git a/xbmc/windowing/X11/WinSystemX11.cpp b/xbmc/windowing/X11/WinSystemX11.cpp -index 5f913f1..af1307c 100644 ---- a/xbmc/windowing/X11/WinSystemX11.cpp -+++ b/xbmc/windowing/X11/WinSystemX11.cpp -@@ -267,7 +267,7 @@ void CWinSystemX11::UpdateResolutions() - else - #endif - { -- int x11screen = DefaultScreen(m_dpy); -+ int x11screen = m_nScreen; - int w = DisplayWidth(m_dpy, x11screen); - int h = DisplayHeight(m_dpy, x11screen); - UpdateDesktopResolution(g_settings.m_ResInfo[RES_DESKTOP], 0, w, h, 0.0); -@@ -393,7 +393,7 @@ bool CWinSystemX11::RefreshGlxContext() - XVisualInfo *visuals; - XVisualInfo *vInfo = NULL; - int availableVisuals = 0; -- vMask.screen = DefaultScreen(m_dpy); -+ vMask.screen = m_nScreen; - XWindowAttributes winAttr; - - /* Assume a depth of 24 in case the below calls to XGetWindowAttributes() -@@ -547,7 +547,7 @@ bool CWinSystemX11::Minimize() - g_graphicsContext.ToggleFullScreenRoot(); - } - -- XIconifyWindow(m_dpy, m_glWindow, DefaultScreen(m_dpy)); -+ XIconifyWindow(m_dpy, m_glWindow, m_nScreen); - - m_minimized = true; - return true; -diff --git a/xbmc/windowing/X11/WinSystemX11.h b/xbmc/windowing/X11/WinSystemX11.h -index 71034fc..3bb4b8e 100644 ---- a/xbmc/windowing/X11/WinSystemX11.h -+++ b/xbmc/windowing/X11/WinSystemX11.h -@@ -47,6 +47,7 @@ class CWinSystemX11 : public CWinSystemBase - virtual bool SetFullScreen(bool fullScreen, RESOLUTION_INFO& res, bool blankOtherDisplays); - virtual void UpdateResolutions(); - virtual int GetNumScreens() { return 1; } -+ virtual int GetCurrentScreen() { return m_nScreen; } - virtual void ShowOSMouse(bool show); - virtual void ResetOSScreensaver(); - virtual bool EnableFrameLimiter(); -diff --git a/xbmc/windowing/X11/WinSystemX11GL.cpp b/xbmc/windowing/X11/WinSystemX11GL.cpp -index f858f88..d192697 100644 ---- a/xbmc/windowing/X11/WinSystemX11GL.cpp -+++ b/xbmc/windowing/X11/WinSystemX11GL.cpp -@@ -203,7 +203,7 @@ bool CWinSystemX11GL::CreateNewWindow(const CStdString& name, bool fullScreen, R - return false; - - m_glxext = " "; -- m_glxext += (const char*)glXQueryExtensionsString(m_dpy, DefaultScreen(m_dpy)); -+ m_glxext += (const char*)glXQueryExtensionsString(m_dpy, m_nScreen); - m_glxext += " "; - - CLog::Log(LOGDEBUG, "GLX_EXTENSIONS:%s", m_glxext.c_str()); --- -1.7.10 - - -From cf018ebbf1eae8f5ae2914ef347aac5f963c0d71 Mon Sep 17 00:00:00 2001 -From: FernetMenta -Date: Thu, 5 Jul 2012 11:45:22 +0200 -Subject: [PATCH 24/73] X11: remove all DefaultScreen and RootWindow macros - (VideoRefClock) - -Note this is on a separate display connection. ---- - xbmc/video/VideoReferenceClock.cpp | 15 ++++++++------- - 1 file changed, 8 insertions(+), 7 deletions(-) - -diff --git a/xbmc/video/VideoReferenceClock.cpp b/xbmc/video/VideoReferenceClock.cpp -index 9785fe7..0004e07 100644 ---- a/xbmc/video/VideoReferenceClock.cpp -+++ b/xbmc/video/VideoReferenceClock.cpp -@@ -270,7 +270,7 @@ bool CVideoReferenceClock::SetupGLX() - } - - bool ExtensionFound = false; -- istringstream Extensions(glXQueryExtensionsString(m_Dpy, DefaultScreen(m_Dpy))); -+ istringstream Extensions(glXQueryExtensionsString(m_Dpy, g_Windowing.GetCurrentScreen())); - string ExtensionStr; - - while (!ExtensionFound) -@@ -297,7 +297,7 @@ bool CVideoReferenceClock::SetupGLX() - m_bIsATI = true; - } - -- m_vInfo = glXChooseVisual(m_Dpy, DefaultScreen(m_Dpy), singleBufferAttributes); -+ m_vInfo = glXChooseVisual(m_Dpy, g_Windowing.GetCurrentScreen(), singleBufferAttributes); - if (!m_vInfo) - { - CLog::Log(LOGDEBUG, "CVideoReferenceClock: glXChooseVisual returned NULL"); -@@ -308,15 +308,16 @@ bool CVideoReferenceClock::SetupGLX() - { - Swa.border_pixel = 0; - Swa.event_mask = StructureNotifyMask; -- Swa.colormap = XCreateColormap(m_Dpy, RootWindow(m_Dpy, m_vInfo->screen), m_vInfo->visual, AllocNone ); -+ Swa.colormap = XCreateColormap(m_Dpy, g_Windowing.GetWindow(), m_vInfo->visual, AllocNone ); - SwaMask = CWBorderPixel | CWColormap | CWEventMask; - -- m_Window = XCreateWindow(m_Dpy, RootWindow(m_Dpy, m_vInfo->screen), 0, 0, 256, 256, 0, -+ m_Window = XCreateWindow(m_Dpy, g_Windowing.GetWindow(), 0, 0, 256, 256, 0, - m_vInfo->depth, InputOutput, m_vInfo->visual, SwaMask, &Swa); - } - else - { -- m_pixmap = XCreatePixmap(m_Dpy, DefaultRootWindow(m_Dpy), 256, 256, m_vInfo->depth); -+ Window window = g_Windowing.GetWindow(); -+ m_pixmap = XCreatePixmap(m_Dpy, window, 256, 256, m_vInfo->depth); - if (!m_pixmap) - { - CLog::Log(LOGDEBUG, "CVideoReferenceClock: unable to create pixmap"); -@@ -383,7 +384,7 @@ bool CVideoReferenceClock::SetupGLX() - - //set up receiving of RandR events, we'll get one when the refreshrate changes - XRRQueryExtension(m_Dpy, &m_RREventBase, &ReturnV); -- XRRSelectInput(m_Dpy, RootWindow(m_Dpy, m_vInfo->screen), RRScreenChangeNotifyMask); -+ XRRSelectInput(m_Dpy, g_Windowing.GetWindow(), RRScreenChangeNotifyMask); - - UpdateRefreshrate(true); //forced refreshrate update - m_MissedVblanks = 0; -@@ -518,7 +519,7 @@ int CVideoReferenceClock::GetRandRRate() - int RefreshRate; - XRRScreenConfiguration *CurrInfo; - -- CurrInfo = XRRGetScreenInfo(m_Dpy, RootWindow(m_Dpy, m_vInfo->screen)); -+ CurrInfo = XRRGetScreenInfo(m_Dpy, g_Windowing.GetWindow()); - RefreshRate = XRRConfigCurrentRate(CurrInfo); - XRRFreeScreenConfigInfo(CurrInfo); - --- -1.7.10 - - -From 5d8bfcd52e5a189515629c15c73434ef6c6bcc88 Mon Sep 17 00:00:00 2001 -From: xbmc -Date: Wed, 20 Jun 2012 17:37:11 +0200 -Subject: [PATCH 25/73] X11: recreate gl context after output has changed - ---- - xbmc/windowing/X11/WinSystemX11.cpp | 24 ++++++++++++++---------- - xbmc/windowing/X11/WinSystemX11.h | 1 + - xbmc/windowing/X11/WinSystemX11GL.cpp | 9 +++++++++ - 3 files changed, 24 insertions(+), 10 deletions(-) - -diff --git a/xbmc/windowing/X11/WinSystemX11.cpp b/xbmc/windowing/X11/WinSystemX11.cpp -index af1307c..d3d15e2 100644 ---- a/xbmc/windowing/X11/WinSystemX11.cpp -+++ b/xbmc/windowing/X11/WinSystemX11.cpp -@@ -168,7 +168,6 @@ bool CWinSystemX11::ResizeWindow(int newWidth, int newHeight, int newLeft, int n - return false; - } - -- RefreshGlxContext(); - m_nWidth = newWidth; - m_nHeight = newHeight; - m_bFullScreen = false; -@@ -219,14 +218,13 @@ bool CWinSystemX11::SetFullScreen(bool fullScreen, RESOLUTION_INFO& res, bool bl - OnLostDevice(); - m_bIsInternalXrr = true; - g_xrandr.SetMode(out, mode); -+ return true; - } - #endif - - if (!SetWindow(res.iWidth, res.iHeight, fullScreen, g_guiSettings.GetString("videoscreen.monitor"))) - return false; - -- RefreshGlxContext(); -- - m_nWidth = res.iWidth; - m_nHeight = res.iHeight; - m_bFullScreen = fullScreen; -@@ -381,11 +379,8 @@ bool CWinSystemX11::RefreshGlxContext() - if (m_glContext) - { - CLog::Log(LOGDEBUG, "CWinSystemX11::RefreshGlxContext: refreshing context"); -- glFinish(); - glXMakeCurrent(m_dpy, None, NULL); - glXMakeCurrent(m_dpy, m_glWindow, m_glContext); -- XSync(m_dpy, FALSE); -- g_Windowing.ResetVSync(); - return true; - } - -@@ -445,14 +440,14 @@ bool CWinSystemX11::RefreshGlxContext() - { - glXMakeCurrent(m_dpy, None, NULL); - glXDestroyContext(m_dpy, m_glContext); -+ XSync(m_dpy, FALSE); -+ m_newGlContext = true; - } - - if ((m_glContext = glXCreateContext(m_dpy, vInfo, NULL, True))) - { - // make this context current - glXMakeCurrent(m_dpy, m_glWindow, m_glContext); -- g_Windowing.ResetVSync(); -- XSync(m_dpy, False); - retVal = true; - } - else -@@ -729,6 +724,7 @@ bool CWinSystemX11::SetWindow(int width, int height, bool fullscreen, const CStd - } - OnLostDevice(); - DestroyWindow(); -+ m_windowDirty = true; - } - - // create main window -@@ -847,13 +843,21 @@ bool CWinSystemX11::SetWindow(int width, int height, bool fullscreen, const CStd - } - XGrabKeyboard(m_dpy, m_glWindow, True, GrabModeAsync, GrabModeAsync, CurrentTime); - } -+ -+ CDirtyRegionList dr; -+ RefreshGlxContext(); -+ XSync(m_dpy, FALSE); -+ g_graphicsContext.Clear(0); -+ g_graphicsContext.Flip(dr); -+ g_Windowing.ResetVSync(); -+ m_windowDirty = false; -+ - CSingleLock lock(m_resourceSection); - // tell any shared resources - for (vector::iterator i = m_resources.begin(); i != m_resources.end(); i++) - (*i)->OnResetDevice(); -- -- m_windowDirty = false; - } -+ - return true; - } - -diff --git a/xbmc/windowing/X11/WinSystemX11.h b/xbmc/windowing/X11/WinSystemX11.h -index 3bb4b8e..cc28f56 100644 ---- a/xbmc/windowing/X11/WinSystemX11.h -+++ b/xbmc/windowing/X11/WinSystemX11.h -@@ -93,6 +93,7 @@ class CWinSystemX11 : public CWinSystemBase - CStdString m_currentOutput; - bool m_windowDirty; - bool m_bIsInternalXrr; -+ bool m_newGlContext; - - private: - bool IsSuitableVisual(XVisualInfo *vInfo); -diff --git a/xbmc/windowing/X11/WinSystemX11GL.cpp b/xbmc/windowing/X11/WinSystemX11GL.cpp -index d192697..0f2d1d2 100644 ---- a/xbmc/windowing/X11/WinSystemX11GL.cpp -+++ b/xbmc/windowing/X11/WinSystemX11GL.cpp -@@ -23,6 +23,7 @@ - - #include "WinSystemX11GL.h" - #include "utils/log.h" -+#include "Application.h" - - CWinSystemX11GL::CWinSystemX11GL() - { -@@ -245,17 +246,25 @@ bool CWinSystemX11GL::CreateNewWindow(const CStdString& name, bool fullScreen, R - - bool CWinSystemX11GL::ResizeWindow(int newWidth, int newHeight, int newLeft, int newTop) - { -+ m_newGlContext = false; - CWinSystemX11::ResizeWindow(newWidth, newHeight, newLeft, newTop); - CRenderSystemGL::ResetRenderSystem(newWidth, newHeight, false, 0); - -+ if (m_newGlContext) -+ g_application.ReloadSkin(); -+ - return true; - } - - bool CWinSystemX11GL::SetFullScreen(bool fullScreen, RESOLUTION_INFO& res, bool blankOtherDisplays) - { -+ m_newGlContext = false; - CWinSystemX11::SetFullScreen(fullScreen, res, blankOtherDisplays); - CRenderSystemGL::ResetRenderSystem(res.iWidth, res.iHeight, fullScreen, res.fRefreshRate); - -+ if (m_newGlContext) -+ g_application.ReloadSkin(); -+ - return true; - } - --- -1.7.10 - - -From bd9a29b7661c75152174959f9f269f32c13a658b Mon Sep 17 00:00:00 2001 -From: FernetMenta -Date: Thu, 5 Jul 2012 12:06:25 +0200 -Subject: [PATCH 26/73] X11: hook video reference clock in windowing - ---- - xbmc/video/VideoReferenceClock.cpp | 71 ++++++++++++++++++++++++++---------- - xbmc/video/VideoReferenceClock.h | 13 ++++++- - 2 files changed, 63 insertions(+), 21 deletions(-) - -diff --git a/xbmc/video/VideoReferenceClock.cpp b/xbmc/video/VideoReferenceClock.cpp -index 0004e07..fa8e35a 100644 ---- a/xbmc/video/VideoReferenceClock.cpp -+++ b/xbmc/video/VideoReferenceClock.cpp -@@ -135,12 +135,23 @@ - m_Context = NULL; - m_pixmap = None; - m_glPixmap = None; -- m_RREventBase = 0; - m_UseNvSettings = true; - m_bIsATI = false; - #endif - } - -+CVideoReferenceClock::~CVideoReferenceClock() -+{ -+#if defined(HAS_GLX) -+ // some ATI voodoo, if we don't close the display, we crash on exit -+ if (m_Dpy) -+ { -+ XCloseDisplay(m_Dpy); -+ m_Dpy = NULL; -+ } -+#endif -+} -+ - void CVideoReferenceClock::Process() - { - bool SetupSuccess = false; -@@ -151,6 +162,10 @@ void CVideoReferenceClock::Process() - m_D3dCallback.Reset(); - g_Windowing.Register(&m_D3dCallback); - #endif -+#if defined(HAS_GLX) && defined(HAS_XRANDR) -+ g_Windowing.Register(this); -+ m_xrrEvent = false; -+#endif - - while(!m_bStop) - { -@@ -211,6 +226,16 @@ void CVideoReferenceClock::Process() - //clean up the vblank clock - #if defined(HAS_GLX) && defined(HAS_XRANDR) - CleanupGLX(); -+ if (m_xrrEvent) -+ { -+ m_releaseEvent.Set(); -+ while (!m_bStop) -+ { -+ if (m_resetEvent.WaitMSec(100)) -+ break; -+ } -+ m_xrrEvent = false; -+ } - #elif defined(_WIN32) && defined(HAS_DX) - CleanupD3D(); - #elif defined(TARGET_DARWIN) -@@ -222,6 +247,9 @@ void CVideoReferenceClock::Process() - #if defined(_WIN32) && defined(HAS_DX) - g_Windowing.Unregister(&m_D3dCallback); - #endif -+#if defined(HAS_GLX) -+ g_Windowing.Unregister(this); -+#endif - } - - bool CVideoReferenceClock::WaitStarted(int MSecs) -@@ -231,6 +259,24 @@ bool CVideoReferenceClock::WaitStarted(int MSecs) - } - - #if defined(HAS_GLX) && defined(HAS_XRANDR) -+ -+void CVideoReferenceClock::OnLostDevice() -+{ -+ if (!m_xrrEvent) -+ { -+ m_releaseEvent.Reset(); -+ m_resetEvent.Reset(); -+ m_xrrEvent = true; -+ m_releaseEvent.Wait(); -+ } -+} -+ -+void CVideoReferenceClock::OnResetDevice() -+{ -+ m_xrrEvent = false; -+ m_resetEvent.Set(); -+} -+ - bool CVideoReferenceClock::SetupGLX() - { - int singleBufferAttributes[] = { -@@ -382,10 +428,6 @@ bool CVideoReferenceClock::SetupGLX() - return false; - } - -- //set up receiving of RandR events, we'll get one when the refreshrate changes -- XRRQueryExtension(m_Dpy, &m_RREventBase, &ReturnV); -- XRRSelectInput(m_Dpy, g_Windowing.GetWindow(), RRScreenChangeNotifyMask); -- - UpdateRefreshrate(true); //forced refreshrate update - m_MissedVblanks = 0; - -@@ -586,6 +628,9 @@ void CVideoReferenceClock::RunGLX() - - while(!m_bStop) - { -+ if (m_xrrEvent) -+ return; -+ - //wait for the next vblank - if (!m_bIsATI) - { -@@ -649,7 +694,6 @@ void CVideoReferenceClock::RunGLX() - UpdateClock((int)(VblankCount - PrevVblankCount), true); - SingleLock.Leave(); - SendVblankSignal(); -- UpdateRefreshrate(); - IsReset = false; - } - else if (!m_bStop) -@@ -1186,23 +1230,10 @@ bool CVideoReferenceClock::UpdateRefreshrate(bool Forced /*= false*/) - - #if defined(HAS_GLX) && defined(HAS_XRANDR) - -- //check for RandR events -- bool GotEvent = Forced || m_RefreshChanged == 2; -- XEvent Event; -- while (XCheckTypedEvent(m_Dpy, m_RREventBase + RRScreenChangeNotify, &Event)) -- { -- if (Event.type == m_RREventBase + RRScreenChangeNotify) -- { -- CLog::Log(LOGDEBUG, "CVideoReferenceClock: Received RandR event %i", Event.type); -- GotEvent = true; -- } -- XRRUpdateConfiguration(&Event); -- } -- - if (!Forced) - m_RefreshChanged = 0; - -- if (!GotEvent) //refreshrate did not change -+ if (!Forced) //refreshrate did not change - return false; - - //the refreshrate can be wrong on nvidia drivers, so read it from nvidia-settings when it's available -diff --git a/xbmc/video/VideoReferenceClock.h b/xbmc/video/VideoReferenceClock.h -index dcc4f09..7eb6317 100644 ---- a/xbmc/video/VideoReferenceClock.h -+++ b/xbmc/video/VideoReferenceClock.h -@@ -30,6 +30,7 @@ - #include - #include - #include -+ #include "guilib/DispResource.h" - #elif defined(_WIN32) && defined(HAS_DX) - #include - #include "guilib/D3DResource.h" -@@ -56,9 +57,13 @@ class CD3DCallback : public ID3DResource - #endif - - class CVideoReferenceClock : public CThread -+#if defined(HAS_GLX) && defined(HAS_XRANDR) -+ ,public IDispResource -+#endif - { - public: - CVideoReferenceClock(); -+ virtual ~CVideoReferenceClock(); - - int64_t GetTime(bool interpolated = true); - int64_t GetFrequency(); -@@ -75,6 +80,11 @@ class CVideoReferenceClock : public CThread - void VblankHandler(int64_t nowtime, double fps); - #endif - -+#if defined(HAS_GLX) && defined(HAS_XRANDR) -+ virtual void OnLostDevice(); -+ virtual void OnResetDevice(); -+#endif -+ - private: - void Process(); - bool UpdateRefreshrate(bool Forced = false); -@@ -121,7 +131,8 @@ class CVideoReferenceClock : public CThread - GLXContext m_Context; - Pixmap m_pixmap; - GLXPixmap m_glPixmap; -- int m_RREventBase; -+ bool m_xrrEvent; -+ CEvent m_releaseEvent, m_resetEvent; - - bool m_UseNvSettings; - bool m_bIsATI; --- -1.7.10 - - -From 702f79eab647ec68030c99d6113976f3c602e87c Mon Sep 17 00:00:00 2001 -From: xbmc -Date: Thu, 21 Jun 2012 17:26:51 +0200 -Subject: [PATCH 27/73] X11: fix video calibrations - ---- - xbmc/settings/Settings.cpp | 1 + - xbmc/windowing/WinSystem.h | 1 + - xbmc/windowing/X11/WinSystemX11.cpp | 36 ++++++++++++++++++++++++++++++++++- - xbmc/windowing/X11/WinSystemX11.h | 1 + - 4 files changed, 38 insertions(+), 1 deletion(-) - -diff --git a/xbmc/settings/Settings.cpp b/xbmc/settings/Settings.cpp -index 8a430ad..fde6e4e 100644 ---- a/xbmc/settings/Settings.cpp -+++ b/xbmc/settings/Settings.cpp -@@ -55,6 +55,7 @@ - #include "filesystem/File.h" - #include "filesystem/DirectoryCache.h" - #include "DatabaseManager.h" -+#include "windowing/WindowingFactory.h" - - using namespace std; - using namespace XFILE; -diff --git a/xbmc/windowing/WinSystem.h b/xbmc/windowing/WinSystem.h -index 05c5eda..852d085 100644 ---- a/xbmc/windowing/WinSystem.h -+++ b/xbmc/windowing/WinSystem.h -@@ -100,6 +100,7 @@ class CWinSystemBase - std::vector ScreenResolutions(int screen); - std::vector RefreshRates(int screen, int width, int height, uint32_t dwFlags); - REFRESHRATE DefaultRefreshRate(int screen, std::vector rates); -+ virtual bool HasCalibration(const RESOLUTION_INFO &resInfo) { return true; }; - - protected: - void UpdateDesktopResolution(RESOLUTION_INFO& newRes, int screen, int width, int height, float refreshRate, uint32_t dwFlags = 0); -diff --git a/xbmc/windowing/X11/WinSystemX11.cpp b/xbmc/windowing/X11/WinSystemX11.cpp -index d3d15e2..487b324 100644 ---- a/xbmc/windowing/X11/WinSystemX11.cpp -+++ b/xbmc/windowing/X11/WinSystemX11.cpp -@@ -320,7 +320,7 @@ void CWinSystemX11::UpdateResolutions() - res.strMode.Format("%s: %s @ %.2fHz", out->name.c_str(), mode.name.c_str(), mode.hz); - res.strOutput = out->name; - res.strId = mode.id; -- res.iSubtitles = (int)(0.95*mode.h); -+ res.iSubtitles = (int)(0.965*mode.h); - res.fRefreshRate = mode.hz; - res.bFullScreen = true; - -@@ -333,8 +333,42 @@ void CWinSystemX11::UpdateResolutions() - g_settings.m_ResInfo.push_back(res); - } - } -+ g_settings.ApplyCalibrations(); - #endif -+} -+ -+bool CWinSystemX11::HasCalibration(const RESOLUTION_INFO &resInfo) -+{ -+ XOutput *out = g_xrandr.GetOutput(m_currentOutput); -+ -+ // keep calibrations done on a not connected output -+ if (!out->name.Equals(resInfo.strOutput)) -+ return true; -+ -+ // keep calibrations not updated with resolution data -+ if (resInfo.iWidth == 0) -+ return true; -+ -+ float fPixRatio; -+ if (resInfo.iHeight>0 && resInfo.iWidth>0 && out->hmm>0 && out->wmm>0) -+ fPixRatio = ((float)out->wmm/(float)resInfo.iWidth) / (((float)out->hmm/(float)resInfo.iHeight)); -+ else -+ fPixRatio = 1.0f; - -+ if (resInfo.Overscan.left != 0) -+ return true; -+ if (resInfo.Overscan.top != 0) -+ return true; -+ if (resInfo.Overscan.right != resInfo.iWidth) -+ return true; -+ if (resInfo.Overscan.bottom != resInfo.iHeight) -+ return true; -+ if (resInfo.fPixelRatio != fPixRatio) -+ return true; -+ if (resInfo.iSubtitles != (int)(0.965*resInfo.iHeight)) -+ return true; -+ -+ return false; - } - - void CWinSystemX11::GetConnectedOutputs(std::vector *outputs) -diff --git a/xbmc/windowing/X11/WinSystemX11.h b/xbmc/windowing/X11/WinSystemX11.h -index cc28f56..c046c86 100644 ---- a/xbmc/windowing/X11/WinSystemX11.h -+++ b/xbmc/windowing/X11/WinSystemX11.h -@@ -61,6 +61,7 @@ class CWinSystemX11 : public CWinSystemBase - virtual bool Show(bool raise = true); - virtual void Register(IDispResource *resource); - virtual void Unregister(IDispResource *resource); -+ virtual bool HasCalibration(const RESOLUTION_INFO &resInfo); - - // Local to WinSystemX11 only - Display* GetDisplay() { return m_dpy; } --- -1.7.10 - - -From 07920e322c9770ebb99becd104ebce0789c502fa Mon Sep 17 00:00:00 2001 -From: FernetMenta -Date: Thu, 5 Jul 2012 12:00:26 +0200 -Subject: [PATCH 28/73] X11: deactivate screen saver on startup - ---- - xbmc/windowing/X11/WinSystemX11.cpp | 29 +++++++++++++++++++++++++++++ - xbmc/windowing/X11/WinSystemX11.h | 1 + - 2 files changed, 30 insertions(+) - -diff --git a/xbmc/windowing/X11/WinSystemX11.cpp b/xbmc/windowing/X11/WinSystemX11.cpp -index 487b324..b3e7ab5 100644 ---- a/xbmc/windowing/X11/WinSystemX11.cpp -+++ b/xbmc/windowing/X11/WinSystemX11.cpp -@@ -521,6 +521,33 @@ void CWinSystemX11::ResetOSScreensaver() - } - } - -+void CWinSystemX11::EnableSystemScreenSaver(bool bEnable) -+{ -+ if (!m_dpy) -+ return; -+ -+ if (bEnable) -+ XForceScreenSaver(m_dpy, ScreenSaverActive); -+ else -+ { -+ Window root_return, child_return; -+ int root_x_return, root_y_return; -+ int win_x_return, win_y_return; -+ unsigned int mask_return; -+ bool isInWin = XQueryPointer(m_dpy, RootWindow(m_dpy, m_nScreen), &root_return, &child_return, -+ &root_x_return, &root_y_return, -+ &win_x_return, &win_y_return, -+ &mask_return); -+ -+ XWarpPointer(m_dpy, None, RootWindow(m_dpy, m_nScreen), 0, 0, 0, 0, root_x_return+300, root_y_return+300); -+ XSync(m_dpy, FALSE); -+ XWarpPointer(m_dpy, None, RootWindow(m_dpy, m_nScreen), 0, 0, 0, 0, 0, 0); -+ XSync(m_dpy, FALSE); -+ XWarpPointer(m_dpy, None, RootWindow(m_dpy, m_nScreen), 0, 0, 0, 0, root_x_return, root_y_return); -+ XSync(m_dpy, FALSE); -+ } -+} -+ - void CWinSystemX11::NotifyAppActiveChange(bool bActivated) - { - if (bActivated && m_bWasFullScreenBeforeMinimize && !m_bFullScreen) -@@ -764,6 +791,8 @@ bool CWinSystemX11::SetWindow(int width, int height, bool fullscreen, const CStd - // create main window - if (!m_glWindow) - { -+ EnableSystemScreenSaver(false); -+ - GLint att[] = - { - GLX_RGBA, -diff --git a/xbmc/windowing/X11/WinSystemX11.h b/xbmc/windowing/X11/WinSystemX11.h -index c046c86..e953d2d 100644 ---- a/xbmc/windowing/X11/WinSystemX11.h -+++ b/xbmc/windowing/X11/WinSystemX11.h -@@ -51,6 +51,7 @@ class CWinSystemX11 : public CWinSystemBase - virtual void ShowOSMouse(bool show); - virtual void ResetOSScreensaver(); - virtual bool EnableFrameLimiter(); -+ virtual void EnableSystemScreenSaver(bool bEnable); - - virtual void NotifyAppActiveChange(bool bActivated); - virtual void NotifyAppFocusChange(bool bGaining); --- -1.7.10 - - -From 835bcc9c7fd477012492ffc4cad2bdd9ce506064 Mon Sep 17 00:00:00 2001 -From: FernetMenta -Date: Thu, 5 Jul 2012 12:10:09 +0200 -Subject: [PATCH 29/73] X11: change method of going full-screen - ---- - xbmc/windowing/X11/WinSystemX11.cpp | 9 ++++++++- - 1 file changed, 8 insertions(+), 1 deletion(-) - -diff --git a/xbmc/windowing/X11/WinSystemX11.cpp b/xbmc/windowing/X11/WinSystemX11.cpp -index b3e7ab5..91f92c1 100644 ---- a/xbmc/windowing/X11/WinSystemX11.cpp -+++ b/xbmc/windowing/X11/WinSystemX11.cpp -@@ -34,6 +34,7 @@ - #include "utils/TimeUtils.h" - #include "settings/GUISettings.h" - #include "windowing/WindowingFactory.h" -+#include - - #if defined(HAS_XRANDR) - #include -@@ -816,7 +817,7 @@ bool CWinSystemX11::SetWindow(int width, int height, bool fullscreen, const CStd - cmap = XCreateColormap(m_dpy, RootWindow(m_dpy, vi->screen), vi->visual, AllocNone); - - int def_vis = (vi->visual == DefaultVisual(m_dpy, vi->screen)); -- swa.override_redirect = fullscreen ? True : False; -+ swa.override_redirect = False; - swa.border_pixel = fullscreen ? 0 : 5; - swa.background_pixel = def_vis ? BlackPixel(m_dpy, vi->screen) : 0; - swa.colormap = cmap; -@@ -832,6 +833,12 @@ bool CWinSystemX11::SetWindow(int width, int height, bool fullscreen, const CStd - InputOutput, vi->visual, - mask, &swa); - -+ if (fullscreen) -+ { -+ Atom fs = XInternAtom(m_dpy, "_NET_WM_STATE_FULLSCREEN", True); -+ XChangeProperty(m_dpy, m_glWindow, XInternAtom(m_dpy, "_NET_WM_STATE", True), XA_ATOM, 32, PropModeReplace, (unsigned char *) &fs, 1); -+ } -+ - // define invisible cursor - Pixmap bitmapNoData; - XColor black; --- -1.7.10 - - -From e2442797ff82b3ed8053f1a6422863ffce9cbe5f Mon Sep 17 00:00:00 2001 -From: xbmc -Date: Thu, 28 Jun 2012 19:12:39 +0200 -Subject: [PATCH 30/73] X11: reset key repeat and key modifier on focus lost - and gain - ---- - xbmc/windowing/WinEventsX11.cpp | 3 +++ - 1 file changed, 3 insertions(+) - -diff --git a/xbmc/windowing/WinEventsX11.cpp b/xbmc/windowing/WinEventsX11.cpp -index 6c22358..d86205d 100644 ---- a/xbmc/windowing/WinEventsX11.cpp -+++ b/xbmc/windowing/WinEventsX11.cpp -@@ -359,6 +359,8 @@ bool CWinEventsX11::MessagePump() - if (WinEvents->m_xic) - XSetICFocus(WinEvents->m_xic); - g_application.m_AppFocused = true; -+ memset(&(WinEvents->m_lastKey), 0, sizeof(XBMC_Event)); -+ WinEvents->m_keymodState = 0; - if (serial == xevent.xfocus.serial) - break; - g_Windowing.NotifyAppFocusChange(g_application.m_AppFocused); -@@ -370,6 +372,7 @@ bool CWinEventsX11::MessagePump() - if (WinEvents->m_xic) - XUnsetICFocus(WinEvents->m_xic); - g_application.m_AppFocused = false; -+ memset(&(WinEvents->m_lastKey), 0, sizeof(XBMC_Event)); - g_Windowing.NotifyAppFocusChange(g_application.m_AppFocused); - serial = xevent.xfocus.serial; - break; --- -1.7.10 - - -From 77a22163a7f611e9183b7cd0b817fc51a42d45de Mon Sep 17 00:00:00 2001 -From: Joakim Plate -Date: Thu, 5 Jul 2012 14:18:46 +0200 -Subject: [PATCH 31/73] X11: replace custom utf8 to unicode with charset - convertor (squash to x11 events) - ---- - xbmc/windowing/WinEventsX11.cpp | 119 ++++----------------------------------- - xbmc/windowing/WinEventsX11.h | 2 - - 2 files changed, 11 insertions(+), 110 deletions(-) - -diff --git a/xbmc/windowing/WinEventsX11.cpp b/xbmc/windowing/WinEventsX11.cpp -index d86205d..76702e6 100644 ---- a/xbmc/windowing/WinEventsX11.cpp -+++ b/xbmc/windowing/WinEventsX11.cpp -@@ -32,6 +32,7 @@ - #include "X11/keysymdef.h" - #include "X11/XF86keysym.h" - #include "utils/log.h" -+#include "utils/CharsetConverter.h" - #include "guilib/GUIWindowManager.h" - #include "input/MouseStat.h" - -@@ -161,7 +162,6 @@ - m_display = 0; - m_window = 0; - m_keybuf = 0; -- m_utf16buf = 0; - } - - CWinEventsX11::~CWinEventsX11() -@@ -172,12 +172,6 @@ - m_keybuf = 0; - } - -- if (m_utf16buf) -- { -- free(m_utf16buf); -- m_utf16buf = 0; -- } -- - if (m_xic) - { - XUnsetICFocus(m_xic); -@@ -203,7 +197,6 @@ bool CWinEventsX11::Init(Display *dpy, Window win) - WinEvents->m_display = dpy; - WinEvents->m_window = win; - WinEvents->m_keybuf = (char*)malloc(32*sizeof(char)); -- WinEvents->m_utf16buf = (uint16_t*)malloc(32*sizeof(uint16_t)); - WinEvents->m_keymodState = 0; - WinEvents->m_wmDeleteMessage = XInternAtom(dpy, "WM_DELETE_WINDOW", False); - WinEvents->m_structureChanged = false; -@@ -433,8 +426,6 @@ bool CWinEventsX11::MessagePump() - } - - Status status; -- int utf16size; -- int utf16length; - int len; - len = Xutf8LookupString(WinEvents->m_xic, &xevent.xkey, - WinEvents->m_keybuf, sizeof(WinEvents->m_keybuf), -@@ -453,36 +444,29 @@ bool CWinEventsX11::MessagePump() - case XLookupChars: - case XLookupBoth: - { -- if (len == 0) -- break; -- utf16size = len * sizeof(uint16_t); -- if (utf16size > sizeof(WinEvents->m_utf16buf)) -- { -- WinEvents->m_utf16buf = (uint16_t *)realloc(WinEvents->m_utf16buf,utf16size); -- if (WinEvents->m_utf16buf == NULL) -- { -- break; -- } -- } -- utf16length = Utf8ToUnicode(WinEvents->m_keybuf, len, WinEvents->m_utf16buf, utf16size); -- if (utf16length < 0) -+ CStdString data(WinEvents->m_keybuf, len); -+ CStdStringW keys; -+ g_charsetConverter.utf8ToW(data, keys, false); -+ -+ if (keys.length() == 0) - { - break; - } -- for (unsigned int i = 0; i < utf16length - 1; i++) -+ -+ for (unsigned int i = 0; i < keys.length() - 1; i++) - { - newEvent.key.keysym.sym = XBMCK_UNKNOWN; -- newEvent.key.keysym.unicode = WinEvents->m_utf16buf[i]; -+ newEvent.key.keysym.unicode = keys[i]; - newEvent.key.state = xevent.xkey.state; - newEvent.key.type = xevent.xkey.type; - ret |= ProcessKey(newEvent, 500); - } -- if (utf16length > 0) -+ if (keys.length() > 0) - { - newEvent.key.keysym.scancode = xevent.xkey.keycode; - xkeysym = XLookupKeysym(&xevent.xkey, 0); - newEvent.key.keysym.sym = LookupXbmcKeySym(xkeysym); -- newEvent.key.keysym.unicode = WinEvents->m_utf16buf[utf16length - 1]; -+ newEvent.key.keysym.unicode = keys[keys.length() - 1]; - newEvent.key.state = xevent.xkey.state; - newEvent.key.type = xevent.xkey.type; - -@@ -743,87 +727,6 @@ bool CWinEventsX11::ProcessKeyRepeat() - return false; - } - --int CWinEventsX11::Utf8ToUnicode(const char *utf8, const int utf8Length, uint16_t *utf16, const int utf16MaxLength) --{ -- // p moves over the output buffer. max_ptr points to the next to the last slot of the buffer. -- uint16_t *p = utf16; -- uint16_t const *const maxPtr = utf16 + utf16MaxLength; -- -- // end_of_input points to the last byte of input as opposed to the next to the last byte. -- char const *const endOfInput = utf8 + utf8Length - 1; -- -- while (utf8 <= endOfInput) -- { -- unsigned char const c = *utf8; -- if (p >= maxPtr) -- { -- //No more output space. -- return -1; -- } -- if (c < 0x80) -- { -- //One byte ASCII. -- *p++ = c; -- utf8 += 1; -- } -- else if (c < 0xC0) -- { -- // Follower byte without preceding leader bytes. -- return -1; -- } -- // 11 bits -- else if (c < 0xE0) -- { -- // Two byte sequence. We need one follower byte. -- if (endOfInput - utf8 < 1 || (((utf8[1] ^ 0x80)) & 0xC0)) -- { -- return -1; -- } -- *p++ = (uint16_t)(((c & 0x1F) << 6) + (utf8[1] & 0x3F)); -- utf8 += 2; -- } -- // 16 bis -- else if (c < 0xF0) -- { -- // Three byte sequence. We need two follower byte. -- if (endOfInput - utf8 < 2 || ((utf8[1] ^ 0x80) & 0xC0) || ((utf8[2] ^ 0x80) & 0xC0)) -- { -- return -1; -- } -- *p++ = (uint16_t)(((c & 0xF) << 12) + ((utf8[1] & 0x3F) << 6) + (utf8[2] & 0x3F)); -- utf8 += 3; -- } -- // 21 bits -- else if (c < 0xF8) -- { -- int plane; -- // Four byte sequence. We need three follower bytes. -- if (endOfInput - utf8 < 3 || ((utf8[1] ^ 0x80) & 0xC0) || -- ((utf8[2] ^ 0x80) & 0xC0) || ((utf8[3] ^ 0x80) & 0xC0)) -- { -- return -1; -- } -- uint32_t unicode = ((c & 0x7) << 18) + ((utf8[1] & 0x3F) << 12) + -- ((utf8[2] & 0x3F) << 6) + (utf8[3] & 0x3F); -- utf8 += 4; -- CLog::Log(LOGERROR, "CWinEventsX11::Utf8ToUnicode: 4 byte unicode not supported"); -- } -- // 26 bits -- else if (c < 0xFC) -- { -- CLog::Log(LOGERROR, "CWinEventsX11::Utf8ToUnicode: 4 byte unicode not supported"); -- utf8 += 5; -- } -- // 31 bit -- else -- { -- CLog::Log(LOGERROR, "CWinEventsX11::Utf8ToUnicode: 4 byte unicode not supported"); -- utf8 += 6; -- } -- } -- return p - utf16; --} -- - XBMCKey CWinEventsX11::LookupXbmcKeySym(KeySym keysym) - { - // try direct mapping first -diff --git a/xbmc/windowing/WinEventsX11.h b/xbmc/windowing/WinEventsX11.h -index 6100933..72955ad 100644 ---- a/xbmc/windowing/WinEventsX11.h -+++ b/xbmc/windowing/WinEventsX11.h -@@ -38,7 +38,6 @@ class CWinEventsX11 : public CWinEventsBase - static bool MessagePump(); - - protected: -- static int Utf8ToUnicode(const char *utf8, const int utf8Length, uint16_t *utf16, const int utf16MaxLength); - static XBMCKey LookupXbmcKeySym(KeySym keysym); - static bool ProcessKey(XBMC_Event &event, int repeatDelay); - static bool ProcessKeyRepeat(); -@@ -48,7 +47,6 @@ class CWinEventsX11 : public CWinEventsBase - Window m_window; - Atom m_wmDeleteMessage; - char *m_keybuf; -- uint16_t *m_utf16buf; - XIM m_xim; - XIC m_xic; - XBMC_Event m_lastKey; --- -1.7.10 - - -From e060b3197bbac54b79b604bbbf9a8e86257980f5 Mon Sep 17 00:00:00 2001 -From: Joakim Plate -Date: Thu, 5 Jul 2012 14:23:54 +0200 -Subject: [PATCH 32/73] X11: fixed invalid usage of sizeof() (squash into x11 - changes) - ---- - xbmc/windowing/WinEventsX11.cpp | 11 +++++++---- - xbmc/windowing/WinEventsX11.h | 1 + - 2 files changed, 8 insertions(+), 4 deletions(-) - -diff --git a/xbmc/windowing/WinEventsX11.cpp b/xbmc/windowing/WinEventsX11.cpp -index 76702e6..c31877e 100644 ---- a/xbmc/windowing/WinEventsX11.cpp -+++ b/xbmc/windowing/WinEventsX11.cpp -@@ -162,6 +162,7 @@ - m_display = 0; - m_window = 0; - m_keybuf = 0; -+ m_keybuf_len = 0; - } - - CWinEventsX11::~CWinEventsX11() -@@ -196,7 +197,8 @@ bool CWinEventsX11::Init(Display *dpy, Window win) - WinEvents = new CWinEventsX11(); - WinEvents->m_display = dpy; - WinEvents->m_window = win; -- WinEvents->m_keybuf = (char*)malloc(32*sizeof(char)); -+ WinEvents->m_keybuf_len = 32*sizeof(char); -+ WinEvents->m_keybuf = (char*)malloc(WinEvents->m_keybuf_len); - WinEvents->m_keymodState = 0; - WinEvents->m_wmDeleteMessage = XInternAtom(dpy, "WM_DELETE_WINDOW", False); - WinEvents->m_structureChanged = false; -@@ -428,13 +430,14 @@ bool CWinEventsX11::MessagePump() - Status status; - int len; - len = Xutf8LookupString(WinEvents->m_xic, &xevent.xkey, -- WinEvents->m_keybuf, sizeof(WinEvents->m_keybuf), -+ WinEvents->m_keybuf, WinEvents->m_keybuf_len, - &xkeysym, &status); - if (status == XBufferOverflow) - { -- WinEvents->m_keybuf = (char*)realloc(WinEvents->m_keybuf, len*sizeof(char)); -+ WinEvents->m_keybuf_len = len; -+ WinEvents->m_keybuf = (char*)realloc(WinEvents->m_keybuf, WinEvents->m_keybuf_len); - len = Xutf8LookupString(WinEvents->m_xic, &xevent.xkey, -- WinEvents->m_keybuf, sizeof(WinEvents->m_keybuf), -+ WinEvents->m_keybuf, WinEvents->m_keybuf_len, - &xkeysym, &status); - } - switch (status) -diff --git a/xbmc/windowing/WinEventsX11.h b/xbmc/windowing/WinEventsX11.h -index 72955ad..102a076 100644 ---- a/xbmc/windowing/WinEventsX11.h -+++ b/xbmc/windowing/WinEventsX11.h -@@ -47,6 +47,7 @@ class CWinEventsX11 : public CWinEventsBase - Window m_window; - Atom m_wmDeleteMessage; - char *m_keybuf; -+ size_t m_keybuf_len; - XIM m_xim; - XIC m_xic; - XBMC_Event m_lastKey; --- -1.7.10 - - -From c52af3ba68292f08331cbbbc940dfcea838a2f44 Mon Sep 17 00:00:00 2001 -From: xbmc -Date: Sat, 9 Jun 2012 18:23:53 +0200 -Subject: [PATCH 33/73] add missing keys to xbmc keytable - ---- - xbmc/input/XBMC_keytable.cpp | 2 ++ - 1 file changed, 2 insertions(+) - -diff --git a/xbmc/input/XBMC_keytable.cpp b/xbmc/input/XBMC_keytable.cpp -index aaf65ba..9d7922f 100644 ---- a/xbmc/input/XBMC_keytable.cpp -+++ b/xbmc/input/XBMC_keytable.cpp -@@ -179,6 +179,8 @@ - , { XBMCK_LAUNCH_APP2, 0, 0, XBMCVK_LAUNCH_APP2, "launch_app2_pc_icon" } - , { XBMCK_LAUNCH_FILE_BROWSER, 0, 0, XBMCVK_LAUNCH_FILE_BROWSER, "launch_file_browser" } - , { XBMCK_LAUNCH_MEDIA_CENTER, 0, 0, XBMCVK_LAUNCH_MEDIA_CENTER, "launch_media_center" } -+, { XBMCK_PLAY, 0, 0, XBMCVK_MEDIA_PLAY_PAUSE, "play_pause" } -+, { XBMCK_STOP, 0, 0, XBMCVK_MEDIA_STOP, "stop" } - - // Function keys - , { XBMCK_F1, 0, 0, XBMCVK_F1, "f1"} --- -1.7.10 - - -From 25587ee807eca2fc9dde4528e3fc930b337e38b0 Mon Sep 17 00:00:00 2001 -From: xbmc -Date: Fri, 16 Mar 2012 15:57:51 +0100 -Subject: [PATCH 34/73] videorefclock: temp deactivate of nv settings - ---- - xbmc/video/VideoReferenceClock.cpp | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/xbmc/video/VideoReferenceClock.cpp b/xbmc/video/VideoReferenceClock.cpp -index fa8e35a..85e36c7 100644 ---- a/xbmc/video/VideoReferenceClock.cpp -+++ b/xbmc/video/VideoReferenceClock.cpp -@@ -135,7 +135,7 @@ - m_Context = NULL; - m_pixmap = None; - m_glPixmap = None; -- m_UseNvSettings = true; -+ m_UseNvSettings = false; - m_bIsATI = false; - #endif - } --- -1.7.10 - - -From 4f8a95de09408321e2df3da891536c314fe3b4d2 Mon Sep 17 00:00:00 2001 -From: xbmc -Date: Mon, 20 Aug 2012 09:09:09 +0200 -Subject: [PATCH 35/73] videorefclock: ask graphics context for refresh rate - ---- - xbmc/video/VideoReferenceClock.cpp | 3 ++- - 1 file changed, 2 insertions(+), 1 deletion(-) - -diff --git a/xbmc/video/VideoReferenceClock.cpp b/xbmc/video/VideoReferenceClock.cpp -index 85e36c7..8209163 100644 ---- a/xbmc/video/VideoReferenceClock.cpp -+++ b/xbmc/video/VideoReferenceClock.cpp -@@ -30,6 +30,7 @@ - #include - #include - #include "windowing/WindowingFactory.h" -+ #include "guilib/GraphicContext.h" - #define NVSETTINGSCMD "nvidia-settings -nt -q RefreshRate3" - #elif defined(TARGET_DARWIN_OSX) - #include -@@ -1254,7 +1255,7 @@ bool CVideoReferenceClock::UpdateRefreshrate(bool Forced /*= false*/) - } - - CSingleLock SingleLock(m_CritSection); -- m_RefreshRate = GetRandRRate(); -+ m_RefreshRate = MathUtils::round_int(g_graphicsContext.GetFPS()); - - CLog::Log(LOGDEBUG, "CVideoReferenceClock: Detected refreshrate: %i hertz", (int)m_RefreshRate); - --- -1.7.10 - - -From 85d81f0c933cb0a75c2c21de86b4065e3db86002 Mon Sep 17 00:00:00 2001 -From: xbmc -Date: Mon, 9 Jul 2012 14:00:18 +0200 -Subject: [PATCH 36/73] X11: fix icon texture after - cc5ed3c2474084ebc0373a3046410e6f766e03f4 - ---- - xbmc/windowing/X11/WinSystemX11.cpp | 43 +++++++++++++++++++++-------------- - 1 file changed, 26 insertions(+), 17 deletions(-) - -diff --git a/xbmc/windowing/X11/WinSystemX11.cpp b/xbmc/windowing/X11/WinSystemX11.cpp -index 91f92c1..174ccef 100644 ---- a/xbmc/windowing/X11/WinSystemX11.cpp -+++ b/xbmc/windowing/X11/WinSystemX11.cpp -@@ -874,22 +874,24 @@ bool CWinSystemX11::SetWindow(int width, int height, bool fullscreen, const CStd - if (!fullscreen) - { - CreateIconPixmap(); -- XWMHints wm_hints; -- XClassHint class_hints; -+ XWMHints *wm_hints; - XTextProperty windowName, iconName; - std::string titleString = "XBMC Media Center"; - char *title = (char*)titleString.c_str(); - - XStringListToTextProperty(&title, 1, &windowName); - XStringListToTextProperty(&title, 1, &iconName); -- wm_hints.initial_state = NormalState; -- wm_hints.input = True; -- wm_hints.icon_pixmap = m_icon; -- wm_hints.flags = StateHint | IconPixmapHint | InputHint; - -+ wm_hints = XAllocWMHints(); -+ wm_hints->initial_state = NormalState; -+ wm_hints->icon_pixmap = m_icon; -+ wm_hints->flags = StateHint | IconPixmapHint; -+ -+ XSync(m_dpy,False); - XSetWMProperties(m_dpy, m_glWindow, &windowName, &iconName, -- NULL, 0, NULL, &wm_hints, -+ NULL, 0, NULL, wm_hints, - NULL); -+ XFree(wm_hints); - - // register interest in the delete window message - Atom wmDeleteMessage = XInternAtom(m_dpy, "WM_DELETE_WINDOW", False); -@@ -974,16 +976,21 @@ bool CWinSystemX11::CreateIconPixmap() - gRatio = vis->green_mask / 255.0; - bRatio = vis->blue_mask / 255.0; - -- CTexture iconTexture; -- iconTexture.LoadFromFile("special://xbmc/media/icon.png"); -- buf = iconTexture.GetPixels(); -+ CBaseTexture *iconTexture = CBaseTexture::LoadFromFile("special://xbmc/media/icon.png"); -+ -+ if (!iconTexture) -+ return false; - -- numBufBytes = iconTexture.GetWidth() * iconTexture.GetHeight() * 4; -+ buf = iconTexture->GetPixels(); -+ -+ numBufBytes = iconTexture->GetWidth() * iconTexture->GetHeight() * 4; -+ int wid = iconTexture->GetWidth(); -+ int hi = iconTexture->GetHeight(); - - if (depth>=24) -- numNewBufBytes = (4 * (iconTexture.GetWidth() * iconTexture.GetHeight())); -+ numNewBufBytes = (4 * (iconTexture->GetWidth() * iconTexture->GetHeight())); - else -- numNewBufBytes = (2 * (iconTexture.GetWidth() * iconTexture.GetHeight())); -+ numNewBufBytes = (2 * (iconTexture->GetWidth() * iconTexture->GetHeight())); - - newBuf = (uint32_t*)malloc(numNewBufBytes); - if (!newBuf) -@@ -992,11 +999,11 @@ bool CWinSystemX11::CreateIconPixmap() - return false; - } - -- for (i=0; iGetHeight();++i) - { -- for (j=0; jGetWidth();++j) - { -- unsigned int pos = i*iconTexture.GetPitch()+j*4; -+ unsigned int pos = i*iconTexture->GetPitch()+j*4; - unsigned int r, g, b; - r = (buf[pos+2] * rRatio); - g = (buf[pos+1] * gRatio); -@@ -1009,7 +1016,7 @@ bool CWinSystemX11::CreateIconPixmap() - } - } - img = XCreateImage(m_dpy, vis, depth,ZPixmap, 0, (char *)newBuf, -- iconTexture.GetWidth(), iconTexture.GetHeight(), -+ iconTexture->GetWidth(), iconTexture->GetHeight(), - (depth>=24)?32:16, 0); - if (!img) - { -@@ -1047,6 +1054,8 @@ bool CWinSystemX11::CreateIconPixmap() - XFreeGC(m_dpy, gc); - XDestroyImage(img); // this also frees newBuf - -+ delete iconTexture; -+ - return true; - } - --- -1.7.10 - - -From 111c2f8fd0f6b698fbff0fda6dc6c17ce3644626 Mon Sep 17 00:00:00 2001 -From: xbmc -Date: Tue, 10 Jul 2012 11:14:12 +0200 -Subject: [PATCH 37/73] X11: check for window manager - ---- - xbmc/windowing/X11/WinSystemX11.cpp | 74 ++++++++++++++++++++++++++++++++++- - xbmc/windowing/X11/WinSystemX11.h | 1 + - 2 files changed, 73 insertions(+), 2 deletions(-) - -diff --git a/xbmc/windowing/X11/WinSystemX11.cpp b/xbmc/windowing/X11/WinSystemX11.cpp -index 174ccef..4f1ae26 100644 ---- a/xbmc/windowing/X11/WinSystemX11.cpp -+++ b/xbmc/windowing/X11/WinSystemX11.cpp -@@ -816,8 +816,10 @@ bool CWinSystemX11::SetWindow(int width, int height, bool fullscreen, const CStd - vi = glXChooseVisual(m_dpy, m_nScreen, att); - cmap = XCreateColormap(m_dpy, RootWindow(m_dpy, vi->screen), vi->visual, AllocNone); - -+ bool hasWM = HasWindowManager(); -+ - int def_vis = (vi->visual == DefaultVisual(m_dpy, vi->screen)); -- swa.override_redirect = False; -+ swa.override_redirect = hasWM ? False : True; - swa.border_pixel = fullscreen ? 0 : 5; - swa.background_pixel = def_vis ? BlackPixel(m_dpy, vi->screen) : 0; - swa.colormap = cmap; -@@ -833,7 +835,7 @@ bool CWinSystemX11::SetWindow(int width, int height, bool fullscreen, const CStd - InputOutput, vi->visual, - mask, &swa); - -- if (fullscreen) -+ if (fullscreen && hasWM) - { - Atom fs = XInternAtom(m_dpy, "_NET_WM_STATE_FULLSCREEN", True); - XChangeProperty(m_dpy, m_glWindow, XInternAtom(m_dpy, "_NET_WM_STATE", True), XA_ATOM, 32, PropModeReplace, (unsigned char *) &fs, 1); -@@ -1059,4 +1061,72 @@ bool CWinSystemX11::CreateIconPixmap() - return true; - } - -+bool CWinSystemX11::HasWindowManager() -+{ -+ Window wm_check; -+ unsigned char *data; -+ int status, real_format; -+ Atom real_type, prop; -+ unsigned long items_read, items_left, i; -+ char req = 0; -+ -+ prop = XInternAtom(m_dpy, "_NET_SUPPORTING_WM_CHECK", True); -+ if (prop == None) -+ return false; -+ status = XGetWindowProperty(m_dpy, DefaultRootWindow(m_dpy), prop, -+ 0L, 1L, False, XA_WINDOW, &real_type, &real_format, -+ &items_read, &items_left, &data); -+ if(status != Success || ! items_read) -+ { -+ if(status == Success) -+ XFree(data); -+ return false; -+ } -+ -+ wm_check = ((Window*)data)[0]; -+ XFree(data); -+ -+ status = XGetWindowProperty(m_dpy, wm_check, prop, -+ 0L, 1L, False, XA_WINDOW, &real_type, &real_format, -+ &items_read, &items_left, &data); -+ -+ if(status != Success || !items_read) -+ { -+ if(status == Success) -+ XFree(data); -+ return false; -+ } -+ -+ if(wm_check != ((Window*)data)[0]) -+ { -+ XFree(data); -+ return false; -+ } -+ -+ XFree(data); -+ -+ prop = XInternAtom(m_dpy, "_NET_WM_NAME", True); -+ if (prop == None) -+ { -+ CLog::Log(LOGDEBUG,"Window Manager Name: "); -+ return true; -+ } -+ -+ status = XGetWindowProperty(m_dpy, wm_check, prop, -+ 0L, (~0L), False, AnyPropertyType, &real_type, &real_format, -+ &items_read, &items_left, &data); -+ -+ if(status == Success && items_read) -+ { -+ CLog::Log(LOGDEBUG,"Window Manager Name: %s", data); -+ } -+ else -+ CLog::Log(LOGDEBUG,"Window Manager Name: "); -+ -+ if(status == Success) -+ XFree(data); -+ -+ return true; -+} -+ - #endif -diff --git a/xbmc/windowing/X11/WinSystemX11.h b/xbmc/windowing/X11/WinSystemX11.h -index e953d2d..0b7c10a 100644 ---- a/xbmc/windowing/X11/WinSystemX11.h -+++ b/xbmc/windowing/X11/WinSystemX11.h -@@ -101,6 +101,7 @@ class CWinSystemX11 : public CWinSystemBase - bool IsSuitableVisual(XVisualInfo *vInfo); - static int XErrorHandler(Display* dpy, XErrorEvent* error); - bool CreateIconPixmap(); -+ bool HasWindowManager(); - - CStopWatch m_screensaverReset; - }; --- -1.7.10 - - -From f1051e1991e5ef5d83ce428b841ac365082042ec Mon Sep 17 00:00:00 2001 -From: xbmc -Date: Thu, 12 Jul 2012 11:11:47 +0200 -Subject: [PATCH 38/73] X11: dont set window on xrandr if no mode available - ---- - xbmc/windowing/X11/WinSystemX11.cpp | 11 ++++++----- - 1 file changed, 6 insertions(+), 5 deletions(-) - -diff --git a/xbmc/windowing/X11/WinSystemX11.cpp b/xbmc/windowing/X11/WinSystemX11.cpp -index 4f1ae26..c11ea89 100644 ---- a/xbmc/windowing/X11/WinSystemX11.cpp -+++ b/xbmc/windowing/X11/WinSystemX11.cpp -@@ -665,16 +665,17 @@ void CWinSystemX11::NotifyXRREvent() - CLog::Log(LOGDEBUG, "%s - notify display reset event", __FUNCTION__); - m_windowDirty = true; - -+ if (!g_xrandr.Query(true)) -+ { -+ CLog::Log(LOGERROR, "WinSystemX11::RefreshWindow - failed to query xrandr"); -+ return; -+ } -+ - // if external event update resolutions - if (!m_bIsInternalXrr) - { - UpdateResolutions(); - } -- else if (!g_xrandr.Query(true)) -- { -- CLog::Log(LOGERROR, "WinSystemX11::RefreshWindow - failed to query xrandr"); -- return; -- } - m_bIsInternalXrr = false; - - CStdString currentOutput = g_guiSettings.GetString("videoscreen.monitor"); --- -1.7.10 - - -From 83b9c33e88077d957884ee22316c218e570dc3d5 Mon Sep 17 00:00:00 2001 -From: xbmc -Date: Thu, 26 Jul 2012 09:34:28 +0200 -Subject: [PATCH 39/73] X11: fix crash after a resolution change on startup - ---- - xbmc/windowing/X11/WinSystemX11.cpp | 3 ++- - 1 file changed, 2 insertions(+), 1 deletion(-) - -diff --git a/xbmc/windowing/X11/WinSystemX11.cpp b/xbmc/windowing/X11/WinSystemX11.cpp -index c11ea89..0bd72d4 100644 ---- a/xbmc/windowing/X11/WinSystemX11.cpp -+++ b/xbmc/windowing/X11/WinSystemX11.cpp -@@ -219,7 +219,8 @@ bool CWinSystemX11::SetFullScreen(bool fullScreen, RESOLUTION_INFO& res, bool bl - OnLostDevice(); - m_bIsInternalXrr = true; - g_xrandr.SetMode(out, mode); -- return true; -+ if (m_glWindow) -+ return true; - } - #endif - --- -1.7.10 - - -From b8956ed57f1b683ae79d7306c7461a31c894e9a9 Mon Sep 17 00:00:00 2001 -From: xbmc -Date: Sat, 15 Sep 2012 18:27:29 +0200 -Subject: [PATCH 40/73] X11: lock graphics context in NotifyXRREvent - ---- - xbmc/windowing/X11/WinSystemX11.cpp | 2 ++ - 1 file changed, 2 insertions(+) - -diff --git a/xbmc/windowing/X11/WinSystemX11.cpp b/xbmc/windowing/X11/WinSystemX11.cpp -index 0bd72d4..ef83133 100644 ---- a/xbmc/windowing/X11/WinSystemX11.cpp -+++ b/xbmc/windowing/X11/WinSystemX11.cpp -@@ -666,6 +666,8 @@ void CWinSystemX11::NotifyXRREvent() - CLog::Log(LOGDEBUG, "%s - notify display reset event", __FUNCTION__); - m_windowDirty = true; - -+ CSingleLock lock(g_graphicsContext); -+ - if (!g_xrandr.Query(true)) - { - CLog::Log(LOGERROR, "WinSystemX11::RefreshWindow - failed to query xrandr"); --- -1.7.10 - - -From aed5d244b81b1a0b171b7fea3b332decafc96c56 Mon Sep 17 00:00:00 2001 -From: Rainer Hochecker -Date: Sat, 8 Oct 2011 16:45:13 +0200 -Subject: [PATCH 41/73] ffmpeg: add xvba hwaccel - ---- - lib/ffmpeg/configure | 8 ++ - lib/ffmpeg/libavcodec/Makefile | 7 +- - lib/ffmpeg/libavcodec/allcodecs.c | 4 + - lib/ffmpeg/libavcodec/h264.c | 1 + - lib/ffmpeg/libavcodec/mpegvideo.c | 1 + - lib/ffmpeg/libavcodec/xvba.c | 66 ++++++++++++ - lib/ffmpeg/libavcodec/xvba.h | 71 ++++++++++++ - lib/ffmpeg/libavcodec/xvba_h264.c | 189 ++++++++++++++++++++++++++++++++ - lib/ffmpeg/libavcodec/xvba_internal.h | 24 +++++ - lib/ffmpeg/libavcodec/xvba_mpeg2.c | 52 +++++++++ - lib/ffmpeg/libavcodec/xvba_vc1.c | 190 +++++++++++++++++++++++++++++++++ - lib/ffmpeg/libavcodec/xvmc_internal.h | 4 +- - lib/ffmpeg/libavutil/pixdesc.c | 6 ++ - lib/ffmpeg/libavutil/pixfmt.h | 1 + - 14 files changed, 622 insertions(+), 2 deletions(-) - create mode 100644 lib/ffmpeg/libavcodec/xvba.c - create mode 100644 lib/ffmpeg/libavcodec/xvba.h - create mode 100644 lib/ffmpeg/libavcodec/xvba_h264.c - create mode 100644 lib/ffmpeg/libavcodec/xvba_internal.h - create mode 100644 lib/ffmpeg/libavcodec/xvba_mpeg2.c - create mode 100644 lib/ffmpeg/libavcodec/xvba_vc1.c - -diff --git a/lib/ffmpeg/configure b/lib/ffmpeg/configure -index c06005b..157cfd3 100755 ---- a/lib/ffmpeg/configure -+++ b/lib/ffmpeg/configure -@@ -113,6 +113,7 @@ Configuration options: - --enable-vdpau enable VDPAU code [autodetect] - --disable-dxva2 disable DXVA2 code - --disable-vda disable VDA 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 - --disable-safe-bitstream-reader -@@ -1084,6 +1085,7 @@ CONFIG_LIST=" - vaapi - vda - vdpau -+ xvba - version3 - x11grab - zlib -@@ -1423,6 +1425,7 @@ h264_dxva2_hwaccel_select="dxva2 h264_decoder" - h264_vaapi_hwaccel_select="vaapi h264_decoder" - h264_vda_hwaccel_deps="VideoDecodeAcceleration_VDADecoder_h pthreads" - h264_vda_hwaccel_select="vda h264_decoder" -+h264_xvba_hwaccel_select="xvba h264_decoder" - h264_vdpau_decoder_select="vdpau h264_decoder" - imc_decoder_select="fft mdct sinewin" - jpegls_decoder_select="golomb" -@@ -1459,6 +1462,7 @@ mpeg4_crystalhd_decoder_select="crystalhd" - mpeg4_decoder_select="h263_decoder mpeg4video_parser" - mpeg4_encoder_select="h263_encoder" - mpeg4_vaapi_hwaccel_select="vaapi mpeg4_decoder" -+mpeg2_xvba_hwaccel_select="xvba mpeg2video_decoder" - mpeg4_vdpau_decoder_select="vdpau mpeg4_decoder" - msmpeg4_crystalhd_decoder_select="crystalhd" - msmpeg4v1_decoder_select="h263_decoder" -@@ -1501,6 +1505,7 @@ vc1_decoder_select="h263_decoder h264chroma" - vc1_dxva2_hwaccel_deps="dxva2api_h" - 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" - vc1image_decoder_select="vc1_decoder" - vorbis_decoder_select="mdct" -@@ -1525,6 +1530,7 @@ wmv3_dxva2_hwaccel_select="vc1_dxva2_hwaccel" - wmv3_vaapi_hwaccel_select="vc1_vaapi_hwaccel" - wmv3_vdpau_decoder_select="vc1_vdpau_decoder" - wmv3image_decoder_select="wmv3_decoder" -+wmv3_xvba_hwaccel_select="vc1_xvba_hwaccel" - zlib_decoder_select="zlib" - zlib_encoder_select="zlib" - zmbv_decoder_select="zlib" -@@ -1533,6 +1539,7 @@ zmbv_encoder_select="zlib" - crystalhd_deps="libcrystalhd_libcrystalhd_if_h" - vaapi_deps="va_va_h" - vda_deps="VideoDecodeAcceleration_VDADecoder_h pthreads" -+xvba_deps="amd_amdxvba_h" - vdpau_deps="vdpau_vdpau_h vdpau_vdpau_x11_h" - - # parsers -@@ -3062,6 +3069,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 972cc59..fc441bf 100644 ---- a/lib/ffmpeg/libavcodec/Makefile -+++ b/lib/ffmpeg/libavcodec/Makefile -@@ -3,7 +3,7 @@ include $(SUBDIR)../config.mak - NAME = avcodec - FFLIBS = avutil - --HEADERS = avcodec.h avfft.h dxva2.h opt.h vaapi.h vda.h vdpau.h version.h xvmc.h -+HEADERS = avcodec.h avfft.h dxva2.h opt.h vaapi.h vda.h vdpau.h version.h xvmc.h xvba.h - - OBJS = allcodecs.o \ - audioconvert.o \ -@@ -51,6 +51,7 @@ OBJS-$(CONFIG_SINEWIN) += sinewin.o - OBJS-$(CONFIG_VAAPI) += vaapi.o - OBJS-$(CONFIG_VDA) += vda.o - OBJS-$(CONFIG_VDPAU) += vdpau.o -+OBJS-$(CONFIG_XVBA) += xvba.o - - # decoders/encoders/hardware accelerators - OBJS-$(CONFIG_A64MULTI_ENCODER) += a64multienc.o elbg.o -@@ -201,6 +202,7 @@ OBJS-$(CONFIG_H264_DECODER) += h264.o \ - OBJS-$(CONFIG_H264_DXVA2_HWACCEL) += dxva2_h264.o - OBJS-$(CONFIG_H264_VAAPI_HWACCEL) += vaapi_h264.o - OBJS-$(CONFIG_H264_VDA_HWACCEL) += vda_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 -@@ -284,6 +286,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 \ -@@ -431,6 +434,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 -@@ -732,6 +736,7 @@ SKIPHEADERS-$(CONFIG_LIBDIRAC) += libdirac.h - SKIPHEADERS-$(CONFIG_LIBSCHROEDINGER) += libschroedinger.h - SKIPHEADERS-$(CONFIG_VAAPI) += vaapi_internal.h - SKIPHEADERS-$(CONFIG_VDA) += vda_internal.h -+SKIPHEADERS-$(CONFIG_XVBA) += xvba_internal.h - SKIPHEADERS-$(CONFIG_VDPAU) += vdpau.h - SKIPHEADERS-$(CONFIG_XVMC) += xvmc.h - SKIPHEADERS-$(HAVE_W32THREADS) += w32pthreads.h -diff --git a/lib/ffmpeg/libavcodec/allcodecs.c b/lib/ffmpeg/libavcodec/allcodecs.c -index 32f3f52..0ff178e 100644 ---- a/lib/ffmpeg/libavcodec/allcodecs.c -+++ b/lib/ffmpeg/libavcodec/allcodecs.c -@@ -59,14 +59,18 @@ void avcodec_register_all(void) - REGISTER_HWACCEL (H264_VAAPI, h264_vaapi); - REGISTER_HWACCEL (H264_VDA, h264_vda); - REGISTER_HWACCEL (MPEG1_VDPAU, mpeg1_vdpau); -+ REGISTER_HWACCEL (H264_XVBA, h264_xvba); - REGISTER_HWACCEL (MPEG2_DXVA2, mpeg2_dxva2); - REGISTER_HWACCEL (MPEG2_VAAPI, mpeg2_vaapi); - REGISTER_HWACCEL (MPEG2_VDPAU, mpeg2_vdpau); - 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 c4785db..e9e7546 100644 ---- a/lib/ffmpeg/libavcodec/h264.c -+++ b/lib/ffmpeg/libavcodec/h264.c -@@ -60,6 +60,7 @@ - PIX_FMT_DXVA2_VLD, - PIX_FMT_VAAPI_VLD, - PIX_FMT_VDA_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 04c149a..b22b631 100644 ---- a/lib/ffmpeg/libavcodec/mpegvideo.c -+++ b/lib/ffmpeg/libavcodec/mpegvideo.c -@@ -136,6 +136,7 @@ static void dct_unquantize_h263_inter_c(MpegEncContext *s, - PIX_FMT_DXVA2_VLD, - PIX_FMT_VAAPI_VLD, - PIX_FMT_VDA_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..be29e5d ---- /dev/null -+++ b/lib/ffmpeg/libavcodec/xvba.c -@@ -0,0 +1,66 @@ -+/* -+ * 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 "xvba_internal.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 uint8_t *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..9f9ff0c ---- /dev/null -+++ b/lib/ffmpeg/libavcodec/xvba.h -@@ -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; -+ 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..a077442 ---- /dev/null -+++ b/lib/ffmpeg/libavcodec/xvba_h264.c -@@ -0,0 +1,189 @@ -+/* -+ * 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->f.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->f.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 == AV_PICTURE_TYPE_I) ? 1 : 0; -+ pic_descriptor->avc_reference = (s->current_picture_ptr->f.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; -+ -+ /* Set correct level */ -+ if (pic_descriptor->level == 41) { -+ const unsigned int mbw = pic_descriptor->width_in_mb; -+ const unsigned int mbh = pic_descriptor->height_in_mb; -+ const unsigned int max_ref_frames = 12288 * 1024 / (mbw * mbh * 384); -+ const unsigned int num_ref_frames = pic_descriptor->avc_num_ref_frames; -+ if (max_ref_frames < num_ref_frames) -+ pic_descriptor->level = 51; -+ } -+ -+ 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[0], h->pps.scaling_matrix8[0], sizeof(iq_matrix->bScalingLists8x8[0])); -+ memcpy(iq_matrix->bScalingLists8x8[1], h->pps.scaling_matrix8[3], sizeof(iq_matrix->bScalingLists8x8[0])); -+ -+ // Wait for an I-frame before start decoding. Workaround for ATI UVD and UVD+ GPUs -+ if (!h->got_first_iframe) { -+ if (h->slice_type != AV_PICTURE_TYPE_I && h->slice_type != AV_PICTURE_TYPE_SI) -+ 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 XVBA. */ -+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->f.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, -+ .start_frame = start_frame, -+ .end_frame = end_frame, -+ .decode_slice = decode_slice, -+}; -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..7315b62 ---- /dev/null -+++ b/lib/ffmpeg/libavcodec/xvba_vc1.c -@@ -0,0 +1,190 @@ -+/* -+ * 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->f.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->f.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 == AV_PICTURE_TYPE_I || v->bi_type == 1; -+ pic_descriptor->avc_reference = (s->current_picture_ptr->f.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 AV_PICTURE_TYPE_B: -+ next = (struct xvba_render_state *)s->next_picture.f.data[0]; -+ assert(next); -+ if (next) -+ pic_descriptor->past_surface = next->surface; -+ // fall-through -+ case AV_PICTURE_TYPE_P: -+ last = (struct xvba_render_state *)s->last_picture.f.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->f.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, -+ .start_frame = start_frame, -+ .end_frame = end_frame, -+ .decode_slice = decode_slice, -+}; -+#endif -+ -+AVHWAccel ff_vc1_xvba_hwaccel = { -+ .name = "vc1_xvba", -+ .type = AVMEDIA_TYPE_VIDEO, -+ .id = CODEC_ID_VC1, -+ .pix_fmt = PIX_FMT_XVBA_VLD, -+ .start_frame = start_frame, -+ .end_frame = end_frame, -+ .decode_slice = decode_slice, -+}; -diff --git a/lib/ffmpeg/libavcodec/xvmc_internal.h b/lib/ffmpeg/libavcodec/xvmc_internal.h -index 04197ce..d925eb1 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 e73fbfe..5abbd14 100644 ---- a/lib/ffmpeg/libavutil/pixdesc.c -+++ b/lib/ffmpeg/libavutil/pixdesc.c -@@ -874,6 +874,12 @@ void av_write_image_line(const uint16_t *src, uint8_t *data[4], const int linesi - .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_YUV420P9LE] = { - .name = "yuv420p9le", - .nb_components = 3, -diff --git a/lib/ffmpeg/libavutil/pixfmt.h b/lib/ffmpeg/libavutil/pixfmt.h -index f0d9c01..0f8cf7b 100644 ---- a/lib/ffmpeg/libavutil/pixfmt.h -+++ b/lib/ffmpeg/libavutil/pixfmt.h -@@ -129,6 +129,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_RGB444LE, ///< packed RGB 4:4:4, 16bpp, (msb)4A 4R 4G 4B(lsb), little-endian, most significant bits to 0 - PIX_FMT_RGB444BE, ///< packed RGB 4:4:4, 16bpp, (msb)4A 4R 4G 4B(lsb), big-endian, most significant bits to 0 --- -1.7.10 - - -From 922cada27e255bc3f685b700c2ffa4a146f87624 Mon Sep 17 00:00:00 2001 -From: xbmc -Date: Thu, 12 Apr 2012 12:09:31 +0200 -Subject: [PATCH 42/73] xvba: add decoder - ---- - configure.in | 48 + - language/English/strings.po | 12 +- - xbmc/cores/VideoRenderers/LinuxRendererGL.cpp | 218 +- - xbmc/cores/VideoRenderers/LinuxRendererGL.h | 15 +- - xbmc/cores/VideoRenderers/RenderFormats.h | 1 + - xbmc/cores/VideoRenderers/RenderManager.cpp | 9 +- - .../dvdplayer/DVDCodecs/Video/DVDVideoCodec.h | 4 + - .../DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp | 16 + - xbmc/cores/dvdplayer/DVDCodecs/Video/Makefile.in | 4 + - xbmc/cores/dvdplayer/DVDCodecs/Video/XVBA.cpp | 2354 ++++++++++++++++++++ - xbmc/cores/dvdplayer/DVDCodecs/Video/XVBA.h | 382 ++++ - xbmc/cores/dvdplayer/DVDPlayerVideo.cpp | 3 + - xbmc/settings/GUISettings.cpp | 3 + - xbmc/settings/VideoSettings.h | 2 + - xbmc/video/dialogs/GUIDialogVideoSettings.cpp | 1 + - 15 files changed, 3064 insertions(+), 8 deletions(-) - create mode 100644 xbmc/cores/dvdplayer/DVDCodecs/Video/XVBA.cpp - create mode 100644 xbmc/cores/dvdplayer/DVDCodecs/Video/XVBA.h - -diff --git a/configure.in b/configure.in -index 350d960..3660fa4 100644 ---- a/configure.in -+++ b/configure.in -@@ -124,6 +124,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. ==" -@@ -247,6 +249,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], -@@ -1759,6 +1767,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 -@@ -1970,6 +2010,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 -@@ -2443,6 +2489,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) -@@ -2626,6 +2673,7 @@ XB_CONFIG_MODULE([lib/ffmpeg], [ - `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 "$use_optimizations" != "no"; then echo --enable-optimizations; else echo --disable-optimizations; 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.po b/language/English/strings.po -index bba7284..ede18b3 100644 ---- a/language/English/strings.po -+++ b/language/English/strings.po -@@ -5124,7 +5124,11 @@ msgctxt "#13436" - msgid "Allow Vdpau OpenGL interop YUV" - msgstr "" - --#empty strings from id 13437 to 13499 -+msgctxt "#13437" -+msgid "Allow hardware acceleration (XVBA)" -+msgstr "" -+ -+#empty strings from id 13438 to 13499 - - msgctxt "#13500" - msgid "A/V sync method" -@@ -6346,7 +6350,11 @@ msgctxt "#16325" - msgid "VDPAU - Bob" - msgstr "" - --#empty strings from id 16326 to 16399 -+msgctxt "#16326" -+msgid "XVBA" -+msgstr "" -+ -+#empty strings from id 16327 to 16399 - - msgctxt "#16400" - msgid "Post-processing" -diff --git a/xbmc/cores/VideoRenderers/LinuxRendererGL.cpp b/xbmc/cores/VideoRenderers/LinuxRendererGL.cpp -index b281ca7..ec3606a 100644 ---- a/xbmc/cores/VideoRenderers/LinuxRendererGL.cpp -+++ b/xbmc/cores/VideoRenderers/LinuxRendererGL.cpp -@@ -63,6 +63,9 @@ - VA_MICRO_VERSION == 0 && VA_SDS_VERSION < 5))) - - #endif -+#ifdef HAVE_LIBXVBA -+#include "cores/dvdplayer/DVDCodecs/Video/XVBA.h" -+#endif - - #ifdef TARGET_DARWIN - #include "osx/CocoaInterface.h" -@@ -129,6 +132,9 @@ - #ifdef HAVE_LIBVDPAU - vdpau = NULL; - #endif -+#ifdef HAVE_LIBXVBA -+ xvba = NULL; -+#endif - } - - CLinuxRendererGL::YUVBUFFER::~YUVBUFFER() -@@ -604,6 +610,9 @@ void CLinuxRendererGL::ReleaseBuffer(int idx) - #ifdef HAVE_LIBVDPAU - SAFE_RELEASE(buf.vdpau); - #endif -+#ifdef HAVE_LIBXVBA -+ SAFE_RELEASE(buf.xvba); -+#endif - #ifdef HAVE_LIBVA - buf.vaapi.surface.reset(); - #endif -@@ -879,7 +888,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()) -@@ -965,6 +974,11 @@ void CLinuxRendererGL::LoadShaders(int field) - CLog::Log(LOGNOTICE, "GL: Using CVBREF render method"); - m_renderMethod = RENDER_CVREF; - } -+ else if (m_format == RENDER_FMT_XVBA) -+ { -+ CLog::Log(LOGNOTICE, "GL: Using XVBA render method"); -+ m_renderMethod = RENDER_XVBA; -+ } - else - { - int requestedMethod = g_guiSettings.GetInt("videoplayer.rendermethod"); -@@ -1113,6 +1127,12 @@ void CLinuxRendererGL::LoadShaders(int field) - m_textureCreate = &CLinuxRendererGL::CreateCVRefTexture; - m_textureDelete = &CLinuxRendererGL::DeleteCVRefTexture; - } -+ else if (m_format == RENDER_FMT_XVBA) -+ { -+ m_textureUpload = &CLinuxRendererGL::UploadXVBATexture; -+ m_textureCreate = &CLinuxRendererGL::CreateXVBATexture; -+ m_textureDelete = &CLinuxRendererGL::DeleteXVBATexture; -+ } - else - { - // setup default YV12 texture handlers -@@ -1225,6 +1245,13 @@ void CLinuxRendererGL::Render(DWORD flags, int renderBuffer) - RenderVAAPI(renderBuffer, m_currentField); - } - #endif -+#ifdef HAVE_LIBXVBA -+ else if (m_renderMethod & RENDER_XVBA) -+ { -+ UpdateVideoFilter(); -+ RenderXVBA(renderBuffer, m_currentField); -+ } -+#endif - else - { - // RENDER_CVREF uses the same render as the default case -@@ -1732,6 +1759,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[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) - { - // used for textues uploaded from rgba or CVPixelBuffers. -@@ -2783,6 +2881,93 @@ bool CLinuxRendererGL::CreateCVRefTexture(int index) - return true; - } - -+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]; -@@ -3368,6 +3553,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); -@@ -3381,6 +3569,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); -@@ -3404,7 +3595,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; - } - -@@ -3476,6 +3668,16 @@ bool CLinuxRendererGL::Supports(EINTERLACEMETHOD method) - 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. -@@ -3518,7 +3720,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 -@@ -3610,4 +3812,14 @@ void CLinuxRendererGL::AddProcessor(struct __CVBuffer *cvBufferRef, int index) - } - #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 --git a/xbmc/cores/VideoRenderers/LinuxRendererGL.h b/xbmc/cores/VideoRenderers/LinuxRendererGL.h -index 2fc34ae..e76624b 100644 ---- a/xbmc/cores/VideoRenderers/LinuxRendererGL.h -+++ b/xbmc/cores/VideoRenderers/LinuxRendererGL.h -@@ -43,6 +43,8 @@ - namespace Shaders { class BaseVideoFilterShader; } - namespace VAAPI { struct CHolder; } - namespace VDPAU { class CVdpauRenderPicture; } -+namespace XVBA { class CXvbaRenderPicture; } -+ - - #define NUM_BUFFERS 10 - -@@ -90,6 +92,7 @@ enum RenderMethod - RENDER_POT=0x10, - RENDER_VAAPI=0x20, - RENDER_CVREF = 0x40, -+ RENDER_XVBA=0x80, - }; - - enum RenderQuality -@@ -151,7 +154,9 @@ class CLinuxRendererGL : public CBaseRenderer - #ifdef TARGET_DARWIN - virtual void AddProcessor(struct __CVBuffer *cvBufferRef, 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 -@@ -210,6 +215,10 @@ class CLinuxRendererGL : public CBaseRenderer - 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); -@@ -225,6 +234,7 @@ class CLinuxRendererGL : public CBaseRenderer - void RenderVDPAU(int renderBuffer, int field); // render using vdpau hardware - void RenderProgressiveWeave(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 - - struct - { -@@ -292,6 +302,9 @@ class CLinuxRendererGL : public CBaseRenderer - #ifdef TARGET_DARWIN_OSX - struct __CVBuffer *cvBufferRef; - #endif -+#ifdef HAVE_LIBXVBA -+ XVBA::CXvbaRenderPicture *xvba; -+#endif - }; - - typedef YUVBUFFER YUVBUFFERS[NUM_BUFFERS]; -diff --git a/xbmc/cores/VideoRenderers/RenderFormats.h b/xbmc/cores/VideoRenderers/RenderFormats.h -index 0262c60..a727d94 100644 ---- a/xbmc/cores/VideoRenderers/RenderFormats.h -+++ b/xbmc/cores/VideoRenderers/RenderFormats.h -@@ -35,6 +35,7 @@ enum ERenderFormat { - RENDER_FMT_OMXEGL, - RENDER_FMT_CVBREF, - RENDER_FMT_BYPASS, -+ RENDER_FMT_XVBA, - }; - - #endif -diff --git a/xbmc/cores/VideoRenderers/RenderManager.cpp b/xbmc/cores/VideoRenderers/RenderManager.cpp -index a521680..0506823 100644 ---- a/xbmc/cores/VideoRenderers/RenderManager.cpp -+++ b/xbmc/cores/VideoRenderers/RenderManager.cpp -@@ -250,8 +250,9 @@ bool CXBMCRenderManager::Configure(unsigned int width, unsigned int height, unsi - - // check if decoder supports buffering - m_bCodecSupportsBuffering = false; -- if (format == RENDER_FMT_VDPAU || -- format == RENDER_FMT_VDPAU_420) -+ if (format == RENDER_FMT_VDPAU -+ || format == RENDER_FMT_VDPAU_420 -+ || format == RENDER_FMT_XVBA) - m_bCodecSupportsBuffering = true; - - bool result = m_pRenderer->Configure(width, height, d_width, d_height, fps, flags, format, extended_format, orientation); -@@ -873,6 +874,10 @@ int CXBMCRenderManager::AddVideoPicture(DVDVideoPicture& pic) - else if(pic.format == RENDER_FMT_VAAPI) - m_pRenderer->AddProcessor(*pic.vaapi, index); - #endif -+#ifdef HAVE_LIBXVBA -+ else if(pic.format == RENDER_FMT_XVBA) -+ m_pRenderer->AddProcessor(pic.xvba, index); -+#endif - m_pRenderer->ReleaseImage(index, false); - - return index; -diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodec.h b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodec.h -index 98d8f89..76d3575 100644 ---- a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodec.h -+++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodec.h -@@ -35,6 +35,7 @@ - namespace DXVA { class CSurfaceContext; } - namespace VAAPI { struct CHolder; } - namespace VDPAU { class CVdpauRenderPicture; } -+namespace XVBA { class CXvbaRenderPicture; } - class COpenMax; - class COpenMaxVideo; - struct OpenMaxVideoBuffer; -@@ -60,6 +61,9 @@ struct DVDVideoPicture - struct { - VAAPI::CHolder* vaapi; - }; -+ struct { -+ XVBA::CXvbaRenderPicture* xvba; -+ }; - - struct { - COpenMax *openMax; -diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp -index a6e42e5..b3252ec 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,19 @@ enum PixelFormat CDVDVideoCodecFFmpeg::GetFormat( struct AVCodecContext * avctx - 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->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 176ceff..c58422b 100644 ---- a/xbmc/cores/dvdplayer/DVDCodecs/Video/Makefile.in -+++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/Makefile.in -@@ -14,6 +14,10 @@ ifeq (@USE_CRYSTALHD@,1) - SRCS += CrystalHD.cpp - SRCS += DVDVideoCodecCrystalHD.cpp - endif -+ifeq (@USE_XVBA@,1) -+SRCS+= XVBA.cpp \ -+ -+endif - ifeq (@USE_VDA@,1) - SRCS += DVDVideoCodecVDA.cpp - endif -diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/XVBA.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/XVBA.cpp -new file mode 100644 -index 0000000..e8e376a ---- /dev/null -+++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/XVBA.cpp -@@ -0,0 +1,2354 @@ -+/* -+ * 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 "system_gl.h" -+#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; -+ 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"); -+ DestroySession(true); -+ } -+ return 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() -+{ -+ 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(bool precleanup /*= false*/) -+{ -+ // wait for unfinished decoding jobs -+ XbmcThreads::EndTime timer; -+ if (m_xvbaConfig.xvbaSession) -+ { -+ for (unsigned int i = 0; i < m_videoSurfaces.size(); ++i) -+ { -+ xvba_render_state *render = m_videoSurfaces[i]; -+ if (render->surface) -+ { -+ XVBA_Surface_Sync_Input syncInput; -+ XVBA_Surface_Sync_Output syncOutput; -+ syncInput.size = sizeof(syncInput); -+ syncInput.session = m_xvbaConfig.xvbaSession; -+ syncInput.surface = render->surface; -+ syncInput.query_status = XVBA_GET_SURFACE_STATUS; -+ syncOutput.size = sizeof(syncOutput); -+ timer.Set(1000); -+ while(!timer.IsTimePast()) -+ { -+ if (Success != g_XVBA_vtable.SyncSurface(&syncInput, &syncOutput)) -+ { -+ CLog::Log(LOGERROR,"XVBA::DestroySession - failed sync surface"); -+ break; -+ } -+ if (!(syncOutput.status_flags & XVBA_STILL_PENDING)) -+ break; -+ Sleep(10); -+ } -+ if (timer.IsTimePast()) -+ CLog::Log(LOGERROR,"XVBA::DestroySession - unfinished decoding job"); -+ } -+ } -+ } -+ -+ if (precleanup) -+ { -+ 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; -+ } -+ } -+ else -+ m_xvbaOutput.Dispose(); -+ -+ XVBA_Destroy_Decode_Buffers_Input bufInput; -+ bufInput.size = sizeof(bufInput); -+ bufInput.num_of_buffers_in_list = 1; -+ bufInput.session = m_xvbaConfig.xvbaSession; -+ -+ for (unsigned int i=0; isurface) -+ { -+ g_XVBA_vtable.DestroySurface(render->surface); -+ render->surface = 0; -+ render->state = 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(); -+ -+ 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; -+ -+ 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_NO_POSTPROC); -+ } -+ -+ 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::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_UNCONFIGURED; -+ m_extTimeout = 10000; -+ Flush(); -+ ReleaseBufferPool(true); -+ 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; -+ m_fence = None; -+ -+ 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; -+} -+ -+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 (m_fence) -+// glDeleteSync(m_fence); -+// m_fence = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0); -+ -+ // 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; -+ } -+ } -+ -+ // 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; -+ } -+ -+ xvba_render_state *render = m_bufferPool.glSurfaces[pic->sourceIdx].render; -+ if (render) -+ { -+ // check if video surface is 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 = RENDER_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(bool precleanup /*= false*/) -+{ -+// if (m_fence) -+// { -+// uint64_t maxTimeout = 1000000000LL; -+// glClientWaitSync(m_fence, GL_SYNC_FLUSH_COMMANDS_BIT, maxTimeout); -+// glDeleteSync(m_fence); -+// m_fence = None; -+// } -+ -+ CSingleLock lock(m_bufferPool.renderPicSec); -+ -+ for (unsigned int i = 0; i < m_bufferPool.glSurfaces.size(); ++i) -+ { -+ if (m_bufferPool.glSurfaces[i].glSurface) -+ { -+ g_XVBA_vtable.DestroySurface(m_bufferPool.glSurfaces[i].glSurface); -+ m_bufferPool.glSurfaces[i].glSurface = 0; -+ } -+ if (m_bufferPool.glSurfaces[i].texture && !precleanup) -+ { -+ glDeleteTextures(1, &m_bufferPool.glSurfaces[i].texture); -+ m_bufferPool.glSurfaces[i].texture = 0; -+ } -+ m_bufferPool.glSurfaces[i].render = 0; -+ m_bufferPool.glSurfaces[i].used = true; -+ } -+ -+ if (!precleanup) -+ { -+ 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; -+ } -+ } -+} -+ -+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; -+ -+ m_Display = g_Windowing.GetDisplay(); -+ glContext = g_Windowing.GetGlxContext(); -+ m_Window = g_Windowing.GetWindow(); -+ -+ // 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, -+ m_Window, -+ 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 --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/XVBA.h b/xbmc/cores/dvdplayer/DVDCodecs/Video/XVBA.h -new file mode 100644 -index 0000000..f38444c ---- /dev/null -+++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/XVBA.h -@@ -0,0 +1,382 @@ -+/* -+ * 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 -+ -+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(); -+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(); -+ 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(bool precleanup = false); -+ 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; -+ GLsync m_fence; -+ 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 precleanup = false); -+ 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; -+ -+ COutput m_xvbaOutput; -+ CXvbaBufferStats m_bufferStats; -+ CEvent m_inMsgEvent; -+ CXvbaRenderPicture *m_presentPicture; -+ -+ int m_speed; -+ int m_codecControl; -+}; -+ -+} -diff --git a/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp b/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp -index 15a39fa..e5e71f3 100644 ---- a/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp -+++ b/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp -@@ -1162,6 +1162,9 @@ int CDVDPlayerVideo::OutputPicture(const DVDVideoPicture* src, double pts) - case RENDER_FMT_NONE: - formatstr = "NONE"; - break; -+ case RENDER_FMT_XVBA: -+ formatstr = "XVBA"; -+ break; - } - - if(m_bAllowFullscreen) -diff --git a/xbmc/settings/GUISettings.cpp b/xbmc/settings/GUISettings.cpp -index 0e320e1..10ef779 100644 ---- a/xbmc/settings/GUISettings.cpp -+++ b/xbmc/settings/GUISettings.cpp -@@ -696,6 +696,9 @@ void CGUISettings::Initialize() - #ifdef HAVE_LIBVA - AddBool(vp, "videoplayer.usevaapi", 13426, true); - #endif -+#ifdef HAVE_LIBXVBA -+ AddBool(vp, "videoplayer.usexvba", 13437, 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/VideoSettings.h b/xbmc/settings/VideoSettings.h -index f8093b2..f54a837 100644 ---- a/xbmc/settings/VideoSettings.h -+++ b/xbmc/settings/VideoSettings.h -@@ -65,6 +65,8 @@ enum EINTERLACEMETHOD - VS_INTERLACEMETHOD_SW_BLEND = 20, - VS_INTERLACEMETHOD_AUTO_ION = 21, - -+ VS_INTERLACEMETHOD_XVBA = 22, -+ - VS_INTERLACEMETHOD_MAX // do not use and keep as last enum value. - }; - -diff --git a/xbmc/video/dialogs/GUIDialogVideoSettings.cpp b/xbmc/video/dialogs/GUIDialogVideoSettings.cpp -index f25d10d..f6b1ea4 100644 ---- a/xbmc/video/dialogs/GUIDialogVideoSettings.cpp -+++ b/xbmc/video/dialogs/GUIDialogVideoSettings.cpp -@@ -110,6 +110,7 @@ void CGUIDialogVideoSettings::CreateSettings() - 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_AUTO_ION , 16325)); -+ entries.push_back(make_pair(VS_INTERLACEMETHOD_XVBA , 16326)); - - /* remove unsupported methods */ - for(vector >::iterator it = entries.begin(); it != entries.end();) --- -1.7.10 - - -From 517eda0bf58a6376a82839ab92e51b97c143edf1 Mon Sep 17 00:00:00 2001 -From: xbmc -Date: Thu, 23 Aug 2012 19:39:49 +0200 -Subject: [PATCH 43/73] ffmpeg: add av_find_default_stream_index to interface - ---- - lib/DllAvFormat.h | 4 ++++ - 1 file changed, 4 insertions(+) - -diff --git a/lib/DllAvFormat.h b/lib/DllAvFormat.h -index 9bda3f3..bf31fcb 100644 ---- a/lib/DllAvFormat.h -+++ b/lib/DllAvFormat.h -@@ -98,6 +98,7 @@ class DllAvFormatInterface - virtual int avformat_write_header (AVFormatContext *s, AVDictionary **options)=0; - virtual int av_write_trailer(AVFormatContext *s)=0; - virtual int av_write_frame (AVFormatContext *s, AVPacket *pkt)=0; -+ virtual int av_find_default_stream_index(AVFormatContext *s)=0; - }; - - #if (defined USE_EXTERNAL_FFMPEG) || (defined TARGET_DARWIN) -@@ -153,6 +154,7 @@ class DllAvFormat : public DllDynamic, DllAvFormatInterface - virtual int avformat_write_header (AVFormatContext *s, AVDictionary **options) { return ::avformat_write_header (s, options); } - virtual int av_write_trailer(AVFormatContext *s) { return ::av_write_trailer(s); } - virtual int av_write_frame (AVFormatContext *s, AVPacket *pkt) { return ::av_write_frame(s, pkt); } -+ virtual int av_find_default_stream_index(AVFormatContext *s) { return ::av_find_default_stream_index(s); } - - // DLL faking. - virtual bool ResolveExports() { return true; } -@@ -209,6 +211,7 @@ class DllAvFormat : public DllDynamic, DllAvFormatInterface - DEFINE_METHOD2(int, avformat_write_header , (AVFormatContext *p1, AVDictionary **p2)) - DEFINE_METHOD1(int, av_write_trailer, (AVFormatContext *p1)) - DEFINE_METHOD2(int, av_write_frame , (AVFormatContext *p1, AVPacket *p2)) -+ DEFINE_METHOD1(int, av_find_default_stream_index, (AVFormatContext *p1)) - BEGIN_METHOD_RESOLVE() - RESOLVE_METHOD_RENAME(av_register_all, av_register_all_dont_call) - RESOLVE_METHOD(av_find_input_format) -@@ -243,6 +246,7 @@ class DllAvFormat : public DllDynamic, DllAvFormatInterface - RESOLVE_METHOD(avformat_write_header) - RESOLVE_METHOD(av_write_trailer) - RESOLVE_METHOD(av_write_frame) -+ RESOLVE_METHOD(av_find_default_stream_index) - END_METHOD_RESOLVE() - - /* dependencies of libavformat */ --- -1.7.10 - - -From 23be471842ae9ea7bd62c18261a5e96a11045d04 Mon Sep 17 00:00:00 2001 -From: xbmc -Date: Mon, 20 Aug 2012 16:06:39 +0200 -Subject: [PATCH 44/73] dvdplayer: observe pts counter overflow - ---- - .../cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.cpp | 198 +++++++++++++++++++- - xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.h | 4 + - 2 files changed, 201 insertions(+), 1 deletion(-) - -diff --git a/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.cpp b/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.cpp -index 7c0ab03..f91be3c 100644 ---- a/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.cpp -+++ b/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.cpp -@@ -18,13 +18,13 @@ - * - */ - --#include "system.h" - #ifndef __STDC_CONSTANT_MACROS - #define __STDC_CONSTANT_MACROS - #endif - #ifndef __STDC_LIMIT_MACROS - #define __STDC_LIMIT_MACROS - #endif -+#include "system.h" - #ifdef _LINUX - #include "stdint.h" - #endif -@@ -495,6 +495,9 @@ bool CDVDDemuxFFmpeg::Open(CDVDInputStream* pInput) - AddStream(i); - } - -+ m_bPtsWrapChecked = false; -+ m_bPtsWrap = false; -+ - return true; - } - -@@ -605,6 +608,12 @@ double CDVDDemuxFFmpeg::ConvertTimestamp(int64_t pts, int den, int num) - if (pts == (int64_t)AV_NOPTS_VALUE) - return DVD_NOPTS_VALUE; - -+ if (m_bPtsWrap) -+ { -+ if (pts < m_iStartTime && pts < m_iEndTime) -+ pts += m_iMaxTime; -+ } -+ - // do calculations in floats as they can easily overflow otherwise - // we don't care for having a completly exact timestamp anyway - double timestamp = (double)pts * num / den; -@@ -729,6 +738,24 @@ DemuxPacket* CDVDDemuxFFmpeg::Read() - pkt.pts = AV_NOPTS_VALUE; - } - -+ if (!m_bPtsWrapChecked && m_pFormatContext->iformat->flags & AVFMT_TS_DISCONT) -+ { -+ int defaultStream = m_dllAvFormat.av_find_default_stream_index(m_pFormatContext); -+ int64_t duration = m_pFormatContext->streams[defaultStream]->duration * 1.5; -+ m_iMaxTime = 1LL<streams[defaultStream]->pts_wrap_bits; -+ m_iStartTime = m_pFormatContext->streams[defaultStream]->start_time; -+ if (m_iStartTime != DVD_NOPTS_VALUE) -+ { -+ m_iEndTime = (m_iStartTime + duration) & ~m_iMaxTime; -+ if (m_iEndTime < m_iStartTime) -+ { -+ CLog::Log(LOGNOTICE,"CDVDDemuxFFmpeg::Read - file contains pts overflow"); -+ m_bPtsWrap = true; -+ } -+ } -+ m_bPtsWrapChecked = true; -+ } -+ - // copy contents into our own packet - pPacket->iSize = pkt.size; - -@@ -845,10 +872,20 @@ bool CDVDDemuxFFmpeg::SeekTime(int time, bool backwords, double *startpts) - int ret; - { - CSingleLock lock(m_critSection); -+ - ret = m_dllAvFormat.av_seek_frame(m_pFormatContext, -1, seek_pts, backwords ? AVSEEK_FLAG_BACKWARD : 0); - - if(ret >= 0) -+ { - UpdateCurrentPTS(); -+ -+ // seek may fail silently on streams which allow discontinuity -+ // if current timestamp is way off asume a pts overflow and try bisect seek -+ if (m_bPtsWrap && fabs(time - m_iCurrentPts/1000) > 10000) -+ { -+ ret = SeekTimeDiscont(seek_pts, backwords) ? 1 : -1; -+ } -+ } - } - - if(m_iCurrentPts == DVD_NOPTS_VALUE) -@@ -867,6 +904,165 @@ bool CDVDDemuxFFmpeg::SeekTime(int time, bool backwords, double *startpts) - return (ret >= 0); - } - -+bool CDVDDemuxFFmpeg::SeekTimeDiscont(int64_t pts, bool backwards) -+{ -+ // this code is taken from ffmpeg function ff_gen_search -+ // it is modified to assume a pts overflow if timestamp < start_time -+ if (!m_pFormatContext->iformat->read_timestamp) -+ return false; -+ -+ int defaultStream = m_dllAvFormat.av_find_default_stream_index(m_pFormatContext); -+ -+ if (defaultStream < 0) -+ { -+ return false; -+ } -+ -+ // timestamp for default must be expressed in AV_TIME_BASE units -+ pts = m_dllAvUtil.av_rescale_rnd(pts, m_pFormatContext->streams[defaultStream]->time_base.den, -+ AV_TIME_BASE * (int64_t)m_pFormatContext->streams[defaultStream]->time_base.num, -+ AV_ROUND_NEAR_INF); -+ -+ int64_t pos, pos_min, pos_max, pos_limit, ts, ts_min, ts_max; -+ int64_t start_pos, filesize; -+ int no_change; -+ -+ pos_min = m_pFormatContext->data_offset; -+ ts_min = m_pFormatContext->iformat->read_timestamp(m_pFormatContext, defaultStream, -+ &pos_min, INT64_MAX); -+ if (ts_min == AV_NOPTS_VALUE) -+ return false; -+ -+ if(ts_min >= pts) -+ { -+ pos = pos_min; -+ return true; -+ } -+ -+ int step= 1024; -+ filesize = m_pInput->GetLength(); -+ pos_max = filesize - 1; -+ do -+ { -+ pos_max -= step; -+ ts_max = m_pFormatContext->iformat->read_timestamp(m_pFormatContext, defaultStream, -+ &pos_max, pos_max + step); -+ step += step; -+ }while (ts_max == AV_NOPTS_VALUE && pos_max >= step); -+ -+ if (ts_max == AV_NOPTS_VALUE) -+ return false; -+ -+ if (ts_max < m_iStartTime && ts_max < m_iEndTime) -+ ts_max += m_iMaxTime; -+ -+ for(;;) -+ { -+ int64_t tmp_pos = pos_max + 1; -+ int64_t tmp_ts = m_pFormatContext->iformat->read_timestamp(m_pFormatContext, defaultStream, -+ &tmp_pos, INT64_MAX); -+ if(tmp_ts == AV_NOPTS_VALUE) -+ break; -+ -+ if (tmp_ts < m_iStartTime && tmp_ts < m_iEndTime) -+ tmp_ts += m_iMaxTime; -+ -+ ts_max = tmp_ts; -+ pos_max = tmp_pos; -+ if (tmp_pos >= filesize) -+ break; -+ } -+ pos_limit = pos_max; -+ -+ if(ts_max <= pts) -+ { -+ bool ret = SeekByte(pos_max); -+ if (ret) -+ { -+ m_iCurrentPts = ConvertTimestamp(ts_max, m_pFormatContext->streams[defaultStream]->time_base.den, -+ m_pFormatContext->streams[defaultStream]->time_base.num); -+ } -+ return ret; -+ } -+ -+ if(ts_min > ts_max) -+ { -+ return false; -+ } -+ else if (ts_min == ts_max) -+ { -+ pos_limit = pos_min; -+ } -+ -+ no_change=0; -+ while (pos_min < pos_limit) -+ { -+ if (no_change == 0) -+ { -+ int64_t approximate_keyframe_distance= pos_max - pos_limit; -+ // interpolate position (better than dichotomy) -+ pos = m_dllAvUtil.av_rescale_rnd(pts - ts_min, pos_max - pos_min, -+ ts_max - ts_min, AV_ROUND_NEAR_INF) -+ + pos_min - approximate_keyframe_distance; -+ } -+ else if (no_change == 1) -+ { -+ // bisection, if interpolation failed to change min or max pos last time -+ pos = (pos_min + pos_limit) >> 1; -+ } -+ else -+ { -+ /* linear search if bisection failed, can only happen if there -+ are very few or no keyframes between min/max */ -+ pos = pos_min; -+ } -+ if (pos <= pos_min) -+ pos= pos_min + 1; -+ else if (pos > pos_limit) -+ pos= pos_limit; -+ start_pos = pos; -+ -+ ts = m_pFormatContext->iformat->read_timestamp(m_pFormatContext, defaultStream, -+ &pos, INT64_MAX); -+ if (pos == pos_max) -+ no_change++; -+ else -+ no_change=0; -+ -+ if (ts == AV_NOPTS_VALUE) -+ { -+ return false; -+ } -+ -+ if (ts < m_iStartTime && ts < m_iEndTime) -+ ts += m_iMaxTime; -+ -+ if (pts <= ts) -+ { -+ pos_limit = start_pos - 1; -+ pos_max = pos; -+ ts_max = ts; -+ } -+ if (pts >= ts) -+ { -+ pos_min = pos; -+ ts_min = ts; -+ } -+ } -+ -+ pos = (backwards) ? pos_min : pos_max; -+ ts = (backwards) ? ts_min : ts_max; -+ -+ bool ret = SeekByte(pos); -+ if (ret) -+ { -+ m_iCurrentPts = ConvertTimestamp(ts, m_pFormatContext->streams[defaultStream]->time_base.den, -+ m_pFormatContext->streams[defaultStream]->time_base.num); -+ } -+ -+ return ret; -+} -+ - bool CDVDDemuxFFmpeg::SeekByte(int64_t pos) - { - g_demuxer.set(this); -diff --git a/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.h b/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.h -index 2b5f2e8..e0acf29 100644 ---- a/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.h -+++ b/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.h -@@ -97,6 +97,7 @@ class CDVDDemuxFFmpeg : public CDVDDemux - DemuxPacket* Read(); - - bool SeekTime(int time, bool backwords = false, double* startpts = NULL); -+ bool SeekTimeDiscont(int64_t pts, bool backwards); - bool SeekByte(int64_t pos); - int GetStreamLength(); - CDemuxStream* GetStream(int iStreamId); -@@ -141,5 +142,8 @@ class CDVDDemuxFFmpeg : public CDVDDemux - XbmcThreads::EndTime m_timeout; - - CDVDInputStream* m_pInput; -+ -+ bool m_bPtsWrap, m_bPtsWrapChecked; -+ int64_t m_iStartTime, m_iMaxTime, m_iEndTime; - }; - --- -1.7.10 - - -From 66382788a903f99ba317e972ba0445fc68320750 Mon Sep 17 00:00:00 2001 -From: xbmc -Date: Tue, 2 Oct 2012 13:02:10 +0200 -Subject: [PATCH 45/73] dvdplayer: avoid short screen flicker caused by - unnecessary reconfigure of renderer - ---- - xbmc/cores/dvdplayer/DVDPlayerVideo.cpp | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - -diff --git a/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp b/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp -index e5e71f3..8b02d81 100644 ---- a/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp -+++ b/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp -@@ -1033,7 +1033,7 @@ int CDVDPlayerVideo::OutputPicture(const DVDVideoPicture* src, double pts) - || m_output.height != pPicture->iHeight - || m_output.dwidth != pPicture->iDisplayWidth - || m_output.dheight != pPicture->iDisplayHeight -- || m_output.framerate != config_framerate -+ || (!m_bFpsInvalid && fmod(m_output.framerate, config_framerate) != 0.0 ) - || m_output.color_format != (unsigned int)pPicture->format - || m_output.extended_format != pPicture->extended_format - || ( m_output.color_matrix != pPicture->color_matrix && pPicture->color_matrix != 0 ) // don't reconfigure on unspecified -@@ -1184,7 +1184,7 @@ int CDVDPlayerVideo::OutputPicture(const DVDVideoPicture* src, double pts) - m_output.height = pPicture->iHeight; - m_output.dwidth = pPicture->iDisplayWidth; - m_output.dheight = pPicture->iDisplayHeight; -- m_output.framerate = config_framerate; -+ m_output.framerate = config_framerate == 0.0 ? g_graphicsContext.GetFPS() : config_framerate; - m_output.color_format = pPicture->format; - m_output.extended_format = pPicture->extended_format; - m_output.color_matrix = pPicture->color_matrix; --- -1.7.10 - - -From 04f4521c1938a7ac17acd59f3bd6be59c7ba8184 Mon Sep 17 00:00:00 2001 -From: xbmc -Date: Sat, 16 Jun 2012 12:46:30 +0200 -Subject: [PATCH 46/73] xvba: do not use vaapi if xvba is present - ---- - xbmc/cores/dvdplayer/DVDCodecs/Video/VAAPI.cpp | 9 +++++++++ - 1 file changed, 9 insertions(+) - -diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/VAAPI.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/VAAPI.cpp -index a2b9195..43a05b3 100644 ---- a/xbmc/cores/dvdplayer/DVDCodecs/Video/VAAPI.cpp -+++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/VAAPI.cpp -@@ -261,6 +261,15 @@ void CDecoder::Close() - - bool CDecoder::Open(AVCodecContext *avctx, enum PixelFormat fmt, unsigned int surfaces) - { -+#ifdef HAVE_LIBXVBA -+ std::string Vendor = g_Windowing.GetRenderVendor(); -+ std::transform(Vendor.begin(), Vendor.end(), Vendor.begin(), ::tolower); -+ if (Vendor.compare(0, 3, "ati") == 0) -+ { -+ return false; -+ } -+#endif -+ - VAEntrypoint entrypoint = VAEntrypointVLD; - VAProfile profile; - --- -1.7.10 - - -From a133b7fa119e859ec50b9f05a33de984105234f3 Mon Sep 17 00:00:00 2001 -From: xbmc -Date: Thu, 11 Oct 2012 12:05:50 +0200 -Subject: [PATCH 47/73] vdpau: advanced settings for auto deinterlacing - ---- - xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp | 8 ++++---- - xbmc/settings/AdvancedSettings.cpp | 4 ++++ - xbmc/settings/AdvancedSettings.h | 2 ++ - 3 files changed, 10 insertions(+), 4 deletions(-) - -diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp -index 235f565..d95797b 100644 ---- a/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp -+++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp -@@ -1770,10 +1770,10 @@ EINTERLACEMETHOD CMixer::GetDeinterlacingMethod(bool log /* = false */) - 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 (m_config.outHeight >= 720) -+ deint = g_advancedSettings.m_videoVDPAUdeintHD; -+ else -+ deint = g_advancedSettings.m_videoVDPAUdeintSD; - - if (deint != -1) - { -diff --git a/xbmc/settings/AdvancedSettings.cpp b/xbmc/settings/AdvancedSettings.cpp -index 844f8e8..d913924 100644 ---- a/xbmc/settings/AdvancedSettings.cpp -+++ b/xbmc/settings/AdvancedSettings.cpp -@@ -106,6 +106,8 @@ void CAdvancedSettings::Initialize() - m_videoAllowMpeg4VAAPI = false; - m_videoDisableBackgroundDeinterlace = false; - m_videoCaptureUseOcclusionQuery = -1; //-1 is auto detect -+ m_videoVDPAUdeintHD = -1; -+ m_videoVDPAUdeintSD = -1; - m_videoVDPAUtelecine = false; - m_videoVDPAUdeintSkipChromaHD = false; - m_DXVACheckCompatibility = false; -@@ -503,6 +505,8 @@ void CAdvancedSettings::ParseSettingsFile(const CStdString &file) - 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::GetBoolean(pElement,"vdpauInvTelecine",m_videoVDPAUtelecine); - XMLUtils::GetBoolean(pElement,"vdpauHDdeintSkipChroma",m_videoVDPAUdeintSkipChromaHD); - -diff --git a/xbmc/settings/AdvancedSettings.h b/xbmc/settings/AdvancedSettings.h -index 72718e5..aaa4702 100644 ---- a/xbmc/settings/AdvancedSettings.h -+++ b/xbmc/settings/AdvancedSettings.h -@@ -133,6 +133,8 @@ class CAdvancedSettings - int m_videoPercentSeekBackwardBig; - CStdString m_videoPPFFmpegDeint; - CStdString m_videoPPFFmpegPostProc; -+ int m_videoVDPAUdeintHD; -+ int m_videoVDPAUdeintSD; - bool m_videoVDPAUtelecine; - bool m_videoVDPAUdeintSkipChromaHD; - bool m_musicUseTimeSeeking; --- -1.7.10 - - -From 62540aeaa356823bd34e9367ac39eef23a6e4ce4 Mon Sep 17 00:00:00 2001 -From: xbmc -Date: Thu, 11 Oct 2012 13:01:08 +0200 -Subject: [PATCH 48/73] dvdplayer: correct determination if video is playing - ---- - xbmc/cores/dvdplayer/DVDPlayer.cpp | 11 +++++++++-- - 1 file changed, 9 insertions(+), 2 deletions(-) - -diff --git a/xbmc/cores/dvdplayer/DVDPlayer.cpp b/xbmc/cores/dvdplayer/DVDPlayer.cpp -index 6fcb6b3..f76691d 100644 ---- a/xbmc/cores/dvdplayer/DVDPlayer.cpp -+++ b/xbmc/cores/dvdplayer/DVDPlayer.cpp -@@ -2382,9 +2382,16 @@ bool CDVDPlayer::IsPaused() const - - bool CDVDPlayer::HasVideo() const - { -- if (m_pInputStream && m_pInputStream->IsStreamType(DVDSTREAM_TYPE_DVD)) return true; -+ bool hasVideo(false); - -- return m_SelectionStreams.Count(STREAM_VIDEO) > 0 ? true : false; -+ if (m_pInputStream && m_pInputStream->IsStreamType(DVDSTREAM_TYPE_DVD)) -+ hasVideo = true; -+ else if (m_SelectionStreams.Count(STREAM_VIDEO) > 0) -+ hasVideo = true; -+ else if (g_renderManager.IsConfigured()) -+ hasVideo = true; -+ -+ return hasVideo; - } - - bool CDVDPlayer::HasAudio() const --- -1.7.10 - - -From 5a093bbd60d1ca47ed7c5e4639f28dafc1b565c1 Mon Sep 17 00:00:00 2001 -From: xbmc -Date: Sun, 14 Oct 2012 13:46:54 +0200 -Subject: [PATCH 49/73] rendermanager: fix stuttering in non full-screen mode, - squash to add buffering - ---- - xbmc/cores/VideoRenderers/RenderManager.cpp | 3 ++- - 1 file changed, 2 insertions(+), 1 deletion(-) - -diff --git a/xbmc/cores/VideoRenderers/RenderManager.cpp b/xbmc/cores/VideoRenderers/RenderManager.cpp -index 0506823..b141c80 100644 ---- a/xbmc/cores/VideoRenderers/RenderManager.cpp -+++ b/xbmc/cores/VideoRenderers/RenderManager.cpp -@@ -1057,8 +1057,9 @@ void CXBMCRenderManager::PrepareNextRender() - presenttime = clocktime + MAXPRESENTDELAY; - - m_sleeptime = presenttime - clocktime; -+ double frametime = 1 / g_graphicsContext.GetFPS(); - -- if (g_graphicsContext.IsFullScreenVideo() || presenttime <= clocktime+0.01) -+ if (g_graphicsContext.IsFullScreenVideo() || presenttime <= clocktime + frametime) - { - m_presentPts = m_renderBuffers[idx].pts; - m_presenttime = presenttime; --- -1.7.10 - - -From d0597caa2c922575efdf081d719d5665c626ffec Mon Sep 17 00:00:00 2001 -From: xbmc -Date: Sun, 14 Oct 2012 17:54:02 +0200 -Subject: [PATCH 50/73] rendermanager: forgot to set flip event if buffering - is not used - ---- - xbmc/cores/VideoRenderers/RenderManager.cpp | 20 ++++++++++---------- - 1 file changed, 10 insertions(+), 10 deletions(-) - -diff --git a/xbmc/cores/VideoRenderers/RenderManager.cpp b/xbmc/cores/VideoRenderers/RenderManager.cpp -index b141c80..9290f80 100644 ---- a/xbmc/cores/VideoRenderers/RenderManager.cpp -+++ b/xbmc/cores/VideoRenderers/RenderManager.cpp -@@ -1096,17 +1096,17 @@ void CXBMCRenderManager::NotifyDisplayFlip() - if (!m_pRenderer) - return; - -- if (m_iNumRenderBuffers < 3) -- return; -- -- int last = m_iDisplayedRenderBuffer; -- m_iDisplayedRenderBuffer = (m_iCurrentRenderBuffer + m_iNumRenderBuffers - 1) % m_iNumRenderBuffers; -- -- if (last != m_iDisplayedRenderBuffer -- && m_iDisplayedRenderBuffer != m_iCurrentRenderBuffer) -+ if (m_iNumRenderBuffers >= 3) - { -- m_pRenderer->ReleaseBuffer(m_iDisplayedRenderBuffer); -- m_overlays.ReleaseBuffer(m_iDisplayedRenderBuffer); -+ int last = m_iDisplayedRenderBuffer; -+ m_iDisplayedRenderBuffer = (m_iCurrentRenderBuffer + m_iNumRenderBuffers - 1) % m_iNumRenderBuffers; -+ -+ if (last != m_iDisplayedRenderBuffer -+ && m_iDisplayedRenderBuffer != m_iCurrentRenderBuffer) -+ { -+ m_pRenderer->ReleaseBuffer(m_iDisplayedRenderBuffer); -+ m_overlays.ReleaseBuffer(m_iDisplayedRenderBuffer); -+ } - } - - lock.Leave(); --- -1.7.10 - - -From c485392afa608bfbcf903fa53a9dd824258c96dd Mon Sep 17 00:00:00 2001 -From: xbmc -Date: Fri, 26 Oct 2012 15:30:22 +0200 -Subject: [PATCH 51/73] vdpau: fix small mem leak - ---- - xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp | 2 ++ - 1 file changed, 2 insertions(+) - -diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp -index d95797b..fec4b88 100644 ---- a/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp -+++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp -@@ -2052,6 +2052,8 @@ void CMixer::Uninit() - m_outputSurfaces.pop(); - } - m_config.vdpProcs.vdp_video_mixer_destroy(m_videoMixer); -+ -+ delete [] m_BlackBar; - } - - void CMixer::Flush() --- -1.7.10 - - -From 9d7228a84013e409149d7b05d34545d1bdf06e27 Mon Sep 17 00:00:00 2001 -From: xbmc -Date: Mon, 29 Oct 2012 18:25:56 +0100 -Subject: [PATCH 52/73] xvba: do not render if there is no valid texture - ---- - xbmc/cores/VideoRenderers/LinuxRendererGL.cpp | 8 +++----- - 1 file changed, 3 insertions(+), 5 deletions(-) - -diff --git a/xbmc/cores/VideoRenderers/LinuxRendererGL.cpp b/xbmc/cores/VideoRenderers/LinuxRendererGL.cpp -index ec3606a..7c3adcb 100644 ---- a/xbmc/cores/VideoRenderers/LinuxRendererGL.cpp -+++ b/xbmc/cores/VideoRenderers/LinuxRendererGL.cpp -@@ -2924,16 +2924,14 @@ void CLinuxRendererGL::UploadXVBATexture(int index) - YUVFIELDS &fields = m_buffers[index].fields; - YUVPLANE &plane = fields[0][1]; - -- if (!xvba) -+ if (!xvba || !xvba->valid) - { -- fields[0][1].id = fields[0][0].id; - m_eventTexturesDone[index]->Set(); -- CLog::Log(LOGWARNING,"CLinuxRendererGL::UploadXVBATexture no xvba texture, index: %d", index); -+ m_skipRender = true; - return; - } --// xvba->Transfer(); - -- fields[0][1].id = xvba->texture; -+ plane.id = xvba->texture; - - im.height = xvba->texHeight; - im.width = xvba->texWidth; --- -1.7.10 - - -From 85be082db41b27cdd3824b8360dc021e17a84c22 Mon Sep 17 00:00:00 2001 -From: xbmc -Date: Fri, 2 Nov 2012 13:20:03 +0100 -Subject: [PATCH 53/73] player: fix rewind - ---- - xbmc/cores/dvdplayer/DVDMessage.h | 5 ++++- - xbmc/cores/dvdplayer/DVDPlayer.cpp | 33 ++++++++++++++++++++----------- - xbmc/cores/dvdplayer/DVDPlayer.h | 7 ++++--- - xbmc/cores/dvdplayer/DVDPlayerVideo.cpp | 10 ++++++---- - xbmc/cores/dvdplayer/DVDPlayerVideo.h | 1 + - 5 files changed, 36 insertions(+), 20 deletions(-) - -diff --git a/xbmc/cores/dvdplayer/DVDMessage.h b/xbmc/cores/dvdplayer/DVDMessage.h -index 30b2f5c..b9831d4 100644 ---- a/xbmc/cores/dvdplayer/DVDMessage.h -+++ b/xbmc/cores/dvdplayer/DVDMessage.h -@@ -218,7 +218,7 @@ class CDVDMsgPlayerSetState : public CDVDMsg - class CDVDMsgPlayerSeek : public CDVDMsg - { - public: -- CDVDMsgPlayerSeek(int time, bool backward, bool flush = true, bool accurate = true, bool restore = true, bool trickplay = false) -+ CDVDMsgPlayerSeek(int time, bool backward, bool flush = true, bool accurate = true, bool restore = true, bool trickplay = false, bool sync = true) - : CDVDMsg(PLAYER_SEEK) - , m_time(time) - , m_backward(backward) -@@ -226,6 +226,7 @@ class CDVDMsgPlayerSeek : public CDVDMsg - , m_accurate(accurate) - , m_restore(restore) - , m_trickplay(trickplay) -+ , m_sync(sync) - {} - int GetTime() { return m_time; } - bool GetBackward() { return m_backward; } -@@ -233,6 +234,7 @@ class CDVDMsgPlayerSeek : public CDVDMsg - bool GetAccurate() { return m_accurate; } - bool GetRestore() { return m_restore; } - bool GetTrickPlay() { return m_trickplay; } -+ bool GetSync() { return m_sync; } - private: - int m_time; - bool m_backward; -@@ -240,6 +242,7 @@ class CDVDMsgPlayerSeek : public CDVDMsg - bool m_accurate; - bool m_restore; // whether to restore any EDL cut time - bool m_trickplay; -+ bool m_sync; - }; - - class CDVDMsgPlayerSeekChapter : public CDVDMsg -diff --git a/xbmc/cores/dvdplayer/DVDPlayer.cpp b/xbmc/cores/dvdplayer/DVDPlayer.cpp -index f76691d..07df0d8 100644 ---- a/xbmc/cores/dvdplayer/DVDPlayer.cpp -+++ b/xbmc/cores/dvdplayer/DVDPlayer.cpp -@@ -1543,11 +1543,13 @@ void CDVDPlayer::HandlePlaySpeed() - } - else if (m_CurrentVideo.id >= 0 - && (m_CurrentVideo.inited == true || GetPlaySpeed() < 0) // allow rewind at end of file -- && m_SpeedState.lastpts != m_dvdPlayerVideo.GetCurrentPts() -+ && (m_SpeedState.lastpts != m_dvdPlayerVideo.GetCurrentPts() || fabs(m_SpeedState.lastabstime - CDVDClock::GetAbsoluteClock()) > DVD_MSEC_TO_TIME(200)) -+ && (m_dvdPlayerVideo.GetCurrentPts() != DVD_NOPTS_VALUE) - && m_SpeedState.lasttime != GetTime()) - { - m_SpeedState.lastpts = m_dvdPlayerVideo.GetCurrentPts(); - m_SpeedState.lasttime = GetTime(); -+ m_SpeedState.lastabstime = CDVDClock::GetAbsoluteClock(); - // check how much off clock video is when ff/rw:ing - // a problem here is that seeking isn't very accurate - // and since the clock will be resynced after seek -@@ -1566,7 +1568,7 @@ void CDVDPlayer::HandlePlaySpeed() - { - CLog::Log(LOGDEBUG, "CDVDPlayer::Process - Seeking to catch up"); - int64_t iTime = (int64_t)DVD_TIME_TO_MSEC(m_clock.GetClock() + m_State.time_offset + 500000.0 * m_playSpeed / DVD_PLAYSPEED_NORMAL); -- m_messenger.Put(new CDVDMsgPlayerSeek(iTime, (GetPlaySpeed() < 0), true, false, false, true)); -+ m_messenger.Put(new CDVDMsgPlayerSeek(iTime, (GetPlaySpeed() < 0), true, false, false, true, false)); - } - } - } -@@ -2030,7 +2032,7 @@ void CDVDPlayer::HandleMessages() - if(!m_pSubtitleDemuxer->SeekTime(time, msg.GetBackward())) - CLog::Log(LOGDEBUG, "failed to seek subtitle demuxer: %d, success", time); - } -- FlushBuffers(!msg.GetFlush(), start, msg.GetAccurate()); -+ FlushBuffers(!msg.GetFlush(), start, msg.GetAccurate(), msg.GetSync()); - } - else - CLog::Log(LOGWARNING, "error while seeking"); -@@ -2168,9 +2170,10 @@ void CDVDPlayer::HandleMessages() - double offset; - offset = CDVDClock::GetAbsoluteClock() - m_State.timestamp; - offset *= m_playSpeed / DVD_PLAYSPEED_NORMAL; -+ offset = DVD_TIME_TO_MSEC(offset); - if(offset > 1000) offset = 1000; - if(offset < -1000) offset = -1000; -- m_State.time += DVD_TIME_TO_MSEC(offset); -+ m_State.time += offset; - m_State.timestamp = CDVDClock::GetAbsoluteClock(); - } - -@@ -2186,7 +2189,8 @@ void CDVDPlayer::HandleMessages() - // do a seek after rewind, clock is not in sync with current pts - if (m_playSpeed < 0 && speed >= 0) - { -- m_messenger.Put(new CDVDMsgPlayerSeek(GetTime(), true, true, true)); -+ int64_t iTime = (int64_t)DVD_TIME_TO_MSEC(m_clock.GetClock() + m_State.time_offset); -+ m_messenger.Put(new CDVDMsgPlayerSeek(iTime, true, true, false, false, true)); - } - - // if playspeed is different then DVD_PLAYSPEED_NORMAL or DVD_PLAYSPEED_PAUSE -@@ -2767,10 +2771,11 @@ int64_t CDVDPlayer::GetTime() - { - offset = CDVDClock::GetAbsoluteClock() - m_State.timestamp; - offset *= m_playSpeed / DVD_PLAYSPEED_NORMAL; -+ offset = DVD_TIME_TO_MSEC(offset); - if(offset > 1000) offset = 1000; - if(offset < -1000) offset = -1000; - } -- return llrint(m_State.time + DVD_TIME_TO_MSEC(offset)); -+ return llrint(m_State.time + offset); - } - - // return length in msec -@@ -3140,7 +3145,7 @@ bool CDVDPlayer::CloseTeletextStream(bool bWaitForBuffers) - return true; - } - --void CDVDPlayer::FlushBuffers(bool queued, double pts, bool accurate) -+void CDVDPlayer::FlushBuffers(bool queued, double pts, bool accurate, bool sync) - { - double startpts; - if(accurate) -@@ -3152,19 +3157,23 @@ void CDVDPlayer::FlushBuffers(bool queued, double pts, bool accurate) - if(startpts != DVD_NOPTS_VALUE) - startpts -= m_offset_pts; - -- m_CurrentAudio.inited = false; -+ if (sync) -+ { -+ m_CurrentAudio.inited = false; -+ m_CurrentVideo.inited = false; -+ m_CurrentSubtitle.inited = false; -+ m_CurrentTeletext.inited = false; -+ } -+ - m_CurrentAudio.dts = DVD_NOPTS_VALUE; - m_CurrentAudio.startpts = startpts; - -- m_CurrentVideo.inited = false; - m_CurrentVideo.dts = DVD_NOPTS_VALUE; - m_CurrentVideo.startpts = startpts; - -- m_CurrentSubtitle.inited = false; - m_CurrentSubtitle.dts = DVD_NOPTS_VALUE; - m_CurrentSubtitle.startpts = startpts; - -- m_CurrentTeletext.inited = false; - m_CurrentTeletext.dts = DVD_NOPTS_VALUE; - m_CurrentTeletext.startpts = startpts; - -@@ -3208,7 +3217,7 @@ void CDVDPlayer::FlushBuffers(bool queued, double pts, bool accurate) - m_CurrentTeletext.started = false; - } - -- if(pts != DVD_NOPTS_VALUE) -+ if(pts != DVD_NOPTS_VALUE && sync) - m_clock.Discontinuity(pts); - UpdatePlayState(0); - } -diff --git a/xbmc/cores/dvdplayer/DVDPlayer.h b/xbmc/cores/dvdplayer/DVDPlayer.h -index d3c201e..70ecea9 100644 ---- a/xbmc/cores/dvdplayer/DVDPlayer.h -+++ b/xbmc/cores/dvdplayer/DVDPlayer.h -@@ -310,7 +310,7 @@ class CDVDPlayer : public IPlayer, public CThread, public IDVDPlayer - bool GetCachingTimes(double& play_left, double& cache_left, double& file_offset); - - -- void FlushBuffers(bool queued, double pts = DVD_NOPTS_VALUE, bool accurate = true); -+ void FlushBuffers(bool queued, double pts = DVD_NOPTS_VALUE, bool accurate = true, bool sync = true); - - void HandleMessages(); - void HandlePlaySpeed(); -@@ -359,8 +359,9 @@ class CDVDPlayer : public IPlayer, public CThread, public IDVDPlayer - int m_playSpeed; - struct SSpeedState - { -- double lastpts; // holds last display pts during ff/rw operations -- double lasttime; -+ double lastpts; // holds last display pts during ff/rw operations -+ int64_t lasttime; -+ double lastabstime; - } m_SpeedState; - - int m_errorCount; -diff --git a/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp b/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp -index 8b02d81..d26ab9c 100644 ---- a/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp -+++ b/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp -@@ -1268,13 +1268,13 @@ int CDVDPlayerVideo::OutputPicture(const DVDVideoPicture* src, double pts) - - if( m_speed < 0 ) - { -- double decoderPts = m_droppingStats.m_lastDecoderPts; -+ double inputPts = m_droppingStats.m_lastPts; - double renderPts = m_droppingStats.m_lastRenderPts; - if (pts > renderPts) - { -- if (decoderPts >= renderPts) -+ if (inputPts >= renderPts) - { -- Sleep(200); -+ Sleep(50); - } - return result | EOS_DROPPED; - } -@@ -1571,7 +1571,7 @@ double CDVDPlayerVideo::GetCurrentPts() - - if( m_stalled ) - iRenderPts = DVD_NOPTS_VALUE; -- else -+ else if ( m_speed == DVD_PLAYSPEED_NORMAL) - iRenderPts = iRenderPts - max(0.0, iSleepTime); - - return iRenderPts; -@@ -1671,6 +1671,8 @@ int CDVDPlayerVideo::CalcDropRequirement(double pts) - int iSkippedDeint = 0; - int iBufferLevel; - -+ m_droppingStats.m_lastPts = pts; -+ - // get decoder stats - if (!m_pVideoCodec->GetPts(iDecoderPts, iSkippedDeint, interlaced)) - iDecoderPts = pts; -diff --git a/xbmc/cores/dvdplayer/DVDPlayerVideo.h b/xbmc/cores/dvdplayer/DVDPlayerVideo.h -index 509d5f7..7cddda7 100644 ---- a/xbmc/cores/dvdplayer/DVDPlayerVideo.h -+++ b/xbmc/cores/dvdplayer/DVDPlayerVideo.h -@@ -51,6 +51,7 @@ class CDroppingStats - double m_totalGain; - double m_lastDecoderPts; - double m_lastRenderPts; -+ double m_lastPts; - unsigned int m_lateFrames; - unsigned int m_dropRequests; - bool m_requestOutputDrop; --- -1.7.10 - - -From 024ecda241754f02ad985fab9116e33b06b8d174 Mon Sep 17 00:00:00 2001 -From: fritsch -Date: Fri, 2 Nov 2012 17:56:12 +0100 -Subject: [PATCH 54/73] xvba: do not create decoder for surfaces larger than - width 2048 or height 1536 - ---- - xbmc/cores/dvdplayer/DVDCodecs/Video/XVBA.cpp | 15 +++++++++++++++ - 1 file changed, 15 insertions(+) - -diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/XVBA.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/XVBA.cpp -index e8e376a..b73c48a 100644 ---- a/xbmc/cores/dvdplayer/DVDCodecs/Video/XVBA.cpp -+++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/XVBA.cpp -@@ -335,6 +335,21 @@ bool CDecoder::Open(AVCodecContext* avctx, const enum PixelFormat fmt, unsigned - return false; - } - -+ // Fixme: Revisit with new SDK -+ // Workaround for 0.74.01-AES-2 that does not signal if surfaces are too large -+ // it seems that xvba does not support anything > 2k -+ // return false, for files that are larger -+ // if you are unlucky, this would kill your decoder -+ // we limit to 2048x1536(+8) now - as this was tested working -+ int surfaceWidth = (avctx->coded_width+15) & ~15; -+ int surfaceHeight = (avctx->coded_height+15) & ~15; -+ if(surfaceHeight > 1544 || surfaceWidth > 2048) -+ { -+ CLog::Log(LOGERROR, "Surface too large, decoder skipped: surfaceWidth %u, surfaceHeight %u", -+ surfaceWidth, surfaceHeight); -+ return false; -+ } -+ - if (!m_dllAvUtil.Load()) - return false; - --- -1.7.10 - - -From 98ebb0d0232cf4a7ea2082f9f16e210a39e983e8 Mon Sep 17 00:00:00 2001 -From: fritsch -Date: Sun, 4 Nov 2012 16:24:10 +0100 -Subject: [PATCH 55/73] xvba: add string for available decoders - we are - important so make sure we are there - ---- - xbmc/cores/dvdplayer/DVDCodecs/DVDFactoryCodec.cpp | 5 +++++ - 1 file changed, 5 insertions(+) - -diff --git a/xbmc/cores/dvdplayer/DVDCodecs/DVDFactoryCodec.cpp b/xbmc/cores/dvdplayer/DVDCodecs/DVDFactoryCodec.cpp -index 0cea7a9..6fb74b7 100644 ---- a/xbmc/cores/dvdplayer/DVDCodecs/DVDFactoryCodec.cpp -+++ b/xbmc/cores/dvdplayer/DVDCodecs/DVDFactoryCodec.cpp -@@ -169,6 +169,11 @@ CDVDVideoCodec* CDVDFactoryCodec::CreateVideoCodec(CDVDStreamInfo &hint, unsigne - #elif defined(_LINUX) && !defined(TARGET_DARWIN) - hwSupport += "VAAPI:no "; - #endif -+#if defined(HAVE_LIBXVBA) && defined(TARGET_LINUX) -+ hwSupport += "XVBA:yes "; -+#elif defined(TARGET_LINUX) -+ hwSupport += "XVBA:no "; -+#endif - - CLog::Log(LOGDEBUG, "CDVDFactoryCodec: compiled in hardware support: %s", hwSupport.c_str()); - --- -1.7.10 - - -From 84e701f7db6603a2942611d5c74ba645c625ec0d Mon Sep 17 00:00:00 2001 -From: fritsch -Date: Thu, 22 Nov 2012 21:32:21 +0100 -Subject: [PATCH 56/73] xvba: revisit Artefacts. There are more broken video - files out there - ---- - lib/ffmpeg/libavcodec/xvba_h264.c | 10 ++++++++-- - 1 file changed, 8 insertions(+), 2 deletions(-) - -diff --git a/lib/ffmpeg/libavcodec/xvba_h264.c b/lib/ffmpeg/libavcodec/xvba_h264.c -index a077442..87af687 100644 ---- a/lib/ffmpeg/libavcodec/xvba_h264.c -+++ b/lib/ffmpeg/libavcodec/xvba_h264.c -@@ -102,10 +102,16 @@ static int end_frame(AVCodecContext *avctx) - pic_descriptor->avc_num_ref_frames = h->sps.ref_frame_count; - pic_descriptor->avc_reserved_8bit = 0; - -- /* Set correct level */ -- if (pic_descriptor->level == 41) { -+ /* Set a level that can decode stuff in every case without a lookup table -+ xvba seems to have problems only when the number of Reframes goes beyond -+ the max support number of Level4.1@High. So in praxis decoding a Level 3.0 -+ file that in deed has level4.1@High specs does not matter. We use this fact -+ and check if the ref_frames stay in the range Level4.1@high can decode if -+ not, we set Level5.1 */ -+ if (pic_descriptor->avc_num_ref_frames > 4) { - const unsigned int mbw = pic_descriptor->width_in_mb; - const unsigned int mbh = pic_descriptor->height_in_mb; -+ // this matches Level4.1@High stats to differ between <= 4.1 and 5.1 - const unsigned int max_ref_frames = 12288 * 1024 / (mbw * mbh * 384); - const unsigned int num_ref_frames = pic_descriptor->avc_num_ref_frames; - if (max_ref_frames < num_ref_frames) --- -1.7.10 - - -From afd776e3e90a1787ce4c3392266d70368de4e164 Mon Sep 17 00:00:00 2001 -From: xbmc -Date: Fri, 23 Nov 2012 09:42:02 +0100 -Subject: [PATCH 57/73] xvba: reactivate accidently disabled - IsDecodingFinished - ---- - xbmc/cores/dvdplayer/DVDCodecs/Video/XVBA.cpp | 2 -- - 1 file changed, 2 deletions(-) - -diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/XVBA.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/XVBA.cpp -index b73c48a..47ff25f 100644 ---- a/xbmc/cores/dvdplayer/DVDCodecs/Video/XVBA.cpp -+++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/XVBA.cpp -@@ -1949,8 +1949,6 @@ void COutput::Flush() - - bool COutput::IsDecodingFinished() - { -- return true; -- - // check for decoding to be finished - CXvbaDecodedPicture decodedPic = m_decodedPics.front(); - --- -1.7.10 - - -From 37576c15f9e3a0c2dce593e9d9cb5a7863845de7 Mon Sep 17 00:00:00 2001 -From: xbmc -Date: Fri, 23 Nov 2012 17:41:12 +0100 -Subject: [PATCH 58/73] xrandr: fix query for multiple screens - ---- - xbmc/windowing/X11/XRandR.cpp | 10 ++++++---- - 1 file changed, 6 insertions(+), 4 deletions(-) - -diff --git a/xbmc/windowing/X11/XRandR.cpp b/xbmc/windowing/X11/XRandR.cpp -index cc933b9..533e03d 100644 ---- a/xbmc/windowing/X11/XRandR.cpp -+++ b/xbmc/windowing/X11/XRandR.cpp -@@ -57,12 +57,14 @@ bool CXRandR::Query(bool force) - - m_outputs.clear(); - // query all screens -+ // we are happy if at least one screen returns results -+ bool success = false; - for(unsigned int screennum=0; screennum -Date: Sun, 2 Dec 2012 15:46:55 +0100 -Subject: [PATCH 59/73] X11: add debug log to print out refresh after xrr - event - ---- - xbmc/windowing/X11/WinSystemX11.cpp | 6 ++++++ - 1 file changed, 6 insertions(+) - -diff --git a/xbmc/windowing/X11/WinSystemX11.cpp b/xbmc/windowing/X11/WinSystemX11.cpp -index ef83133..76c6362 100644 ---- a/xbmc/windowing/X11/WinSystemX11.cpp -+++ b/xbmc/windowing/X11/WinSystemX11.cpp -@@ -685,6 +685,12 @@ void CWinSystemX11::NotifyXRREvent() - XOutput *out = g_xrandr.GetOutput(currentOutput); - XMode mode = g_xrandr.GetCurrentMode(currentOutput); - -+ if (out) -+ CLog::Log(LOGDEBUG, "%s - current output: %s, mode: %s, refresh: %.3f", __FUNCTION__ -+ , out->name.c_str(), mode.id.c_str(), mode.hz); -+ else -+ CLog::Log(LOGWARNING, "%s - output name not set", __FUNCTION__); -+ - RESOLUTION_INFO res; - unsigned int i; - bool found(false); --- -1.7.10 - - -From d418ae1053a3842eb3e6a3bbd84666a5ee3defe2 Mon Sep 17 00:00:00 2001 -From: xbmc -Date: Tue, 11 Dec 2012 11:08:13 +0100 -Subject: [PATCH 60/73] X11: dont call XCloseDisplay on shutdown, it crashes - when powered doen by cec on ATI - ---- - xbmc/windowing/X11/WinSystemX11.cpp | 3 ++- - 1 file changed, 2 insertions(+), 1 deletion(-) - -diff --git a/xbmc/windowing/X11/WinSystemX11.cpp b/xbmc/windowing/X11/WinSystemX11.cpp -index 76c6362..e4e25b2 100644 ---- a/xbmc/windowing/X11/WinSystemX11.cpp -+++ b/xbmc/windowing/X11/WinSystemX11.cpp -@@ -108,7 +108,8 @@ bool CWinSystemX11::DestroyWindowSystem() - //we don't call XCloseDisplay() here, since ati keeps a pointer to our m_dpy - //so instead we just let m_dpy die on exit - // i have seen core dumps on ATI if the display is not closed here -- XCloseDisplay(m_dpy); -+ // crashes when shutting down via cec -+// XCloseDisplay(m_dpy); - } - - // m_SDLSurface is free()'d by SDL_Quit(). --- -1.7.10 - - -From 3b700401e9aace50b5ce6c5d7ba2a2e33bb5217f Mon Sep 17 00:00:00 2001 -From: xbmc -Date: Wed, 12 Dec 2012 09:52:17 +0100 -Subject: [PATCH 61/73] vdpau: make interop gl default and remove setting, - rename and intvert interop yuv - ---- - language/English/strings.po | 2 +- - xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp | 17 ++++++++++------- - xbmc/settings/GUISettings.cpp | 3 +-- - xbmc/settings/GUIWindowSettingsCategory.cpp | 23 +++-------------------- - 4 files changed, 15 insertions(+), 30 deletions(-) - -diff --git a/language/English/strings.po b/language/English/strings.po -index ede18b3..281a8a1 100644 ---- a/language/English/strings.po -+++ b/language/English/strings.po -@@ -5121,7 +5121,7 @@ msgid "Allow Vdpau OpenGL interop" - msgstr "" - - msgctxt "#13436" --msgid "Allow Vdpau OpenGL interop YUV" -+msgid "Prefer VDPAU Video Mixer" - msgstr "" - - msgctxt "#13437" -diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp -index fec4b88..ad140fb 100644 ---- a/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp -+++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp -@@ -365,12 +365,15 @@ bool CDecoder::Supports(EINTERLACEMETHOD method) - || method == VS_INTERLACEMETHOD_AUTO) - return true; - -- if (g_guiSettings.GetBool("videoplayer.usevdpauinteropyuv")) -+ if (!m_vdpauConfig.usePixmaps) - { - if (method == VS_INTERLACEMETHOD_RENDER_BOB) - return true; - } - -+ if (method == VS_INTERLACEMETHOD_VDPAU_INVERSE_TELECINE) -+ return false; -+ - for(SInterlaceMapping* p = g_interlace_mapping; p->method != VS_INTERLACEMETHOD_NONE; p++) - { - if(p->method == method) -@@ -1847,7 +1850,7 @@ void CMixer::SetDeinterlacing() - - SetDeintSkipChroma(); - -- m_config.useInteropYuv = g_guiSettings.GetBool("videoplayer.usevdpauinteropyuv"); -+ m_config.useInteropYuv = !g_guiSettings.GetBool("videoplayer.usevdpaumixer"); - } - - void CMixer::SetDeintSkipChroma() -@@ -2039,7 +2042,7 @@ void CMixer::Init() - m_vdpError = false; - - m_config.upscale = g_advancedSettings.m_videoVDPAUScaling; -- m_config.useInteropYuv = g_guiSettings.GetBool("videoplayer.usevdpauinteropyuv"); -+ m_config.useInteropYuv = !g_guiSettings.GetBool("videoplayer.usevdpaumixer"); - - CreateVdpauMixer(); - } -@@ -2149,11 +2152,12 @@ void CMixer::InitCycle() - DVP_FLAG_INTERLACED); - m_config.useInteropYuv = false; - } -- else if (method == VS_INTERLACEMETHOD_RENDER_BOB && m_config.useInteropYuv) -+ else if (method == VS_INTERLACEMETHOD_RENDER_BOB) - { - m_mixersteps = 1; - m_mixerfield = VDP_VIDEO_MIXER_PICTURE_STRUCTURE_FRAME; - m_mixerInput[1].DVDPic.format = RENDER_FMT_VDPAU_420; -+ m_config.useInteropYuv = true; - } - else - { -@@ -3185,7 +3189,7 @@ bool COutput::GLInit() - glVDPAUGetSurfaceivNV = NULL; - #endif - -- m_config.usePixmaps = !g_guiSettings.GetBool("videoplayer.usevdpauinterop"); -+ m_config.usePixmaps = false; - - #ifdef GL_NV_vdpau_interop - if (glewIsSupported("GL_NV_vdpau_interop")) -@@ -3217,8 +3221,7 @@ bool COutput::GLInit() - #endif - { - m_config.usePixmaps = true; -- g_guiSettings.SetBool("videoplayer.usevdpauinterop",false); -- g_guiSettings.SetBool("videoplayer.usevdpauinteropyuv",false); -+ g_guiSettings.SetBool("videoplayer.usevdpaumixer",true); - } - if (!glXBindTexImageEXT) - glXBindTexImageEXT = (PFNGLXBINDTEXIMAGEEXTPROC)glXGetProcAddress((GLubyte *) "glXBindTexImageEXT"); -diff --git a/xbmc/settings/GUISettings.cpp b/xbmc/settings/GUISettings.cpp -index 10ef779..a4bd524 100644 ---- a/xbmc/settings/GUISettings.cpp -+++ b/xbmc/settings/GUISettings.cpp -@@ -690,8 +690,7 @@ void CGUISettings::Initialize() - - #ifdef HAVE_LIBVDPAU - AddBool(vp, "videoplayer.usevdpau", 13425, true); -- AddBool(vp, "videoplayer.usevdpauinterop", 13435, true); -- AddBool(vp, "videoplayer.usevdpauinteropyuv", 13436, false); -+ AddBool(vp, "videoplayer.usevdpaumixer", 13436, true); - #endif - #ifdef HAVE_LIBVA - AddBool(vp, "videoplayer.usevaapi", 13426, true); -diff --git a/xbmc/settings/GUIWindowSettingsCategory.cpp b/xbmc/settings/GUIWindowSettingsCategory.cpp -index 3c19a06..b9f18e4 100644 ---- a/xbmc/settings/GUIWindowSettingsCategory.cpp -+++ b/xbmc/settings/GUIWindowSettingsCategory.cpp -@@ -602,9 +602,9 @@ void CGUIWindowSettingsCategory::UpdateSettings() - pControl->SetEnabled(true); - } - } -- else if (strSetting.Equals("videoplayer.usevdpauinteropyuv")) -+ else if (strSetting.Equals("videoplayer.usevdpaumixer")) - { -- bool hasInterop = g_guiSettings.GetBool("videoplayer.usevdpauinterop"); -+ bool hasInterop = true; - #ifndef GL_NV_vdpau_interop - hasInterop = false; - #endif -@@ -616,24 +616,7 @@ void CGUIWindowSettingsCategory::UpdateSettings() - else - { - pControl->SetEnabled(false); -- g_guiSettings.SetBool("videoplayer.usevdpauinteropyuv",false); -- } -- } -- else if (strSetting.Equals("videoplayer.usevdpauinterop")) -- { -- bool hasInterop = g_guiSettings.GetBool("videoplayer.usevdpau"); --#ifndef GL_NV_vdpau_interop -- hasInterop = false; --#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.usevdpauinterop",false); -+ g_guiSettings.SetBool("videoplayer.usevdpaumixer",true); - } - } - else --- -1.7.10 - - -From a060312a4e236858bf3c9a97d663c5643796b649 Mon Sep 17 00:00:00 2001 -From: xbmc -Date: Wed, 12 Dec 2012 18:34:47 +0100 -Subject: [PATCH 62/73] vdpau: drop studio level conversion - ---- - language/English/strings.po | 6 +- - xbmc/cores/VideoRenderers/LinuxRendererGL.cpp | 4 +- - xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp | 94 +----------------------- - xbmc/settings/GUISettings.cpp | 1 - - 4 files changed, 7 insertions(+), 98 deletions(-) - -diff --git a/language/English/strings.po b/language/English/strings.po -index 281a8a1..fc896b3 100644 ---- a/language/English/strings.po -+++ b/language/English/strings.po -@@ -4371,11 +4371,7 @@ msgctxt "#13121" - msgid "VDPAU HQ Upscaling level" - msgstr "" - --msgctxt "#13122" --msgid "VDPAU Studio level color conversion" --msgstr "" -- --#empty strings from id 13123 to 13129 -+#empty strings from id 13122 to 13129 - - msgctxt "#13130" - msgid "Blank other displays" -diff --git a/xbmc/cores/VideoRenderers/LinuxRendererGL.cpp b/xbmc/cores/VideoRenderers/LinuxRendererGL.cpp -index 7c3adcb..0bb924b 100644 ---- a/xbmc/cores/VideoRenderers/LinuxRendererGL.cpp -+++ b/xbmc/cores/VideoRenderers/LinuxRendererGL.cpp -@@ -3545,7 +3545,7 @@ bool CLinuxRendererGL::Supports(ERENDERFEATURE feature) - { - if(feature == RENDERFEATURE_BRIGHTNESS) - { -- if ((m_renderMethod & RENDER_VDPAU) && !g_guiSettings.GetBool("videoplayer.vdpaustudiolevel")) -+ if (m_renderMethod & RENDER_VDPAU) - return true; - - if (m_renderMethod & RENDER_VAAPI) -@@ -3561,7 +3561,7 @@ bool CLinuxRendererGL::Supports(ERENDERFEATURE feature) - - if(feature == RENDERFEATURE_CONTRAST) - { -- if ((m_renderMethod & RENDER_VDPAU) && !g_guiSettings.GetBool("videoplayer.vdpaustudiolevel")) -+ if (m_renderMethod & RENDER_VDPAU) - return true; - - if (m_renderMethod & RENDER_VAAPI) -diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp -index ad140fb..5851e1a 100644 ---- a/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp -+++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp -@@ -57,15 +57,6 @@ - }; - 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 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 - { - const EINTERLACEMETHOD method; -@@ -1614,74 +1605,6 @@ void CMixer::PostProcOff() - 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; -@@ -1701,19 +1624,10 @@ void CMixer::SetColor() - //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); -- } -+ 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__); - } - -diff --git a/xbmc/settings/GUISettings.cpp b/xbmc/settings/GUISettings.cpp -index a4bd524..67aeec9 100644 ---- a/xbmc/settings/GUISettings.cpp -+++ b/xbmc/settings/GUISettings.cpp -@@ -772,7 +772,6 @@ void CGUISettings::Initialize() - AddSeparator(vp, "videoplayer.sep1.5"); - #ifdef HAVE_LIBVDPAU - AddBool(NULL, "videoplayer.vdpauUpscalingLevel", 13121, false); -- AddBool(vp, "videoplayer.vdpaustudiolevel", 13122, false); - #endif - #endif - AddSeparator(vp, "videoplayer.sep5"); --- -1.7.10 - - -From 6d03704ce1cbc7d09d684da1ced478b2b59c0b35 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Gr=C3=A9gory=20Coutant?= -Date: Wed, 12 Dec 2012 19:49:47 +0100 -Subject: [PATCH 63/73] x11: support for multiple x screens - ---- - xbmc/windowing/X11/XRandR.cpp | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/xbmc/windowing/X11/XRandR.cpp b/xbmc/windowing/X11/XRandR.cpp -index 533e03d..7a16488 100644 ---- a/xbmc/windowing/X11/XRandR.cpp -+++ b/xbmc/windowing/X11/XRandR.cpp -@@ -92,7 +92,7 @@ bool CXRandR::Query(bool force, int screennum) - pclose(file); - - TiXmlElement *pRootElement = xmlDoc.RootElement(); -- if (strcasecmp(pRootElement->Value(), "screen") != screennum) -+ if (atoi(pRootElement->Attribute("id")) != screennum) - { - // TODO ERROR - return false; --- -1.7.10 - - -From 597c8449084e1e5ebfebfb31db570f7826d06517 Mon Sep 17 00:00:00 2001 -From: xbmc -Date: Wed, 12 Dec 2012 20:28:49 +0100 -Subject: [PATCH 64/73] vdpau: observe ffmpeg tags for color space - ---- - xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp | 38 ++++++++++++++++-------- - xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.h | 1 + - 2 files changed, 27 insertions(+), 12 deletions(-) - -diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp -index 5851e1a..8858614 100644 ---- a/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp -+++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp -@@ -907,6 +907,7 @@ int CDecoder::Decode(AVCodecContext *avctx, AVFrame *pFrame) - memset(&pic.DVDPic, 0, sizeof(pic.DVDPic)); - ((CDVDVideoCodecFFmpeg*)avctx->opaque)->GetPictureCommon(&pic.DVDPic); - pic.render = render; -+ pic.DVDPic.color_matrix = avctx->colorspace; - m_bufferStats.IncDecoded(); - m_vdpauOutput.m_dataPort.SendOutMessage(COutputDataProtocol::NEWFRAME, &pic, sizeof(pic)); - -@@ -1513,10 +1514,6 @@ void CMixer::InitCSCMatrix(int Width) - 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() -@@ -1527,11 +1524,13 @@ void CMixer::CheckFeatures() - m_Upscale = m_config.upscale; - } - if (m_Brightness != g_settings.m_currentVideoSettings.m_Brightness || -- m_Contrast != g_settings.m_currentVideoSettings.m_Contrast) -+ m_Contrast != g_settings.m_currentVideoSettings.m_Contrast || -+ m_ColorMatrix != m_mixerInput[1].DVDPic.color_matrix) - { - SetColor(); - m_Brightness = g_settings.m_currentVideoSettings.m_Brightness; - m_Contrast = g_settings.m_currentVideoSettings.m_Contrast; -+ m_ColorMatrix = m_mixerInput[1].DVDPic.color_matrix; - } - if (m_NoiseReduction != g_settings.m_currentVideoSettings.m_NoiseReduction) - { -@@ -1615,13 +1614,27 @@ void CMixer::SetColor() - 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); -+ switch(m_mixerInput[1].DVDPic.color_matrix) -+ { -+ case AVCOL_SPC_BT709: -+ colorStandard = VDP_COLOR_STANDARD_ITUR_BT_709; -+ break; -+ case AVCOL_SPC_BT470BG: -+ case AVCOL_SPC_SMPTE170M: -+ colorStandard = VDP_COLOR_STANDARD_ITUR_BT_601; -+ break; -+ case AVCOL_SPC_SMPTE240M: -+ colorStandard = VDP_COLOR_STANDARD_SMPTE_240M; -+ break; -+ case AVCOL_SPC_FCC: -+ case AVCOL_SPC_UNSPECIFIED: -+ case AVCOL_SPC_RGB: -+ default: -+ if(m_config.surfaceWidth > 1000) -+ colorStandard = VDP_COLOR_STANDARD_ITUR_BT_709; -+ else -+ colorStandard = VDP_COLOR_STANDARD_ITUR_BT_601; -+ } - - VdpVideoMixerAttribute attributes[] = { VDP_VIDEO_MIXER_ATTRIBUTE_CSC_MATRIX }; - vdp_st = m_config.vdpProcs.vdp_generate_csc_matrix(&m_Procamp, colorStandard, &m_CSCMatrix); -@@ -1952,6 +1965,7 @@ void CMixer::Init() - m_Sharpness = 0.0; - m_DeintMode = 0; - m_Deint = 0; -+ m_ColorMatrix = 0; - m_PostProc = false; - m_vdpError = false; - -diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.h b/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.h -index 4d1559c..471ad68 100644 ---- a/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.h -+++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.h -@@ -334,6 +334,7 @@ class CMixer : private CThread - int m_DeintMode; - int m_Deint; - int m_Upscale; -+ unsigned int m_ColorMatrix : 4; - uint32_t *m_BlackBar; - VdpVideoMixerPictureStructure m_mixerfield; - int m_mixerstep; --- -1.7.10 - - -From 3f9308d76025ef1e31923fa9a06587f75c00f870 Mon Sep 17 00:00:00 2001 -From: xbmc -Date: Thu, 20 Dec 2012 19:35:38 +0100 -Subject: [PATCH 65/73] fix compile error after recent change - ---- - xbmc/settings/GUIWindowSettingsCategory.cpp | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/xbmc/settings/GUIWindowSettingsCategory.cpp b/xbmc/settings/GUIWindowSettingsCategory.cpp -index b9f18e4..cacb32a 100644 ---- a/xbmc/settings/GUIWindowSettingsCategory.cpp -+++ b/xbmc/settings/GUIWindowSettingsCategory.cpp -@@ -2453,7 +2453,7 @@ void CGUIWindowSettingsCategory::FillInMonitors(CStdString strSetting) - { - // we expect "videoscreen.monitor" but it might be hidden on some platforms, - // so check that we actually have a visable control. -- CBaseSettingControl *control = GetSetting(strSetting); -+ BaseSettingControlPtr control = GetSetting(strSetting); - if (control) - { - control->SetDelayed(); --- -1.7.10 - - -From 213792b2678760d42740d581a1ee71e186a31c4d Mon Sep 17 00:00:00 2001 -From: xbmc -Date: Mon, 24 Dec 2012 16:02:42 +0100 -Subject: [PATCH 66/73] pvr: increase changes counter of stream on stream - change, cosmetics after - dd307930d39d92f145a01a16600cd00e01ec39be - ---- - xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxPVRClient.cpp | 5 ++--- - 1 file changed, 2 insertions(+), 3 deletions(-) - -diff --git a/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxPVRClient.cpp b/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxPVRClient.cpp -index 8c984f6..034e545 100644 ---- a/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxPVRClient.cpp -+++ b/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxPVRClient.cpp -@@ -348,9 +348,7 @@ void CDVDDemuxPVRClient::RequestStreams() - if (stm) - { - st = dynamic_cast(stm); -- if (!st -- || (st->codec != (CodecID)props.stream[i].iCodecId) -- || (st->iChannels != props.stream[i].iChannels)) -+ if (!st || (st->codec != (CodecID)props.stream[i].iCodecId)) - DisposeStream(i); - } - if (!m_streams[i]) -@@ -367,6 +365,7 @@ void CDVDDemuxPVRClient::RequestStreams() - st->iBitsPerSample = props.stream[i].iBitsPerSample; - m_streams[i] = st; - st->m_parser_split = true; -+ st->changes++; - } - else if (props.stream[i].iCodecType == AVMEDIA_TYPE_VIDEO) - { --- -1.7.10 - - -From e810d3bd68e89e800fba217e88184c2df0fe4040 Mon Sep 17 00:00:00 2001 -From: xbmc -Date: Thu, 17 Jan 2013 16:03:22 +0100 -Subject: [PATCH 67/73] X11: add keymapping for XF86XK_Sleep - ---- - xbmc/windowing/WinEventsX11.cpp | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/xbmc/windowing/WinEventsX11.cpp b/xbmc/windowing/WinEventsX11.cpp -index c31877e..ed31c04 100644 ---- a/xbmc/windowing/WinEventsX11.cpp -+++ b/xbmc/windowing/WinEventsX11.cpp -@@ -143,6 +143,7 @@ - , {XK_Break, XBMCK_BREAK} - , {XK_Menu, XBMCK_MENU} - , {XF86XK_PowerOff, XBMCK_POWER} -+, {XF86XK_Sleep, XBMCK_SLEEP} - , {XK_EcuSign, XBMCK_EURO} - , {XK_Undo, XBMCK_UNDO} - /* Media keys */ --- -1.7.10 - - -From 2cb807b2f801f06723cde1bdd636550c08fc08ab Mon Sep 17 00:00:00 2001 -From: fritsch -Date: Sat, 12 Jan 2013 13:03:50 +0100 -Subject: [PATCH 68/73] dvdplayer: Allow multithread decoding for hi10p - content by default - -This allows decoding of some hi10p material on e.g. AMD Fusion with -both cores at the max. This introduces a new advancedsetting named -disablehi10pmultithreading to disable hi10p decoded multithreaded. ---- - .../DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp | 18 ++++++++++++++++-- - .../dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.h | 1 + - xbmc/settings/AdvancedSettings.cpp | 2 ++ - xbmc/settings/AdvancedSettings.h | 1 + - 4 files changed, 20 insertions(+), 2 deletions(-) - -diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp -index b3252ec..3f8a6e8 100644 ---- a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp -+++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp -@@ -154,6 +154,7 @@ enum PixelFormat CDVDVideoCodecFFmpeg::GetFormat( struct AVCodecContext * avctx - m_iScreenHeight = 0; - m_iOrientation = 0; - m_bSoftware = false; -+ m_isHi10p = false; - m_pHardware = NULL; - m_iLastKeyframe = 0; - m_dts = DVD_NOPTS_VALUE; -@@ -204,7 +205,10 @@ bool CDVDVideoCodecFFmpeg::Open(CDVDStreamInfo &hints, CDVDCodecOptions &options - case FF_PROFILE_H264_HIGH_444_PREDICTIVE: - case FF_PROFILE_H264_HIGH_444_INTRA: - case FF_PROFILE_H264_CAVLC_444: -+ // this is needed to not open the decoders - m_bSoftware = true; -+ // this we need to enable multithreading for hi10p via advancedsettings -+ m_isHi10p = true; - break; - } - } -@@ -277,8 +281,18 @@ bool CDVDVideoCodecFFmpeg::Open(CDVDStreamInfo &hints, CDVDCodecOptions &options - m_pCodecContext->codec_tag = hints.codec_tag; - /* Only allow slice threading, since frame threading is more - * sensitive to changes in frame sizes, and it causes crashes -- * during HW accell */ -- m_pCodecContext->thread_type = FF_THREAD_SLICE; -+ * during HW accell - so we unset it in this case. -+ * -+ * When we detect Hi10p and user did not disable hi10pmultithreading -+ * via advancedsettings.xml we keep the ffmpeg default thread type. -+ * */ -+ if(m_isHi10p && !g_advancedSettings.m_videoDisableHi10pMultithreading) -+ { -+ CLog::Log(LOGDEBUG,"CDVDVideoCodecFFmpeg::Open() Keep default threading for Hi10p: %d", -+ m_pCodecContext->thread_type); -+ } -+ else -+ m_pCodecContext->thread_type = FF_THREAD_SLICE; - - #if defined(TARGET_DARWIN_IOS) - // ffmpeg with enabled neon will crash and burn if this is enabled -diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.h b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.h -index bf4367c..db1d2b2 100644 ---- a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.h -+++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.h -@@ -116,6 +116,7 @@ class CDVDVideoCodecFFmpeg : public CDVDVideoCodec - - std::string m_name; - bool m_bSoftware; -+ bool m_isHi10p; - IHardwareDecoder *m_pHardware; - int m_iLastKeyframe; - double m_dts; -diff --git a/xbmc/settings/AdvancedSettings.cpp b/xbmc/settings/AdvancedSettings.cpp -index d913924..6a48309 100644 ---- a/xbmc/settings/AdvancedSettings.cpp -+++ b/xbmc/settings/AdvancedSettings.cpp -@@ -116,6 +116,7 @@ void CAdvancedSettings::Initialize() - m_DXVANoDeintProcForProgressive = false; - m_videoFpsDetect = 1; - m_videoDefaultLatency = 0.0; -+ m_videoDisableHi10pMultithreading = false; - - m_musicUseTimeSeeking = true; - m_musicTimeSeekForward = 10; -@@ -502,6 +503,7 @@ void CAdvancedSettings::ParseSettingsFile(const CStdString &file) - XMLUtils::GetBoolean(pElement,"enablehighqualityhwscalers", m_videoEnableHighQualityHwScalers); - XMLUtils::GetFloat(pElement,"autoscalemaxfps",m_videoAutoScaleMaxFps, 0.0f, 1000.0f); - XMLUtils::GetBoolean(pElement,"allowmpeg4vdpau",m_videoAllowMpeg4VDPAU); -+ XMLUtils::GetBoolean(pElement,"disablehi10pmultithreading",m_videoDisableHi10pMultithreading); - XMLUtils::GetBoolean(pElement,"allowmpeg4vaapi",m_videoAllowMpeg4VAAPI); - XMLUtils::GetBoolean(pElement, "disablebackgrounddeinterlace", m_videoDisableBackgroundDeinterlace); - XMLUtils::GetInt(pElement, "useocclusionquery", m_videoCaptureUseOcclusionQuery, -1, 1); -diff --git a/xbmc/settings/AdvancedSettings.h b/xbmc/settings/AdvancedSettings.h -index aaa4702..863e4f3 100644 ---- a/xbmc/settings/AdvancedSettings.h -+++ b/xbmc/settings/AdvancedSettings.h -@@ -168,6 +168,7 @@ class CAdvancedSettings - bool m_DXVAForceProcessorRenderer; - bool m_DXVANoDeintProcForProgressive; - int m_videoFpsDetect; -+ bool m_videoDisableHi10pMultithreading; - - CStdString m_videoDefaultPlayer; - CStdString m_videoDefaultDVDPlayer; --- -1.7.10 - - -From 5e52fa15742e1300ac394738ead4ca2792c4812c Mon Sep 17 00:00:00 2001 -From: xbmc -Date: Mon, 21 Jan 2013 09:00:19 +0100 -Subject: [PATCH 69/73] X11: remove toggle full screen after resume - ---- - xbmc/powermanagement/PowerManager.cpp | 5 ----- - 1 file changed, 5 deletions(-) - -diff --git a/xbmc/powermanagement/PowerManager.cpp b/xbmc/powermanagement/PowerManager.cpp -index a5534c9..7e2ddc6 100644 ---- a/xbmc/powermanagement/PowerManager.cpp -+++ b/xbmc/powermanagement/PowerManager.cpp -@@ -223,11 +223,6 @@ void CPowerManager::OnWake() - #if defined(_WIN32) - ShowWindow(g_hWnd,SW_RESTORE); - SetForegroundWindow(g_hWnd); --#elif !defined(TARGET_DARWIN_OSX) -- // Hack to reclaim focus, thus rehiding system mouse pointer. -- // Surely there's a better way? -- g_graphicsContext.ToggleFullScreenRoot(); -- g_graphicsContext.ToggleFullScreenRoot(); - #endif - } - g_application.ResetScreenSaver(); --- -1.7.10 - - -From e8f3e20dfb3bde4434e2aea69b34e22ba1859a31 Mon Sep 17 00:00:00 2001 -From: xbmc -Date: Wed, 23 Jan 2013 17:03:02 +0100 -Subject: [PATCH 70/73] xrandr: set screen on mode change command - ---- - xbmc/windowing/X11/XRandR.cpp | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/xbmc/windowing/X11/XRandR.cpp b/xbmc/windowing/X11/XRandR.cpp -index 7a16488..6531ba3 100644 ---- a/xbmc/windowing/X11/XRandR.cpp -+++ b/xbmc/windowing/X11/XRandR.cpp -@@ -246,7 +246,7 @@ bool CXRandR::SetMode(XOutput output, XMode mode) - m_currentMode = modeFound.id; - char cmd[255]; - if (getenv("XBMC_BIN_HOME")) -- snprintf(cmd, sizeof(cmd), "%s/xbmc-xrandr --output %s --mode %s", getenv("XBMC_BIN_HOME"), outputFound.name.c_str(), modeFound.id.c_str()); -+ snprintf(cmd, sizeof(cmd), "%s/xbmc-xrandr --screen %d --output %s --mode %s", getenv("XBMC_BIN_HOME"), outputFound.screen, outputFound.name.c_str(), modeFound.id.c_str()); - else - return false; - CLog::Log(LOGINFO, "XRANDR: %s", cmd); --- -1.7.10 - - -From f229dba603070e1f0528d395c9d5d63f9044ae6e Mon Sep 17 00:00:00 2001 -From: xbmc -Date: Wed, 23 Jan 2013 17:03:39 +0100 -Subject: [PATCH 71/73] X11: recreate glx context when output changes - ---- - xbmc/windowing/X11/WinSystemX11.cpp | 6 +++--- - xbmc/windowing/X11/WinSystemX11.h | 2 +- - 2 files changed, 4 insertions(+), 4 deletions(-) - -diff --git a/xbmc/windowing/X11/WinSystemX11.cpp b/xbmc/windowing/X11/WinSystemX11.cpp -index e4e25b2..b87e264 100644 ---- a/xbmc/windowing/X11/WinSystemX11.cpp -+++ b/xbmc/windowing/X11/WinSystemX11.cpp -@@ -409,11 +409,11 @@ bool CWinSystemX11::IsSuitableVisual(XVisualInfo *vInfo) - return true; - } - --bool CWinSystemX11::RefreshGlxContext() -+bool CWinSystemX11::RefreshGlxContext(bool force) - { - bool retVal = false; - -- if (m_glContext) -+ if (m_glContext && !force) - { - CLog::Log(LOGDEBUG, "CWinSystemX11::RefreshGlxContext: refreshing context"); - glXMakeCurrent(m_dpy, None, NULL); -@@ -930,7 +930,7 @@ bool CWinSystemX11::SetWindow(int width, int height, bool fullscreen, const CStd - } - - CDirtyRegionList dr; -- RefreshGlxContext(); -+ RefreshGlxContext(!m_currentOutput.Equals(output)); - XSync(m_dpy, FALSE); - g_graphicsContext.Clear(0); - g_graphicsContext.Flip(dr); -diff --git a/xbmc/windowing/X11/WinSystemX11.h b/xbmc/windowing/X11/WinSystemX11.h -index 0b7c10a..33b1739 100644 ---- a/xbmc/windowing/X11/WinSystemX11.h -+++ b/xbmc/windowing/X11/WinSystemX11.h -@@ -74,7 +74,7 @@ class CWinSystemX11 : public CWinSystemBase - void NotifyMouseCoverage(bool covered); - - protected: -- bool RefreshGlxContext(); -+ bool RefreshGlxContext(bool force); - void CheckDisplayEvents(); - void OnLostDevice(); - bool SetWindow(int width, int height, bool fullscreen, const CStdString &output); --- -1.7.10 - - -From ae08a23a2f4fd78139e2ebca8a4a87ab619feb0b Mon Sep 17 00:00:00 2001 -From: xbmc -Date: Sun, 27 Jan 2013 12:10:19 +0100 -Subject: [PATCH 72/73] vdpau: switch off de-interlacing on ff - ---- - xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp | 5 +++-- - 1 file changed, 3 insertions(+), 2 deletions(-) - -diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp -index 8858614..3e21d9d 100644 ---- a/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp -+++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp -@@ -2043,8 +2043,9 @@ void CMixer::InitCycle() - EINTERLACEMETHOD method = GetDeinterlacingMethod(); - bool interlaced = m_mixerInput[1].DVDPic.iFlags & DVP_FLAG_INTERLACED; - -- if (mode == VS_DEINTERLACEMODE_FORCE || -- (mode == VS_DEINTERLACEMODE_AUTO && interlaced)) -+ if (!(flags & DVP_FLAG_NO_POSTPROC) && -+ (mode == VS_DEINTERLACEMODE_FORCE || -+ (mode == VS_DEINTERLACEMODE_AUTO && interlaced))) - { - if((method == VS_INTERLACEMETHOD_AUTO && interlaced) - || method == VS_INTERLACEMETHOD_VDPAU_BOB --- -1.7.10 - - -From 1ea917e026e8c5df15de6ce6276cba9e58d09d3d Mon Sep 17 00:00:00 2001 -From: xbmc -Date: Sat, 2 Feb 2013 13:17:09 +0100 -Subject: [PATCH 73/73] vdpau: fix mp4 part2 decoding, activate by default - ---- - xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp | 8 ++------ - xbmc/settings/AdvancedSettings.cpp | 2 +- - 2 files changed, 3 insertions(+), 7 deletions(-) - -diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp -index 3e21d9d..524efae 100644 ---- a/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp -+++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp -@@ -127,10 +127,9 @@ bool CDecoder::Open(AVCodecContext* avctx, const enum PixelFormat, unsigned int - VdpDecoderProfile profile = 0; - if(avctx->codec_id == CODEC_ID_H264) - profile = VDP_DECODER_PROFILE_H264_HIGH; --#ifdef VDP_DECODER_PROFILE_MPEG4_PART2_ASP - else if(avctx->codec_id == CODEC_ID_MPEG4) - profile = VDP_DECODER_PROFILE_MPEG4_PART2_ASP; --#endif -+ - if(profile) - { - if (!CDVDCodecUtils::IsVP3CompatibleWidth(avctx->coded_width)) -@@ -530,13 +529,10 @@ void CDecoder::ReadFormatOf( PixelFormat fmt - vdp_decoder_profile = VDP_DECODER_PROFILE_VC1_ADVANCED; - vdp_chroma_type = VDP_CHROMA_TYPE_420; - break; --#if (defined PIX_FMT_VDPAU_MPEG4_IN_AVUTIL) && \ -- (defined VDP_DECODER_PROFILE_MP) - case PIX_FMT_VDPAU_MPEG4: -- vdp_decoder_profile = VDP_DECOPEG4_PART2_ASP; -+ vdp_decoder_profile = VDP_DECODER_PROFILE_MPEG4_PART2_ASP; - vdp_chroma_type = VDP_CHROMA_TYPE_420; - break; --#endif - default: - vdp_decoder_profile = 0; - vdp_chroma_type = 0; -diff --git a/xbmc/settings/AdvancedSettings.cpp b/xbmc/settings/AdvancedSettings.cpp -index 6a48309..d390ec7 100644 ---- a/xbmc/settings/AdvancedSettings.cpp -+++ b/xbmc/settings/AdvancedSettings.cpp -@@ -102,7 +102,7 @@ void CAdvancedSettings::Initialize() - m_videoNonLinStretchRatio = 0.5f; - m_videoEnableHighQualityHwScalers = false; - m_videoAutoScaleMaxFps = 30.0f; -- m_videoAllowMpeg4VDPAU = false; -+ m_videoAllowMpeg4VDPAU = true; - m_videoAllowMpeg4VAAPI = false; - m_videoDisableBackgroundDeinterlace = false; - m_videoCaptureUseOcclusionQuery = -1; //-1 is auto detect --- -1.7.10 - diff --git a/packages/mediacenter/xbmc/unpack b/packages/mediacenter/xbmc/unpack deleted file mode 100755 index f21b1bc057..0000000000 --- a/packages/mediacenter/xbmc/unpack +++ /dev/null @@ -1,32 +0,0 @@ -#!/bin/sh - -################################################################################ -# This file is part of OpenELEC - http://www.openelec.tv -# Copyright (C) 2009-2012 Stephan Raue (stephan@openelec.tv) -# -# 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 OpenELEC.tv; see the file COPYING. If not, write to -# the Free Software Foundation, 51 Franklin Street, Suite 500, Boston, MA 02110, USA. -# http://www.gnu.org/copyleft/gpl.html -################################################################################ - -. config/options $1 - -echo "### Applying architecture based patches ###" - -if [ ! $TARGET_ARCH = arm ]; then - for patch in `ls $PKG_DIR/patches.x86`; do - cat $PKG_DIR/patches.x86/$patch | patch -d \ - `echo $PKG_BUILD | cut -f1 -d\ ` -p1 - done -fi From 285acff8801fe501fc5a40888006b048a5aca47c Mon Sep 17 00:00:00 2001 From: Stephan Raue Date: Sun, 24 Feb 2013 23:37:10 +0100 Subject: [PATCH 13/13] projects/Ultra/filesystem: remove not more needed default sound configs Signed-off-by: Stephan Raue --- .../Ultra/filesystem/etc/init.d/03_oemscript | 41 --------- .../usr/share/xtreamer/asound.conf.ultra1 | 85 ------------------- .../usr/share/xtreamer/asound.conf.ultra2 | 85 ------------------- 3 files changed, 211 deletions(-) delete mode 100644 projects/Ultra/filesystem/etc/init.d/03_oemscript delete mode 100644 projects/Ultra/filesystem/usr/share/xtreamer/asound.conf.ultra1 delete mode 100644 projects/Ultra/filesystem/usr/share/xtreamer/asound.conf.ultra2 diff --git a/projects/Ultra/filesystem/etc/init.d/03_oemscript b/projects/Ultra/filesystem/etc/init.d/03_oemscript deleted file mode 100644 index 17676f18c0..0000000000 --- a/projects/Ultra/filesystem/etc/init.d/03_oemscript +++ /dev/null @@ -1,41 +0,0 @@ -################################################################################ -# This file is part of OpenELEC - http://www.openelec.tv -# Copyright (C) 2009-2012 Stephan Raue (stephan@openelec.tv) -# -# 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 OpenELEC.tv; see the file COPYING. If not, write to -# the Free Software Foundation, 51 Franklin Street, Suite 500, Boston, MA 02110, USA. -# http://www.gnu.org/copyleft/gpl.html -################################################################################ - -# -# OEM scripts -# -# runlevels: openelec, installer, textmode - -if [ ! -f /etc/asound.conf -a ! -f $HOME/.config/asound.conf ]; then - - DMI_BOARD_VENDOR=`cat /sys/class/dmi/id/board_vendor` -# DMI_BOARD_VERSION=`cat /sys/class/dmi/id/board_version` - SYSTEM_CPU=`grep -m1 model /proc/cpuinfo | awk '{print $3}'` - - if [ "$DMI_BOARD_VENDOR" = "XtReAmEr" ]; then - if [ "$SYSTEM_CPU" = "28" ]; then - # Xtreamer Ultra 1 - cp /usr/share/xtreamer/asound.conf.ultra1 /run/asound.conf - elif [ "$SYSTEM_CPU" = "54" ]; then - # Xtreamer Ultra 2 - cp /usr/share/xtreamer/asound.conf.ultra2 /run/asound.conf - fi - fi -fi diff --git a/projects/Ultra/filesystem/usr/share/xtreamer/asound.conf.ultra1 b/projects/Ultra/filesystem/usr/share/xtreamer/asound.conf.ultra1 deleted file mode 100644 index f214e3c83f..0000000000 --- a/projects/Ultra/filesystem/usr/share/xtreamer/asound.conf.ultra1 +++ /dev/null @@ -1,85 +0,0 @@ -pcm.!default { - type plug - slave { - pcm "both" - } -} - -pcm.both { - type route - slave { - pcm multi - channels 6 - } - ttable.0.0 1.0 - ttable.1.1 1.0 - ttable.0.2 1.0 - ttable.1.3 1.0 - ttable.0.4 1.0 - ttable.1.5 1.0 -} - -pcm.multi { - type multi - slaves.a { - pcm "hdmi_hw" - channels 2 - } - slaves.b { - pcm "digital_hw" - channels 2 - } - slaves.c { - pcm "analog_hw" - channels 2 - } - bindings.0.slave a - bindings.0.channel 0 - bindings.1.slave a - bindings.1.channel 1 - bindings.2.slave b - bindings.2.channel 0 - bindings.3.slave b - bindings.3.channel 1 - bindings.4.slave c - bindings.4.channel 0 - bindings.5.slave c - bindings.5.channel 1 -} - -pcm.hdmi_hw { - type hw - card 1 - device 7 - channels 2 -} - -pcm.hdmi_formatted { - type plug - slave { - pcm hdmi_hw - rate 48000 - channels 2 - } -} - -pcm.hdmi_complete { - type softvol - slave.pcm hdmi_formatted - control.name hdmi_volume - control.card 1 -} - -pcm.digital_hw { - type hw - card 0 - device 1 - channels 2 -} - -pcm.analog_hw { - type hw - card 0 - device 0 - channels 2 -} diff --git a/projects/Ultra/filesystem/usr/share/xtreamer/asound.conf.ultra2 b/projects/Ultra/filesystem/usr/share/xtreamer/asound.conf.ultra2 deleted file mode 100644 index 8ea89e09c1..0000000000 --- a/projects/Ultra/filesystem/usr/share/xtreamer/asound.conf.ultra2 +++ /dev/null @@ -1,85 +0,0 @@ -pcm.!default { - type plug - slave { - pcm "both" - } -} - -pcm.both { - type route - slave { - pcm multi - channels 6 - } - ttable.0.0 1.0 - ttable.1.1 1.0 - ttable.0.2 1.0 - ttable.1.3 1.0 - ttable.0.4 1.0 - ttable.1.5 1.0 -} - -pcm.multi { - type multi - slaves.a { - pcm "hdmi_hw" - channels 2 - } - slaves.b { - pcm "digital_hw" - channels 2 - } - slaves.c { - pcm "analog_hw" - channels 2 - } - bindings.0.slave a - bindings.0.channel 0 - bindings.1.slave a - bindings.1.channel 1 - bindings.2.slave b - bindings.2.channel 0 - bindings.3.slave b - bindings.3.channel 1 - bindings.4.slave c - bindings.4.channel 0 - bindings.5.slave c - bindings.5.channel 1 -} - -pcm.hdmi_hw { - type hw - card 1 - device 3 - channels 2 -} - -pcm.hdmi_formatted { - type plug - slave { - pcm hdmi_hw - rate 48000 - channels 2 - } -} - -pcm.hdmi_complete { - type softvol - slave.pcm hdmi_formatted - control.name hdmi_volume - control.card 1 -} - -pcm.digital_hw { - type hw - card 0 - device 1 - channels 2 -} - -pcm.analog_hw { - type hw - card 0 - device 0 - channels 2 -}