diff --git a/packages/mediacenter/xbmc-master-theme-Confluence/package.mk b/packages/mediacenter/xbmc-master-theme-Confluence/package.mk
new file mode 100644
index 0000000000..f605dda03e
--- /dev/null
+++ b/packages/mediacenter/xbmc-master-theme-Confluence/package.mk
@@ -0,0 +1,52 @@
+################################################################################
+# This file is part of OpenELEC - http://www.openelec.tv
+# Copyright (C) 2009-2014 Stephan Raue (stephan@openelec.tv)
+#
+# OpenELEC is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 2 of the License, or
+# (at your option) any later version.
+#
+# OpenELEC 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. If not, see .
+################################################################################
+
+PKG_NAME="xbmc-master-theme-Confluence"
+PKG_VERSION="14-088e9fa"
+PKG_REV="1"
+PKG_ARCH="any"
+PKG_LICENSE="GPL"
+PKG_SITE="http://www.xbmc.org"
+PKG_URL="$DISTRO_SRC/$PKG_NAME-$PKG_VERSION.tar.xz"
+PKG_DEPENDS_TARGET="toolchain xbmc-master"
+PKG_PRIORITY="optional"
+PKG_SECTION="mediacenter"
+PKG_SHORTDESC="xbmc-theme-Confluence: XBMC Mediacenter default theme"
+PKG_LONGDESC="XBMC Media Center (which was formerly named Xbox Media Center) is a free and open source cross-platform media player and home entertainment system software with a 10-foot user interface designed for the living-room TV. Its graphical user interface allows the user to easily manage video, photos, podcasts, and music from a computer, optical disk, local network, and the internet using a remote control."
+
+PKG_IS_ADDON="no"
+PKG_AUTORECONF="no"
+
+make_target() {
+ TexturePacker -input media/ \
+ -output Textures.xbt \
+ -dupecheck \
+ -use_none
+}
+
+makeinstall_target() {
+ mkdir -p $INSTALL/usr/share/xbmc/addons/skin.confluence
+ cp -R */ $INSTALL/usr/share/xbmc/addons/skin.confluence
+ cp *.txt $INSTALL/usr/share/xbmc/addons/skin.confluence
+ cp *.xml $INSTALL/usr/share/xbmc/addons/skin.confluence
+ cp *.png $INSTALL/usr/share/xbmc/addons/skin.confluence
+ rm -rf $INSTALL/usr/share/xbmc/addons/skin.confluence/media
+
+ mkdir -p $INSTALL/usr/share/xbmc/addons/skin.confluence/media
+ cp Textures.xbt $INSTALL/usr/share/xbmc/addons/skin.confluence/media
+}
diff --git a/packages/mediacenter/xbmc-master-theme-Confluence/patches/xbmc-master-theme-Confluence-001-add_oe_settings_to_homescreen.patch b/packages/mediacenter/xbmc-master-theme-Confluence/patches/xbmc-master-theme-Confluence-001-add_oe_settings_to_homescreen.patch
new file mode 100644
index 0000000000..79a3addf5a
--- /dev/null
+++ b/packages/mediacenter/xbmc-master-theme-Confluence/patches/xbmc-master-theme-Confluence-001-add_oe_settings_to_homescreen.patch
@@ -0,0 +1,14 @@
+--- a/720p/IncludesHomeMenuItems.xml 2012-07-22 21:56:07.000000000 +0400
++++ b/720p/IncludesHomeMenuItems.xml 2012-09-13 23:34:16.975470148 +0400
+@@ -189,6 +189,11 @@
+
+ ActivateWindow(Settings)
+
++
++ ButtonHomeSubCommonValues
++
++ RunAddon(service.openelec.settings)
++
+
+ ButtonHomeSubCommonValues
+
diff --git a/packages/mediacenter/xbmc-master/config/advancedsettings.xml b/packages/mediacenter/xbmc-master/config/advancedsettings.xml
new file mode 100644
index 0000000000..c54111aaa3
--- /dev/null
+++ b/packages/mediacenter/xbmc-master/config/advancedsettings.xml
@@ -0,0 +1,23 @@
+
+
+ false
+ cputemp
+ gputemp
+
+
+ 30
+
+
+ 4.0
+
+
diff --git a/packages/mediacenter/xbmc-master/config/appliance.xml b/packages/mediacenter/xbmc-master/config/appliance.xml
new file mode 100644
index 0000000000..98fd49f28c
--- /dev/null
+++ b/packages/mediacenter/xbmc-master/config/appliance.xml
@@ -0,0 +1,49 @@
+
+
+
+
+
+
+
+
+ true
+
+
+
+
+
+
+
+ true
+
+
+
+
+
+
+
+ true
+
+
+
+
+
+
+
+
+
+ /usr/bin/setwakeup.sh
+
+
+
+
+
+
diff --git a/packages/mediacenter/xbmc-master/config/os.openelec.tv/addon.xml b/packages/mediacenter/xbmc-master/config/os.openelec.tv/addon.xml
new file mode 100644
index 0000000000..206659f9da
--- /dev/null
+++ b/packages/mediacenter/xbmc-master/config/os.openelec.tv/addon.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
diff --git a/packages/mediacenter/xbmc-master/config/repository.openelec.tv/addon.xml b/packages/mediacenter/xbmc-master/config/repository.openelec.tv/addon.xml
new file mode 100644
index 0000000000..7b21ca7f12
--- /dev/null
+++ b/packages/mediacenter/xbmc-master/config/repository.openelec.tv/addon.xml
@@ -0,0 +1,17 @@
+
+
+
+ @ADDON_URL@/addons.xml
+ @ADDON_URL@/addons.xml.md5
+ @ADDON_URL@
+
+
+ Install Add-ons, Plugins, Games and Programs from [COLOR FF757677]Open[/COLOR][COLOR FF8ABEE2]ELEC[/COLOR]
+ Download and install Add-ons, Plugins, Games and Programs from the Official [COLOR FF757677]Open[/COLOR][COLOR FF8ABEE2]ELEC[/COLOR] addon repository.[CR] By using the official Repository you will be able to take advantage of our extensive file mirror service to help get you faster downloads from a region close to you.[CR] All addons on this repository have under gone basic testing, if you find a broken or not working addon please report it to [COLOR FF757677]Open[/COLOR][COLOR FF8ABEE2]ELEC[/COLOR] so we can take any action needed.
+ all
+
+
diff --git a/packages/mediacenter/xbmc-master/config/repository.openelec.tv/icon.png b/packages/mediacenter/xbmc-master/config/repository.openelec.tv/icon.png
new file mode 100644
index 0000000000..1147ae1d37
Binary files /dev/null and b/packages/mediacenter/xbmc-master/config/repository.openelec.tv/icon.png differ
diff --git a/packages/mediacenter/xbmc-master/debug.d/xbmc.conf b/packages/mediacenter/xbmc-master/debug.d/xbmc.conf
new file mode 100644
index 0000000000..7c6c362ac3
--- /dev/null
+++ b/packages/mediacenter/xbmc-master/debug.d/xbmc.conf
@@ -0,0 +1 @@
+XBMC_DEBUG="--debug"
diff --git a/packages/mediacenter/xbmc-master/fonts/DejaVuSans.ttf b/packages/mediacenter/xbmc-master/fonts/DejaVuSans.ttf
new file mode 100644
index 0000000000..84ca1d7503
Binary files /dev/null and b/packages/mediacenter/xbmc-master/fonts/DejaVuSans.ttf differ
diff --git a/packages/mediacenter/xbmc-master/fonts/Trebuchet MS Bold.ttf b/packages/mediacenter/xbmc-master/fonts/Trebuchet MS Bold.ttf
new file mode 100644
index 0000000000..867f56d776
Binary files /dev/null and b/packages/mediacenter/xbmc-master/fonts/Trebuchet MS Bold.ttf differ
diff --git a/packages/mediacenter/xbmc-master/fonts/YanoneKaffeesatz-Bold.ttf b/packages/mediacenter/xbmc-master/fonts/YanoneKaffeesatz-Bold.ttf
new file mode 100644
index 0000000000..e9964b0809
Binary files /dev/null and b/packages/mediacenter/xbmc-master/fonts/YanoneKaffeesatz-Bold.ttf differ
diff --git a/packages/mediacenter/xbmc-master/package.mk b/packages/mediacenter/xbmc-master/package.mk
new file mode 100644
index 0000000000..787277878a
--- /dev/null
+++ b/packages/mediacenter/xbmc-master/package.mk
@@ -0,0 +1,512 @@
+################################################################################
+# This file is part of OpenELEC - http://www.openelec.tv
+# Copyright (C) 2009-2014 Stephan Raue (stephan@openelec.tv)
+#
+# OpenELEC is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 2 of the License, or
+# (at your option) any later version.
+#
+# OpenELEC 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. If not, see .
+################################################################################
+
+PKG_NAME="xbmc-master"
+PKG_VERSION="14-088e9fa"
+PKG_REV="1"
+PKG_ARCH="any"
+PKG_LICENSE="GPL"
+PKG_SITE="http://www.xbmc.org"
+PKG_URL="$DISTRO_SRC/$PKG_NAME-$PKG_VERSION.tar.xz"
+PKG_DEPENDS_TARGET="toolchain boost Python zlib bzip2 systemd pciutils lzo pcre swig:host libass enca curl rtmpdump fontconfig fribidi gnutls tinyxml libjpeg-turbo libpng tiff freetype jasper libsamplerate libogg libcdio libmodplug faad2 flac libmpeg2 taglib libxml2 libxslt yajl sqlite libvorbis ffmpeg"
+PKG_PRIORITY="optional"
+PKG_SECTION="mediacenter"
+PKG_SHORTDESC="xbmc: XBMC Mediacenter"
+PKG_LONGDESC="XBMC Media Center (which was formerly named Xbox Media Center) is a free and open source cross-platform media player and home entertainment system software with a 10-foot user interface designed for the living-room TV. Its graphical user interface allows the user to easily manage video, photos, podcasts, and music from a computer, optical disk, local network, and the internet using a remote control."
+
+PKG_IS_ADDON="no"
+PKG_AUTORECONF="no"
+
+# for dbus support
+ PKG_DEPENDS_TARGET="$PKG_DEPENDS_TARGET dbus"
+
+# needed for hosttools (Texturepacker)
+ PKG_DEPENDS_TARGET="$PKG_DEPENDS_TARGET lzo:host SDL:host SDL_image:host"
+
+if [ "$DISPLAYSERVER" = "x11" ]; then
+# for libX11 support
+ PKG_DEPENDS_TARGET="$PKG_DEPENDS_TARGET libX11 libXext"
+# for libXrandr support
+ PKG_DEPENDS_TARGET="$PKG_DEPENDS_TARGET libXrandr"
+ XBMC_XORG="--enable-x11 --enable-xrandr"
+else
+ XBMC_XORG="--disable-x11 --disable-xrandr"
+fi
+
+if [ "$OPENGL" = "Mesa" ]; then
+# for OpenGL (GLX) support
+ PKG_DEPENDS_TARGET="$PKG_DEPENDS_TARGET Mesa glu glew"
+ XBMC_OPENGL="--enable-gl"
+else
+ XBMC_OPENGL="--disable-gl"
+fi
+
+if [ "$OPENGLES_SUPPORT" = yes ]; then
+# for OpenGL-ES support
+ PKG_DEPENDS_TARGET="$PKG_DEPENDS_TARGET $OPENGLES"
+ XBMC_OPENGLES="--enable-gles"
+else
+ XBMC_OPENGLES="--disable-gles"
+fi
+
+if [ "$SDL_SUPPORT" = yes ]; then
+# for SDL support
+ PKG_DEPENDS_TARGET="$PKG_DEPENDS_TARGET SDL SDL_image"
+ XBMC_SDL="--enable-sdl"
+else
+ XBMC_SDL="--disable-sdl"
+fi
+
+if [ "$ALSA_SUPPORT" = yes ]; then
+# for ALSA support
+ PKG_DEPENDS_TARGET="$PKG_DEPENDS_TARGET alsa-lib"
+ XBMC_ALSA="--enable-alsa"
+else
+ XBMC_ALSA="--disable-alsa"
+fi
+
+if [ "$PULSEAUDIO_SUPPORT" = yes ]; then
+# for PulseAudio support
+ PKG_DEPENDS_TARGET="$PKG_DEPENDS_TARGET pulseaudio"
+ XBMC_PULSEAUDIO="--enable-pulse"
+else
+ XBMC_PULSEAUDIO="--disable-pulse"
+fi
+
+if [ "$ESPEAK_SUPPORT" = yes ]; then
+# for espeak support
+ PKG_DEPENDS_TARGET="$PKG_DEPENDS_TARGET espeak"
+fi
+
+if [ "$CEC_SUPPORT" = yes ]; then
+# for CEC support
+ PKG_DEPENDS_TARGET="$PKG_DEPENDS_TARGET libcec"
+ XBMC_CEC="--enable-libcec"
+else
+ XBMC_CEC="--disable-libcec"
+fi
+
+if [ "$XBMC_SCR_RSXS" = yes ]; then
+# for RSXS Screensaver support
+ PKG_DEPENDS_TARGET="$PKG_DEPENDS_TARGET libXt libXmu"
+ XBMC_RSXS="--enable-rsxs"
+# fix build of RSXS Screensaver support if not using libiconv
+ export jm_cv_func_gettimeofday_clobber=no
+else
+ XBMC_RSXS="--disable-rsxs"
+fi
+
+if [ "$XBMC_VIS_PROJECTM" = yes ]; then
+# for ProjectM Visualisation support
+ XBMC_PROJECTM="--enable-projectm"
+else
+ XBMC_PROJECTM="--disable-projectm"
+fi
+
+if [ "$XBMC_VIS_GOOM" = yes ]; then
+# for GOOM Visualisation support
+ XBMC_GOOM="--enable-goom"
+else
+ XBMC_GOOM="--disable-goom"
+fi
+
+if [ "$XBMC_VIS_WAVEFORM" = yes ]; then
+# for Waveform Visualisation support
+ XBMC_WAVEFORM="--enable-waveform"
+else
+ XBMC_WAVEFORM="--disable-waveform"
+fi
+
+if [ "$XBMC_VIS_SPECTRUM" = yes ]; then
+# for Spectrum Visualisation support
+ XBMC_SPECTRUM="--enable-spectrum"
+else
+ XBMC_SPECTRUM="--disable-spectrum"
+fi
+
+if [ "$XBMC_VIS_FISHBMC" = yes ]; then
+# for FishBMC Visualisation support
+ XBMC_FISHBMC="--enable-fishbmc"
+else
+ XBMC_FISHBMC="--disable-fishbmc"
+fi
+
+if [ "$JOYSTICK_SUPPORT" = yes ]; then
+# for Joystick support
+ XBMC_JOYSTICK="--enable-joystick"
+else
+ XBMC_JOYSTICK="--disable-joystick"
+fi
+
+if [ "$OPTICAL_DRIVE_SUPPORT" = yes ]; then
+ XBMC_OPTICAL="--enable-optical-drive"
+else
+ XBMC_OPTICAL="--disable-optical-drive"
+fi
+
+if [ "$NONFREE_SUPPORT" = yes ]; then
+# for non-free support
+ XBMC_NONFREE="--enable-non-free"
+else
+ XBMC_NONFREE="--disable-non-free"
+fi
+
+if [ "$DVDCSS_SUPPORT" = yes ]; then
+ XBMC_DVDCSS="--enable-dvdcss"
+else
+ XBMC_DVDCSS="--disable-dvdcss"
+fi
+
+if [ "$FAAC_SUPPORT" = yes ]; then
+ PKG_DEPENDS_TARGET="$PKG_DEPENDS_TARGET faac"
+fi
+
+if [ "$ENCODER_LAME" = yes ]; then
+ PKG_DEPENDS_TARGET="$PKG_DEPENDS_TARGET lame"
+ XBMC_LAMEENC="--enable-libmp3lame"
+else
+ XBMC_LAMEENC="--disable-libmp3lame"
+fi
+
+if [ "$BLURAY_SUPPORT" = yes ]; then
+ PKG_DEPENDS_TARGET="$PKG_DEPENDS_TARGET libbluray"
+ XBMC_BLURAY="--enable-libbluray"
+else
+ XBMC_BLURAY="--disable-libbluray"
+fi
+
+if [ "$AVAHI_DAEMON" = yes ]; then
+ PKG_DEPENDS_TARGET="$PKG_DEPENDS_TARGET avahi"
+ XBMC_AVAHI="--enable-avahi"
+else
+ XBMC_AVAHI="--disable-avahi"
+fi
+
+if [ "$MYSQL_SUPPORT" = yes ]; then
+ PKG_DEPENDS_TARGET="$PKG_DEPENDS_TARGET mysql"
+ XBMC_MYSQL="--enable-mysql"
+else
+ XBMC_MYSQL="--disable-mysql"
+fi
+
+if [ "$AIRPLAY_SUPPORT" = yes ]; then
+ PKG_DEPENDS_TARGET="$PKG_DEPENDS_TARGET libplist"
+ XBMC_AIRPLAY="--enable-airplay"
+else
+ XBMC_AIRPLAY="--disable-airplay"
+fi
+
+if [ "$AIRTUNES_SUPPORT" = yes ]; then
+ PKG_DEPENDS_TARGET="$PKG_DEPENDS_TARGET libshairplay"
+ XBMC_AIRTUNES="--enable-airtunes"
+else
+ XBMC_AIRTUNES="--disable-airtunes"
+fi
+
+if [ "$NFS_SUPPORT" = yes ]; then
+ PKG_DEPENDS_TARGET="$PKG_DEPENDS_TARGET libnfs"
+ XBMC_NFS="--enable-nfs"
+else
+ XBMC_NFS="--disable-nfs"
+fi
+
+if [ "$AFP_SUPPORT" = yes ]; then
+ PKG_DEPENDS_TARGET="$PKG_DEPENDS_TARGET afpfs-ng"
+ XBMC_AFP="--enable-afpclient"
+else
+ XBMC_AFP="--disable-afpclient"
+fi
+
+if [ "$SAMBA_SUPPORT" = yes ]; then
+ PKG_DEPENDS_TARGET="$PKG_DEPENDS_TARGET samba"
+ XBMC_SAMBA="--enable-samba"
+else
+ XBMC_SAMBA="--disable-samba"
+fi
+
+if [ "$WEBSERVER" = yes ]; then
+ PKG_DEPENDS_TARGET="$PKG_DEPENDS_TARGET libmicrohttpd"
+ XBMC_WEBSERVER="--enable-webserver"
+else
+ XBMC_WEBSERVER="--disable-webserver"
+fi
+
+if [ "$UPNP_SUPPORT" = yes ]; then
+ XBMC_UPNP="--enable-upnp"
+else
+ XBMC_UPNP="--disable-upnp"
+fi
+
+if [ "$SSHLIB_SUPPORT" = yes ]; then
+ PKG_DEPENDS_TARGET="$PKG_DEPENDS_TARGET libssh"
+ XBMC_SSH="--enable-ssh"
+else
+ XBMC_SSH="--disable-ssh"
+fi
+
+if [ ! "$XBMCPLAYER_DRIVER" = default ]; then
+ PKG_DEPENDS_TARGET="$PKG_DEPENDS_TARGET $XBMCPLAYER_DRIVER"
+
+ if [ "$XBMCPLAYER_DRIVER" = bcm2835-driver ]; then
+ XBMC_OPENMAX="--enable-openmax"
+ XBMC_PLAYER="--enable-player=omxplayer"
+ XBMC_CODEC="--with-platform=raspberry-pi"
+ BCM2835_INCLUDES="-I$SYSROOT_PREFIX/usr/include/interface/vcos/pthreads/ \
+ -I$SYSROOT_PREFIX/usr/include/interface/vmcs_host/linux"
+ XBMC_CFLAGS="$XBMC_CFLAGS $BCM2835_INCLUDES"
+ XBMC_CXXFLAGS="$XBMC_CXXFLAGS $BCM2835_INCLUDES"
+ elif [ "$XBMCPLAYER_DRIVER" = libfslvpuwrap ]; then
+ XBMC_CODEC="--enable-codec=imxvpu"
+ else
+ XBMC_OPENMAX="--disable-openmax"
+ fi
+fi
+
+if [ "$VDPAU" = yes ]; then
+ PKG_DEPENDS_TARGET="$PKG_DEPENDS_TARGET libvdpau"
+ XBMC_VDPAU="--enable-vdpau"
+else
+ XBMC_VDPAU="--disable-vdpau"
+fi
+
+if [ "$VAAPI" = yes ]; then
+# configure GPU drivers and dependencies:
+ get_graphicdrivers
+
+ PKG_DEPENDS_TARGET="$PKG_DEPENDS_TARGET $LIBVA"
+ XBMC_VAAPI="--enable-vaapi"
+else
+ XBMC_VAAPI="--disable-vaapi"
+fi
+
+if [ "$CRYSTALHD" = yes ]; then
+ PKG_DEPENDS_TARGET="$PKG_DEPENDS_TARGET crystalhd"
+ XBMC_CRYSTALHD="--enable-crystalhd"
+else
+ XBMC_CRYSTALHD="--disable-crystalhd"
+fi
+
+export CXX_FOR_BUILD="$HOST_CXX"
+export CC_FOR_BUILD="$HOST_CC"
+export CXXFLAGS_FOR_BUILD="$HOST_CXXFLAGS"
+export CFLAGS_FOR_BUILD="$HOST_CFLAGS"
+export LDFLAGS_FOR_BUILD="$HOST_LDFLAGS"
+
+export PYTHON_VERSION="2.7"
+export PYTHON_CPPFLAGS="-I$SYSROOT_PREFIX/usr/include/python$PYTHON_VERSION"
+export PYTHON_LDFLAGS="-L$SYSROOT_PREFIX/usr/lib/python$PYTHON_VERSION -lpython$PYTHON_VERSION"
+export PYTHON_SITE_PKG="$SYSROOT_PREFIX/usr/lib/python$PYTHON_VERSION/site-packages"
+export ac_python_version="$PYTHON_VERSION"
+
+PKG_CONFIGURE_OPTS_TARGET="gl_cv_func_gettimeofday_clobber=no \
+ ac_cv_lib_bluetooth_hci_devid=no \
+ --disable-debug \
+ --disable-optimizations \
+ $XBMC_OPENGL \
+ $XBMC_OPENGLES \
+ $XBMC_SDL \
+ $XBMC_OPENMAX \
+ $XBMC_VDPAU \
+ $XBMC_VAAPI \
+ $XBMC_CRYSTALHD \
+ --disable-vtbdecoder \
+ --disable-tegra \
+ --disable-profiling \
+ $XBMC_JOYSTICK \
+ $XBMC_CEC \
+ --enable-udev \
+ --disable-libusb \
+ $XBMC_GOOM \
+ $XBMC_RSXS \
+ $XBMC_PROJECTM \
+ $XBMC_WAVEFORM \
+ $XBMC_SPECTRUM \
+ $XBMC_FISHBMC \
+ $XBMC_XORG \
+ --disable-ccache \
+ $XBMC_ALSA \
+ $XBMC_PULSEAUDIO \
+ --enable-rtmp \
+ $XBMC_SAMBA \
+ $XBMC_NFS \
+ $XBMC_AFP \
+ --enable-libvorbisenc \
+ --disable-libcap \
+ $XBMC_LAMEENC \
+ $XBMC_DVDCSS \
+ --disable-mid \
+ --disable-hal \
+ $XBMC_AVAHI \
+ $XBMC_UPNP \
+ $XBMC_MYSQL \
+ $XBMC_SSH \
+ $XBMC_AIRPLAY \
+ $XBMC_AIRTUNES \
+ $XBMC_NONFREE \
+ --disable-asap-codec \
+ $XBMC_WEBSERVER \
+ $XBMC_OPTICAL \
+ $XBMC_BLURAY \
+ --enable-texturepacker \
+ $XBMC_CODEC \
+ $XBMC_PLAYER"
+
+pre_build_target() {
+# adding fake Makefile for stripped skin
+ mkdir -p $PKG_BUILD/addons/skin.confluence/media
+ touch $PKG_BUILD/addons/skin.confluence/media/Makefile.in
+
+# autoreconf
+ BOOTSTRAP_STANDALONE=1 make -C $PKG_BUILD -f bootstrap.mk
+}
+
+pre_configure_target() {
+# xbmc fails to build in subdirs
+ cd $ROOT/$PKG_BUILD
+ rm -rf .$TARGET_NAME
+
+# xbmc fails to build with LTO optimization if build without GOLD support
+ [ ! "$GOLD_SUPPORT" = "yes" ] && strip_lto
+
+# Todo: XBMC segfaults on exit when building with LTO support
+ strip_lto
+
+ export CFLAGS="$CFLAGS $XBMC_CFLAGS"
+ export CXXFLAGS="$CXXFLAGS $XBMC_CXXFLAGS"
+ export LIBS="$LIBS -lz"
+}
+
+make_target() {
+# build helpertools for host
+ make -C tools/depends/native/JsonSchemaBuilder \
+ CXX="$HOST_CXX" CFLAGS="$HOST_CXXFLAGS" LFLAGS="$HOST_LDFLAGS"
+
+# setup skin dir from default skin
+ SKIN_DIR="skin.`tolower $SKIN_DEFAULT`"
+
+# setup default skin inside the sources
+ sed -i -e "s|skin.confluence|$SKIN_DIR|g" $ROOT/$PKG_BUILD/xbmc/settings/Settings.h
+
+ make externals
+ make xbmc.bin
+
+ if [ "$DISPLAYSERVER" = "x11" ]; then
+ make xbmc-xrandr
+ fi
+
+ make -C tools/TexturePacker
+ cp -PR tools/TexturePacker/TexturePacker $ROOT/$TOOLCHAIN/bin
+}
+
+post_makeinstall_target() {
+ rm -rf $INSTALL/usr/bin/xbmc
+ rm -rf $INSTALL/usr/bin/xbmc-standalone
+ rm -rf $INSTALL/usr/lib/xbmc/*.cmake
+
+ mkdir -p $INSTALL/usr/lib/xbmc
+ cp $PKG_DIR/scripts/xbmc-config $INSTALL/usr/lib/xbmc
+ cp $PKG_DIR/scripts/xbmc-hacks $INSTALL/usr/lib/xbmc
+ cp $PKG_DIR/scripts/xbmc-sources $INSTALL/usr/lib/xbmc
+
+ mkdir -p $INSTALL/usr/lib/openelec
+ cp $PKG_DIR/scripts/systemd-addon-wrapper $INSTALL/usr/lib/openelec
+
+ mkdir -p $INSTALL/usr/bin
+ cp $PKG_DIR/scripts/cputemp $INSTALL/usr/bin
+ ln -sf cputemp $INSTALL/usr/bin/gputemp
+ cp $PKG_DIR/scripts/setwakeup.sh $INSTALL/usr/bin
+ cp tools/EventClients/Clients/XBMC\ Send/xbmc-send.py $INSTALL/usr/bin/xbmc-send
+
+ if [ ! "$DISPLAYSERVER" = "x11" ]; then
+ rm -rf $INSTALL/usr/lib/xbmc/xbmc-xrandr
+ fi
+
+ if [ ! "$XBMC_SCR_RSXS" = yes ]; then
+ rm -rf $INSTALL/usr/share/xbmc/addons/screensaver.rsxs.*
+ fi
+
+ if [ ! "$XBMC_VIS_PROJECTM" = yes ]; then
+ rm -rf $INSTALL/usr/share/xbmc/addons/visualization.projectm
+ fi
+
+ rm -rf $INSTALL/usr/share/applications
+ rm -rf $INSTALL/usr/share/icons
+ rm -rf $INSTALL/usr/share/xbmc/addons/repository.pvr-*
+ rm -rf $INSTALL/usr/share/xbmc/addons/script.module.pysqlite
+ rm -rf $INSTALL/usr/share/xbmc/addons/script.module.simplejson
+ rm -rf $INSTALL/usr/share/xbmc/addons/visualization.dxspectrum
+ rm -rf $INSTALL/usr/share/xbmc/addons/visualization.itunes
+ rm -rf $INSTALL/usr/share/xbmc/addons/visualization.milkdrop
+ rm -rf $INSTALL/usr/share/xbmc/addons/service.xbmc.versioncheck
+ rm -rf $INSTALL/usr/share/xsessions
+
+ mkdir -p $INSTALL/usr/share/xbmc/addons
+ cp -R $PKG_DIR/config/os.openelec.tv $INSTALL/usr/share/xbmc/addons
+ $SED "s|@OS_VERSION@|$OS_VERSION|g" -i $INSTALL/usr/share/xbmc/addons/os.openelec.tv/addon.xml
+ cp -R $PKG_DIR/config/repository.openelec.tv $INSTALL/usr/share/xbmc/addons
+ $SED "s|@ADDON_URL@|$ADDON_URL|g" -i $INSTALL/usr/share/xbmc/addons/repository.openelec.tv/addon.xml
+
+ mkdir -p $INSTALL/usr/lib/python"$PYTHON_VERSION"/site-packages/xbmc
+ cp -R tools/EventClients/lib/python/* $INSTALL/usr/lib/python"$PYTHON_VERSION"/site-packages/xbmc
+
+# install project specific configs
+ mkdir -p $INSTALL/usr/share/xbmc/config
+ if [ -f $PROJECT_DIR/$PROJECT/xbmc/guisettings.xml ]; then
+ cp -R $PROJECT_DIR/$PROJECT/xbmc/guisettings.xml $INSTALL/usr/share/xbmc/config
+ fi
+
+ if [ -f $PROJECT_DIR/$PROJECT/xbmc/sources.xml ]; then
+ cp -R $PROJECT_DIR/$PROJECT/xbmc/sources.xml $INSTALL/usr/share/xbmc/config
+ fi
+
+ mkdir -p $INSTALL/usr/share/xbmc/system/
+ if [ -f $PROJECT_DIR/$PROJECT/xbmc/advancedsettings.xml ]; then
+ cp $PROJECT_DIR/$PROJECT/xbmc/advancedsettings.xml $INSTALL/usr/share/xbmc/system/
+ else
+ cp $PKG_DIR/config/advancedsettings.xml $INSTALL/usr/share/xbmc/system/
+ fi
+
+ mkdir -p $INSTALL/usr/share/xbmc/system/settings
+ if [ -f $PROJECT_DIR/$PROJECT/xbmc/appliance.xml ]; then
+ cp $PROJECT_DIR/$PROJECT/xbmc/appliance.xml $INSTALL/usr/share/xbmc/system/settings
+ else
+ cp $PKG_DIR/config/appliance.xml $INSTALL/usr/share/xbmc/system/settings
+ fi
+
+ if [ "$XBMC_EXTRA_FONTS" = yes ]; then
+ mkdir -p $INSTALL/usr/share/xbmc/media/Fonts
+ cp $PKG_DIR/fonts/*.ttf $INSTALL/usr/share/xbmc/media/Fonts
+ fi
+}
+
+post_install() {
+# link default.target to xbmc.target
+ ln -sf xbmc.target $INSTALL/usr/lib/systemd/system/default.target
+
+ enable_service xbmc-autostart.service
+ enable_service xbmc-cleanlogs.service
+ enable_service xbmc-config.service
+ enable_service xbmc-hacks.service
+ enable_service xbmc-sources.service
+ enable_service xbmc-halt.service
+ enable_service xbmc-poweroff.service
+ enable_service xbmc-reboot.service
+ enable_service xbmc-waitonnetwork.service
+ enable_service xbmc.service
+ enable_service xbmc-lirc-suspend.service
+}
diff --git a/packages/mediacenter/xbmc-master/patches/xbmc-master-101-fix_libdvd_xFLAGS-0.1.patch b/packages/mediacenter/xbmc-master/patches/xbmc-master-101-fix_libdvd_xFLAGS-0.1.patch
new file mode 100644
index 0000000000..00df7bb51c
--- /dev/null
+++ b/packages/mediacenter/xbmc-master/patches/xbmc-master-101-fix_libdvd_xFLAGS-0.1.patch
@@ -0,0 +1,73 @@
+diff -Naur xbmc-master-14-088e9fa/lib/libdvd/libdvdnav/misc/dvdnav-config2.sh xbmc-master-14-088e9fa.patch/lib/libdvd/libdvdnav/misc/dvdnav-config2.sh
+--- xbmc-master-14-088e9fa/lib/libdvd/libdvdnav/misc/dvdnav-config2.sh 2014-05-01 16:53:36.000000000 +0200
++++ xbmc-master-14-088e9fa.patch/lib/libdvd/libdvdnav/misc/dvdnav-config2.sh 2014-05-01 17:54:59.643325427 +0200
+@@ -56,17 +56,17 @@
+ fi
+
+ if test "$echo_cflags" = "yes"; then
+- echo -I$prefix/include $dvdread_cflags $extracflags $threadcflags
++ echo $dvdread_cflags $extracflags $threadcflags
+ fi
+
+ if test "$echo_minicflags" = "yes"; then
+- echo -I$prefix/include -I$prefix/include/dvdnav $extracflags $threadcflags
++ echo $extracflags $threadcflags
+ fi
+
+ if test "$echo_libs" = "yes"; then
+- echo -L$libdir -ldvdnav $dvdread_libs $threadlib
++ echo -ldvdnav $dvdread_libs $threadlib
+ fi
+
+ if test "$echo_minilibs" = "yes"; then
+- echo -L$libdir -ldvdnavmini $threadlib
++ echo -ldvdnavmini $threadlib
+ fi
+diff -Naur xbmc-master-14-088e9fa/lib/libdvd/libdvdnav/misc/dvdnavmini.pc.in xbmc-master-14-088e9fa.patch/lib/libdvd/libdvdnav/misc/dvdnavmini.pc.in
+--- xbmc-master-14-088e9fa/lib/libdvd/libdvdnav/misc/dvdnavmini.pc.in 2014-05-01 16:53:36.000000000 +0200
++++ xbmc-master-14-088e9fa.patch/lib/libdvd/libdvdnav/misc/dvdnavmini.pc.in 2014-05-01 17:56:12.030447794 +0200
+@@ -7,5 +7,5 @@
+ Description: DVD Navigation mini library
+ Version: @VERSION@
+
+-Cflags: -I${includedir} @DVDREAD_CFLAGS@ @THREAD_CFLAGS@
+-Libs: -L${libdir} -ldvdnav @THREAD_LIBS@
++Cflags: @DVDREAD_CFLAGS@ @THREAD_CFLAGS@
++Libs: -ldvdnav @THREAD_LIBS@
+diff -Naur xbmc-master-14-088e9fa/lib/libdvd/libdvdnav/misc/dvdnav.pc.in xbmc-master-14-088e9fa.patch/lib/libdvd/libdvdnav/misc/dvdnav.pc.in
+--- xbmc-master-14-088e9fa/lib/libdvd/libdvdnav/misc/dvdnav.pc.in 2014-05-01 16:53:36.000000000 +0200
++++ xbmc-master-14-088e9fa.patch/lib/libdvd/libdvdnav/misc/dvdnav.pc.in 2014-05-01 17:55:50.427406667 +0200
+@@ -8,5 +8,5 @@
+ Version: @VERSION@
+
+ Requires.private: dvdread >= 4.1.2
+-Cflags: -I${includedir} @THREAD_CFLAGS@
+-Libs: -L${libdir} -ldvdnav @THREAD_LIBS@
++Cflags: @THREAD_CFLAGS@
++Libs: -ldvdnav @THREAD_LIBS@
+diff -Naur xbmc-master-14-088e9fa/lib/libdvd/libdvdread/misc/dvdread-config.sh xbmc-master-14-088e9fa.patch/lib/libdvd/libdvdread/misc/dvdread-config.sh
+--- xbmc-master-14-088e9fa/lib/libdvd/libdvdread/misc/dvdread-config.sh 2014-05-01 16:53:36.000000000 +0200
++++ xbmc-master-14-088e9fa.patch/lib/libdvd/libdvdread/misc/dvdread-config.sh 2014-05-01 17:56:55.745553577 +0200
+@@ -48,9 +48,9 @@
+ fi
+
+ if test "$echo_cflags" = "yes"; then
+- echo -I$prefix/include $extracflags
++ echo $extracflags
+ fi
+
+ if test "$echo_libs" = "yes"; then
+- echo -L$libdir $dvdreadlib
++ echo $dvdreadlib
+ fi
+diff -Naur xbmc-master-14-088e9fa/lib/libdvd/libdvdread/misc/dvdread.pc.in xbmc-master-14-088e9fa.patch/lib/libdvd/libdvdread/misc/dvdread.pc.in
+--- xbmc-master-14-088e9fa/lib/libdvd/libdvdread/misc/dvdread.pc.in 2014-05-01 16:53:36.000000000 +0200
++++ xbmc-master-14-088e9fa.patch/lib/libdvd/libdvdread/misc/dvdread.pc.in 2014-05-01 17:57:28.731937685 +0200
+@@ -7,5 +7,5 @@
+ Description: Low level DVD access library
+ Version: @VERSION@
+
+-Cflags: -I${includedir}
+-Libs: -L${libdir} -ldvdread
++Cflags: -I.
++Libs: -ldvdread
diff --git a/packages/mediacenter/xbmc-master/patches/xbmc-master-102-disable_backslash-0.1.patch b/packages/mediacenter/xbmc-master/patches/xbmc-master-102-disable_backslash-0.1.patch
new file mode 100644
index 0000000000..0888920258
--- /dev/null
+++ b/packages/mediacenter/xbmc-master/patches/xbmc-master-102-disable_backslash-0.1.patch
@@ -0,0 +1,12 @@
+diff -Naur xbmc-30a9070/system/keymaps/keyboard.xml xbmc-30a9070.patch/system/keymaps/keyboard.xml
+--- xbmc-30a9070/system/keymaps/keyboard.xml 2011-07-28 06:20:13.000000000 +0200
++++ xbmc-30a9070.patch/system/keymaps/keyboard.xml 2011-07-28 09:39:57.210973380 +0200
+@@ -90,7 +90,7 @@
+ Number7
+ Number8
+ Number9
+- ToggleFullScreen
++
+ FirstPage
+ LastPage
+
diff --git a/packages/mediacenter/xbmc-master/patches/xbmc-master-103-disable-online-check.patch b/packages/mediacenter/xbmc-master/patches/xbmc-master-103-disable-online-check.patch
new file mode 100644
index 0000000000..6f357d3aa7
--- /dev/null
+++ b/packages/mediacenter/xbmc-master/patches/xbmc-master-103-disable-online-check.patch
@@ -0,0 +1,61 @@
+From 7503fd2355ab44503cf38809c5ba70ef2c0f2144 Mon Sep 17 00:00:00 2001
+From: Stefan Saraev
+Date: Fri, 10 Jan 2014 19:44:16 +0200
+Subject: [PATCH] disable online check
+
+---
+ xbmc/GUIInfoManager.cpp | 1 -
+ xbmc/utils/SystemInfo.cpp | 5 +----
+ xbmc/windows/GUIWindowSystemInfo.cpp | 1 -
+ 3 files changed, 1 insertion(+), 6 deletions(-)
+
+diff --git a/xbmc/GUIInfoManager.cpp b/xbmc/GUIInfoManager.cpp
+index 10173ee..70a474a 100644
+--- a/xbmc/GUIInfoManager.cpp
++++ b/xbmc/GUIInfoManager.cpp
+@@ -271,7 +271,6 @@ const infomap system_labels[] = {{ "hasnetwork", SYSTEM_ETHERNET_LINK_ACT
+ { "currentwindow", SYSTEM_CURRENT_WINDOW },
+ { "currentcontrol", SYSTEM_CURRENT_CONTROL },
+ { "dvdlabel", SYSTEM_DVD_LABEL },
+- { "internetstate", SYSTEM_INTERNET_STATE },
+ { "kernelversion", SYSTEM_KERNEL_VERSION },
+ { "uptime", SYSTEM_UPTIME },
+ { "totaluptime", SYSTEM_TOTALUPTIME },
+diff --git a/xbmc/utils/SystemInfo.cpp b/xbmc/utils/SystemInfo.cpp
+index c77d495..06459dc 100644
+--- a/xbmc/utils/SystemInfo.cpp
++++ b/xbmc/utils/SystemInfo.cpp
+@@ -72,7 +72,6 @@ bool CSysInfoJob::DoWork()
+ {
+ m_info.systemUptime = GetSystemUpTime(false);
+ m_info.systemTotalUptime = GetSystemUpTime(true);
+- m_info.internetState = GetInternetState();
+ m_info.videoEncoder = GetVideoEncoder();
+ m_info.cpuFrequency = GetCPUFreqInfo();
+ m_info.kernelVersion = CSysInfo::GetKernelVersion();
+@@ -569,9 +568,7 @@ CStdString CSysInfo::GetKernelVersion()
+
+ bool CSysInfo::HasInternet()
+ {
+- if (m_info.internetState != CSysData::UNKNOWN)
+- return m_info.internetState == CSysData::CONNECTED;
+- return (m_info.internetState = CSysInfoJob::GetInternetState()) == CSysData::CONNECTED;
++ return m_info.internetState == CSysData::UNKNOWN;
+ }
+
+ CStdString CSysInfo::GetHddSpaceInfo(int drive, bool shortText)
+diff --git a/xbmc/windows/GUIWindowSystemInfo.cpp b/xbmc/windows/GUIWindowSystemInfo.cpp
+index 60aa49d..a0a2e27 100644
+--- a/xbmc/windows/GUIWindowSystemInfo.cpp
++++ b/xbmc/windows/GUIWindowSystemInfo.cpp
+@@ -126,7 +126,6 @@ void CGUIWindowSystemInfo::FrameMove()
+ SetControlLabel(i++, "%s: %s", 13160, NETWORK_GATEWAY_ADDRESS);
+ SetControlLabel(i++, "%s: %s", 13161, NETWORK_DNS1_ADDRESS);
+ SetControlLabel(i++, "%s: %s", 20307, NETWORK_DNS2_ADDRESS);
+- SetControlLabel(i++, "%s %s", 13295, SYSTEM_INTERNET_STATE);
+ }
+ else if (m_section == CONTROL_BT_VIDEO)
+ {
+--
+1.8.3.2
+
diff --git a/packages/mediacenter/xbmc-master/patches/xbmc-master-104-use-udevil-to-umount.patch b/packages/mediacenter/xbmc-master/patches/xbmc-master-104-use-udevil-to-umount.patch
new file mode 100644
index 0000000000..86bfb5c4fe
--- /dev/null
+++ b/packages/mediacenter/xbmc-master/patches/xbmc-master-104-use-udevil-to-umount.patch
@@ -0,0 +1,39 @@
+From 855160db446fe0059f072b207d53c15ba18d952f Mon Sep 17 00:00:00 2001
+From: Stefan Saraev
+Date: Thu, 17 Apr 2014 12:12:50 +0300
+Subject: [PATCH] use udevil to umount
+
+---
+ xbmc/linux/PosixMountProvider.cpp | 2 +-
+ xbmc/storage/linux/UDevProvider.cpp | 2 +-
+ 2 files changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/xbmc/linux/PosixMountProvider.cpp b/xbmc/linux/PosixMountProvider.cpp
+index 2339709..7001563 100644
+--- a/xbmc/linux/PosixMountProvider.cpp
++++ b/xbmc/linux/PosixMountProvider.cpp
+@@ -131,7 +131,7 @@ bool CPosixMountProvider::Eject(CStdString mountpath)
+ {
+ // just go ahead and try to umount the disk
+ // if it does umount, life is good, if not, no loss.
+- std::string cmd = "umount \"" + mountpath + "\"";
++ std::string cmd = "udevil umount \"" + mountpath + "\"";
+ int status = system(cmd.c_str());
+
+ if (status == 0)
+diff --git a/xbmc/storage/linux/UDevProvider.cpp b/xbmc/storage/linux/UDevProvider.cpp
+index 73aa408..8bd02b6 100644
+--- a/xbmc/storage/linux/UDevProvider.cpp
++++ b/xbmc/storage/linux/UDevProvider.cpp
+@@ -183,7 +183,7 @@ bool CUDevProvider::Eject(CStdString mountpath)
+ {
+ // just go ahead and try to umount the disk
+ // if it does umount, life is good, if not, no loss.
+- std::string cmd = "umount \"" + mountpath + "\"";
++ std::string cmd = "udevil umount \"" + mountpath + "\"";
+ int status = system(cmd.c_str());
+
+ if (status == 0)
+--
+1.9.1
+
diff --git a/packages/mediacenter/xbmc-master/patches/xbmc-master-501-enable_PYTHONOPTIMIZE_with_external_Python-0.1.patch b/packages/mediacenter/xbmc-master/patches/xbmc-master-501-enable_PYTHONOPTIMIZE_with_external_Python-0.1.patch
new file mode 100644
index 0000000000..d58eeecb9d
--- /dev/null
+++ b/packages/mediacenter/xbmc-master/patches/xbmc-master-501-enable_PYTHONOPTIMIZE_with_external_Python-0.1.patch
@@ -0,0 +1,18 @@
+diff --git a/xbmc/interfaces/python/XBPython.cpp b/xbmc/interfaces/python/XBPython.cpp
+index 01a129e..07b4878 100644
+--- a/xbmc/interfaces/python/XBPython.cpp
++++ b/xbmc/interfaces/python/XBPython.cpp
+@@ -445,10 +445,9 @@ bool XBPython::InitializeEngine()
+ // at http://docs.python.org/using/cmdline.html#environment-variables
+
+ #if !defined(TARGET_WINDOWS) && !defined(TARGET_ANDROID)
+- /* PYTHONOPTIMIZE is set off intentionally when using external Python.
+- Reason for this is because we cannot be sure what version of Python
+- was used to compile the various Python object files (i.e. .pyo,
+- .pyc, etc.). */
++ // Required for python to find optimized code (pyo) files
++ setenv("PYTHONOPTIMIZE", "1", 1);
++
+ // check if we are running as real xbmc.app or just binary
+ if (!CUtil::GetFrameworksPath(true).empty())
+ {
diff --git a/packages/mediacenter/xbmc-master/patches/xbmc-master-502-add_openelec.tv_RSS_news-0.1.patch b/packages/mediacenter/xbmc-master/patches/xbmc-master-502-add_openelec.tv_RSS_news-0.1.patch
new file mode 100644
index 0000000000..f0b08b5e8d
--- /dev/null
+++ b/packages/mediacenter/xbmc-master/patches/xbmc-master-502-add_openelec.tv_RSS_news-0.1.patch
@@ -0,0 +1,11 @@
+diff -Naur xbmc-12.0.7/userdata/RssFeeds.xml xbmc-12.0.7.patch/userdata/RssFeeds.xml
+--- xbmc-12.0.7/userdata/RssFeeds.xml 2013-03-15 14:25:26.000000000 +0100
++++ xbmc-12.0.7.patch/userdata/RssFeeds.xml 2013-03-15 14:40:54.695338102 +0100
+@@ -3,6 +3,7 @@
+
+
+
++ http://feeds.openelec.tv/news
+ http://feeds.xbmc.org/xbmc
+
+
diff --git a/packages/mediacenter/xbmc-master/patches/xbmc-master-990.15-depends-mark_our_wrapped_functions_as_used.patch b/packages/mediacenter/xbmc-master/patches/xbmc-master-990.15-depends-mark_our_wrapped_functions_as_used.patch
new file mode 100644
index 0000000000..7e78fbb3b9
--- /dev/null
+++ b/packages/mediacenter/xbmc-master/patches/xbmc-master-990.15-depends-mark_our_wrapped_functions_as_used.patch
@@ -0,0 +1,458 @@
+From 0c2eaf5082a30fb06bad553775e805a745d59ee2 Mon Sep 17 00:00:00 2001
+From: theuni
+Date: Tue, 22 Jan 2013 04:09:07 -0500
+Subject: [PATCH] depends: mark our wrapped functions as used
+
+otherwise they get stripped when enabling dead code stripping
+---
+ xbmc/cores/DllLoader/exports/wrapper.c | 138 ++++++++++++++++-----------------
+ 1 file changed, 69 insertions(+), 69 deletions(-)
+
+diff -Naur xbmc-f81d56e/xbmc/cores/DllLoader/exports/wrapper.c xbmc-f81d56e.patch/xbmc/cores/DllLoader/exports/wrapper.c
+--- xbmc-f81d56e/xbmc/cores/DllLoader/exports/wrapper.c 2013-05-18 12:30:19.000000000 +0200
++++ xbmc-f81d56e.patch/xbmc/cores/DllLoader/exports/wrapper.c 2013-05-18 16:55:55.222087716 +0200
+@@ -115,7 +115,7 @@
+ int dll_setvbuf(FILE *stream, char *buf, int type, size_t size);
+ struct mntent *dll_getmntent(FILE *fp);
+
+-void *__wrap_dlopen(const char *filename, int flag)
++__attribute__((used)) void *__wrap_dlopen(const char *filename, int flag)
+ {
+ #if defined(TARGET_ANDROID)
+ return dll_dlopen(filename, flag);
+@@ -124,213 +124,213 @@
+ #endif
+ }
+
+-FILE *__wrap_popen(const char *command, const char *mode)
++__attribute__((used)) FILE *__wrap_popen(const char *command, const char *mode)
+ {
+ return dll_popen(command, mode);
+ }
+
+-void* __wrap_calloc( size_t num, size_t size )
++__attribute__((used)) void* __wrap_calloc( size_t num, size_t size )
+ {
+ return dllcalloc(num, size);
+ }
+
+-void* __wrap_malloc(size_t size)
++__attribute__((used)) void* __wrap_malloc(size_t size)
+ {
+ return dllmalloc(size);
+ }
+
+-void* __wrap_realloc( void *memblock, size_t size )
++__attribute__((used)) void* __wrap_realloc( void *memblock, size_t size )
+ {
+ return dllrealloc(memblock, size);
+ }
+
+-void __wrap_free( void* pPtr )
++__attribute__((used)) void __wrap_free( void* pPtr )
+ {
+ dllfree(pPtr);
+ }
+
+-int __wrap_open(const char *file, int oflag, ...)
++__attribute__((used)) int __wrap_open(const char *file, int oflag, ...)
+ {
+ return dll_open(file, oflag);
+ }
+
+-int __wrap_open64(const char *file, int oflag, ...)
++__attribute__((used)) int __wrap_open64(const char *file, int oflag, ...)
+ {
+ return dll_open(file, oflag);
+ }
+
+-int __wrap_close(int fd)
++__attribute__((used)) int __wrap_close(int fd)
+ {
+ return dll_close(fd);
+ }
+
+-ssize_t __wrap_write(int fd, const void *buf, size_t count)
++__attribute__((used)) ssize_t __wrap_write(int fd, const void *buf, size_t count)
+ {
+ return dll_write(fd, buf, count);
+ }
+
+-ssize_t __wrap_read(int fd, void *buf, size_t count)
++__attribute__((used)) ssize_t __wrap_read(int fd, void *buf, size_t count)
+ {
+ return dll_read(fd, buf, count);
+ }
+
+-__off_t __wrap_lseek(int fildes, __off_t offset, int whence)
++__attribute__((used)) __off_t __wrap_lseek(int fildes, __off_t offset, int whence)
+ {
+ return dll_lseek(fildes, offset, whence);
+ }
+
+-__off64_t __wrap_lseek64(int fildes, __off64_t offset, int whence)
++__attribute__((used)) __off64_t __wrap_lseek64(int fildes, __off64_t offset, int whence)
+ {
+ __off64_t seekRes = dll_lseeki64(fildes, offset, whence);
+ return seekRes;
+ }
+
+-int __wrap_fclose(FILE *fp)
++__attribute__((used)) int __wrap_fclose(FILE *fp)
+ {
+ return dll_fclose(fp);
+ }
+
+-int __wrap_ferror(FILE *stream)
++__attribute__((used)) int __wrap_ferror(FILE *stream)
+ {
+ return dll_ferror(stream);
+ }
+
+-void __wrap_clearerr(FILE *stream)
++__attribute__((used)) void __wrap_clearerr(FILE *stream)
+ {
+ return dll_clearerr(stream);
+ }
+
+-int __wrap_feof(FILE *stream)
++__attribute__((used)) int __wrap_feof(FILE *stream)
+ {
+ return dll_feof(stream);
+ }
+
+-int __wrap_fileno(FILE *stream)
++__attribute__((used)) int __wrap_fileno(FILE *stream)
+ {
+ return dll_fileno(stream);
+ }
+
+-FILE *__wrap_fopen(const char *path, const char *mode)
++__attribute__((used)) FILE *__wrap_fopen(const char *path, const char *mode)
+ {
+ return dll_fopen(path, mode);
+ }
+
+-FILE *__wrap_fopen64(const char *path, const char *mode)
++__attribute__((used)) FILE *__wrap_fopen64(const char *path, const char *mode)
+ {
+ return dll_fopen(path, mode);
+ }
+
+-FILE *__wrap_fdopen(int fildes, const char *mode)
++__attribute__((used)) FILE *__wrap_fdopen(int fildes, const char *mode)
+ {
+ return dll_fdopen(fildes, mode);
+ }
+
+-FILE *__wrap_freopen(const char *path, const char *mode, FILE *stream)
++__attribute__((used)) FILE *__wrap_freopen(const char *path, const char *mode, FILE *stream)
+ {
+ return dll_freopen(path, mode, stream);
+ }
+
+-size_t __wrap_fread(void *ptr, size_t size, size_t nmemb, FILE *stream)
++__attribute__((used)) size_t __wrap_fread(void *ptr, size_t size, size_t nmemb, FILE *stream)
+ {
+ return dll_fread(ptr, size, nmemb, stream);
+ }
+
+-size_t __wrap_fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream)
++__attribute__((used)) size_t __wrap_fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream)
+ {
+ return dll_fwrite(ptr, size, nmemb, stream);
+ }
+
+-int __wrap_fflush(FILE *stream)
++__attribute__((used)) int __wrap_fflush(FILE *stream)
+ {
+ return dll_fflush(stream);
+ }
+
+-int __wrap_fputc(int c, FILE *stream)
++__attribute__((used)) int __wrap_fputc(int c, FILE *stream)
+ {
+ return dll_fputc(c, stream);
+ }
+
+-int __wrap_fputs(const char *s, FILE *stream)
++__attribute__((used)) int __wrap_fputs(const char *s, FILE *stream)
+ {
+ return dll_fputs(s, stream);
+ }
+
+-int __wrap__IO_putc(int c, FILE *stream)
++__attribute__((used)) int __wrap__IO_putc(int c, FILE *stream)
+ {
+ return dll_putc(c, stream);
+ }
+
+-int __wrap_fseek(FILE *stream, long offset, int whence)
++__attribute__((used)) int __wrap_fseek(FILE *stream, long offset, int whence)
+ {
+ return dll_fseek(stream, offset, whence);
+ }
+
+-int __wrap_fseeko64(FILE *stream, off64_t offset, int whence)
++__attribute__((used)) int __wrap_fseeko64(FILE *stream, off64_t offset, int whence)
+ {
+ return dll_fseek64(stream, offset, whence);
+ }
+
+-long __wrap_ftell(FILE *stream)
++__attribute__((used)) long __wrap_ftell(FILE *stream)
+ {
+ return dll_ftell(stream);
+ }
+
+-off64_t __wrap_ftello64(FILE *stream)
++__attribute__((used)) off64_t __wrap_ftello64(FILE *stream)
+ {
+ return dll_ftell64(stream);
+ }
+
+-void __wrap_rewind(FILE *stream)
++__attribute__((used)) void __wrap_rewind(FILE *stream)
+ {
+ dll_rewind(stream);
+ }
+
+-int __wrap_fgetpos(FILE *stream, fpos_t *pos)
++__attribute__((used)) int __wrap_fgetpos(FILE *stream, fpos_t *pos)
+ {
+ return dll_fgetpos(stream, pos);
+ }
+
+-int __wrap_fgetpos64(FILE *stream, fpos64_t *pos)
++__attribute__((used)) int __wrap_fgetpos64(FILE *stream, fpos64_t *pos)
+ {
+ return dll_fgetpos64(stream, pos);
+ }
+
+-int __wrap_fsetpos(FILE *stream, fpos_t *pos)
++__attribute__((used)) int __wrap_fsetpos(FILE *stream, fpos_t *pos)
+ {
+ return dll_fsetpos(stream, pos);
+ }
+
+-int __wrap_fsetpos64(FILE *stream, fpos64_t *pos)
++__attribute__((used)) int __wrap_fsetpos64(FILE *stream, fpos64_t *pos)
+ {
+ return dll_fsetpos64(stream, pos);
+ }
+
+-DIR * __wrap_opendir(const char *name)
++__attribute__((used)) DIR * __wrap_opendir(const char *name)
+ {
+ return dll_opendir(name);
+ }
+
+-struct dirent * __wrap_readdir(DIR* dirp)
++__attribute__((used)) struct dirent * __wrap_readdir(DIR* dirp)
+ {
+ return dll_readdir(dirp);
+ }
+
+-struct dirent * __wrap_readdir64(DIR* dirp)
++__attribute__((used)) struct dirent * __wrap_readdir64(DIR* dirp)
+ {
+ return dll_readdir(dirp);
+ }
+
+-int __wrap_closedir(DIR* dirp)
++__attribute__((used)) int __wrap_closedir(DIR* dirp)
+ {
+ return dll_closedir(dirp);
+ }
+
+-void __wrap_rewinddir(DIR* dirp)
++__attribute__((used)) void __wrap_rewinddir(DIR* dirp)
+ {
+ dll_rewinddir(dirp);
+ }
+
+-int __wrap_fprintf(FILE *stream, const char *format, ...)
++__attribute__((used)) int __wrap_fprintf(FILE *stream, const char *format, ...)
+ {
+ int res;
+ va_list va;
+@@ -340,12 +340,12 @@
+ return res;
+ }
+
+-int __wrap_vfprintf(FILE *stream, const char *format, va_list ap)
++__attribute__((used)) int __wrap_vfprintf(FILE *stream, const char *format, va_list ap)
+ {
+ return dll_vfprintf(stream, format, ap);
+ }
+
+-int __wrap_printf(const char *format, ...)
++__attribute__((used)) int __wrap_printf(const char *format, ...)
+ {
+ int res;
+ va_list va;
+@@ -355,42 +355,42 @@
+ return res;
+ }
+
+-int __wrap_fgetc(FILE *stream)
++__attribute__((used)) int __wrap_fgetc(FILE *stream)
+ {
+ return dll_fgetc(stream);
+ }
+
+-char *__wrap_fgets(char *s, int size, FILE *stream)
++__attribute__((used)) char *__wrap_fgets(char *s, int size, FILE *stream)
+ {
+ return dll_fgets(s, size, stream);
+ }
+
+-int __wrap__IO_getc(FILE *stream)
++__attribute__((used)) int __wrap__IO_getc(FILE *stream)
+ {
+ return dll_getc(stream);
+ }
+
+-int __wrap__IO_getc_unlocked(FILE *stream)
++__attribute__((used)) int __wrap__IO_getc_unlocked(FILE *stream)
+ {
+ return dll_getc(stream);
+ }
+
+-int __wrap_getc_unlocked(FILE *stream)
++__attribute__((used)) int __wrap_getc_unlocked(FILE *stream)
+ {
+ return dll_getc(stream);
+ }
+
+-int __wrap_ungetc(int c, FILE *stream)
++__attribute__((used)) int __wrap_ungetc(int c, FILE *stream)
+ {
+ return dll_ungetc(c, stream);
+ }
+
+-int __wrap_getc(FILE *stream)
++__attribute__((used)) int __wrap_getc(FILE *stream)
+ {
+ return dll_getc(stream);
+ }
+
+-int __wrap_ioctl(int d, unsigned long int request, ...)
++__attribute__((used)) int __wrap_ioctl(int d, unsigned long int request, ...)
+ {
+ int res;
+ va_list va;
+@@ -400,57 +400,57 @@
+ return res;
+ }
+
+-int __wrap__stat(const char *path, struct _stat *buffer)
++__attribute__((used)) int __wrap__stat(const char *path, struct _stat *buffer)
+ {
+ return dll_stat(path, buffer);
+ }
+
+-int __wrap_stat(const char *path, struct _stat *buffer)
++__attribute__((used)) int __wrap_stat(const char *path, struct _stat *buffer)
+ {
+ return dll_stat(path, buffer);
+ }
+
+-int __wrap___xstat64(int __ver, const char *__filename, struct stat64 *__stat_buf)
++__attribute__((used)) int __wrap___xstat64(int __ver, const char *__filename, struct stat64 *__stat_buf)
+ {
+ return dll_stat64(__filename, __stat_buf);
+ }
+
+-int __wrap___lxstat64(int __ver, const char *__filename, struct stat64 *__stat_buf)
++__attribute__((used)) int __wrap___lxstat64(int __ver, const char *__filename, struct stat64 *__stat_buf)
+ {
+ return dll_stat64(__filename, __stat_buf);
+ }
+
+-void __wrap_flockfile(FILE *file)
++__attribute__((used)) void __wrap_flockfile(FILE *file)
+ {
+ dll_flockfile(file);
+ }
+
+-int __wrap_ftrylockfile(FILE *file)
++__attribute__((used)) int __wrap_ftrylockfile(FILE *file)
+ {
+ return dll_ftrylockfile(file);
+ }
+
+-void __wrap_funlockfile(FILE *file)
++__attribute__((used)) void __wrap_funlockfile(FILE *file)
+ {
+ dll_funlockfile(file);
+ }
+
+-int __wrap___fxstat64(int ver, int fd, struct stat64 *buf)
++__attribute__((used)) int __wrap___fxstat64(int ver, int fd, struct stat64 *buf)
+ {
+ return dll_fstat64(fd, buf);
+ }
+
+-int __wrap_fstat(int fd, struct _stat *buf)
++__attribute__((used)) int __wrap_fstat(int fd, struct _stat *buf)
+ {
+ return dll_fstat(fd, buf);
+ }
+
+-int __wrap_setvbuf(FILE *stream, char *buf, int type, size_t size)
++__attribute__((used)) int __wrap_setvbuf(FILE *stream, char *buf, int type, size_t size)
+ {
+ return dll_setvbuf(stream, buf, type, size);
+ }
+
+-struct mntent *__wrap_getmntent(FILE *fp)
++__attribute__((used)) struct mntent *__wrap_getmntent(FILE *fp)
+ {
+ #ifdef _LINUX
+ return dll_getmntent(fp);
+@@ -464,12 +464,12 @@
+ // thing to actually call our wrapped functions.
+ #if _FORTIFY_SOURCE > 1
+
+-size_t __wrap___fread_chk(void * ptr, size_t ptrlen, size_t size, size_t n, FILE * stream)
++__attribute__((used)) size_t __wrap___fread_chk(void * ptr, size_t ptrlen, size_t size, size_t n, FILE * stream)
+ {
+ return dll_fread(ptr, size, n, stream);
+ }
+
+-int __wrap___printf_chk(int flag, const char *format, ...)
++__attribute__((used)) int __wrap___printf_chk(int flag, const char *format, ...)
+ {
+ int res;
+ va_list va;
+@@ -479,12 +479,12 @@
+ return res;
+ }
+
+-int __wrap___vfprintf_chk(FILE* stream, int flag, const char *format, _G_va_list ap)
++__attribute__((used)) int __wrap___vfprintf_chk(FILE* stream, int flag, const char *format, _G_va_list ap)
+ {
+ return dll_vfprintf(stream, format, ap);
+ }
+
+-int __wrap___fprintf_chk(FILE * stream, int flag, const char *format, ...)
++__attribute__((used)) int __wrap___fprintf_chk(FILE * stream, int flag, const char *format, ...)
+ {
+ int res;
+ va_list va;
+@@ -494,12 +494,12 @@
+ return res;
+ }
+
+-char *__wrap___fgets_chk(char *s, size_t size, int n, FILE *stream)
++__attribute__((used)) char *__wrap___fgets_chk(char *s, size_t size, int n, FILE *stream)
+ {
+ return dll_fgets(s, n, stream);
+ }
+
+-size_t __wrap___read_chk(int fd, void *buf, size_t nbytes, size_t buflen)
++__attribute__((used)) size_t __wrap___read_chk(int fd, void *buf, size_t nbytes, size_t buflen)
+ {
+ return dll_read(fd, buf, nbytes);
+ }
diff --git a/packages/mediacenter/xbmc-master/patches/xbmc-master-995.01-fernetmenta-fixes-40dad6e.patch b/packages/mediacenter/xbmc-master/patches/xbmc-master-995.01-fernetmenta-fixes-40dad6e.patch
new file mode 100644
index 0000000000..5ec3bbe576
--- /dev/null
+++ b/packages/mediacenter/xbmc-master/patches/xbmc-master-995.01-fernetmenta-fixes-40dad6e.patch
@@ -0,0 +1,3603 @@
+From 8b2e394a1d9b4b0a3942ae1d2f76aaa20916119e Mon Sep 17 00:00:00 2001
+From: xbmc
+Date: Mon, 28 May 2012 10:34:39 +0200
+Subject: [PATCH 01/31] videoplayer: adapt lateness detection and dropping to
+ buffering
+
+---
+ xbmc/cores/VideoRenderers/RenderManager.cpp | 16 +-
+ xbmc/cores/VideoRenderers/RenderManager.h | 12 +-
+ .../dvdplayer/DVDCodecs/Video/DVDVideoCodec.h | 15 +-
+ .../DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp | 31 ++++
+ .../DVDCodecs/Video/DVDVideoCodecFFmpeg.h | 7 +
+ xbmc/cores/dvdplayer/DVDPlayerVideo.cpp | 194 +++++++++++++++++----
+ xbmc/cores/dvdplayer/DVDPlayerVideo.h | 23 +++
+ 7 files changed, 260 insertions(+), 38 deletions(-)
+
+diff --git a/xbmc/cores/VideoRenderers/RenderManager.cpp b/xbmc/cores/VideoRenderers/RenderManager.cpp
+index 6832721..f4b381e 100644
+--- a/xbmc/cores/VideoRenderers/RenderManager.cpp
++++ b/xbmc/cores/VideoRenderers/RenderManager.cpp
+@@ -286,6 +286,8 @@ bool CXBMCRenderManager::Configure(unsigned int width, unsigned int height, unsi
+ m_bIsStarted = true;
+ m_bReconfigured = true;
+ m_presentstep = PRESENT_IDLE;
++ m_presentpts = DVD_NOPTS_VALUE;
++ m_sleeptime = 1.0;
+ m_presentevent.notifyAll();
+
+ m_firstFlipPage = false; // tempfix
+@@ -629,7 +631,7 @@ 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*/, double pts /* = 0 */, int source /*= -1*/, EFIELDSYNC sync /*= FS_NONE*/)
+ {
+ { CSharedLock lock(m_sharedSection);
+
+@@ -697,6 +699,7 @@ void CXBMCRenderManager::FlipPage(volatile bool& bStop, double timestamp /* = 0L
+ m.timestamp = timestamp;
+ m.presentfield = sync;
+ m.presentmethod = presentmethod;
++ m.pts = pts;
+ requeue(m_queued, m_free);
+
+ /* signal to any waiters to check state */
+@@ -1065,6 +1068,8 @@ void CXBMCRenderManager::PrepareNextRender()
+ m_discard.push_back(m_presentsource);
+ m_presentsource = idx;
+ m_queued.pop_front();
++ m_sleeptime = m_Queue[idx].timestamp - clocktime;
++ m_presentpts = m_Queue[idx].pts;
+ m_presentevent.notifyAll();
+ }
+ }
+@@ -1081,3 +1086,12 @@ void CXBMCRenderManager::DiscardBuffer()
+ m_presentstep = PRESENT_IDLE;
+ m_presentevent.notifyAll();
+ }
++
++bool CXBMCRenderManager::GetStats(double &sleeptime, double &pts, int &bufferLevel)
++{
++ CSingleLock lock(m_presentlock);
++ sleeptime = m_sleeptime;
++ pts = m_presentpts;
++ bufferLevel = m_queued.size() + m_discard.size();
++ return true;
++}
+diff --git a/xbmc/cores/VideoRenderers/RenderManager.h b/xbmc/cores/VideoRenderers/RenderManager.h
+index c469795..949c652b 100644
+--- a/xbmc/cores/VideoRenderers/RenderManager.h
++++ b/xbmc/cores/VideoRenderers/RenderManager.h
+@@ -98,10 +98,11 @@ class CXBMCRenderManager
+ *
+ * @param bStop reference to stop flag of calling thread
+ * @param timestamp of frame delivered with AddVideoPicture
++ * @param pts used for lateness detection
+ * @param source depreciated
+ * @param sync signals frame, top, or bottom field
+ */
+- void FlipPage(volatile bool& bStop, double timestamp = 0.0, int source = -1, EFIELDSYNC sync = FS_NONE);
++ void FlipPage(volatile bool& bStop, double timestamp = 0.0, double pts = 0.0, int source = -1, EFIELDSYNC sync = FS_NONE);
+ unsigned int PreInit();
+ void UnInit();
+ bool Flush();
+@@ -176,6 +177,12 @@ class CXBMCRenderManager
+ int WaitForBuffer(volatile bool& bStop, int timeout = 100);
+
+ /**
++ * 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);
++
++ /**
+ * Video player call this on flush in oder to discard any queued frames
+ */
+ void DiscardBuffer();
+@@ -222,6 +229,7 @@ class CXBMCRenderManager
+
+ struct SPresent
+ {
++ double pts;
+ double timestamp;
+ EFIELDSYNC presentfield;
+ EPRESENTMETHOD presentmethod;
+@@ -233,6 +241,8 @@ class CXBMCRenderManager
+
+ ERenderFormat m_format;
+
++ double m_sleeptime;
++ double m_presentpts;
+ double m_presentcorr;
+ double m_presenterr;
+ double m_errorbuff[ERRORBUFFSIZE];
+diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodec.h b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodec.h
+index 1553789..7761f7fa 100644
+--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodec.h
++++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodec.h
+@@ -134,6 +134,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
+@@ -151,6 +155,9 @@ class CDVDCodecOptions;
+ #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:
+@@ -268,7 +275,6 @@ class CDVDVideoCodec
+ return 0;
+ }
+
+-
+ /**
+ * Number of references to old pictures that are allowed to
+ * be retained when calling decode on the next demux packet
+@@ -285,4 +291,11 @@ class CDVDVideoCodec
+ * Interact with user settings so that user disabled codecs are disabled
+ */
+ static bool IsCodecDisabled(DVDCodecAvailableType* map, unsigned int size, AVCodecID id);
++
++ 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 b6c1e04..275a0a1 100644
+--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp
++++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp
+@@ -167,6 +167,7 @@ CDVDVideoCodecFFmpeg::CDVDVideoCodecFFmpeg() : CDVDVideoCodec()
+ m_iLastKeyframe = 0;
+ m_dts = DVD_NOPTS_VALUE;
+ m_started = false;
++ m_decoderPts = DVD_NOPTS_VALUE;
+ }
+
+ CDVDVideoCodecFFmpeg::~CDVDVideoCodecFFmpeg()
+@@ -342,6 +343,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
+@@ -543,6 +552,7 @@ int CDVDVideoCodecFFmpeg::Decode(uint8_t* pData, int iSize, double dts, double p
+ void CDVDVideoCodecFFmpeg::Reset()
+ {
+ m_started = false;
++ m_decoderPts = DVD_NOPTS_VALUE;
+ m_iLastKeyframe = m_pCodecContext->has_b_frames;
+ avcodec_flush_buffers(m_pCodecContext);
+
+@@ -640,6 +650,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;
+
+@@ -821,3 +847,8 @@ unsigned CDVDVideoCodecFFmpeg::GetAllowedReferences()
+ 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 75ac0f2..51e4c80 100644
+--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.h
++++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.h
+@@ -50,6 +50,7 @@ class CDVDVideoCodecFFmpeg : public CDVDVideoCodec
+ virtual int Check (AVCodecContext* avctx) = 0;
+ virtual void Reset () {}
+ virtual unsigned GetAllowedReferences() { return 0; }
++ virtual bool CanSkipDeint() {return false; }
+ virtual const std::string Name() = 0;
+ virtual CCriticalSection* Section() { return NULL; }
+ };
+@@ -67,6 +68,8 @@ class CDVDVideoCodecFFmpeg : public CDVDVideoCodec
+ virtual const char* GetName() { return m_name.c_str(); }; // m_name is never changed after open
+ virtual unsigned GetConvergeCount();
+ virtual unsigned GetAllowedReferences();
++ 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; };
+@@ -122,4 +125,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 99b3155..4fad1a3 100644
+--- a/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp
++++ b/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp
+@@ -38,6 +38,7 @@
+ #include "DVDCodecs/DVDCodecs.h"
+ #include "DVDCodecs/Overlay/DVDOverlayCodecCC.h"
+ #include "DVDCodecs/Overlay/DVDOverlaySSA.h"
++#include "guilib/GraphicContext.h"
+ #include
+ #include
+ #include
+@@ -320,8 +321,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)
+ {
+@@ -431,6 +434,7 @@ void CDVDPlayerVideo::Process()
+ picture.iFlags &= ~DVP_FLAG_ALLOCATED;
+ m_packets.clear();
+ m_started = false;
++ m_droppingStats.Reset();
+ }
+ else if (pMsg->IsType(CDVDMsg::GENERAL_FLUSH)) // private message sent by (CDVDPlayerVideo::Flush())
+ {
+@@ -443,6 +447,7 @@ void CDVDPlayerVideo::Process()
+ //we need to recalculate the framerate
+ //TODO: this needs to be set on a streamchange instead
+ ResetFrameRateCalc();
++ m_droppingStats.Reset();
+
+ m_stalled = true;
+ m_started = false;
+@@ -460,8 +465,10 @@ void CDVDPlayerVideo::Process()
+ m_speed = static_cast(pMsg)->m_value;
+ if(m_speed == DVD_PLAYSPEED_PAUSE)
+ m_iNrOfPicturesNotToSkip = 0;
++
+ if (m_pVideoCodec)
+ m_pVideoCodec->SetSpeed(m_speed);
++ m_droppingStats.Reset();
+ }
+ else if (pMsg->IsType(CDVDMsg::PLAYER_STARTED))
+ {
+@@ -507,6 +514,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++;
++ }
++
+ if (m_messageQueue.GetDataSize() == 0
+ || m_speed < 0)
+ {
+@@ -559,15 +588,7 @@ 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++;
+- }
++
+ // reset the request, the following while loop may break before
+ // setting the flag to a new value
+ bRequestDrop = false;
+@@ -1176,33 +1197,12 @@ 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_DROPPED))
+ {
+- 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
+- }
+- m_iDroppedRequest++;
+- }
+- }
+- else
+- {
+- m_iDroppedRequest = 0;
+- }
+-
+- if( (pPicture->iFlags & DVP_FLAG_DROPPED) )
++ m_droppingStats.AddOutputDropGain(pts, 1/m_fFrameRate);
++ CLog::Log(LOGDEBUG,"%s - dropped in output", __FUNCTION__);
+ return result | EOS_DROPPED;
++ }
+
+ // set fieldsync if picture is interlaced
+ EFIELDSYNC mDisplayField = FS_NONE;
+@@ -1235,7 +1235,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, (iCurrentClock + iSleepTime) / DVD_TIME_BASE, pts, -1, mDisplayField);
+
+ return result;
+ #else
+@@ -1535,3 +1535,127 @@ 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;
++ if (bNewFrame)
++ m_droppingStats.m_dropRequests++;
++ }
++ }
++ }
++ else
++ {
++ m_droppingStats.m_dropRequests = 0;
++ m_droppingStats.m_lateFrames = 0;
++ }
++ 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;
++}
++
++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 f8ad541..186e271 100644
+--- a/xbmc/cores/dvdplayer/DVDPlayerVideo.h
++++ b/xbmc/cores/dvdplayer/DVDPlayerVideo.h
+@@ -36,6 +36,25 @@ class CDVDOverlayCodecCC;
+
+ #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;
++};
++
++
+ class CDVDPlayerVideo : public CThread
+ {
+ public:
+@@ -104,6 +123,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);
+@@ -129,6 +149,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
+@@ -182,5 +203,7 @@ class CDVDPlayerVideo : public CThread
+ CPullupCorrection m_pullupCorrection;
+
+ std::list m_packets;
++
++ CDroppingStats m_droppingStats;
+ };
+
+--
+1.9.1
+
+
+From e39d9892089539a7b18bb3fe1191865ea45190ba Mon Sep 17 00:00:00 2001
+From: xbmc
+Date: Sun, 2 Sep 2012 16:05:21 +0200
+Subject: [PATCH 02/31] video player: present correct pts to user for a/v sync
+ (after buffering in renderer)
+
+---
+ xbmc/cores/dvdplayer/DVDPlayerVideo.cpp | 25 +++++++++++++++++++++++++
+ xbmc/cores/dvdplayer/DVDPlayerVideo.h | 2 +-
+ 2 files changed, 26 insertions(+), 1 deletion(-)
+
+diff --git a/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp b/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp
+index 4fad1a3..1d29b6f 100644
+--- a/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp
++++ b/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp
+@@ -1455,6 +1455,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
+
+@@ -1573,6 +1589,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 186e271..59c7f09 100644
+--- a/xbmc/cores/dvdplayer/DVDPlayerVideo.h
++++ b/xbmc/cores/dvdplayer/DVDPlayerVideo.h
+@@ -100,7 +100,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.9.1
+
+
+From 0570c7ff2c7179228fc9a27f7b3ccfac94b7bdfb Mon Sep 17 00:00:00 2001
+From: xbmc
+Date: Sat, 16 Feb 2013 18:25:53 +0100
+Subject: [PATCH 03/31] videoplayer: some rework and documentation
+
+---
+ .../dvdplayer/DVDCodecs/Video/DVDVideoCodec.h | 28 ++++++++++++++++++++--
+ .../DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp | 11 +++++++++
+ .../DVDCodecs/Video/DVDVideoCodecFFmpeg.h | 2 +-
+ xbmc/cores/dvdplayer/DVDPlayerVideo.cpp | 2 +-
+ 4 files changed, 39 insertions(+), 4 deletions(-)
+
+diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodec.h b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodec.h
+index 7761f7fa..2fbc656 100644
+--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodec.h
++++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodec.h
+@@ -156,7 +156,6 @@ class CDVDCodecOptions;
+ #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
+ {
+@@ -292,10 +291,35 @@ class CDVDVideoCodec
+ */
+ static bool IsCodecDisabled(DVDCodecAvailableType* map, unsigned int size, AVCodecID id);
+
+- virtual bool GetPts(double &pts, int &skippedDeint, int &interlaced)
++ /* For calculation of dropping requirements player asks for some information.
++ *
++ * - pts : right after decoder, used to detect gaps (dropped frames in decoder)
++ * - skippedDeint : indicates if decoder has just skipped a deinterlacing cycle
++ * instead of dropping a full frame
++ * - interlaced : when detecting gaps in pts, player needs to know whether
++ * it's interlaced or not
++ *
++ * If codec does not implement this method, pts of decoded frame at input
++ * video player is used. In case coded does post-proc and de-interlacing there
++ * may be quite some frames queued up between exit decoder and entry player.
++ */
++ virtual bool GetCodecStats(double &pts, int &skippedDeint, int &interlaced)
+ {
+ return false;
+ }
+
++ /**
++ * Codec can be informed by player with the following flags:
++ *
++ * DVP_FLAG_NO_POSTPROC : if speed is not normal the codec can switch off
++ * postprocessing and de-interlacing
++ *
++ * DVP_FLAG_DRAIN : codecs may do postprocessing and de-interlacing.
++ * If video buffers in RenderManager are about to run dry,
++ * this is signaled to codec. Codec can wait for post-proc
++ * to be finished instead of returning empty and getting another
++ * packet.
++ *
++ */
+ virtual void SetCodecControl(int flags) {}
+ };
+diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp
+index 275a0a1..6bbb84d 100644
+--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp
++++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp
+@@ -848,6 +848,17 @@ unsigned CDVDVideoCodecFFmpeg::GetAllowedReferences()
+ return 0;
+ }
+
++bool CDVDVideoCodecFFmpeg::GetCodecStats(double &pts, int &skippedDeint, int &interlaced)
++{
++ pts = m_decoderPts;
++ skippedDeint = m_skippedDeint;
++ if (m_pFrame)
++ interlaced = m_pFrame->interlaced_frame;
++ else
++ interlaced = 0;
++ return true;
++}
++
+ 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 51e4c80..fa3269c 100644
+--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.h
++++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.h
+@@ -68,7 +68,7 @@ class CDVDVideoCodecFFmpeg : public CDVDVideoCodec
+ virtual const char* GetName() { return m_name.c_str(); }; // m_name is never changed after open
+ virtual unsigned GetConvergeCount();
+ virtual unsigned GetAllowedReferences();
+- 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 bool GetCodecStats(double &pts, int &skippedDeint, int &interlaced);
+ virtual void SetCodecControl(int flags);
+
+ bool IsHardwareAllowed() { return !m_bSoftware; }
+diff --git a/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp b/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp
+index 1d29b6f..ee07f30 100644
+--- a/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp
++++ b/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp
+@@ -1566,7 +1566,7 @@ int CDVDPlayerVideo::CalcDropRequirement(double pts)
+ int iBufferLevel;
+
+ // get decoder stats
+- if (!m_pVideoCodec->GetPts(iDecoderPts, iSkippedDeint, interlaced))
++ if (!m_pVideoCodec->GetCodecStats(iDecoderPts, iSkippedDeint, interlaced))
+ iDecoderPts = pts;
+ if (iDecoderPts == DVD_NOPTS_VALUE)
+ iDecoderPts = pts;
+--
+1.9.1
+
+
+From 381675ecca0d1fb63fd8aa9f6ec739e5c18ee4f8 Mon Sep 17 00:00:00 2001
+From: Rainer Hochecker
+Date: Sat, 1 Jun 2013 11:21:19 +0200
+Subject: [PATCH 04/31] renderer: bump buffers to 5
+
+---
+ xbmc/cores/VideoRenderers/BaseRenderer.h | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/xbmc/cores/VideoRenderers/BaseRenderer.h b/xbmc/cores/VideoRenderers/BaseRenderer.h
+index dc2712a..9edfbd4 100644
+--- a/xbmc/cores/VideoRenderers/BaseRenderer.h
++++ b/xbmc/cores/VideoRenderers/BaseRenderer.h
+@@ -29,7 +29,7 @@
+
+ #define MAX_PLANES 3
+ #define MAX_FIELDS 3
+-#define NUM_BUFFERS 3
++#define NUM_BUFFERS 5
+
+ class CSetting;
+
+--
+1.9.1
+
+
+From 35ba3c519542ad7b02b592bb2c2c9ff8a05719ce Mon Sep 17 00:00:00 2001
+From: xbmc
+Date: Mon, 28 May 2012 10:41:31 +0200
+Subject: [PATCH 05/31] 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 ee07f30..b3175cd 100644
+--- a/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp
++++ b/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp
+@@ -708,6 +708,8 @@ void CDVDPlayerVideo::Process()
+
+ int iResult = OutputPicture(&picture, pts);
+
++ frametime = (double)DVD_TIME_BASE/m_fFrameRate;
++
+ if(m_started == false)
+ {
+ m_codecname = m_pVideoCodec->GetName();
+--
+1.9.1
+
+
+From f12924d8f83c0dffb4275a7a56846f82a57aed2b Mon Sep 17 00:00:00 2001
+From: xbmc
+Date: Mon, 28 May 2012 10:43:06 +0200
+Subject: [PATCH 06/31] 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 b3175cd..9c36bdb 100644
+--- a/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp
++++ b/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp
+@@ -1497,7 +1497,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.9.1
+
+
+From 56524c7db6419b70dff776dab252bcf0d6c9a457 Mon Sep 17 00:00:00 2001
+From: xbmc
+Date: Mon, 28 May 2012 10:49:05 +0200
+Subject: [PATCH 07/31] 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 3f2e0df..097af37 100644
+--- a/xbmc/cores/dvdplayer/DVDPlayer.cpp
++++ b/xbmc/cores/dvdplayer/DVDPlayer.cpp
+@@ -1633,7 +1633,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())
+ {
+@@ -2294,6 +2294,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.9.1
+
+
+From 52736a2ab8fc4264c02a1712449db2a91df95f1e Mon Sep 17 00:00:00 2001
+From: xbmc
+Date: Mon, 20 Aug 2012 16:06:39 +0200
+Subject: [PATCH 08/31] dvdplayer: observe pts counter overflow
+
+---
+ .../cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.cpp | 197 ++++++++++++++++++++-
+ xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.h | 4 +
+ 2 files changed, 200 insertions(+), 1 deletion(-)
+
+diff --git a/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.cpp b/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.cpp
+index 872c81f..eda7dc9 100644
+--- a/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.cpp
++++ b/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.cpp
+@@ -18,7 +18,6 @@
+ *
+ */
+
+-#include "system.h"
+ #ifndef __STDC_CONSTANT_MACROS
+ #define __STDC_CONSTANT_MACROS
+ #endif
+@@ -26,6 +25,7 @@
+ #define __STDC_LIMIT_MACROS
+ #endif
+ #ifdef TARGET_POSIX
++#include "system.h"
+ #include "stdint.h"
+ #endif
+ #include "DVDDemuxFFmpeg.h"
+@@ -417,6 +417,9 @@ bool CDVDDemuxFFmpeg::Open(CDVDInputStream* pInput)
+
+ CreateStreams();
+
++ m_bPtsWrapChecked = false;
++ m_bPtsWrap = false;
++
+ return true;
+ }
+
+@@ -558,6 +561,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;
+@@ -697,6 +706,24 @@ DemuxPacket* CDVDDemuxFFmpeg::Read()
+ m_pkt.pkt.pts = AV_NOPTS_VALUE;
+ }
+
++ if (!m_bPtsWrapChecked && m_pFormatContext->iformat->flags & AVFMT_TS_DISCONT)
++ {
++ int defaultStream = 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 = m_pkt.pkt.size;
+
+@@ -830,7 +857,16 @@ bool CDVDDemuxFFmpeg::SeekTime(int time, bool backwords, double *startpts)
+ ret = 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)
+@@ -849,6 +885,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 = av_find_default_stream_index(m_pFormatContext);
++
++ if (defaultStream < 0)
++ {
++ return false;
++ }
++
++ // timestamp for default must be expressed in AV_TIME_BASE units
++ pts = 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 = 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)
+ {
+ CSingleLock lock(m_critSection);
+diff --git a/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.h b/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.h
+index 44e101c..3b0f615 100644
+--- a/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.h
++++ b/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.h
+@@ -99,6 +99,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);
+@@ -153,5 +154,8 @@ class CDVDDemuxFFmpeg : public CDVDDemux
+ AVPacket pkt; // packet ffmpeg returned
+ int result; // result from av_read_packet
+ }m_pkt;
++
++ bool m_bPtsWrap, m_bPtsWrapChecked;
++ int64_t m_iStartTime, m_iMaxTime, m_iEndTime;
+ };
+
+--
+1.9.1
+
+
+From b73d59d45e8c2f0b882cde7e549a82aee59f82ac Mon Sep 17 00:00:00 2001
+From: xbmc
+Date: Tue, 2 Oct 2012 13:02:10 +0200
+Subject: [PATCH 09/31] dvdplayer: avoid short screen flicker caused by
+ unnecessary reconfigure of renderer
+
+---
+ xbmc/cores/dvdplayer/DVDPlayerVideo.cpp | 5 ++++-
+ 1 file changed, 4 insertions(+), 1 deletion(-)
+
+diff --git a/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp b/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp
+index 9c36bdb..322a581 100644
+--- a/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp
++++ b/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp
+@@ -1054,13 +1054,16 @@ int CDVDPlayerVideo::OutputPicture(const DVDVideoPicture* src, double pts)
+
+ #ifdef HAS_VIDEO_PLAYBACK
+ double config_framerate = m_bFpsInvalid ? 0.0 : m_fFrameRate;
++ double render_framerate = g_graphicsContext.GetFPS();
++ if (CSettings::Get().GetInt("videoplayer.adjustrefreshrate") == ADJUST_REFRESHRATE_OFF)
++ render_framerate = config_framerate;
+ /* check so that our format or aspect has changed. if it has, reconfigure renderer */
+ if (!g_renderManager.IsConfigured()
+ || ( m_output.width != pPicture->iWidth )
+ || ( 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 && render_framerate != config_framerate)
+ || ( 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
+--
+1.9.1
+
+
+From 11c8f418d34212924278702cf6355ca6ed11496e Mon Sep 17 00:00:00 2001
+From: xbmc
+Date: Thu, 11 Oct 2012 12:05:50 +0200
+Subject: [PATCH 10/31] 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 719b70a..9c962ae 100644
+--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp
++++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp
+@@ -1962,10 +1962,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 a13330f..0d5e546 100644
+--- a/xbmc/settings/AdvancedSettings.cpp
++++ b/xbmc/settings/AdvancedSettings.cpp
+@@ -163,6 +163,8 @@ void CAdvancedSettings::Initialize()
+ m_videoAutoScaleMaxFps = 30.0f;
+ 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;
+@@ -600,6 +602,8 @@ void CAdvancedSettings::ParseSettingsFile(const CStdString &file)
+ XMLUtils::GetBoolean(pElement,"disableswmultithreading",m_videoDisableSWMultithreading);
+ 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 3b417a6..7075f05 100644
+--- a/xbmc/settings/AdvancedSettings.h
++++ b/xbmc/settings/AdvancedSettings.h
+@@ -160,6 +160,8 @@ class CAdvancedSettings : public ISettingCallback, public ISettingsHandler
+ 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.9.1
+
+
+From 4da96e30c0b33a844c203ccc68ac52c027cad150 Mon Sep 17 00:00:00 2001
+From: xbmc
+Date: Fri, 2 Nov 2012 13:20:03 +0100
+Subject: [PATCH 11/31] player: fix rewind
+
+---
+ xbmc/cores/dvdplayer/DVDMessage.h | 5 ++++-
+ xbmc/cores/dvdplayer/DVDPlayer.cpp | 30 +++++++++++++++++++-----------
+ xbmc/cores/dvdplayer/DVDPlayer.h | 7 ++++---
+ xbmc/cores/dvdplayer/DVDPlayerVideo.cpp | 4 +++-
+ xbmc/cores/dvdplayer/DVDPlayerVideo.h | 1 +
+ 5 files changed, 31 insertions(+), 16 deletions(-)
+
+diff --git a/xbmc/cores/dvdplayer/DVDMessage.h b/xbmc/cores/dvdplayer/DVDMessage.h
+index 2ea8b8f..e8274f9 100644
+--- a/xbmc/cores/dvdplayer/DVDMessage.h
++++ b/xbmc/cores/dvdplayer/DVDMessage.h
+@@ -220,7 +220,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)
+@@ -228,6 +228,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; }
+@@ -235,6 +236,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;
+@@ -242,6 +244,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 097af37..c41b0b7 100644
+--- a/xbmc/cores/dvdplayer/DVDPlayer.cpp
++++ b/xbmc/cores/dvdplayer/DVDPlayer.cpp
+@@ -1634,11 +1634,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
+@@ -1657,7 +1659,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));
+ }
+ }
+ }
+@@ -2143,7 +2145,7 @@ void CDVDPlayer::HandleMessages()
+ else
+ m_StateInput.dts = start;
+
+- FlushBuffers(!msg.GetFlush(), start, msg.GetAccurate());
++ FlushBuffers(!msg.GetFlush(), start, msg.GetAccurate(), msg.GetSync());
+ }
+ else
+ CLog::Log(LOGWARNING, "error while seeking");
+@@ -2279,9 +2281,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();
+ }
+
+@@ -2297,7 +2300,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
+@@ -3294,7 +3298,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)
+@@ -3306,19 +3310,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;
+
+@@ -3362,7 +3370,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 e2a836b..6ecaf3f 100644
+--- a/xbmc/cores/dvdplayer/DVDPlayer.h
++++ b/xbmc/cores/dvdplayer/DVDPlayer.h
+@@ -308,7 +308,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();
+@@ -357,8 +357,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 322a581..9c5469b 100644
+--- a/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp
++++ b/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp
+@@ -1470,7 +1470,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;
+@@ -1570,6 +1570,8 @@ int CDVDPlayerVideo::CalcDropRequirement(double pts)
+ int iSkippedDeint = 0;
+ int iBufferLevel;
+
++ m_droppingStats.m_lastPts = pts;
++
+ // get decoder stats
+ if (!m_pVideoCodec->GetCodecStats(iDecoderPts, iSkippedDeint, interlaced))
+ iDecoderPts = pts;
+diff --git a/xbmc/cores/dvdplayer/DVDPlayerVideo.h b/xbmc/cores/dvdplayer/DVDPlayerVideo.h
+index 59c7f09..65dea76 100644
+--- a/xbmc/cores/dvdplayer/DVDPlayerVideo.h
++++ b/xbmc/cores/dvdplayer/DVDPlayerVideo.h
+@@ -50,6 +50,7 @@ class CDroppingStats
+ double m_totalGain;
+ double m_lastDecoderPts;
+ double m_lastRenderPts;
++ double m_lastPts;
+ unsigned int m_lateFrames;
+ unsigned int m_dropRequests;
+ };
+--
+1.9.1
+
+
+From d7de75d7c04355b6bbc834b2c4d12ce3fa3234b7 Mon Sep 17 00:00:00 2001
+From: xbmc
+Date: Mon, 24 Dec 2012 16:02:42 +0100
+Subject: [PATCH 12/31] 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 6c8e6db..95cc18f 100644
+--- a/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxPVRClient.cpp
++++ b/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxPVRClient.cpp
+@@ -328,9 +328,7 @@ void CDVDDemuxPVRClient::RequestStreams()
+ if (stm)
+ {
+ st = dynamic_cast(stm);
+- if (!st
+- || (st->codec != (AVCodecID)props.stream[i].iCodecId)
+- || (st->iChannels != props.stream[i].iChannels))
++ if (!st || (st->codec != (AVCodecID)props.stream[i].iCodecId))
+ DisposeStream(i);
+ }
+ if (!m_streams[i])
+@@ -347,6 +345,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 == XBMC_CODEC_TYPE_VIDEO)
+ {
+--
+1.9.1
+
+
+From 4cc882624c5d58b3f9f3922b1887a6e07c708a40 Mon Sep 17 00:00:00 2001
+From: xbmc
+Date: Fri, 14 Dec 2012 14:19:15 +0100
+Subject: [PATCH 13/31] pvr: do not show selection dialog for a single menu
+ hook
+
+---
+ xbmc/pvr/addons/PVRClients.cpp | 9 ++++++---
+ 1 file changed, 6 insertions(+), 3 deletions(-)
+
+diff --git a/xbmc/pvr/addons/PVRClients.cpp b/xbmc/pvr/addons/PVRClients.cpp
+index 14c9cde..57b18a5 100644
+--- a/xbmc/pvr/addons/PVRClients.cpp
++++ b/xbmc/pvr/addons/PVRClients.cpp
+@@ -733,6 +733,7 @@ void CPVRClients::ProcessMenuHooks(int iClientID, PVR_MENUHOOK_CAT cat, const CF
+ {
+ hooks = client->GetMenuHooks();
+ std::vector hookIDs;
++ int selection = 0;
+
+ CGUIDialogSelect* pDialog = (CGUIDialogSelect*)g_windowManager.GetWindow(WINDOW_DIALOG_SELECT);
+ pDialog->Reset();
+@@ -743,9 +744,11 @@ void CPVRClients::ProcessMenuHooks(int iClientID, PVR_MENUHOOK_CAT cat, const CF
+ pDialog->Add(client->GetString(hooks->at(i).iLocalizedStringId));
+ hookIDs.push_back(i);
+ }
+- pDialog->DoModal();
+-
+- int selection = pDialog->GetSelectedLabel();
++ if (hookIDs.size() > 1)
++ {
++ pDialog->DoModal();
++ selection = pDialog->GetSelectedLabel();
++ }
+ if (selection >= 0)
+ client->CallMenuHook(hooks->at(hookIDs.at(selection)), item);
+ }
+--
+1.9.1
+
+
+From d606020220c81523be3e5170ab1b64ee647a7168 Mon Sep 17 00:00:00 2001
+From: xbmc
+Date: Sun, 24 Mar 2013 16:04:48 +0100
+Subject: [PATCH 14/31] linux: use CLOCK_MONOTONIC_RAW as this is not subject
+ to NTP
+
+---
+ xbmc/threads/SystemClock.cpp | 2 +-
+ xbmc/utils/TimeUtils.cpp | 2 +-
+ 2 files changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/xbmc/threads/SystemClock.cpp b/xbmc/threads/SystemClock.cpp
+index 657a154..35e3abf 100644
+--- a/xbmc/threads/SystemClock.cpp
++++ b/xbmc/threads/SystemClock.cpp
+@@ -43,7 +43,7 @@ namespace XbmcThreads
+ now_time = (uint64_t)timeGetTime();
+ #else
+ struct timespec ts = {};
+- clock_gettime(CLOCK_MONOTONIC, &ts);
++ clock_gettime(CLOCK_MONOTONIC_RAW, &ts);
+ now_time = (ts.tv_sec * 1000) + (ts.tv_nsec / 1000000);
+ #endif
+ if (!start_time_set)
+diff --git a/xbmc/utils/TimeUtils.cpp b/xbmc/utils/TimeUtils.cpp
+index c06b8c5..4390d2e 100644
+--- a/xbmc/utils/TimeUtils.cpp
++++ b/xbmc/utils/TimeUtils.cpp
+@@ -43,7 +43,7 @@ int64_t CurrentHostCounter(void)
+ return( (int64_t)PerformanceCount.QuadPart );
+ #else
+ struct timespec now;
+- clock_gettime(CLOCK_MONOTONIC, &now);
++ clock_gettime(CLOCK_MONOTONIC_RAW, &now);
+ return( ((int64_t)now.tv_sec * 1000000000L) + now.tv_nsec );
+ #endif
+ }
+--
+1.9.1
+
+
+From 5959ff6e728f22c6cc6086cb5e39a0c58fefa07b Mon Sep 17 00:00:00 2001
+From: xbmc
+Date: Thu, 28 Mar 2013 15:18:53 +0100
+Subject: [PATCH 15/31] OMXPlayer: some caching fixes for pvr
+
+---
+ xbmc/cores/omxplayer/OMXPlayer.cpp | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/xbmc/cores/omxplayer/OMXPlayer.cpp b/xbmc/cores/omxplayer/OMXPlayer.cpp
+index 502df4a..c8579a2 100644
+--- a/xbmc/cores/omxplayer/OMXPlayer.cpp
++++ b/xbmc/cores/omxplayer/OMXPlayer.cpp
+@@ -2548,7 +2548,8 @@ void COMXPlayer::HandleMessages()
+ m_messenger.Put(new CDVDMsgPlayerSeek(GetTime(), (speed < 0), true, false, false, true));
+
+ m_playSpeed = speed;
+- m_caching = CACHESTATE_DONE;
++ if (m_caching != CACHESTATE_PVR && m_playSpeed != DVD_PLAYSPEED_NORMAL)
++ m_caching = CACHESTATE_DONE;
+ m_clock.SetSpeed(speed);
+ m_av_clock.OMXSetSpeed(speed);
+ m_av_clock.OMXPause();
+--
+1.9.1
+
+
+From 79db06b63ec9bbb30ce0bb8027808d2c0967fa4f Mon Sep 17 00:00:00 2001
+From: xbmc
+Date: Thu, 28 Mar 2013 20:50:59 +0100
+Subject: [PATCH 16/31] fix incorrect display of fps when dr kicks in
+
+---
+ xbmc/Application.cpp | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/xbmc/Application.cpp b/xbmc/Application.cpp
+index 79bfa63..d863c6b 100644
+--- a/xbmc/Application.cpp
++++ b/xbmc/Application.cpp
+@@ -2331,10 +2331,11 @@ void CApplication::Render()
+ if (frameTime < singleFrameTime)
+ Sleep(singleFrameTime - frameTime);
+ }
+- m_lastFrameTime = XbmcThreads::SystemClockMillis();
+
+ if (flip)
+ g_graphicsContext.Flip(dirtyRegions);
++
++ m_lastFrameTime = XbmcThreads::SystemClockMillis();
+ CTimeUtils::UpdateFrameTime(flip);
+
+ g_renderManager.UpdateResolution();
+--
+1.9.1
+
+
+From f5d25c94791473ff296257e1bb7b35be267bc7d2 Mon Sep 17 00:00:00 2001
+From: Rainer Hochecker
+Date: Tue, 11 Jun 2013 16:20:29 +0200
+Subject: [PATCH 17/31] renderer: allow some lateness within vblank interval
+
+---
+ xbmc/cores/VideoRenderers/RenderManager.cpp | 12 ++++++++++--
+ xbmc/cores/VideoRenderers/RenderManager.h | 1 +
+ 2 files changed, 11 insertions(+), 2 deletions(-)
+
+diff --git a/xbmc/cores/VideoRenderers/RenderManager.cpp b/xbmc/cores/VideoRenderers/RenderManager.cpp
+index f4b381e..5e9f666 100644
+--- a/xbmc/cores/VideoRenderers/RenderManager.cpp
++++ b/xbmc/cores/VideoRenderers/RenderManager.cpp
+@@ -380,6 +380,8 @@ void CXBMCRenderManager::FrameFinish()
+ if(g_graphicsContext.IsFullScreenVideo())
+ WaitPresentTime(m.timestamp);
+
++ m_clock_framefinish = GetPresentTime();
++
+ { CSingleLock lock(m_presentlock);
+
+ if(m_presentstep == PRESENT_FRAME)
+@@ -1032,6 +1034,12 @@ void CXBMCRenderManager::PrepareNextRender()
+
+ double clocktime = GetPresentTime();
+ double frametime = 1.0 / GetMaximumFPS();
++ double correction = 0.0;
++ int fps = g_VideoReferenceClock.GetRefreshRate();
++ if((fps > 0) && g_graphicsContext.IsFullScreenVideo() && (clocktime != m_clock_framefinish))
++ {
++ correction = frametime;
++ }
+
+ /* see if any future queued frames are already due */
+ std::deque::reverse_iterator curr, prev;
+@@ -1040,8 +1048,8 @@ void CXBMCRenderManager::PrepareNextRender()
+ ++prev;
+ while (prev != m_queued.rend())
+ {
+- if(clocktime > m_Queue[*prev].timestamp /* previous frame is late */
+- && clocktime > m_Queue[*curr].timestamp - frametime) /* selected frame is close to it's display time */
++ if(clocktime > m_Queue[*prev].timestamp + correction /* previous frame is late */
++ && clocktime > m_Queue[*curr].timestamp - frametime + correction) /* selected frame is close to it's display time */
+ break;
+ ++curr;
+ ++prev;
+diff --git a/xbmc/cores/VideoRenderers/RenderManager.h b/xbmc/cores/VideoRenderers/RenderManager.h
+index 949c652b..d84ff6c 100644
+--- a/xbmc/cores/VideoRenderers/RenderManager.h
++++ b/xbmc/cores/VideoRenderers/RenderManager.h
+@@ -252,6 +252,7 @@ class CXBMCRenderManager
+ XbmcThreads::ConditionVariable m_presentevent;
+ CCriticalSection m_presentlock;
+ CEvent m_flushEvent;
++ double m_clock_framefinish;
+
+
+ OVERLAY::CRenderer m_overlays;
+--
+1.9.1
+
+
+From 04dfa8be7362e22e339a8f23df47230b841388bc Mon Sep 17 00:00:00 2001
+From: Rainer Hochecker
+Date: Thu, 25 Jul 2013 17:18:13 +0200
+Subject: [PATCH 18/31] ActiveAE: slightly reduce buffer size
+
+---
+ xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAE.cpp | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAE.cpp b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAE.cpp
+index 27c237b..a01f77c 100644
+--- a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAE.cpp
++++ b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAE.cpp
+@@ -30,8 +30,8 @@ using namespace ActiveAE;
+ #include "settings/AdvancedSettings.h"
+ #include "windowing/WindowingFactory.h"
+
+-#define MAX_CACHE_LEVEL 0.5 // total cache time of stream in seconds
+-#define MAX_WATER_LEVEL 0.25 // buffered time after stream stages in seconds
++#define MAX_CACHE_LEVEL 0.4 // total cache time of stream in seconds
++#define MAX_WATER_LEVEL 0.2 // buffered time after stream stages in seconds
+ #define MAX_BUFFER_TIME 0.1 // max time of a buffer in seconds
+
+ void CEngineStats::Reset(unsigned int sampleRate)
+--
+1.9.1
+
+
+From f7370bcc07fb1cd8ab03baa9fff133569c5b8668 Mon Sep 17 00:00:00 2001
+From: Rainer Hochecker
+Date: Sun, 4 Aug 2013 10:11:16 +0200
+Subject: [PATCH 19/31] Revert "vdpau: comment some features that will be added
+ later"
+
+This reverts commit e00b4f65864d623ab4d2e9e5c06db138e661f1cf.
+---
+ xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp | 12 ++++--------
+ 1 file changed, 4 insertions(+), 8 deletions(-)
+
+diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp
+index 9c962ae..485c5d3 100644
+--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp
++++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp
+@@ -1092,8 +1092,7 @@ int CDecoder::Decode(AVCodecContext *avctx, AVFrame *pFrame)
+ m_bufferStats.IncDecoded();
+ m_vdpauOutput.m_dataPort.SendOutMessage(COutputDataProtocol::NEWFRAME, &pic, sizeof(pic));
+
+- //TODO
+- // m_codecControl = pic.DVDPic.iFlags & (DVP_FLAG_DRAIN | DVP_FLAG_NO_POSTPROC);
++ m_codecControl = pic.DVDPic.iFlags & (DVP_FLAG_DRAIN | DVP_FLAG_NO_POSTPROC);
+ }
+
+ int retval = 0;
+@@ -2286,8 +2285,7 @@ void CMixer::InitCycle()
+ int flags;
+ uint64_t latency;
+ m_config.stats->GetParams(latency, flags);
+- // TODO
+- if (0) //flags & DVP_FLAG_NO_POSTPROC)
++ if (flags & DVP_FLAG_NO_POSTPROC)
+ SetPostProcFeatures(false);
+ else
+ SetPostProcFeatures(true);
+@@ -2299,8 +2297,7 @@ void CMixer::InitCycle()
+ bool interlaced = m_mixerInput[1].DVDPic.iFlags & DVP_FLAG_INTERLACED;
+ m_SeenInterlaceFlag |= interlaced;
+
+- // TODO
+- if (//!(flags & DVP_FLAG_NO_POSTPROC) &&
++ if (!(flags & DVP_FLAG_NO_POSTPROC) &&
+ (mode == VS_DEINTERLACEMODE_FORCE ||
+ (mode == VS_DEINTERLACEMODE_AUTO && interlaced)))
+ {
+@@ -2322,8 +2319,7 @@ void CMixer::InitCycle()
+ m_config.stats->SetCanSkipDeint(true);
+ }
+
+- // TODO
+- if (0) //m_mixerInput[1].DVDPic.iFlags & DVP_FLAG_DROPDEINT)
++ if (m_mixerInput[1].DVDPic.iFlags & DVP_FLAG_DROPDEINT)
+ {
+ m_mixersteps = 1;
+ }
+--
+1.9.1
+
+
+From 90335f7140d075a7c182767bd205c78eec93063a Mon Sep 17 00:00:00 2001
+From: Marcel Groothuis
+Date: Thu, 5 Dec 2013 22:02:50 +0100
+Subject: [PATCH 21/31] ffmpeg demuxer: faster channel change for PVR addons
+ without internal demuxing (such as MediaPortal, ArgusTV, MythTV, NextPVR)
+ Credits: FernetMenta, Davilla, Popcornmix, Whaupt
+
+---
+ .../cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.cpp | 143 ++++++++++++++++++---
+ xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.h | 5 +-
+ .../dvdplayer/DVDDemuxers/DVDFactoryDemuxer.cpp | 13 +-
+ 3 files changed, 139 insertions(+), 22 deletions(-)
+
+diff --git a/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.cpp b/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.cpp
+index eda7dc9..6266fba 100644
+--- a/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.cpp
++++ b/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.cpp
+@@ -52,6 +52,8 @@
+ #include "URL.h"
+ #include "cores/FFmpeg.h"
+
++#define FF_MAX_EXTRADATA_SIZE ((1 << 28) - FF_INPUT_BUFFER_PADDING_SIZE)
++
+ void CDemuxStreamAudioFFmpeg::GetStreamInfo(std::string& strInfo)
+ {
+ if(!m_stream) return;
+@@ -153,6 +155,7 @@ CDVDDemuxFFmpeg::CDVDDemuxFFmpeg() : CDVDDemux()
+ m_program = UINT_MAX;
+ m_pkt.result = -1;
+ memset(&m_pkt.pkt, 0, sizeof(AVPacket));
++ m_streaminfo = true; /* set to true if we want to look for streams before playback */
+ }
+
+ CDVDDemuxFFmpeg::~CDVDDemuxFFmpeg()
+@@ -173,10 +176,11 @@ bool CDVDDemuxFFmpeg::Aborted()
+ return false;
+ }
+
+-bool CDVDDemuxFFmpeg::Open(CDVDInputStream* pInput)
++bool CDVDDemuxFFmpeg::Open(CDVDInputStream* pInput, bool streaminfo)
+ {
+ AVInputFormat* iformat = NULL;
+ std::string strFile;
++ m_streaminfo = streaminfo;
+ m_iCurrentPts = DVD_NOPTS_VALUE;
+ m_speed = DVD_PLAYSPEED_NORMAL;
+ m_program = UINT_MAX;
+@@ -187,8 +191,6 @@ bool CDVDDemuxFFmpeg::Open(CDVDInputStream* pInput)
+ m_pInput = pInput;
+ strFile = m_pInput->GetFileName();
+
+- bool streaminfo = true; /* set to true if we want to look for streams before playback*/
+-
+ if( m_pInput->GetContent().length() > 0 )
+ {
+ std::string content = m_pInput->GetContent();
+@@ -378,13 +380,12 @@ bool CDVDDemuxFFmpeg::Open(CDVDInputStream* pInput)
+ m_bMatroska = strncmp(m_pFormatContext->iformat->name, "matroska", 8) == 0; // for "matroska.webm"
+ m_bAVI = strcmp(m_pFormatContext->iformat->name, "avi") == 0;
+
+- if (streaminfo)
++ if (m_streaminfo)
+ {
+- /* too speed up dvd switches, only analyse very short */
++ /* to speed up dvd switches, only analyse very short */
+ if(m_pInput->IsStreamType(DVDSTREAM_TYPE_DVD))
+ m_pFormatContext->max_analyze_duration = 500000;
+
+-
+ CLog::Log(LOGDEBUG, "%s - avformat_find_stream_info starting", __FUNCTION__);
+ int iErr = avformat_find_stream_info(m_pFormatContext, NULL);
+ if (iErr < 0)
+@@ -404,6 +405,9 @@ bool CDVDDemuxFFmpeg::Open(CDVDInputStream* pInput)
+ }
+ CLog::Log(LOGDEBUG, "%s - av_find_stream_info finished", __FUNCTION__);
+ }
++ else
++ m_program = 0;
++
+ // reset any timeout
+ m_timeout.SetInfinite();
+
+@@ -457,7 +461,7 @@ void CDVDDemuxFFmpeg::Reset()
+ {
+ CDVDInputStream* pInputStream = m_pInput;
+ Dispose();
+- Open(pInputStream);
++ Open(pInputStream, m_streaminfo);
+ }
+
+ void CDVDDemuxFFmpeg::Flush()
+@@ -652,25 +656,32 @@ DemuxPacket* CDVDDemuxFFmpeg::Read()
+ }
+ else
+ {
++ ParsePacket(&m_pkt.pkt);
++
+ AVStream *stream = m_pFormatContext->streams[m_pkt.pkt.stream_index];
+
+- if (m_program != UINT_MAX)
++ if (IsVideoReady())
+ {
+- /* check so packet belongs to selected program */
+- for (unsigned int i = 0; i < m_pFormatContext->programs[m_program]->nb_stream_indexes; i++)
++ if (m_program != UINT_MAX)
+ {
+- if(m_pkt.pkt.stream_index == (int)m_pFormatContext->programs[m_program]->stream_index[i])
++ /* check so packet belongs to selected program */
++ for (unsigned int i = 0; i < m_pFormatContext->programs[m_program]->nb_stream_indexes; i++)
+ {
+- pPacket = CDVDDemuxUtils::AllocateDemuxPacket(m_pkt.pkt.size);
+- break;
++ if(m_pkt.pkt.stream_index == (int)m_pFormatContext->programs[m_program]->stream_index[i])
++ {
++ pPacket = CDVDDemuxUtils::AllocateDemuxPacket(m_pkt.pkt.size);
++ break;
++ }
+ }
+- }
+
+- if (!pPacket)
+- bReturnEmpty = true;
++ if (!pPacket)
++ bReturnEmpty = true;
++ }
++ else
++ pPacket = CDVDDemuxUtils::AllocateDemuxPacket(m_pkt.pkt.size);
+ }
+ else
+- pPacket = CDVDDemuxUtils::AllocateDemuxPacket(m_pkt.pkt.size);
++ bReturnEmpty = true;
+
+ if (pPacket)
+ {
+@@ -1611,3 +1622,101 @@ bool CDVDDemuxFFmpeg::IsProgramChange()
+ }
+ return false;
+ }
++
++void CDVDDemuxFFmpeg::ParsePacket(AVPacket *pkt)
++{
++ AVStream *st = m_pFormatContext->streams[pkt->stream_index];
++ CDemuxStream *stream = GetStreamInternal(pkt->stream_index);
++
++ // if the stream is new, tell ffmpeg to parse the stream
++ if (!stream && !st->parser)
++ {
++ st->need_parsing = AVSTREAM_PARSE_FULL;
++ }
++
++ // split extradata
++ if(st->parser && st->parser->parser->split && !st->codec->extradata)
++ {
++ int i = st->parser->parser->split(st->codec, pkt->data, pkt->size);
++ if (i > 0 && i < FF_MAX_EXTRADATA_SIZE)
++ {
++ // Found extradata, fill it in. This will cause
++ // a new stream to be created and used.
++ st->codec->extradata_size = i;
++ st->codec->extradata = (uint8_t*)av_malloc(st->codec->extradata_size + FF_INPUT_BUFFER_PADDING_SIZE);
++ if (st->codec->extradata)
++ {
++ CLog::Log(LOGDEBUG, "CDVDDemuxFFmpeg::Read() fetching extradata, extradata_size(%d)", st->codec->extradata_size);
++ memcpy(st->codec->extradata, pkt->data, st->codec->extradata_size);
++ memset(st->codec->extradata + i, 0, FF_INPUT_BUFFER_PADDING_SIZE);
++ }
++ else
++ {
++ st->codec->extradata_size = 0;
++ }
++ }
++ }
++
++ // for video we need a decoder to get desired information into codec context
++ if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO &&
++ (!st->codec->width || st->codec->pix_fmt == PIX_FMT_NONE))
++ {
++ // open a decoder, it will be cleared down by ffmpeg on closing the stream
++ if (!st->codec->codec)
++ {
++ const AVCodec* codec;
++ AVDictionary *thread_opt = NULL;
++ codec = avcodec_find_decoder(st->codec->codec_id);
++ // Force thread count to 1 since the h264 decoder will not extract
++ // SPS and PPS to extradata during multi-threaded decoding
++ av_dict_set(&thread_opt, "threads", "1", 0);
++ avcodec_open2(st->codec, codec, &thread_opt);
++
++ av_dict_free(&thread_opt);
++ }
++
++ // We don't need to actually decode here
++ // we just want to transport SPS data into codec context
++ st->codec->skip_idct = AVDISCARD_ALL;
++ st->codec->skip_frame = AVDISCARD_ALL;
++ st->codec->skip_loop_filter = AVDISCARD_ALL;
++
++ // We are looking for an IDR frame
++ AVFrame picture;
++ memset(&picture, 0, sizeof(AVFrame));
++ picture.pts = picture.pkt_dts = picture.pkt_pts = picture.best_effort_timestamp = AV_NOPTS_VALUE;
++ picture.pkt_pos = -1;
++ picture.key_frame = 1;
++ picture.format = -1;
++
++ int got_picture = 0;
++ avcodec_decode_video2(st->codec, &picture, &got_picture, pkt);
++ }
++}
++
++bool CDVDDemuxFFmpeg::IsVideoReady()
++{
++ AVStream *st;
++ if(m_program != UINT_MAX)
++ {
++ for (unsigned int i = 0; i < m_pFormatContext->programs[m_program]->nb_stream_indexes; i++)
++ {
++ int idx = m_pFormatContext->programs[m_program]->stream_index[i];
++ st = m_pFormatContext->streams[idx];
++ if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO &&
++ (!st->codec->width || st->codec->pix_fmt == PIX_FMT_NONE))
++ return false;
++ }
++ }
++ else
++ {
++ for (unsigned int i = 0; i < m_pFormatContext->nb_streams; i++)
++ {
++ st = m_pFormatContext->streams[i];
++ if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO &&
++ (!st->codec->width || st->codec->pix_fmt == PIX_FMT_NONE))
++ return false;
++ }
++ }
++ return true;
++}
+diff --git a/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.h b/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.h
+index 3b0f615..083182e 100644
+--- a/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.h
++++ b/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.h
+@@ -88,7 +88,7 @@ class CDVDDemuxFFmpeg : public CDVDDemux
+ CDVDDemuxFFmpeg();
+ virtual ~CDVDDemuxFFmpeg();
+
+- bool Open(CDVDInputStream* pInput);
++ bool Open(CDVDInputStream* pInput, bool streaminfo = true);
+ void Dispose();
+ void Reset();
+ void Flush();
+@@ -127,6 +127,8 @@ class CDVDDemuxFFmpeg : public CDVDDemux
+ CDemuxStream* GetStreamInternal(int iStreamId);
+ void CreateStreams(unsigned int program = UINT_MAX);
+ void DisposeStreams();
++ void ParsePacket(AVPacket *pkt);
++ bool IsVideoReady();
+
+ AVDictionary *GetFFMpegOptionsFromURL(const CURL &url);
+ double ConvertTimestamp(int64_t pts, int den, int num);
+@@ -157,5 +159,6 @@ class CDVDDemuxFFmpeg : public CDVDDemux
+
+ bool m_bPtsWrap, m_bPtsWrapChecked;
+ int64_t m_iStartTime, m_iMaxTime, m_iEndTime;
++ bool m_streaminfo;
+ };
+
+diff --git a/xbmc/cores/dvdplayer/DVDDemuxers/DVDFactoryDemuxer.cpp b/xbmc/cores/dvdplayer/DVDDemuxers/DVDFactoryDemuxer.cpp
+index ca689d0..f383563 100644
+--- a/xbmc/cores/dvdplayer/DVDDemuxers/DVDFactoryDemuxer.cpp
++++ b/xbmc/cores/dvdplayer/DVDDemuxers/DVDFactoryDemuxer.cpp
+@@ -99,26 +99,31 @@ CDVDDemux* CDVDFactoryDemuxer::CreateDemuxer(CDVDInputStream* pInputStream)
+ }
+ #endif
+
++ bool streaminfo = true; /* Look for streams before playback */
+ if (pInputStream->IsStreamType(DVDSTREAM_TYPE_PVRMANAGER))
+ {
+ CDVDInputStreamPVRManager* pInputStreamPVR = (CDVDInputStreamPVRManager*)pInputStream;
+ CDVDInputStream* pOtherStream = pInputStreamPVR->GetOtherStream();
++
++ /* Don't parse the streaminfo for live streams to reduce the channel switch time */
++ bool liveStream = (pInputStream->GetFileName().substr(0, 14) == "pvr://channels");
++ streaminfo = !liveStream;
++
+ if(pOtherStream)
+ {
+ /* Used for MediaPortal PVR addon (uses PVR otherstream for playback of rtsp streams) */
+ if (pOtherStream->IsStreamType(DVDSTREAM_TYPE_FFMPEG))
+ {
+ auto_ptr demuxer(new CDVDDemuxFFmpeg());
+- if(demuxer->Open(pOtherStream))
++ if(demuxer->Open(pOtherStream, streaminfo))
+ return demuxer.release();
+ else
+ return NULL;
+ }
+ }
+
+- std::string filename = pInputStream->GetFileName();
+ /* Use PVR demuxer only for live streams */
+- if (filename.substr(0, 14) == "pvr://channels")
++ if (liveStream)
+ {
+ boost::shared_ptr client;
+ if (g_PVRClients->GetPlayingClient(client) &&
+@@ -134,7 +139,7 @@ CDVDDemux* CDVDFactoryDemuxer::CreateDemuxer(CDVDInputStream* pInputStream)
+ }
+
+ auto_ptr demuxer(new CDVDDemuxFFmpeg());
+- if(demuxer->Open(pInputStream))
++ if(demuxer->Open(pInputStream, streaminfo))
+ return demuxer.release();
+ else
+ return NULL;
+--
+1.9.1
+
+
+From 8aaaf75e93f67c6a1edca07ccc6116204676db7e Mon Sep 17 00:00:00 2001
+From: Rainer Hochecker
+Date: Thu, 14 Nov 2013 20:35:04 +0100
+Subject: [PATCH 22/31] ffmpeg demuxer: make sure we start mpegts video with an
+ i-frame
+
+---
+ .../cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.cpp | 31 +++++++++++++++++++++-
+ xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.h | 1 +
+ 2 files changed, 31 insertions(+), 1 deletion(-)
+
+diff --git a/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.cpp b/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.cpp
+index 6266fba..c6472b8 100644
+--- a/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.cpp
++++ b/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.cpp
+@@ -376,6 +376,13 @@ bool CDVDDemuxFFmpeg::Open(CDVDInputStream* pInput, bool streaminfo)
+ if (iformat && (strcmp(iformat->name, "mjpeg") == 0) && m_ioContext->seekable == 0)
+ m_pFormatContext->max_analyze_duration = 500000;
+
++ bool short_analyze = false;
++ if (iformat && (strcmp(iformat->name, "mpegts") == 0))
++ {
++ m_pFormatContext->max_analyze_duration = 500000;
++ short_analyze = true;
++ }
++
+ // we need to know if this is matroska or avi later
+ m_bMatroska = strncmp(m_pFormatContext->iformat->name, "matroska", 8) == 0; // for "matroska.webm"
+ m_bAVI = strcmp(m_pFormatContext->iformat->name, "avi") == 0;
+@@ -404,6 +411,12 @@ bool CDVDDemuxFFmpeg::Open(CDVDInputStream* pInput, bool streaminfo)
+ }
+ }
+ CLog::Log(LOGDEBUG, "%s - av_find_stream_info finished", __FUNCTION__);
++
++ if (short_analyze)
++ {
++ // make sure we start video with an i-frame
++ ResetVideoStreams();
++ }
+ }
+ else
+ m_program = 0;
+@@ -1658,7 +1671,7 @@ void CDVDDemuxFFmpeg::ParsePacket(AVPacket *pkt)
+ }
+
+ // for video we need a decoder to get desired information into codec context
+- if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO &&
++ if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO && st->codec->extradata &&
+ (!st->codec->width || st->codec->pix_fmt == PIX_FMT_NONE))
+ {
+ // open a decoder, it will be cleared down by ffmpeg on closing the stream
+@@ -1720,3 +1733,19 @@ bool CDVDDemuxFFmpeg::IsVideoReady()
+ }
+ return true;
+ }
++
++void CDVDDemuxFFmpeg::ResetVideoStreams()
++{
++ AVStream *st;
++ for (unsigned int i = 0; i < m_pFormatContext->nb_streams; i++)
++ {
++ st = m_pFormatContext->streams[i];
++ if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO)
++ {
++ if (st->codec->extradata)
++ m_dllAvUtil.av_free(st->codec->extradata);
++ st->codec->extradata = NULL;
++ st->codec->width = 0;
++ }
++ }
++}
+diff --git a/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.h b/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.h
+index 083182e..26ee264 100644
+--- a/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.h
++++ b/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.h
+@@ -129,6 +129,7 @@ class CDVDDemuxFFmpeg : public CDVDDemux
+ void DisposeStreams();
+ void ParsePacket(AVPacket *pkt);
+ bool IsVideoReady();
++ void ResetVideoStreams();
+
+ AVDictionary *GetFFMpegOptionsFromURL(const CURL &url);
+ double ConvertTimestamp(int64_t pts, int den, int num);
+--
+1.9.1
+
+
+From b1a69aca87ab81242602fbbff061b9be2a32fefe Mon Sep 17 00:00:00 2001
+From: Wolfgang Haupt
+Date: Thu, 5 Dec 2013 22:11:57 +0100
+Subject: [PATCH 23/31] DVDFactoryDemuxer: skip streaminfo for udp tcp and
+ pvr-channels
+
+---
+ .../dvdplayer/DVDDemuxers/DVDFactoryDemuxer.cpp | 14 ++++++---
+ xbmc/utils/URIUtils.cpp | 35 ++++++++++++++++++++++
+ xbmc/utils/URIUtils.h | 4 +++
+ 3 files changed, 49 insertions(+), 4 deletions(-)
+
+diff --git a/xbmc/cores/dvdplayer/DVDDemuxers/DVDFactoryDemuxer.cpp b/xbmc/cores/dvdplayer/DVDDemuxers/DVDFactoryDemuxer.cpp
+index f383563..d6580fd 100644
+--- a/xbmc/cores/dvdplayer/DVDDemuxers/DVDFactoryDemuxer.cpp
++++ b/xbmc/cores/dvdplayer/DVDDemuxers/DVDFactoryDemuxer.cpp
+@@ -105,9 +105,9 @@ CDVDDemux* CDVDFactoryDemuxer::CreateDemuxer(CDVDInputStream* pInputStream)
+ CDVDInputStreamPVRManager* pInputStreamPVR = (CDVDInputStreamPVRManager*)pInputStream;
+ CDVDInputStream* pOtherStream = pInputStreamPVR->GetOtherStream();
+
+- /* Don't parse the streaminfo for live streams to reduce the channel switch time */
+- bool liveStream = (pInputStream->GetFileName().substr(0, 14) == "pvr://channels");
+- streaminfo = !liveStream;
++ /* Don't parse the streaminfo for some cases of streams to reduce the channel switch time */
++ bool useFastswitch = URIUtils::IsUsingFastSwitch(pInputStream->GetFileName());
++ streaminfo = !useFastswitch;
+
+ if(pOtherStream)
+ {
+@@ -123,7 +123,7 @@ CDVDDemux* CDVDFactoryDemuxer::CreateDemuxer(CDVDInputStream* pInputStream)
+ }
+
+ /* Use PVR demuxer only for live streams */
+- if (liveStream)
++ if (URIUtils::IsPVRChannel(pInputStream->GetFileName()))
+ {
+ boost::shared_ptr client;
+ if (g_PVRClients->GetPlayingClient(client) &&
+@@ -138,6 +138,12 @@ CDVDDemux* CDVDFactoryDemuxer::CreateDemuxer(CDVDInputStream* pInputStream)
+ }
+ }
+
++ if (pInputStream->IsStreamType(DVDSTREAM_TYPE_FFMPEG))
++ {
++ bool useFastswitch = URIUtils::IsUsingFastSwitch(pInputStream->GetFileName());
++ streaminfo = !useFastswitch;
++ }
++
+ auto_ptr demuxer(new CDVDDemuxFFmpeg());
+ if(demuxer->Open(pInputStream, streaminfo))
+ return demuxer.release();
+diff --git a/xbmc/utils/URIUtils.cpp b/xbmc/utils/URIUtils.cpp
+index fd2eb5a..22932b7 100644
+--- a/xbmc/utils/URIUtils.cpp
++++ b/xbmc/utils/URIUtils.cpp
+@@ -788,6 +788,36 @@ bool URIUtils::IsFTP(const CStdString& strFile)
+ StringUtils::StartsWithNoCase(strFile2, "ftps:");
+ }
+
++bool URIUtils::IsUDP(const CStdString& strFile)
++{
++ CStdString strFile2(strFile);
++
++ if (IsStack(strFile))
++ strFile2 = CStackDirectory::GetFirstStackedFile(strFile);
++
++ return StringUtils::StartsWithNoCase(strFile2, "udp:");
++}
++
++bool URIUtils::IsTCP(const CStdString& strFile)
++{
++ CStdString strFile2(strFile);
++
++ if (IsStack(strFile))
++ strFile2 = CStackDirectory::GetFirstStackedFile(strFile);
++
++ return StringUtils::StartsWithNoCase(strFile2, "tcp:");
++}
++
++bool URIUtils::IsPVRChannel(const CStdString& strFile)
++{
++ CStdString strFile2(strFile);
++
++ if (IsStack(strFile))
++ strFile2 = CStackDirectory::GetFirstStackedFile(strFile);
++
++ return StringUtils::StartsWithNoCase(strFile2, "pvr://channels");
++}
++
+ bool URIUtils::IsDAV(const CStdString& strFile)
+ {
+ CStdString strFile2(strFile);
+@@ -1284,3 +1314,8 @@ bool URIUtils::UpdateUrlEncoding(std::string &strFilename)
+ strFilename = newFilename;
+ return true;
+ }
++
++bool URIUtils::IsUsingFastSwitch(const CStdString& strFile)
++{
++ return IsUDP(strFile) || IsTCP(strFile) || IsPVRChannel(strFile);
++}
+diff --git a/xbmc/utils/URIUtils.h b/xbmc/utils/URIUtils.h
+index b94e94c..b45630f 100644
+--- a/xbmc/utils/URIUtils.h
++++ b/xbmc/utils/URIUtils.h
+@@ -88,6 +88,8 @@ class URIUtils
+ static bool IsDOSPath(const CStdString &path);
+ static bool IsDVD(const CStdString& strFile);
+ static bool IsFTP(const CStdString& strFile);
++ static bool IsUDP(const CStdString& strFile);
++ static bool IsTCP(const CStdString& strFile);
+ static bool IsHD(const CStdString& strFileName);
+ static bool IsHDHomeRun(const CStdString& strFile);
+ static bool IsSlingbox(const CStdString& strFile);
+@@ -127,6 +129,8 @@ class URIUtils
+ static bool IsAndroidApp(const CStdString& strFile);
+ static bool IsLibraryFolder(const CStdString& strFile);
+ static bool IsLibraryContent(const std::string& strFile);
++ static bool IsPVRChannel(const CStdString& strFile);
++ static bool IsUsingFastSwitch(const CStdString& strFile);
+
+ static void AddSlashAtEnd(std::string& strFolder);
+ static bool HasSlashAtEnd(const std::string& strFile, bool checkURL = false);
+--
+1.9.1
+
+
+From e73bfd14cbcfe83c21110b19e08d6f52f41f81e7 Mon Sep 17 00:00:00 2001
+From: Rainer Hochecker
+Date: Tue, 28 Jan 2014 08:43:29 +0100
+Subject: [PATCH 24/31] squash fast switch
+
+---
+ .../cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.cpp | 23 ++++++++++++++--------
+ 1 file changed, 15 insertions(+), 8 deletions(-)
+
+diff --git a/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.cpp b/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.cpp
+index c6472b8..63f1372 100644
+--- a/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.cpp
++++ b/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.cpp
+@@ -1710,15 +1710,19 @@ void CDVDDemuxFFmpeg::ParsePacket(AVPacket *pkt)
+ bool CDVDDemuxFFmpeg::IsVideoReady()
+ {
+ AVStream *st;
++ bool hasVideo = false;
+ if(m_program != UINT_MAX)
+ {
+ for (unsigned int i = 0; i < m_pFormatContext->programs[m_program]->nb_stream_indexes; i++)
+ {
+ int idx = m_pFormatContext->programs[m_program]->stream_index[i];
+ st = m_pFormatContext->streams[idx];
+- if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO &&
+- (!st->codec->width || st->codec->pix_fmt == PIX_FMT_NONE))
+- return false;
++ if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO)
++ {
++ if (st->codec->width && st->codec->pix_fmt != PIX_FMT_NONE)
++ return true;
++ hasVideo = true;
++ }
+ }
+ }
+ else
+@@ -1726,12 +1730,15 @@ bool CDVDDemuxFFmpeg::IsVideoReady()
+ for (unsigned int i = 0; i < m_pFormatContext->nb_streams; i++)
+ {
+ st = m_pFormatContext->streams[i];
+- if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO &&
+- (!st->codec->width || st->codec->pix_fmt == PIX_FMT_NONE))
+- return false;
++ if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO)
++ {
++ if (st->codec->width && st->codec->pix_fmt != PIX_FMT_NONE)
++ return true;
++ hasVideo = true;
++ }
+ }
+ }
+- return true;
++ return !hasVideo;
+ }
+
+ void CDVDDemuxFFmpeg::ResetVideoStreams()
+@@ -1743,7 +1750,7 @@ void CDVDDemuxFFmpeg::ResetVideoStreams()
+ if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO)
+ {
+ if (st->codec->extradata)
+- m_dllAvUtil.av_free(st->codec->extradata);
++ av_free(st->codec->extradata);
+ st->codec->extradata = NULL;
+ st->codec->width = 0;
+ }
+--
+1.9.1
+
+
+From 62afa1ee0982f4c68ce5a885220576f5751af81a Mon Sep 17 00:00:00 2001
+From: Rainer Hochecker
+Date: Sun, 13 Apr 2014 10:52:26 +0200
+Subject: [PATCH 25/31] squash fast channel
+
+---
+ xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.cpp | 13 ++++++++++---
+ xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.h | 1 +
+ 2 files changed, 11 insertions(+), 3 deletions(-)
+
+diff --git a/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.cpp b/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.cpp
+index 63f1372..0e4be8e 100644
+--- a/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.cpp
++++ b/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.cpp
+@@ -156,6 +156,7 @@ CDVDDemuxFFmpeg::CDVDDemuxFFmpeg() : CDVDDemux()
+ m_pkt.result = -1;
+ memset(&m_pkt.pkt, 0, sizeof(AVPacket));
+ m_streaminfo = true; /* set to true if we want to look for streams before playback */
++ m_checkvideo = false;
+ }
+
+ CDVDDemuxFFmpeg::~CDVDDemuxFFmpeg()
+@@ -376,11 +377,10 @@ bool CDVDDemuxFFmpeg::Open(CDVDInputStream* pInput, bool streaminfo)
+ if (iformat && (strcmp(iformat->name, "mjpeg") == 0) && m_ioContext->seekable == 0)
+ m_pFormatContext->max_analyze_duration = 500000;
+
+- bool short_analyze = false;
+ if (iformat && (strcmp(iformat->name, "mpegts") == 0))
+ {
+ m_pFormatContext->max_analyze_duration = 500000;
+- short_analyze = true;
++ m_checkvideo = true;
+ }
+
+ // we need to know if this is matroska or avi later
+@@ -412,14 +412,17 @@ bool CDVDDemuxFFmpeg::Open(CDVDInputStream* pInput, bool streaminfo)
+ }
+ CLog::Log(LOGDEBUG, "%s - av_find_stream_info finished", __FUNCTION__);
+
+- if (short_analyze)
++ if (m_checkvideo)
+ {
+ // make sure we start video with an i-frame
+ ResetVideoStreams();
+ }
+ }
+ else
++ {
+ m_program = 0;
++ m_checkvideo = true;
++ }
+
+ // reset any timeout
+ m_timeout.SetInfinite();
+@@ -1711,6 +1714,10 @@ bool CDVDDemuxFFmpeg::IsVideoReady()
+ {
+ AVStream *st;
+ bool hasVideo = false;
++
++ if(!m_checkvideo)
++ return true;
++
+ if(m_program != UINT_MAX)
+ {
+ for (unsigned int i = 0; i < m_pFormatContext->programs[m_program]->nb_stream_indexes; i++)
+diff --git a/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.h b/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.h
+index 26ee264..322a3b8 100644
+--- a/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.h
++++ b/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.h
+@@ -161,5 +161,6 @@ class CDVDDemuxFFmpeg : public CDVDDemux
+ bool m_bPtsWrap, m_bPtsWrapChecked;
+ int64_t m_iStartTime, m_iMaxTime, m_iEndTime;
+ bool m_streaminfo;
++ bool m_checkvideo;
+ };
+
+--
+1.9.1
+
+
+From 6a8561267a785e169a01ecda71ac9676744f2bbd Mon Sep 17 00:00:00 2001
+From: Rainer Hochecker
+Date: Sun, 22 Dec 2013 14:52:29 +0100
+Subject: [PATCH 26/31] linux: add shared lib for sse4 operations
+
+---
+ Makefile.in | 8 ++-
+ configure.in | 18 +++++++
+ xbmc/DllPaths_generated.h.in | 3 ++
+ xbmc/linux/sse4/CopyFrame.cpp | 115 ++++++++++++++++++++++++++++++++++++++++++
+ xbmc/linux/sse4/DllLibSSE4.h | 43 ++++++++++++++++
+ xbmc/linux/sse4/Makefile.in | 20 ++++++++
+ 6 files changed, 206 insertions(+), 1 deletion(-)
+ create mode 100644 xbmc/linux/sse4/CopyFrame.cpp
+ create mode 100644 xbmc/linux/sse4/DllLibSSE4.h
+ create mode 100644 xbmc/linux/sse4/Makefile.in
+
+diff --git a/Makefile.in b/Makefile.in
+index 002bb23..78211b3 100644
+--- a/Makefile.in
++++ b/Makefile.in
+@@ -311,6 +311,12 @@ CHECK_LIBADD=@WAYLAND_TEST_LIBS@
+ endif
+ endif
+
++ifeq (@USE_SSE4@,1)
++LIBSSE4+=sse4
++sse4 : force
++ $(MAKE) -C xbmc/linux/sse4
++endif
++
+ CHECK_PROGRAMS = xbmc-test
+
+ CLEAN_FILES += $(CHECK_PROGRAMS) $(CHECK_EXTENSIONS)
+@@ -438,7 +444,7 @@ endif
+
+ codecs: papcodecs dvdpcodecs dvdpextcodecs
+
+-libs: libhdhomerun imagelib libexif system/libcpluff-@ARCH@.so $(CMYTH)
++libs: $(LIBSSE4) libhdhomerun imagelib libexif system/libcpluff-@ARCH@.so $(CMYTH)
+
+ externals: codecs libs visualizations screensavers libaddon pvraddons
+
+diff --git a/configure.in b/configure.in
+index 3fcb178..9140b25 100644
+--- a/configure.in
++++ b/configure.in
+@@ -827,6 +827,19 @@ elif test "$use_arch" = "arm"; then
+ fi
+ fi
+
++use_sse4=no
++if test "$ARCH" = "x86_64-linux" || test "$ARCH" = "i486-linux"; then
++ SAVE_CFLAGS="$CFLAGS"
++ CFLAGS="-msse4.1"
++ AC_COMPILE_IFELSE(
++ [AC_LANG_SOURCE([int foo;])],
++ [ use_sse4=yes
++ USE_SSE4=1],
++ [ use_sse=no
++ USE_SSE4=0])
++ CFLAGS="$SAVE_CFLAGS"
++fi
++
+ # Checks for library functions.
+ AC_FUNC_ALLOCA
+ AC_FUNC_CHOWN
+@@ -2598,6 +2611,10 @@ if test "$use_codec_libstagefright" = "yes"; then
+ OUTPUT_FILES="$OUTPUT_FILES xbmc/cores/dvdplayer/DVDCodecs/Video/libstagefrightICS/Makefile"
+ fi
+
++if test "$use_sse4" = "yes"; then
++OUTPUT_FILES="$OUTPUT_FILES xbmc/linux/sse4/Makefile"
++fi
++
+ OUTPUT_FILES="$OUTPUT_FILES \
+ xbmc/interfaces/python/Makefile \
+ xbmc/interfaces/python/test/Makefile"
+@@ -2676,6 +2693,7 @@ AC_SUBST(USE_ANDROID)
+ AC_SUBST(GTEST_CONFIGURED)
+ AC_SUBST(USE_DOXYGEN)
+ AC_SUBST(USE_PVR_ADDONS)
++AC_SUBST(USE_SSE4)
+
+ # pushd and popd are not available in other shells besides bash, so implement
+ # our own pushd/popd functions
+diff --git a/xbmc/DllPaths_generated.h.in b/xbmc/DllPaths_generated.h.in
+index 8e81555..dd6e0ed 100644
+--- a/xbmc/DllPaths_generated.h.in
++++ b/xbmc/DllPaths_generated.h.in
+@@ -94,4 +94,7 @@
+ /* xkbcommon */
+ #define DLL_PATH_XKBCOMMON "@XKBCOMMON_LIBRARY_SONAME@"
+
++/* sse4 */
++#define DLL_PATH_LIBSSE4 "special://xbmcbin/system/libsse4-@ARCH@.so"
++
+ #endif
+diff --git a/xbmc/linux/sse4/CopyFrame.cpp b/xbmc/linux/sse4/CopyFrame.cpp
+new file mode 100644
+index 0000000..6d23d83
+--- /dev/null
++++ b/xbmc/linux/sse4/CopyFrame.cpp
+@@ -0,0 +1,115 @@
++/*
++ * Copyright (C) 2005-2013 Team XBMC
++ * http://xbmc.org
++ *
++ * This library 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.
++ *
++ * This library 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 General Public License
++ * along with XBMC; see the file COPYING. If not, see
++ * .
++ *
++ */
++
++#include "smmintrin.h"
++
++#define CACHED_BUFFER_SIZE 4096
++typedef unsigned int UINT;
++
++extern "C"
++{
++
++/*
++ * http://software.intel.com/en-us/articles/copying-accelerated-video-decode-frame-buffers
++ * COPIES VIDEO FRAMES FROM USWC MEMORY TO WB SYSTEM MEMORY VIA CACHED BUFFER
++ * ASSUMES PITCH IS A MULTIPLE OF 64B CACHE LINE SIZE, WIDTH MAY NOT BE
++ */
++void copy_frame( void * pSrc, void * pDest, void * pCacheBlock,
++ UINT width, UINT height, UINT pitch )
++{
++ __m128i x0, x1, x2, x3;
++ __m128i *pLoad;
++ __m128i *pStore;
++ __m128i *pCache;
++ UINT x, y, yLoad, yStore;
++ UINT rowsPerBlock;
++ UINT width64;
++ UINT extraPitch;
++
++
++ rowsPerBlock = CACHED_BUFFER_SIZE / pitch;
++ width64 = (width + 63) & ~0x03f;
++ extraPitch = (pitch - width64) / 16;
++
++ pLoad = (__m128i *)pSrc;
++ pStore = (__m128i *)pDest;
++
++ // COPY THROUGH 4KB CACHED BUFFER
++ for( y = 0; y < height; y += rowsPerBlock )
++ {
++ // ROWS LEFT TO COPY AT END
++ if( y + rowsPerBlock > height )
++ rowsPerBlock = height - y;
++
++ pCache = (__m128i *)pCacheBlock;
++
++ _mm_mfence();
++
++ // LOAD ROWS OF PITCH WIDTH INTO CACHED BLOCK
++ for( yLoad = 0; yLoad < rowsPerBlock; yLoad++ )
++ {
++ // COPY A ROW, CACHE LINE AT A TIME
++ for( x = 0; x < pitch; x +=64 )
++ {
++ x0 = _mm_stream_load_si128( pLoad +0 );
++ x1 = _mm_stream_load_si128( pLoad +1 );
++ x2 = _mm_stream_load_si128( pLoad +2 );
++ x3 = _mm_stream_load_si128( pLoad +3 );
++
++ _mm_store_si128( pCache +0, x0 );
++ _mm_store_si128( pCache +1, x1 );
++ _mm_store_si128( pCache +2, x2 );
++ _mm_store_si128( pCache +3, x3 );
++
++ pCache += 4;
++ pLoad += 4;
++ }
++ }
++
++ _mm_mfence();
++
++ pCache = (__m128i *)pCacheBlock;
++
++ // STORE ROWS OF FRAME WIDTH FROM CACHED BLOCK
++ for( yStore = 0; yStore < rowsPerBlock; yStore++ )
++ {
++ // copy a row, cache line at a time
++ for( x = 0; x < width64; x +=64 )
++ {
++ x0 = _mm_load_si128( pCache );
++ x1 = _mm_load_si128( pCache +1 );
++ x2 = _mm_load_si128( pCache +2 );
++ x3 = _mm_load_si128( pCache +3 );
++
++ _mm_stream_si128( pStore, x0 );
++ _mm_stream_si128( pStore +1, x1 );
++ _mm_stream_si128( pStore +2, x2 );
++ _mm_stream_si128( pStore +3, x3 );
++
++ pCache += 4;
++ pStore += 4;
++ }
++
++ pCache += extraPitch;
++ pStore += extraPitch;
++ }
++ }
++}
++}
+diff --git a/xbmc/linux/sse4/DllLibSSE4.h b/xbmc/linux/sse4/DllLibSSE4.h
+new file mode 100644
+index 0000000..01424ac
+--- /dev/null
++++ b/xbmc/linux/sse4/DllLibSSE4.h
+@@ -0,0 +1,43 @@
++#pragma once
++/*
++ * Copyright (C) 2005-2013 Team XBMC
++ * http://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 "DynamicDll.h"
++
++extern "C" {
++
++}
++
++class DllLibSSE4Interface
++{
++public:
++ virtual ~DllLibSSE4Interface() {}
++ virtual void copy_frame(void * pSrc, void * pDest, void * pCacheBlock, UINT width, UINT height, UINT pitch) = 0;
++};
++
++class DllLibSSE4 : public DllDynamic, DllLibSSE4Interface
++{
++ DECLARE_DLL_WRAPPER(DllLibSSE4, DLL_PATH_LIBSSE4)
++ DEFINE_METHOD6(void, copy_frame, (void *p1, void *p2, void *p3, UINT p4, UINT p5, UINT p6))
++
++ BEGIN_METHOD_RESOLVE()
++ RESOLVE_METHOD(copy_frame)
++ END_METHOD_RESOLVE()
++};
+diff --git a/xbmc/linux/sse4/Makefile.in b/xbmc/linux/sse4/Makefile.in
+new file mode 100644
+index 0000000..45aa826
+--- /dev/null
++++ b/xbmc/linux/sse4/Makefile.in
+@@ -0,0 +1,20 @@
++ARCH=@ARCH@
++DEFINES+=
++CXXFLAGS=-fPIC -msse4.1
++LIBNAME=libsse4
++OBJS=CopyFrame.o
++
++LIB_SHARED=@abs_top_srcdir@/system/$(LIBNAME)-$(ARCH).so
++
++all: $(LIB_SHARED)
++
++$(LIB_SHARED): $(OBJS)
++ $(CXX) $(CFLAGS) $(LDFLAGS) -shared -g -o $(LIB_SHARED) $(OBJS)
++
++CLEAN_FILES = \
++ $(LIB_SHARED) \
++
++DISTCLEAN_FILES= \
++ Makefile \
++
++include ../../../Makefile.include
+--
+1.9.1
+
+
+From 2e6de7059eabe3c19d50d4dd171f4fa0842acffe Mon Sep 17 00:00:00 2001
+From: Rainer Hochecker
+Date: Thu, 19 Dec 2013 15:36:11 +0100
+Subject: [PATCH 27/31] vaapi: option to enable sw filters
+
+---
+ language/English/strings.po | 17 ++-
+ system/settings/settings.xml | 15 ++
+ xbmc/cores/VideoRenderers/RenderManager.cpp | 4 +-
+ xbmc/cores/dvdplayer/DVDCodecs/DVDCodecUtils.cpp | 1 +
+ .../DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp | 76 +++++++++--
+ .../DVDCodecs/Video/DVDVideoCodecFFmpeg.h | 3 +
+ xbmc/cores/dvdplayer/DVDCodecs/Video/VAAPI.cpp | 152 +++++++++++++++++++++
+ xbmc/cores/dvdplayer/DVDCodecs/Video/VAAPI.h | 31 +++++
+ xbmc/cores/dvdplayer/DVDPlayerVideo.cpp | 32 ++---
+ 9 files changed, 290 insertions(+), 41 deletions(-)
+
+diff --git a/language/English/strings.po b/language/English/strings.po
+index a2e539e..17c9274 100755
+--- a/language/English/strings.po
++++ b/language/English/strings.po
+@@ -6092,7 +6092,13 @@ msgctxt "#13456"
+ msgid "Hardware accelerated"
+ msgstr ""
+
+-#empty strings from id 13457 to 13499
++#. Option for video related setting #13454: sw filter
++#: system/settings/settings.xml
++msgctxt "#13457"
++msgid "Use SW Filter for VAAPI"
++msgstr ""
++
++#empty strings from id 13458 to 13499
+
+ #: system/settings/settings.xml
+ msgctxt "#13500"
+@@ -15167,7 +15173,14 @@ msgctxt "#36431"
+ msgid "Defines whether video decoding should be performed in software (requires more CPU) or with hardware acceleration where possible."
+ msgstr ""
+
+-#empty strings from id 36432 to 36499
++#. Description for video related setting #13457: vaapi sw filter
++#: system/settings/settings.xml
++msgctxt "#36432"
++msgid "This option enables the deinterlacing methods available for software decoding. It gives the possiblity to use high quality deinterlacers in combination with VAAPI."
++msgstr ""
++
++#empty strings from id 36433 to 36499
++
+ #end reservation
+
+ #: system/settings/settings.xml
+diff --git a/system/settings/settings.xml b/system/settings/settings.xml
+index 0e4e952..ba17337 100644
+--- a/system/settings/settings.xml
++++ b/system/settings/settings.xml
+@@ -715,6 +715,21 @@
+ false
+
+
++
++ HAVE_LIBVA
++
++
++
++ true
++ 1
++
++
++ true
++
++ 3
++ false
++
++
+
+ HasDXVA2
+
+diff --git a/xbmc/cores/VideoRenderers/RenderManager.cpp b/xbmc/cores/VideoRenderers/RenderManager.cpp
+index 5e9f666..32ce5bb 100644
+--- a/xbmc/cores/VideoRenderers/RenderManager.cpp
++++ b/xbmc/cores/VideoRenderers/RenderManager.cpp
+@@ -988,10 +988,10 @@ EINTERLACEMETHOD CXBMCRenderManager::AutoInterlaceMethodInternal(EINTERLACEMETHO
+ if (mInt == VS_INTERLACEMETHOD_NONE)
+ return VS_INTERLACEMETHOD_NONE;
+
+- if(!m_pRenderer->Supports(mInt))
++ if(m_pRenderer && !m_pRenderer->Supports(mInt))
+ mInt = VS_INTERLACEMETHOD_AUTO;
+
+- if (mInt == VS_INTERLACEMETHOD_AUTO)
++ if (m_pRenderer && mInt == VS_INTERLACEMETHOD_AUTO)
+ return m_pRenderer->AutoInterlaceMethod();
+
+ return mInt;
+diff --git a/xbmc/cores/dvdplayer/DVDCodecs/DVDCodecUtils.cpp b/xbmc/cores/dvdplayer/DVDCodecs/DVDCodecUtils.cpp
+index 2958d43..06e0010 100644
+--- a/xbmc/cores/dvdplayer/DVDCodecs/DVDCodecUtils.cpp
++++ b/xbmc/cores/dvdplayer/DVDCodecs/DVDCodecUtils.cpp
+@@ -464,6 +464,7 @@ static const EFormatMap g_format_map[] = {
+ , { PIX_FMT_YUV420P16, RENDER_FMT_YUV420P16 }
+ , { PIX_FMT_UYVY422, RENDER_FMT_UYVY422 }
+ , { PIX_FMT_YUYV422, RENDER_FMT_YUYV422 }
++, { PIX_FMT_NV12, RENDER_FMT_NV12 }
+ , { PIX_FMT_VAAPI_VLD, RENDER_FMT_VAAPI }
+ , { PIX_FMT_DXVA2_VLD, RENDER_FMT_DXVA }
+ , { PIX_FMT_NONE , RENDER_FMT_NONE }
+diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp
+index 6bbb84d..f308c09 100644
+--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp
++++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp
+@@ -38,6 +38,7 @@
+ #include "utils/log.h"
+ #include "boost/shared_ptr.hpp"
+ #include "threads/Atomics.h"
++#include "settings/MediaSettings.h"
+
+ #ifndef TARGET_POSIX
+ #define RINT(x) ((x) >= 0 ? ((int)((x) + 0.5)) : ((int)((x) - 0.5)))
+@@ -168,6 +169,7 @@ CDVDVideoCodecFFmpeg::CDVDVideoCodecFFmpeg() : CDVDVideoCodec()
+ m_dts = DVD_NOPTS_VALUE;
+ m_started = false;
+ m_decoderPts = DVD_NOPTS_VALUE;
++ m_interlace = false;
+ }
+
+ CDVDVideoCodecFFmpeg::~CDVDVideoCodecFFmpeg()
+@@ -375,7 +377,7 @@ unsigned int CDVDVideoCodecFFmpeg::SetFilters(unsigned int flags)
+ {
+ m_filters_next.clear();
+
+- if(m_pHardware)
++ if(m_pHardware && !m_pHardware->UseFilter())
+ return 0;
+
+ if(flags & FILTER_ROTATE)
+@@ -449,10 +451,10 @@ int CDVDVideoCodecFFmpeg::Decode(uint8_t* pData, int iSize, double dts, double p
+ if(section)
+ lock = shared_ptr(new CSingleLock(*section));
+
+- int result;
++ int result = 0;
+ if(pData)
+ result = m_pHardware->Check(m_pCodecContext);
+- else
++ else if (!m_pHardware->UseFilter())
+ result = m_pHardware->Decode(m_pCodecContext, NULL);
+
+ if(result)
+@@ -507,19 +509,60 @@ int CDVDVideoCodecFFmpeg::Decode(uint8_t* pData, int iSize, double dts, double p
+ || m_pCodecContext->codec_id == AV_CODEC_ID_SVQ3)
+ m_started = true;
+
+- if(m_pHardware == NULL)
++ m_interlace = m_pFrame->interlaced_frame;
++
++ if(m_pHardware == NULL || m_pHardware->UseFilter())
+ {
++ if (m_pHardware)
++ {
++ m_pFrame->pkt_dts = pts_dtoi(m_dts);
++ int result = m_pHardware->Decode(m_pCodecContext, m_pFrame);
++ if (result == VC_BUFFER || result == VC_ERROR)
++ return result;
++ m_pHardware->MapFrame(m_pCodecContext, m_pFrame);
++ m_dts = pts_itod(m_pFrame->pkt_dts);
++ m_pFrame->pkt_dts = 0;
++ }
++
+ bool need_scale = std::find( m_formats.begin()
+ , m_formats.end()
+- , m_pCodecContext->pix_fmt) == m_formats.end();
++ , m_pFrame->format) == m_formats.end();
+
+ bool need_reopen = false;
++
++
++ // ask codec to do deinterlacing if possible
++ EDEINTERLACEMODE mDeintMode = CMediaSettings::Get().GetCurrentVideoSettings().m_DeinterlaceMode;
++ EINTERLACEMETHOD mInt = g_renderManager.AutoInterlaceMethod(CMediaSettings::Get().GetCurrentVideoSettings().m_InterlaceMethod);
++
++ unsigned int mFilters = 0;
++
++ if (mDeintMode != VS_DEINTERLACEMODE_OFF)
++ {
++ if (mDeintMode == VS_DEINTERLACEMODE_FORCE ||
++ m_pFrame->interlaced_frame)
++ {
++ if (mInt == VS_INTERLACEMETHOD_DEINTERLACE)
++ mFilters = CDVDVideoCodec::FILTER_DEINTERLACE_ANY;
++ else if(mInt == VS_INTERLACEMETHOD_DEINTERLACE_HALF)
++ mFilters = CDVDVideoCodec::FILTER_DEINTERLACE_ANY | CDVDVideoCodec::FILTER_DEINTERLACE_HALFED;
++
++ if (mDeintMode == VS_DEINTERLACEMODE_AUTO && mFilters)
++ mFilters |= CDVDVideoCodec::FILTER_DEINTERLACE_FLAGGED;
++ }
++ }
++
++ if (!g_renderManager.Supports(RENDERFEATURE_ROTATION))
++ mFilters |= CDVDVideoCodec::FILTER_ROTATE;
++
++ SetFilters(mFilters);
++
+ if(!m_filters.Equals(m_filters_next))
+ need_reopen = true;
+
+ if(m_pFilterIn)
+ {
+- if(m_pFilterIn->outputs[0]->format != m_pCodecContext->pix_fmt
++ if(m_pFilterIn->outputs[0]->format != m_pFrame->format
+ || m_pFilterIn->outputs[0]->w != m_pCodecContext->width
+ || m_pFilterIn->outputs[0]->h != m_pCodecContext->height)
+ need_reopen = true;
+@@ -536,7 +579,7 @@ int CDVDVideoCodecFFmpeg::Decode(uint8_t* pData, int iSize, double dts, double p
+ }
+
+ int result;
+- if(m_pHardware)
++ if(m_pHardware && !m_pHardware->UseFilter())
+ result = m_pHardware->Decode(m_pCodecContext, m_pFrame);
+ else if(m_pFilterGraph)
+ result = FilterProcess(m_pFrame);
+@@ -620,6 +663,7 @@ bool CDVDVideoCodecFFmpeg::GetPictureCommon(DVDVideoPicture* pDvdVideoPicture)
+ pDvdVideoPicture->chroma_position = m_pCodecContext->chroma_sample_location;
+ pDvdVideoPicture->color_primaries = m_pCodecContext->color_primaries;
+ pDvdVideoPicture->color_transfer = m_pCodecContext->color_trc;
++ pDvdVideoPicture->color_matrix = m_pCodecContext->colorspace;
+ if(m_pCodecContext->color_range == AVCOL_RANGE_JPEG
+ || m_pCodecContext->pix_fmt == PIX_FMT_YUVJ420P)
+ pDvdVideoPicture->color_range = 1;
+@@ -643,7 +687,11 @@ bool CDVDVideoCodecFFmpeg::GetPictureCommon(DVDVideoPicture* pDvdVideoPicture)
+ pDvdVideoPicture->qscale_type = DVP_QSCALE_UNKNOWN;
+ }
+
+- pDvdVideoPicture->dts = m_dts;
++ if (pDvdVideoPicture->iRepeatPicture)
++ pDvdVideoPicture->dts = DVD_NOPTS_VALUE;
++ else
++ pDvdVideoPicture->dts = m_dts;
++
+ m_dts = DVD_NOPTS_VALUE;
+ if (m_pFrame->reordered_opaque)
+ pDvdVideoPicture->pts = pts_itod(m_pFrame->reordered_opaque);
+@@ -674,7 +722,7 @@ bool CDVDVideoCodecFFmpeg::GetPictureCommon(DVDVideoPicture* pDvdVideoPicture)
+
+ bool CDVDVideoCodecFFmpeg::GetPicture(DVDVideoPicture* pDvdVideoPicture)
+ {
+- if(m_pHardware)
++ if(m_pHardware && !m_pHardware->UseFilter())
+ return m_pHardware->GetPicture(m_pCodecContext, m_pFrame, pDvdVideoPicture);
+
+ if(!GetPictureCommon(pDvdVideoPicture))
+@@ -694,6 +742,7 @@ bool CDVDVideoCodecFFmpeg::GetPicture(DVDVideoPicture* pDvdVideoPicture)
+ pix_fmt = (PixelFormat)m_pFrame->format;
+
+ pDvdVideoPicture->format = CDVDCodecUtils::EFormatFromPixfmt(pix_fmt);
++
+ return true;
+ }
+
+@@ -707,7 +756,7 @@ int CDVDVideoCodecFFmpeg::FilterOpen(const CStdString& filters, bool scale)
+ if (filters.empty() && !scale)
+ return 0;
+
+- if (m_pHardware)
++ if (m_pHardware && !m_pHardware->UseFilter())
+ {
+ CLog::Log(LOGWARNING, "CDVDVideoCodecFFmpeg::FilterOpen - skipped opening filters on hardware decode");
+ return 0;
+@@ -725,7 +774,7 @@ int CDVDVideoCodecFFmpeg::FilterOpen(const CStdString& filters, bool scale)
+ CStdString args = StringUtils::Format("%d:%d:%d:%d:%d:%d:%d",
+ m_pCodecContext->width,
+ m_pCodecContext->height,
+- m_pCodecContext->pix_fmt,
++ m_pFrame->format,
+ m_pCodecContext->time_base.num,
+ m_pCodecContext->time_base.den,
+ m_pCodecContext->sample_aspect_ratio.num,
+@@ -852,10 +901,7 @@ bool CDVDVideoCodecFFmpeg::GetCodecStats(double &pts, int &skippedDeint, int &in
+ {
+ pts = m_decoderPts;
+ skippedDeint = m_skippedDeint;
+- if (m_pFrame)
+- interlaced = m_pFrame->interlaced_frame;
+- else
+- interlaced = 0;
++ interlaced = m_interlace;
+ return true;
+ }
+
+diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.h b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.h
+index fa3269c..6baf42a 100644
+--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.h
++++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.h
+@@ -53,6 +53,8 @@ class CDVDVideoCodecFFmpeg : public CDVDVideoCodec
+ virtual bool CanSkipDeint() {return false; }
+ virtual const std::string Name() = 0;
+ virtual CCriticalSection* Section() { return NULL; }
++ virtual bool UseFilter() { return false; }
++ virtual bool MapFrame(AVCodecContext* avctx, AVFrame* frame) { return false; }
+ };
+
+ CDVDVideoCodecFFmpeg();
+@@ -129,4 +131,5 @@ class CDVDVideoCodecFFmpeg : public CDVDVideoCodec
+ int m_skippedDeint;
+ bool m_requestSkipDeint;
+ int m_codecControlFlags;
++ bool m_interlace;
+ };
+diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/VAAPI.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/VAAPI.cpp
+index 386d50a..315f3ca 100644
+--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/VAAPI.cpp
++++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/VAAPI.cpp
+@@ -26,6 +26,15 @@
+ #include
+ #include "utils/log.h"
+ #include "threads/SingleLock.h"
++#include "XMemUtils.h"
++#include "utils/CPUInfo.h"
++#include "settings/Settings.h"
++
++extern "C" {
++#include "libavutil/avutil.h"
++}
++
++#define CACHED_BUFFER_SIZE 4096
+
+ #define CHECK(a) \
+ do { \
+@@ -168,12 +177,17 @@ CDecoder::CDecoder()
+ m_context = 0;
+ m_hwaccel = (vaapi_context*)calloc(1, sizeof(vaapi_context));
+ memset(m_surfaces, 0, sizeof(*m_surfaces));
++ m_frame_buffer = NULL;
++ m_cache = NULL;
+ }
+
+ CDecoder::~CDecoder()
+ {
+ Close();
+ free(m_hwaccel);
++ _aligned_free(m_frame_buffer);
++ _aligned_free(m_cache);
++ m_dllSSE4.Unload();
+ }
+
+ void CDecoder::RelBuffer(uint8_t *data)
+@@ -393,6 +407,11 @@ bool CDecoder::Open(AVCodecContext *avctx, enum PixelFormat fmt, unsigned int su
+ if (!EnsureContext(avctx))
+ return false;
+
++ if (avctx->width <= 1920 && avctx->height <= 1088)
++ CheckUseFilter();
++ else
++ m_use_filter = false;
++
+ m_hwaccel->display = m_display->get();
+
+ avctx->hwaccel_context = m_hwaccel;
+@@ -475,7 +494,35 @@ int CDecoder::Decode(AVCodecContext* avctx, AVFrame* frame)
+ return status;
+
+ if(frame)
++ {
++ if (m_use_filter)
++ {
++ VASurfaceID surface = GetSurfaceID(frame);
++ std::list::iterator it;
++ for(it = m_surfaces_used.begin(); it != m_surfaces_used.end(); ++it)
++ {
++ if((*it)->m_id == surface)
++ {
++ m_holder.surface = *it;
++ break;
++ }
++ }
++ if (it == m_surfaces_used.end())
++ {
++ CLog::Log(LOGERROR, "VAAPI::Decode - surface not found");
++ return VC_ERROR;
++ }
++ CProcPic pic;
++ memset(&pic.frame, 0, sizeof(AVFrame));
++ av_frame_ref(&pic.frame, frame);
++ pic.surface = *it;
++ m_surfaces_proc.push_back(pic);
++ if (m_surfaces_proc.size() < m_renderbuffers_count)
++ return VC_BUFFER;
++ }
++
+ return VC_BUFFER | VC_PICTURE;
++ }
+ else
+ return VC_BUFFER;
+ }
+@@ -553,4 +600,109 @@ unsigned CDecoder::GetAllowedReferences()
+ return m_renderbuffers_count;
+ }
+
++void CDecoder::Reset()
++{
++ m_surfaces_proc.clear();
++}
++
++void CDecoder::CheckUseFilter()
++{
++ m_use_filter = true;
++ _aligned_free(m_frame_buffer);
++ _aligned_free(m_cache);
++ if (CSettings::Get().GetBool("videoplayer.usevaapiswfilter"))
++ {
++ if (!(g_cpuInfo.GetCPUFeatures() & CPU_FEATURE_SSE4))
++ {
++ CLog::Log(LOGNOTICE,"VAAPI::CheckUseFilter cpu does not support SSE4");
++ m_use_filter = false;
++ return;
++ }
++ if (!m_dllSSE4.Load())
++ {
++ CLog::Log(LOGNOTICE,"VAAPI::CheckUseFilter failed loading sse4 lib");
++ m_use_filter = false;
++ return;
++ }
++ VAImage image;
++ VASurfaceID surface = m_surfaces_free.front()->m_id;
++ VAStatus status = vaDeriveImage(m_display->get(), surface, &image);
++ m_use_filter = true;
++ if (status != VA_STATUS_SUCCESS)
++ {
++ CLog::Log(LOGNOTICE,"VAAPI::CheckUseFilter vaDeriveImage not supported");
++ m_use_filter = false;
++ }
++ if (image.format.fourcc != VA_FOURCC_NV12)
++ {
++ CLog::Log(LOGNOTICE,"VAAPI::CheckUseFilter image format not NV12");
++ m_use_filter = false;
++ }
++ if ((image.pitches[0] % 64) || (image.pitches[1] % 64))
++ {
++ CLog::Log(LOGNOTICE,"VAAPI::CheckUseFilter patches no multiple of 64");
++ m_use_filter = false;
++ }
++ if (m_use_filter)
++ {
++ m_frame_buffer = (uint8_t*)_aligned_malloc(image.height*image.width*2 + 256, 64);
++ m_cache = (uint8_t*)_aligned_malloc(CACHED_BUFFER_SIZE, 64);
++ }
++ vaDestroyImage(m_display->get(),image.image_id);
++ }
++ else
++ {
++ m_use_filter = false;
++ }
++}
++
++bool CDecoder::MapFrame(AVCodecContext* avctx, AVFrame* frame)
++{
++ if (m_surfaces_proc.empty())
++ {
++ return false;
++ }
++ if(frame)
++ {
++ CProcPic pic = m_surfaces_proc.front();
++ m_surfaces_proc.pop_front();
++ VASurfaceID surface = pic.surface->m_id;
++ VASurfaceStatus surf_status;
++ VAImage image;
++ uint8_t *buf;
++ CHECK(vaQuerySurfaceStatus(m_display->get(), surface, &surf_status))
++ while (surf_status != VASurfaceReady)
++ {
++ Sleep(1);
++ CHECK(vaQuerySurfaceStatus(m_display->get(), surface, &surf_status))
++ }
++ CHECK(vaDeriveImage(m_display->get(), surface, &image));
++ CHECK(vaMapBuffer(m_display->get(), image.buf, (void**)&buf))
++
++ uint8_t *src, *dst;
++ src = buf + image.offsets[0];
++ dst = m_frame_buffer + image.offsets[0];
++ m_dllSSE4.copy_frame(src, dst, m_cache, image.width, image.height, image.pitches[0]);
++ src = buf + image.offsets[1];
++ dst = m_frame_buffer + image.offsets[1];
++ m_dllSSE4.copy_frame(src, dst, m_cache, image.width, image.height/2, image.pitches[1]);
++
++ av_frame_unref(frame);
++ av_frame_move_ref(frame, &pic.frame);
++
++ frame->format = AV_PIX_FMT_NV12;
++ frame->data[0] = m_frame_buffer + image.offsets[0];
++ frame->linesize[0] = image.pitches[0];
++ frame->data[1] = m_frame_buffer + image.offsets[1];
++ frame->linesize[1] = image.pitches[1];
++ frame->data[2] = NULL;
++ frame->data[3] = NULL;
++ frame->pkt_size = image.data_size;
++
++ CHECK(vaUnmapBuffer(m_display->get(), image.buf))
++ CHECK(vaDestroyImage(m_display->get(),image.image_id))
++ }
++ return true;
++}
++
+ #endif
+diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/VAAPI.h b/xbmc/cores/dvdplayer/DVDCodecs/Video/VAAPI.h
+index ec99162..616b124 100644
+--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/VAAPI.h
++++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/VAAPI.h
+@@ -27,9 +27,11 @@
+ #include
+ #include
+ #include
++#include "linux/sse4/DllLibSSE4.h"
+
+ extern "C" {
+ #include "libavcodec/vaapi.h"
++#include "libavcodec/avcodec.h"
+ }
+
+ namespace VAAPI {
+@@ -102,11 +104,31 @@ struct CHolder
+ {}
+ };
+
++struct CProcPic
++{
++ AVFrame frame;
++ CSurfacePtr surface;
++ CProcPic()
++ {}
++ CProcPic(const CProcPic &other)
++ {
++ memcpy(&this->frame, &other.frame, sizeof(AVFrame));
++ surface = other.surface;
++ }
++ CProcPic & operator= (const CProcPic &other)
++ {
++ memcpy(&this->frame, &other.frame, sizeof(AVFrame));
++ surface = other.surface;
++ return *this;
++ }
++};
++
+ class CDecoder
+ : public CDVDVideoCodecFFmpeg::IHardwareDecoder
+ {
+ bool EnsureContext(AVCodecContext *avctx);
+ bool EnsureSurfaces(AVCodecContext *avctx, unsigned n_surfaces_count);
++ void CheckUseFilter();
+ public:
+ CDecoder();
+ ~CDecoder();
+@@ -115,9 +137,12 @@ class CDecoder
+ virtual bool GetPicture(AVCodecContext* avctx, AVFrame* frame, DVDVideoPicture* picture);
+ virtual int Check (AVCodecContext* avctx);
+ virtual void Close();
++ virtual void Reset();
+ virtual const std::string Name() { return "vaapi"; }
+ virtual CCriticalSection* Section() { if(m_display) return m_display.get(); else return NULL; }
+ virtual unsigned GetAllowedReferences();
++ virtual bool UseFilter() { return m_use_filter; }
++ virtual bool MapFrame(AVCodecContext* avctx, AVFrame* frame);
+
+ int GetBuffer(AVCodecContext *avctx, AVFrame *pic, int flags);
+ void RelBuffer(uint8_t *data);
+@@ -133,14 +158,20 @@ class CDecoder
+ int m_refs;
+ std::list m_surfaces_used;
+ std::list m_surfaces_free;
++ std::list m_surfaces_proc;
+
+ CDisplayPtr m_display;
+ VAConfigID m_config;
+ VAContextID m_context;
++ bool m_use_filter;
++ uint8_t *m_frame_buffer;
++ uint8_t *m_cache;
+
+ vaapi_context *m_hwaccel;
+
+ CHolder m_holder; // silly struct to pass data to renderer
++
++ DllLibSSE4 m_dllSSE4;
+ };
+
+ }
+diff --git a/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp b/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp
+index 9c5469b..b30e450 100644
+--- a/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp
++++ b/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp
+@@ -554,28 +554,6 @@ void CDVDPlayerVideo::Process()
+ // decoder still needs to provide an empty image structure, with correct flags
+ m_pVideoCodec->SetDropState(bRequestDrop);
+
+- // ask codec to do deinterlacing if possible
+- EDEINTERLACEMODE mDeintMode = CMediaSettings::Get().GetCurrentVideoSettings().m_DeinterlaceMode;
+- EINTERLACEMETHOD mInt = g_renderManager.AutoInterlaceMethod(CMediaSettings::Get().GetCurrentVideoSettings().m_InterlaceMethod);
+-
+- unsigned int mFilters = 0;
+-
+- if (mDeintMode != VS_DEINTERLACEMODE_OFF)
+- {
+- if (mInt == VS_INTERLACEMETHOD_DEINTERLACE)
+- mFilters = CDVDVideoCodec::FILTER_DEINTERLACE_ANY;
+- else if(mInt == VS_INTERLACEMETHOD_DEINTERLACE_HALF)
+- mFilters = CDVDVideoCodec::FILTER_DEINTERLACE_ANY | CDVDVideoCodec::FILTER_DEINTERLACE_HALFED;
+-
+- if (mDeintMode == VS_DEINTERLACEMODE_AUTO && mFilters)
+- mFilters |= CDVDVideoCodec::FILTER_DEINTERLACE_FLAGGED;
+- }
+-
+- if (!g_renderManager.Supports(RENDERFEATURE_ROTATION))
+- mFilters |= CDVDVideoCodec::FILTER_ROTATE;
+-
+- mFilters = m_pVideoCodec->SetFilters(mFilters);
+-
+ int iDecoderState = m_pVideoCodec->Decode(pPacket->pData, pPacket->iSize, pPacket->dts, pPacket->pts);
+
+ // buffer packets so we can recover should decoder flush for some reason
+@@ -662,6 +640,8 @@ void CDVDPlayerVideo::Process()
+
+ //Deinterlace if codec said format was interlaced or if we have selected we want to deinterlace
+ //this video
++ EDEINTERLACEMODE mDeintMode = CMediaSettings::Get().GetCurrentVideoSettings().m_DeinterlaceMode;
++ EINTERLACEMETHOD mInt = g_renderManager.AutoInterlaceMethod(CMediaSettings::Get().GetCurrentVideoSettings().m_InterlaceMethod);
+ if ((mDeintMode == VS_DEINTERLACEMODE_AUTO && (picture.iFlags & DVP_FLAG_INTERLACED)) || mDeintMode == VS_DEINTERLACEMODE_FORCE)
+ {
+ if(mInt == VS_INTERLACEMETHOD_SW_BLEND)
+@@ -704,7 +684,15 @@ void CDVDPlayerVideo::Process()
+ }
+
+ if (picture.iRepeatPicture)
++ {
++ double pts;
++ int skipped, deint;
++ m_pVideoCodec->GetCodecStats(pts, skipped, deint);
++ picture.iDuration = frametime;
++ if (deint && (frametime <= 0.02*DVD_TIME_BASE))
++ picture.iDuration *= 2;
+ picture.iDuration *= picture.iRepeatPicture + 1;
++ }
+
+ int iResult = OutputPicture(&picture, pts);
+
+--
+1.9.1
+
+
+From 6d4f961cdac4c91aa8288dc35a618f735eb8868a Mon Sep 17 00:00:00 2001
+From: Rainer Hochecker
+Date: Fri, 24 Jan 2014 18:29:33 +0100
+Subject: [PATCH 28/31] dvdplayer: flush ffmpeg after hw decoder returned an
+ error
+
+---
+ xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp | 9 +++++++++
+ 1 file changed, 9 insertions(+)
+
+diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp
+index f308c09..830ce60 100644
+--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp
++++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp
+@@ -458,7 +458,12 @@ int CDVDVideoCodecFFmpeg::Decode(uint8_t* pData, int iSize, double dts, double p
+ result = m_pHardware->Decode(m_pCodecContext, NULL);
+
+ if(result)
++ {
++ if (result & VC_ERROR)
++ avcodec_flush_buffers(m_pCodecContext);
++
+ return result;
++ }
+ }
+
+ if(m_pFilterGraph)
+@@ -580,7 +585,11 @@ int CDVDVideoCodecFFmpeg::Decode(uint8_t* pData, int iSize, double dts, double p
+
+ int result;
+ if(m_pHardware && !m_pHardware->UseFilter())
++ {
+ result = m_pHardware->Decode(m_pCodecContext, m_pFrame);
++ if (result & VC_ERROR)
++ avcodec_flush_buffers(m_pCodecContext);
++ }
+ else if(m_pFilterGraph)
+ result = FilterProcess(m_pFrame);
+ else
+--
+1.9.1
+
+
+From bce0b976b37a99b3acddc2b1368f984c5c3bf712 Mon Sep 17 00:00:00 2001
+From: Rainer Hochecker
+Date: Tue, 28 Jan 2014 10:05:26 +0100
+Subject: [PATCH 29/31] xbmc pr 3080
+
+---
+ .../dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp | 14 ++++++++++++--
+ 1 file changed, 12 insertions(+), 2 deletions(-)
+
+diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp
+index 830ce60..8715afb 100644
+--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp
++++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp
+@@ -482,6 +482,14 @@ int CDVDVideoCodecFFmpeg::Decode(uint8_t* pData, int iSize, double dts, double p
+ av_init_packet(&avpkt);
+ avpkt.data = pData;
+ avpkt.size = iSize;
++#define SET_PKT_TS(ts) \
++ if(ts != DVD_NOPTS_VALUE)\
++ avpkt.ts = (ts / DVD_TIME_BASE) * AV_TIME_BASE;\
++ else\
++ avpkt.ts = AV_NOPTS_VALUE
++ SET_PKT_TS(pts);
++ SET_PKT_TS(dts);
++#undef SET_PKT_TS
+ /* We lie, but this flag is only used by pngdec.c.
+ * Setting it correctly would allow CorePNG decoding. */
+ avpkt.flags = AV_PKT_FLAG_KEY;
+@@ -702,8 +710,10 @@ bool CDVDVideoCodecFFmpeg::GetPictureCommon(DVDVideoPicture* pDvdVideoPicture)
+ pDvdVideoPicture->dts = m_dts;
+
+ m_dts = DVD_NOPTS_VALUE;
+- if (m_pFrame->reordered_opaque)
+- pDvdVideoPicture->pts = pts_itod(m_pFrame->reordered_opaque);
++
++ int64_t bpts = av_frame_get_best_effort_timestamp(m_pFrame);
++ if(bpts != AV_NOPTS_VALUE)
++ pDvdVideoPicture->pts = (double)bpts * DVD_TIME_BASE / AV_TIME_BASE;
+ else
+ pDvdVideoPicture->pts = DVD_NOPTS_VALUE;
+
+--
+1.9.1
+
+
+From c0100ee3de95343854714e52635291d58150da74 Mon Sep 17 00:00:00 2001
+From: Rainer Hochecker
+Date: Tue, 28 Jan 2014 17:24:58 +0100
+Subject: [PATCH 30/31] set preatpicture if pts is equal to last frame
+
+---
+ xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp | 8 ++++++++
+ 1 file changed, 8 insertions(+)
+
+diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp
+index 8715afb..dec00d5 100644
+--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp
++++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp
+@@ -713,7 +713,15 @@ bool CDVDVideoCodecFFmpeg::GetPictureCommon(DVDVideoPicture* pDvdVideoPicture)
+
+ int64_t bpts = av_frame_get_best_effort_timestamp(m_pFrame);
+ if(bpts != AV_NOPTS_VALUE)
++ {
+ pDvdVideoPicture->pts = (double)bpts * DVD_TIME_BASE / AV_TIME_BASE;
++ if (pDvdVideoPicture->pts == m_decoderPts)
++ {
++ pDvdVideoPicture->iRepeatPicture = -0.5;
++ pDvdVideoPicture->pts = DVD_NOPTS_VALUE;
++ pDvdVideoPicture->dts = DVD_NOPTS_VALUE;
++ }
++ }
+ else
+ pDvdVideoPicture->pts = DVD_NOPTS_VALUE;
+
+--
+1.9.1
+
+
+From 40dad6e6f9c1a96ac4e2f337e348b03f1e029bd3 Mon Sep 17 00:00:00 2001
+From: Rainer Hochecker
+Date: Tue, 11 Feb 2014 18:15:06 +0100
+Subject: [PATCH 31/31] ActiveAE: add some debug logging
+
+---
+ xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEStream.cpp | 6 ++++++
+ 1 file changed, 6 insertions(+)
+
+diff --git a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEStream.cpp b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEStream.cpp
+index 0287e73..6904cb9 100644
+--- a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEStream.cpp
++++ b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEStream.cpp
+@@ -276,7 +276,13 @@ unsigned int CActiveAEStream::AddData(void *data, unsigned int size)
+ }
+ }
+ if (!m_inMsgEvent.WaitMSec(200))
++ {
++ double cachetime = GetCacheTime();
++ CSingleLock lock(m_streamLock);
++ CLog::Log(LOGWARNING, "CActiveAEStream::AddData - timeout waiting for buffer, paused: %d, cache time: %f, free buffers: %d",
++ m_paused, cachetime, m_streamFreeBuffers);
+ break;
++ }
+ }
+ return copied;
+ }
+--
+1.9.1
+
diff --git a/packages/mediacenter/xbmc-master/patches/xbmc-master-995.02-dont-set-_NET_WM_STATE_FULLSCREEN.patch b/packages/mediacenter/xbmc-master/patches/xbmc-master-995.02-dont-set-_NET_WM_STATE_FULLSCREEN.patch
new file mode 100644
index 0000000000..3f331b1574
--- /dev/null
+++ b/packages/mediacenter/xbmc-master/patches/xbmc-master-995.02-dont-set-_NET_WM_STATE_FULLSCREEN.patch
@@ -0,0 +1,29 @@
+From 4f6188bc2bcee52ab3a150fff336b58c11f8928a Mon Sep 17 00:00:00 2001
+From: Stefan Saraev
+Date: Sat, 22 Mar 2014 22:18:28 +0200
+Subject: [PATCH] dont set _NET_WM_STATE_FULLSCREEN
+
+---
+ xbmc/windowing/X11/WinSystemX11.cpp | 6 ------
+ 1 files changed, 0 insertions(+), 6 deletions(-)
+
+diff --git a/xbmc/windowing/X11/WinSystemX11.cpp b/xbmc/windowing/X11/WinSystemX11.cpp
+index c95f4ec..d12e050 100644
+--- a/xbmc/windowing/X11/WinSystemX11.cpp
++++ b/xbmc/windowing/X11/WinSystemX11.cpp
+@@ -903,12 +903,6 @@ bool CWinSystemX11::SetWindow(int width, int height, bool fullscreen, const std:
+ InputOutput, vi->visual,
+ mask, &swa);
+
+- if (fullscreen && hasWM)
+- {
+- Atom fs = XInternAtom(m_dpy, "_NET_WM_STATE_FULLSCREEN", True);
+- XChangeProperty(m_dpy, m_mainWindow, XInternAtom(m_dpy, "_NET_WM_STATE", True), XA_ATOM, 32, PropModeReplace, (unsigned char *) &fs, 1);
+- }
+-
+ // define invisible cursor
+ Pixmap bitmapNoData;
+ XColor black;
+--
+1.7.2.5
+
diff --git a/packages/mediacenter/xbmc-master/patches/xbmc-master-995.10-disable-minimize.patch b/packages/mediacenter/xbmc-master/patches/xbmc-master-995.10-disable-minimize.patch
new file mode 100644
index 0000000000..c0fe5a62ab
--- /dev/null
+++ b/packages/mediacenter/xbmc-master/patches/xbmc-master-995.10-disable-minimize.patch
@@ -0,0 +1,18 @@
+commit 17807066bc04cd28bba89fd176d4d0f69ead9728
+Author: Stefan Saraev
+Date: Sat Oct 12 16:18:50 2013 +0300
+
+ disable minimize
+
+diff --git a/xbmc/Application.cpp b/xbmc/Application.cpp
+index b5d40c0..18bea9d 100644
+--- a/xbmc/Application.cpp
++++ b/xbmc/Application.cpp
+@@ -5448,7 +5448,6 @@ bool CApplication::SwitchToFullScreen()
+
+ void CApplication::Minimize()
+ {
+- g_Windowing.Minimize();
+ }
+
+ PLAYERCOREID CApplication::GetCurrentPlayer()
diff --git a/packages/mediacenter/xbmc-master/patches/xbmc-master-995.12-run-tzdata-setup-on-timezone-change.patch b/packages/mediacenter/xbmc-master/patches/xbmc-master-995.12-run-tzdata-setup-on-timezone-change.patch
new file mode 100644
index 0000000000..51a7e52381
--- /dev/null
+++ b/packages/mediacenter/xbmc-master/patches/xbmc-master-995.12-run-tzdata-setup-on-timezone-change.patch
@@ -0,0 +1,26 @@
+From 25be1b385303a8114d7e227ffab52a22de42ccd1 Mon Sep 17 00:00:00 2001
+From: Stefan Saraev
+Date: Tue, 26 Nov 2013 20:53:08 +0200
+Subject: [PATCH] run tzdata-setup on timezone change
+
+---
+ xbmc/linux/LinuxTimezone.cpp | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/xbmc/linux/LinuxTimezone.cpp b/xbmc/linux/LinuxTimezone.cpp
+index be7bce6..4000181 100644
+--- a/xbmc/linux/LinuxTimezone.cpp
++++ b/xbmc/linux/LinuxTimezone.cpp
+@@ -158,6 +158,9 @@ void CLinuxTimezone::OnSettingChanged(const CSetting *setting)
+ const std::string &settingId = setting->GetId();
+ if (settingId == "locale.timezone")
+ {
++ const std::string cmd = std::string("sh /usr/lib/openelec/tzdata-setup ") + ((CSettingString*)setting)->GetValue().c_str();
++ system(cmd.c_str());
++
+ SetTimezone(((CSettingString*)setting)->GetValue());
+
+ CDateTime::ResetTimezoneBias();
+--
+1.8.3.2
+
diff --git a/packages/mediacenter/xbmc-master/patches/xbmc-master-999.00-service-addons-use-a-wrapper-to-setup-systemd.patch b/packages/mediacenter/xbmc-master/patches/xbmc-master-999.00-service-addons-use-a-wrapper-to-setup-systemd.patch
new file mode 100644
index 0000000000..d81adcd3f1
--- /dev/null
+++ b/packages/mediacenter/xbmc-master/patches/xbmc-master-999.00-service-addons-use-a-wrapper-to-setup-systemd.patch
@@ -0,0 +1,97 @@
+From 9c1dea43c9b9b66c48d057d3c0e44cd4a807e4dc Mon Sep 17 00:00:00 2001
+From: Stefan Saraev
+Date: Fri, 20 Dec 2013 00:36:34 +0200
+Subject: [PATCH] service addons: use a wrapper to setup systemd
+
+---
+ xbmc/addons/AddonDatabase.cpp | 3 +++
+ xbmc/addons/AddonInstaller.cpp | 10 ++++++++++
+ xbmc/addons/AddonInstaller.h | 2 ++
+ 3 files changed, 15 insertions(+)
+
+diff --git a/xbmc/addons/AddonDatabase.cpp b/xbmc/addons/AddonDatabase.cpp
+index 4202363..105749f 100644
+--- a/xbmc/addons/AddonDatabase.cpp
++++ b/xbmc/addons/AddonDatabase.cpp
+@@ -20,6 +20,7 @@
+
+ #include "AddonDatabase.h"
+ #include "addons/AddonManager.h"
++#include "addons/AddonInstaller.h"
+ #include "utils/log.h"
+ #include "utils/Variant.h"
+ #include "utils/StringUtils.h"
+@@ -581,6 +582,7 @@ bool CAddonDatabase::DisableAddon(const CStdString &addonID, bool disable /* = t
+ boost::shared_ptr service = boost::dynamic_pointer_cast(addon);
+ if (service)
+ service->Stop();
++ CAddonInstaller::Get().CallOEWrapper(addonID, true);
+ }
+ // restart the pvr manager when disabling a pvr add-on with the pvr manager enabled
+ else if (CAddonMgr::Get().GetAddon(addonID, addon, ADDON_PVRDLL, false) && addon &&
+@@ -601,6 +603,7 @@ bool CAddonDatabase::DisableAddon(const CStdString &addonID, bool disable /* = t
+ // If the addon is a service, start it
+ if (CAddonMgr::Get().GetAddon(addonID, addon, ADDON_SERVICE, false) && addon && disabled)
+ {
++ CAddonInstaller::Get().CallOEWrapper(addonID, false);
+ boost::shared_ptr service = boost::dynamic_pointer_cast(addon);
+ if (service)
+ service->Start();
+diff --git a/xbmc/addons/AddonInstaller.cpp b/xbmc/addons/AddonInstaller.cpp
+index 8c9f241..d2f4610 100644
+--- a/xbmc/addons/AddonInstaller.cpp
++++ b/xbmc/addons/AddonInstaller.cpp
+@@ -70,6 +70,13 @@ CAddonInstaller &CAddonInstaller::Get()
+ return addonInstaller;
+ }
+
++void CAddonInstaller::CallOEWrapper(const std::string& ID, bool disable)
++{
++ char cmd[255];
++ snprintf(cmd, sizeof(cmd), "/usr/lib/openelec/systemd-addon-wrapper %s %d", ID.c_str(), disable);
++ system(cmd);
++}
++
+ void CAddonInstaller::OnJobComplete(unsigned int jobID, bool success, CJob* job)
+ {
+ if (success)
+@@ -586,6 +593,7 @@ bool CAddonInstallJob::OnPreInstall()
+ boost::shared_ptr service = boost::dynamic_pointer_cast(addon);
+ if (service)
+ service->Stop();
++ CAddonInstaller::Get().CallOEWrapper(m_addon->ID(), true);
+ CAddonMgr::Get().RemoveAddon(m_addon->ID()); // remove it
+ return running;
+ }
+@@ -713,6 +721,7 @@ void CAddonInstallJob::OnPostInstall(bool reloadAddon)
+ AddonPtr addon;
+ CAddonMgr::Get().GetAddon(m_addon->ID(), addon);
+ boost::shared_ptr service = boost::dynamic_pointer_cast(addon);
++ CAddonInstaller::Get().CallOEWrapper(m_addon->ID(), false);
+ if (service)
+ service->Start();
+ }
+@@ -794,6 +803,7 @@ bool CAddonUnInstallJob::DoWork()
+ boost::shared_ptr service = boost::dynamic_pointer_cast(m_addon);
+ if (service)
+ service->Stop();
++ CAddonInstaller::Get().CallOEWrapper(m_addon->ID(), true);
+ }
+
+ AddonPtr repoPtr = CAddonInstallJob::GetRepoForAddon(m_addon);
+diff --git a/xbmc/addons/AddonInstaller.h b/xbmc/addons/AddonInstaller.h
+index 39cab93..2938c7f 100644
+--- a/xbmc/addons/AddonInstaller.h
++++ b/xbmc/addons/AddonInstaller.h
+@@ -29,6 +29,8 @@ class CAddonInstaller : public IJobCallback
+ public:
+ static CAddonInstaller &Get();
+
++ void CallOEWrapper(const std::string& ID, bool disable);
++
+ bool IsDownloading() const;
+ void GetInstallList(ADDON::VECADDONS &addons) const;
+ bool GetProgress(const CStdString &addonID, unsigned int &percent) const;
+--
+1.8.3.2
+
diff --git a/packages/mediacenter/xbmc-master/patches/xbmc-master-999.80.01-PR4592.patch b/packages/mediacenter/xbmc-master/patches/xbmc-master-999.80.01-PR4592.patch
new file mode 100644
index 0000000000..ecc9edc561
--- /dev/null
+++ b/packages/mediacenter/xbmc-master/patches/xbmc-master-999.80.01-PR4592.patch
@@ -0,0 +1,62 @@
+From 6a926768eba981c6498f852fe26dfa6644da82ac Mon Sep 17 00:00:00 2001
+From: "Chris \"Koying\" Browet"
+Date: Wed, 23 Apr 2014 16:33:19 +0200
+Subject: [PATCH] FIX: [linux] fix & optimize input device checking
+
+---
+ xbmc/input/linux/LinuxInputDevices.cpp | 12 +++++++++++-
+ xbmc/input/linux/LinuxInputDevices.h | 1 +
+ 2 files changed, 12 insertions(+), 1 deletion(-)
+
+diff --git a/xbmc/input/linux/LinuxInputDevices.cpp b/xbmc/input/linux/LinuxInputDevices.cpp
+index 4b642ae..f11ec01 100644
+--- a/xbmc/input/linux/LinuxInputDevices.cpp
++++ b/xbmc/input/linux/LinuxInputDevices.cpp
+@@ -936,6 +936,11 @@ char* CLinuxInputDevice::GetDeviceName()
+ return m_deviceName;
+ }
+
++std::string CLinuxInputDevice::GetFileName()
++{
++ return m_fileName;
++}
++
+ bool CLinuxInputDevice::IsUnplugged()
+ {
+ return m_bUnplugged;
+@@ -945,6 +950,11 @@ bool CLinuxInputDevices::CheckDevice(const char *device)
+ {
+ int fd;
+
++ // Does the device exists?
++ struct stat buffer;
++ if (stat(device, &buffer) != 0)
++ return false;
++
+ /* Check if we are able to open the device */
+ fd = open(device, O_RDWR);
+ if (fd < 0)
+@@ -1016,7 +1026,7 @@ void CLinuxInputDevices::CheckHotplugged()
+
+ for (size_t j = 0; j < m_devices.size(); j++)
+ {
+- if (strcmp(m_devices[j]->GetDeviceName(),buf) == 0)
++ if (m_devices[j]->GetFileName().compare(buf) == 0)
+ {
+ ispresent = true;
+ break;
+diff --git a/xbmc/input/linux/LinuxInputDevices.h b/xbmc/input/linux/LinuxInputDevices.h
+index c385ed7..a406d9c 100644
+--- a/xbmc/input/linux/LinuxInputDevices.h
++++ b/xbmc/input/linux/LinuxInputDevices.h
+@@ -42,6 +42,7 @@ class CLinuxInputDevice
+ ~CLinuxInputDevice();
+ XBMC_Event ReadEvent();
+ char* GetDeviceName();
++ std::string GetFileName();
+ bool IsUnplugged();
+
+ private:
+--
+1.9.1
+
diff --git a/packages/mediacenter/xbmc-master/patches/xbmc-master-999.80.02-PR4624.patch b/packages/mediacenter/xbmc-master/patches/xbmc-master-999.80.02-PR4624.patch
new file mode 100644
index 0000000000..2c23e9e047
--- /dev/null
+++ b/packages/mediacenter/xbmc-master/patches/xbmc-master-999.80.02-PR4624.patch
@@ -0,0 +1,31 @@
+From 3fae42dcad347a3a3b6d1a2ed0ba8c0d7f172de0 Mon Sep 17 00:00:00 2001
+From: Rainer Hochecker
+Date: Wed, 30 Apr 2014 15:29:51 +0200
+Subject: [PATCH] paplayer: dvdplayercodec - check if seek is possible before
+ trying to seek
+
+---
+ xbmc/cores/paplayer/DVDPlayerCodec.cpp | 7 +++++--
+ 1 file changed, 5 insertions(+), 2 deletions(-)
+
+diff --git a/xbmc/cores/paplayer/DVDPlayerCodec.cpp b/xbmc/cores/paplayer/DVDPlayerCodec.cpp
+index c60abc8..89e9dbe 100644
+--- a/xbmc/cores/paplayer/DVDPlayerCodec.cpp
++++ b/xbmc/cores/paplayer/DVDPlayerCodec.cpp
+@@ -202,8 +202,11 @@ bool DVDPlayerCodec::Init(const CStdString &strFile, unsigned int filecache)
+ }
+ else
+ {
+- m_pInputStream->Seek(0, SEEK_SET);
+- m_pDemuxer->Reset();
++ if (m_pInputStream->Seek(0, SEEK_POSSIBLE))
++ {
++ m_pInputStream->Seek(0, SEEK_SET);
++ m_pDemuxer->Reset();
++ }
+ m_bCanSeek = false;
+ }
+
+--
+1.9.1
+
diff --git a/packages/mediacenter/xbmc-master/patches/xbmc-master-999.90-show_rss-setting_in_standard_group.patch b/packages/mediacenter/xbmc-master/patches/xbmc-master-999.90-show_rss-setting_in_standard_group.patch
new file mode 100644
index 0000000000..50186d7813
--- /dev/null
+++ b/packages/mediacenter/xbmc-master/patches/xbmc-master-999.90-show_rss-setting_in_standard_group.patch
@@ -0,0 +1,12 @@
+diff -Naur xbmc-13.alpha-536cf62/system/settings/settings.xml xbmc-13.alpha-536cf62.patch/system/settings/settings.xml
+--- xbmc-13.alpha-536cf62/system/settings/settings.xml 2014-01-29 18:31:46.000000000 +0100
++++ xbmc-13.alpha-536cf62.patch/system/settings/settings.xml 2014-01-31 13:12:46.789297639 +0100
+@@ -91,7 +91,7 @@
+
+
+
+- 1
++ 0
+ true
+
+
diff --git a/packages/mediacenter/xbmc-master/profile.d/02-xbmc.conf b/packages/mediacenter/xbmc-master/profile.d/02-xbmc.conf
new file mode 100644
index 0000000000..882e7d0f0a
--- /dev/null
+++ b/packages/mediacenter/xbmc-master/profile.d/02-xbmc.conf
@@ -0,0 +1,29 @@
+################################################################################
+# This file is part of OpenELEC - http://www.openelec.tv
+# Copyright (C) 2009-2014 Stephan Raue (stephan@openelec.tv)
+#
+# OpenELEC is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 2 of the License, or
+# (at your option) any later version.
+#
+# OpenELEC 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. If not, see .
+################################################################################
+
+# PATH
+for addon in /storage/.xbmc/addons/*/bin /usr/lib/xbmc/addons/*/bin; do
+ [ -d "$addon" ] && PATH="$PATH:$addon"
+done
+export PATH
+
+# LD_LIBRARY_PATH
+for addon in /storage/.xbmc/addons/*/lib /usr/lib/xbmc/addons/*/lib; do
+ [ -d "$addon" ] && LD_LIBRARY_PATH="$LD_LIBRARY_PATH:$addon"
+done
+export LD_LIBRARY_PATH
diff --git a/packages/mediacenter/xbmc-master/profile.d/03-addons.conf b/packages/mediacenter/xbmc-master/profile.d/03-addons.conf
new file mode 100644
index 0000000000..bdd7525920
--- /dev/null
+++ b/packages/mediacenter/xbmc-master/profile.d/03-addons.conf
@@ -0,0 +1,40 @@
+################################################################################
+# This file is part of OpenELEC - http://www.openelec.tv
+# Copyright (C) 2009-2014 Stephan Raue (stephan@openelec.tv)
+#
+# OpenELEC is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 2 of the License, or
+# (at your option) any later version.
+#
+# OpenELEC 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. If not, see .
+################################################################################
+
+oe_setup_addon() {
+ if [ ! -z $1 ] ; then
+ DEF="/storage/.xbmc/addons/$1/settings-default.xml"
+ CUR="/storage/.xbmc/userdata/addon_data/$1/settings.xml"
+
+ # copy defaults
+ if [ -f "$DEF" -a ! -f "$CUR" ] ; then
+ cp "$DEF" "$CUR"
+ fi
+
+ # parse config
+ [ -f "$DEF" ] && eval $(cat "$DEF" | awk -F\" '{print $2"=\""$4"\""}' | sed '/^=/d')
+ [ -f "$CUR" ] && eval $(cat "$CUR" | awk -F\" '{print $2"=\""$4"\""}' | sed '/^=/d')
+
+ # export some useful variables
+ ADDON_DIR="$HOME/.xbmc/addons/$1"
+ ADDON_HOME="$HOME/.xbmc/userdata/addon_data/$1"
+ ADDON_LOG_FILE="$ADDON_HOME/service.log"
+
+ [ ! -d $ADDON_HOME ] && mkdir -p $ADDON_HOME
+ fi
+}
diff --git a/packages/mediacenter/xbmc-master/scripts/cputemp b/packages/mediacenter/xbmc-master/scripts/cputemp
new file mode 100755
index 0000000000..1136827f2d
--- /dev/null
+++ b/packages/mediacenter/xbmc-master/scripts/cputemp
@@ -0,0 +1,67 @@
+#!/bin/sh
+
+################################################################################
+# This file is part of OpenELEC - http://www.openelec.tv
+# Copyright (C) 2009-2014 Stephan Raue (stephan@openelec.tv)
+#
+# OpenELEC is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 2 of the License, or
+# (at your option) any later version.
+#
+# OpenELEC 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. If not, see .
+################################################################################
+
+# inspired by
+# https://github.com/xtranophilist/gnome-shell-extension-cpu-temperature/blob/master/extension.js
+
+TEMP=0
+
+if [ $(basename "$0") = "gputemp" -o "$1" = "gpu" ]; then
+ if which lspci >/dev/null; then
+ if lspci -n | grep 0300 | grep -q 10de; then
+ [ -x /usr/bin/nvidia-smi ] && TEMP=`/usr/bin/nvidia-smi -q -x | grep 'gpu_temp' | awk '{ print $1 }' | sed 's,,,g'`
+ fi
+ fi
+fi
+
+if [ "$1" = "cpu" -o "$TEMP" = "0" ]; then
+ if [ -f /sys/class/hwmon/hwmon1/temp1_input ]; then
+ # used on Asus systems (ie. AT5IONT-I)
+ TEMP=`cat /sys/class/hwmon/hwmon1/temp1_input`
+ elif [ -f /sys/devices/platform/coretemp.0/temp1_input ]; then
+ # used with coretemp
+ TEMP=`cat /sys/devices/platform/coretemp.0/temp1_input`
+ elif [ -f /sys/devices/platform/coretemp.0/temp2_input ]; then
+ # used with coretemp
+ TEMP=`cat /sys/devices/platform/coretemp.0/temp2_input`
+ elif [ -f /sys/bus/acpi/devices/LNXTHERM\:00/thermal_zone/temp ]; then
+ # used on some intel systems
+ TEMP=`cat /sys/bus/acpi/devices/LNXTHERM\:00/thermal_zone/temp`
+ elif [ -f /sys/devices/virtual/thermal/thermal_zone0/temp ]; then
+ # used on some intel systems
+ TEMP=`cat /sys/devices/virtual/thermal/thermal_zone0/temp`
+ elif [ -f /sys/class/hwmon/hwmon0/temp1_input ]; then
+ # hwmon for new 2.6.39, 3.0 linux kernels
+ TEMP=`cat /sys/class/hwmon/hwmon0/temp1_input`
+ elif [ -f /sys/class/hwmon/hwmon0/device/temp1_input ]; then
+ # used on AMD systems
+ TEMP=`cat /sys/class/hwmon/hwmon0/device/temp1_input`
+ elif [ -f /sys/class/hwmon/hwmon0/device/temp2_input ]; then
+ # used on ION systems
+ TEMP=`cat /sys/class/hwmon/hwmon0/device/temp2_input`
+ elif [ -f /sys/class/thermal/thermal_zone0/temp ]; then
+ # used on RaspberryPi
+ TEMP=`cat /sys/class/thermal/thermal_zone0/temp`
+ fi
+
+ TEMP="$(( $TEMP / 1000 ))"
+fi
+
+echo "${TEMP} C"
diff --git a/packages/mediacenter/xbmc-master/scripts/setwakeup.sh b/packages/mediacenter/xbmc-master/scripts/setwakeup.sh
new file mode 100755
index 0000000000..76aa3d7c26
--- /dev/null
+++ b/packages/mediacenter/xbmc-master/scripts/setwakeup.sh
@@ -0,0 +1,26 @@
+#!/bin/sh
+
+################################################################################
+# This file is part of OpenELEC - http://www.openelec.tv
+# Copyright (C) 2009-2014 Stephan Raue (stephan@openelec.tv)
+#
+# OpenELEC is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 2 of the License, or
+# (at your option) any later version.
+#
+# OpenELEC 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. If not, see .
+################################################################################
+
+if [ -f /sys/class/rtc/rtc0/wakealarm ]; then
+ logger -t setwakeup.sh "### Setting system wakeup time ###"
+ echo 0 > /sys/class/rtc/rtc0/wakealarm
+ echo $1 > /sys/class/rtc/rtc0/wakealarm
+ logger -t setwakeup.sh "### $(cat /proc/driver/rtc) ###"
+fi
diff --git a/packages/mediacenter/xbmc-master/scripts/systemd-addon-wrapper b/packages/mediacenter/xbmc-master/scripts/systemd-addon-wrapper
new file mode 100755
index 0000000000..e963c61af9
--- /dev/null
+++ b/packages/mediacenter/xbmc-master/scripts/systemd-addon-wrapper
@@ -0,0 +1,34 @@
+#!/bin/sh
+################################################################################
+# This file is part of OpenELEC - http://www.openelec.tv
+# Copyright (C) 2009-2014 Stephan Raue (stephan@openelec.tv)
+#
+# OpenELEC is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 2 of the License, or
+# (at your option) any later version.
+#
+# OpenELEC 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. If not, see .
+################################################################################
+
+if [ ! -d /storage/.config/system.d ] ; then
+ mkdir -p /storage/.config/system.d
+fi
+
+if [ -f "/storage/.xbmc/addons/$1/system.d/$1.service" ] ; then
+ if [ $2 -eq 1 ] ; then
+ # disable = true: cleanup
+ systemctl stop "$1.service"
+ systemctl disable "/storage/.xbmc/addons/$1/system.d/$1.service"
+ else
+ # disable = false: setup
+ systemctl enable "/storage/.xbmc/addons/$1/system.d/$1.service"
+ systemctl start "$1.service"
+ fi
+fi
diff --git a/packages/mediacenter/xbmc-master/scripts/xbmc-config b/packages/mediacenter/xbmc-master/scripts/xbmc-config
new file mode 100755
index 0000000000..1ad05bf38e
--- /dev/null
+++ b/packages/mediacenter/xbmc-master/scripts/xbmc-config
@@ -0,0 +1,26 @@
+#!/bin/sh
+################################################################################
+# This file is part of OpenELEC - http://www.openelec.tv
+# Copyright (C) 2009-2014 Stephan Raue (stephan@openelec.tv)
+#
+# OpenELEC is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 2 of the License, or
+# (at your option) any later version.
+#
+# OpenELEC 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. If not, see .
+################################################################################
+
+if [ -e /run/lirc/lircd.irtrans ]; then
+ XBMC_ARGS="--lircdev /run/lirc/lircd.irtrans"
+else
+ XBMC_ARGS="--lircdev /run/lirc/lircd"
+fi
+
+echo "XBMC_ARGS=\"$XBMC_ARGS\"" > /run/openelec/xbmc.conf
diff --git a/packages/mediacenter/xbmc-master/scripts/xbmc-hacks b/packages/mediacenter/xbmc-master/scripts/xbmc-hacks
new file mode 100755
index 0000000000..2fabd47a19
--- /dev/null
+++ b/packages/mediacenter/xbmc-master/scripts/xbmc-hacks
@@ -0,0 +1,27 @@
+#!/bin/sh
+################################################################################
+# This file is part of OpenELEC - http://www.openelec.tv
+# Copyright (C) 2009-2014 Stephan Raue (stephan@openelec.tv)
+#
+# OpenELEC is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 2 of the License, or
+# (at your option) any later version.
+#
+# OpenELEC 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. If not, see .
+################################################################################
+
+# hack: make addon-bins executable
+ chmod +x /storage/.xbmc/addons/*/bin/*
+
+# hack: update RSSnews.xml in userdata
+ if [ -f /storage/.xbmc/userdata/RssFeeds.xml ]; then
+ sed -e "s,http://openelec.tv/news?format=feed&type=rss,http://feeds.openelec.tv/news,g" \
+ -i /storage/.xbmc/userdata/RssFeeds.xml
+ fi
diff --git a/packages/mediacenter/xbmc-master/scripts/xbmc-sources b/packages/mediacenter/xbmc-master/scripts/xbmc-sources
new file mode 100755
index 0000000000..12fa659a8f
--- /dev/null
+++ b/packages/mediacenter/xbmc-master/scripts/xbmc-sources
@@ -0,0 +1,85 @@
+#!/bin/sh
+################################################################################
+# This file is part of OpenELEC - http://www.openelec.tv
+# Copyright (C) 2009-2014 Stephan Raue (stephan@openelec.tv)
+#
+# OpenELEC is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 2 of the License, or
+# (at your option) any later version.
+#
+# OpenELEC 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. If not, see .
+################################################################################
+
+. /etc/profile
+
+#
+# setup XBMC sources
+#
+
+ if [ ! -f $HOME/.xbmc/userdata/sources.xml ]; then
+ if [ -f /usr/share/xbmc/config/sources.xml ]; then
+ # include project specific sources
+ cp /usr/share/xbmc/config/sources.xml $HOME/.xbmc/userdata
+ else
+ cat > $HOME/.xbmc/userdata/sources.xml << EOF
+
+
+
+
+
+ Music
+ $HOME/music/
+
+
+
+
+
+ Pictures
+ $HOME/pictures/
+
+
+
+EOF
+ fi
+ fi
+
+#
+# common setup guisettings
+#
+
+ if [ ! -f $HOME/.xbmc/userdata/guisettings.xml ] ; then
+ echo "" > $HOME/.xbmc/userdata/guisettings.xml
+
+ cat >> $HOME/.xbmc/userdata/guisettings.xml << EOF
+
+ $HOME/screenshots/
+
+EOF
+
+ #
+ # include project specific options
+ #
+
+ if [ -f /usr/share/xbmc/config/guisettings.xml ]; then
+ cat /usr/share/xbmc/config/guisettings.xml >> $HOME/.xbmc/userdata/guisettings.xml
+ fi
+
+ echo "" >> $HOME/.xbmc/userdata/guisettings.xml
+ fi
diff --git a/packages/mediacenter/xbmc-master/sleep.d.serial/10-addon-sleep.sh b/packages/mediacenter/xbmc-master/sleep.d.serial/10-addon-sleep.sh
new file mode 100755
index 0000000000..e44529791e
--- /dev/null
+++ b/packages/mediacenter/xbmc-master/sleep.d.serial/10-addon-sleep.sh
@@ -0,0 +1,30 @@
+#!/bin/sh
+
+################################################################################
+# This file is part of OpenELEC - http://www.openelec.tv
+# Copyright (C) 2009-2014 Stephan Raue (stephan@openelec.tv)
+#
+# OpenELEC is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 2 of the License, or
+# (at your option) any later version.
+#
+# OpenELEC 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. If not, see .
+################################################################################
+
+. /etc/profile
+
+# see https://wiki.archlinux.org/index.php/Power_Management#Hooks_in_.2Fusr.2Flib.2Fsystemd.2Fsystem-sleep
+
+for script in $HOME/.xbmc/addons/*/sleep.d/*.power; do
+ progress "running addon sleep script $script ($@)..."
+ sh $script $@
+done
+
+exit 0
\ No newline at end of file
diff --git a/packages/mediacenter/xbmc-master/sleep.d.serial/20-custon-sleep.sh b/packages/mediacenter/xbmc-master/sleep.d.serial/20-custon-sleep.sh
new file mode 100755
index 0000000000..3ad0e0c04e
--- /dev/null
+++ b/packages/mediacenter/xbmc-master/sleep.d.serial/20-custon-sleep.sh
@@ -0,0 +1,32 @@
+#!/bin/sh
+
+################################################################################
+# This file is part of OpenELEC - http://www.openelec.tv
+# Copyright (C) 2009-2013 Stephan Raue (stephan@openelec.tv)
+#
+# OpenELEC is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 2 of the License, or
+# (at your option) any later version.
+#
+# OpenELEC 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. If not, see .
+################################################################################
+
+. /etc/profile
+
+# see https://wiki.archlinux.org/index.php/Power_Management#Hooks_in_.2Fusr.2Flib.2Fsystemd.2Fsystem-sleep
+
+for script in $HOME/.config/sleep.d/*.power; do
+ if [ -f $script ]; then
+ progress "running custom sleep script $script ($@)..."
+ sh $script $@
+ fi
+done
+
+exit 0
\ No newline at end of file
diff --git a/packages/mediacenter/xbmc-master/sleep.d/openelec-sleep.sh b/packages/mediacenter/xbmc-master/sleep.d/openelec-sleep.sh
new file mode 100755
index 0000000000..6b314cd7bd
--- /dev/null
+++ b/packages/mediacenter/xbmc-master/sleep.d/openelec-sleep.sh
@@ -0,0 +1,46 @@
+#!/bin/sh
+
+################################################################################
+# This file is part of OpenELEC - http://www.openelec.tv
+# Copyright (C) 2009-2014 Stephan Raue (stephan@openelec.tv)
+#
+# OpenELEC is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 2 of the License, or
+# (at your option) any later version.
+#
+# OpenELEC 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. If not, see .
+################################################################################
+
+. /etc/profile
+
+run_scripts()
+{
+ list_scripts $1
+ for script in $SCRIPTS ; do
+ progress "running sleep script $script ($1)..."
+ sh /usr/lib/systemd/system-sleep.serial/$script $1
+ done
+}
+
+list_scripts()
+{
+ case $1 in
+ pre)
+ SCRIPTS=$(ls /usr/lib/systemd/system-sleep.serial/ | sort)
+ ;;
+ post)
+ SCRIPTS=$(ls /usr/lib/systemd/system-sleep.serial/ | sort -r)
+ ;;
+ esac
+}
+
+run_scripts $1
+
+exit 0
diff --git a/packages/mediacenter/xbmc-master/splash/splash.png b/packages/mediacenter/xbmc-master/splash/splash.png
new file mode 100644
index 0000000000..6b2897b0a1
Binary files /dev/null and b/packages/mediacenter/xbmc-master/splash/splash.png differ
diff --git a/packages/mediacenter/xbmc-master/splash/splash1.png b/packages/mediacenter/xbmc-master/splash/splash1.png
new file mode 100644
index 0000000000..ac0aa0052f
Binary files /dev/null and b/packages/mediacenter/xbmc-master/splash/splash1.png differ
diff --git a/packages/mediacenter/xbmc-master/system.d/xbmc-autostart.service b/packages/mediacenter/xbmc-master/system.d/xbmc-autostart.service
new file mode 100644
index 0000000000..2e98307e0f
--- /dev/null
+++ b/packages/mediacenter/xbmc-master/system.d/xbmc-autostart.service
@@ -0,0 +1,13 @@
+[Unit]
+Description=XBMC user autostart script
+Before=xbmc.service
+After=graphical.target
+
+[Service]
+Type=oneshot
+Environment=HOME=/storage
+ExecStart=-/bin/sh -c ". /etc/profile; exec /bin/sh /storage/.config/autostart.sh"
+RemainAfterExit=yes
+
+[Install]
+WantedBy=xbmc.service
diff --git a/packages/mediacenter/xbmc-master/system.d/xbmc-cleanlogs.service b/packages/mediacenter/xbmc-master/system.d/xbmc-cleanlogs.service
new file mode 100644
index 0000000000..9faab0eec2
--- /dev/null
+++ b/packages/mediacenter/xbmc-master/system.d/xbmc-cleanlogs.service
@@ -0,0 +1,13 @@
+[Unit]
+Description=XBMC clean debug logs
+ConditionKernelCommandLine=!debugging
+ConditionPathExists=!/storage/.cache/debug.openelec
+Before=xbmc.service
+
+[Service]
+Type=oneshot
+ExecStart=-/bin/sh -c 'rm -rf /storage/.xbmc/userdata/addon_data/*/*.log /storage/.xbmc/userdata/addon_data/*/log/*'
+RemainAfterExit=yes
+
+[Install]
+WantedBy=xbmc.service
diff --git a/packages/mediacenter/xbmc-master/system.d/xbmc-config.service b/packages/mediacenter/xbmc-master/system.d/xbmc-config.service
new file mode 100644
index 0000000000..cb0f33faf8
--- /dev/null
+++ b/packages/mediacenter/xbmc-master/system.d/xbmc-config.service
@@ -0,0 +1,12 @@
+[Unit]
+Description=XBMC configfile writer
+Before=xbmc.service
+
+[Service]
+Type=oneshot
+Environment=HOME=/storage
+ExecStart=/usr/lib/xbmc/xbmc-config
+RemainAfterExit=yes
+
+[Install]
+WantedBy=xbmc.service
diff --git a/packages/mediacenter/xbmc-master/system.d/xbmc-hacks.service b/packages/mediacenter/xbmc-master/system.d/xbmc-hacks.service
new file mode 100644
index 0000000000..efb48a6ac3
--- /dev/null
+++ b/packages/mediacenter/xbmc-master/system.d/xbmc-hacks.service
@@ -0,0 +1,12 @@
+[Unit]
+Description=XBMC hacks
+Before=xbmc.service
+
+[Service]
+Type=oneshot
+Environment=HOME=/storage
+ExecStart=/usr/lib/xbmc/xbmc-hacks
+RemainAfterExit=yes
+
+[Install]
+WantedBy=xbmc.service
diff --git a/packages/mediacenter/xbmc-master/system.d/xbmc-halt.service b/packages/mediacenter/xbmc-master/system.d/xbmc-halt.service
new file mode 100644
index 0000000000..16ab30c50e
--- /dev/null
+++ b/packages/mediacenter/xbmc-master/system.d/xbmc-halt.service
@@ -0,0 +1,14 @@
+[Unit]
+Description=XBMC halt script
+After=xbmc.service
+Before=systemd-halt.service
+DefaultDependencies=no
+
+[Service]
+Type=oneshot
+Environment=HOME=/storage
+ExecStart=-/bin/sh /storage/.config/shutdown.sh halt
+RemainAfterExit=yes
+
+[Install]
+WantedBy=halt.target
diff --git a/packages/mediacenter/xbmc-master/system.d/xbmc-lirc-suspend.service b/packages/mediacenter/xbmc-master/system.d/xbmc-lirc-suspend.service
new file mode 100644
index 0000000000..f229b6b193
--- /dev/null
+++ b/packages/mediacenter/xbmc-master/system.d/xbmc-lirc-suspend.service
@@ -0,0 +1,13 @@
+[Unit]
+Description=LIRC sleep hook
+Before=sleep.target
+StopWhenUnneeded=yes
+
+[Service]
+Type=oneshot
+RemainAfterExit=yes
+ExecStart=-/usr/bin/xbmc-send --host=127.0.0.1 -a "LIRC.Stop"
+ExecStop=-/usr/bin/xbmc-send --host=127.0.0.1 -a "LIRC.Start"
+
+[Install]
+WantedBy=sleep.target
diff --git a/packages/mediacenter/xbmc-master/system.d/xbmc-poweroff.service b/packages/mediacenter/xbmc-master/system.d/xbmc-poweroff.service
new file mode 100644
index 0000000000..8a607da56a
--- /dev/null
+++ b/packages/mediacenter/xbmc-master/system.d/xbmc-poweroff.service
@@ -0,0 +1,14 @@
+[Unit]
+Description=XBMC poweroff script
+After=xbmc.service
+Before=systemd-poweroff.service
+DefaultDependencies=no
+
+[Service]
+Type=oneshot
+Environment=HOME=/storage
+ExecStart=-/bin/sh /storage/.config/shutdown.sh poweroff
+RemainAfterExit=yes
+
+[Install]
+WantedBy=poweroff.target
diff --git a/packages/mediacenter/xbmc-master/system.d/xbmc-reboot.service b/packages/mediacenter/xbmc-master/system.d/xbmc-reboot.service
new file mode 100644
index 0000000000..7ee1d5dabe
--- /dev/null
+++ b/packages/mediacenter/xbmc-master/system.d/xbmc-reboot.service
@@ -0,0 +1,14 @@
+[Unit]
+Description=XBMC reboot script
+After=xbmc.service
+Before=systemd-reboot.service
+DefaultDependencies=no
+
+[Service]
+Type=oneshot
+Environment=HOME=/storage
+ExecStart=-/bin/sh /storage/.config/shutdown.sh reboot
+RemainAfterExit=yes
+
+[Install]
+WantedBy=reboot.target
diff --git a/packages/mediacenter/xbmc-master/system.d/xbmc-sources.service b/packages/mediacenter/xbmc-master/system.d/xbmc-sources.service
new file mode 100644
index 0000000000..48e6dfb8a7
--- /dev/null
+++ b/packages/mediacenter/xbmc-master/system.d/xbmc-sources.service
@@ -0,0 +1,12 @@
+[Unit]
+Description=XBMC sources Setup
+Before=xbmc.service
+
+[Service]
+Type=oneshot
+Environment=HOME=/storage
+ExecStart=/usr/lib/xbmc/xbmc-sources
+RemainAfterExit=yes
+
+[Install]
+WantedBy=xbmc.service
diff --git a/packages/mediacenter/xbmc-master/system.d/xbmc-waitonnetwork.service b/packages/mediacenter/xbmc-master/system.d/xbmc-waitonnetwork.service
new file mode 100644
index 0000000000..dc27a793ee
--- /dev/null
+++ b/packages/mediacenter/xbmc-master/system.d/xbmc-waitonnetwork.service
@@ -0,0 +1,17 @@
+[Unit]
+Description=Wait on network
+After=connman.service
+Before=xorg.service fbset.service
+
+ConditionPathExists=/storage/.cache/openelec/network_wait
+
+[Service]
+Type=oneshot
+EnvironmentFile=/storage/.cache/openelec/network_wait
+ExecStartPre=/bin/sh -c 'echo "waiting on Network to come online ... (max. $WAIT_NETWORK_TIME sec.)"
+ExecStart=/usr/bin/cm-online ${WAIT_NETWORK_TIME}
+StandardOutput=tty
+RemainAfterExit=yes
+
+[Install]
+WantedBy=xbmc.service
diff --git a/packages/mediacenter/xbmc-master/system.d/xbmc.service b/packages/mediacenter/xbmc-master/system.d/xbmc.service
new file mode 100644
index 0000000000..545d31c62e
--- /dev/null
+++ b/packages/mediacenter/xbmc-master/system.d/xbmc.service
@@ -0,0 +1,21 @@
+[Unit]
+Description=XBMC Media Center
+After=graphical.target
+Requires=graphical.target
+
+[Service]
+Environment=DISPLAY=:0.0
+Environment=SDL_MOUSE_RELATIVE=0
+Environment=HOME=/storage
+EnvironmentFile=-/run/openelec/xbmc.conf
+EnvironmentFile=-/run/openelec/debug/xbmc.conf
+ExecStart=/bin/sh -c ". /etc/profile; exec /usr/lib/xbmc/xbmc.bin --standalone -fs $XBMC_ARGS $XBMC_DEBUG"
+# keep KillMode=process unless there is no good reason to switch to cgroup
+KillMode=process
+TimeoutStopSec=5
+Restart=always
+RestartSec=2
+StartLimitInterval=0
+
+[Install]
+WantedBy=xbmc.target
diff --git a/packages/mediacenter/xbmc-master/system.d/xbmc.target b/packages/mediacenter/xbmc-master/system.d/xbmc.target
new file mode 100644
index 0000000000..02e0fc0c82
--- /dev/null
+++ b/packages/mediacenter/xbmc-master/system.d/xbmc.target
@@ -0,0 +1,9 @@
+[Unit]
+Description=XBMC Mediacenter Interface
+Requires=multi-user.target graphical.target
+After=graphical.target
+Conflicts=rescue.target
+AllowIsolate=yes
+
+[Install]
+Alias=default.target
diff --git a/packages/mediacenter/xbmc-master/tmpfiles.d/xbmc-userdirs.conf b/packages/mediacenter/xbmc-master/tmpfiles.d/xbmc-userdirs.conf
new file mode 100644
index 0000000000..62552cdc49
--- /dev/null
+++ b/packages/mediacenter/xbmc-master/tmpfiles.d/xbmc-userdirs.conf
@@ -0,0 +1,24 @@
+################################################################################
+# This file is part of OpenELEC - http://www.openelec.tv
+# Copyright (C) 2009-2014 Stephan Raue (stephan@openelec.tv)
+#
+# OpenELEC is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 2 of the License, or
+# (at your option) any later version.
+#
+# OpenELEC 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. If not, see .
+################################################################################
+
+d /storage/.xbmc/userdata 0755 root root - -
+d /storage/music 0755 root root - -
+d /storage/pictures 0755 root root - -
+d /storage/tvshows 0755 root root - -
+d /storage/videos 0755 root root - -
+d /storage/screenshots 0755 root root - -
diff --git a/packages/mediacenter/xbmc-master/tmpfiles.d/xbmc.conf b/packages/mediacenter/xbmc-master/tmpfiles.d/xbmc.conf
new file mode 100644
index 0000000000..24bcf7a5b7
--- /dev/null
+++ b/packages/mediacenter/xbmc-master/tmpfiles.d/xbmc.conf
@@ -0,0 +1,19 @@
+################################################################################
+# This file is part of OpenELEC - http://www.openelec.tv
+# Copyright (C) 2009-2014 Stephan Raue (stephan@openelec.tv)
+#
+# OpenELEC is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 2 of the License, or
+# (at your option) any later version.
+#
+# OpenELEC 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. If not, see .
+################################################################################
+
+d /run/xbmc 0755 root root - -
diff --git a/projects/Cuboxi/patches/xbmc-master/xbmc-001-imx6_support.patch b/projects/Cuboxi/patches/xbmc-master/xbmc-001-imx6_support.patch
new file mode 100644
index 0000000000..0bec4d85f4
--- /dev/null
+++ b/projects/Cuboxi/patches/xbmc-master/xbmc-001-imx6_support.patch
@@ -0,0 +1,3548 @@
+diff -Naur xbmc-13b4/configure.in xbmc-imx6-13b4/configure.in
+--- xbmc-13b4/configure.in 2014-04-24 11:49:30.784354037 +0200
++++ xbmc-imx6-13b4/configure.in 2014-04-24 11:50:13.695216693 +0200
+@@ -558,7 +558,7 @@
+
+ AC_ARG_ENABLE([codec],
+ [AS_HELP_STRING([--enable-codec],
+- [enable additional codecs from a list of comma separated names, (default is none, choices are amcodec, libstagefright)])],
++ [enable additional codecs from a list of comma separated names, (default is none, choices are amcodec, libstagefright and imxvpu)])],
+ [add_codecs=$enableval],
+ [add_codecs=no])
+
+@@ -1034,6 +1034,15 @@
+ AC_MSG_RESULT($wayland_disabled)
+ fi
+
++# i.MX6
++AC_MSG_CHECKING([for i.MX framebuffer support])
++AC_CHECK_HEADER([linux/mxcfb.h], have_imxfb=yes,have_imxfb=no)
++AC_MSG_RESULT($have_imxfb)
++if test "x$have_imxfb" = "xyes"; then
++ AC_DEFINE([HAS_IMXFB], [1], [Whether i.MX framebuffer support is enabled.])
++ AC_SUBST([USE_IMXFB], 1)
++fi
++
+ # Checks for platforms libraries.
+ if test "$use_gles" = "yes"; then
+ use_gl="no"
+@@ -1991,6 +2000,17 @@
+ *libstagefright*)
+ XB_ADD_CODEC([LIBSTAGEFRIGHT], [libstagefright], [$codecs])
+ ;;
++ *imxvpu*)
++ AC_CHECK_HEADER([imx-mm/vpu/vpu_wrapper.h],, AC_MSG_ERROR($missing_headers))
++ AC_CHECK_LIB([vpu], main, LIBS="$LIBS -lfslvpuwrap -lvpu", AC_MSG_ERROR($missing_library))
++ XB_ADD_CODEC([IMXVPU], [imxvpu], [$codecs])
++ CXXFLAGS="$CXXFLAGS -Wno-psabi -DLINUX "
++ CFLAGS="$CFLAGS -DLINUX"
++ if test "$use_x11" = "no"; then
++ CXXFLAGS="$CXXFLAGS -DEGL_API_FB"
++ CFLAGS="$CFLAGS -DEGL_API_FB"
++ fi
++ ;;
+ *)
+ esac
+ done
+diff -Naur xbmc-13b4/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEResample.cpp xbmc-imx6-13b4/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEResample.cpp
+--- xbmc-13b4/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEResample.cpp 2014-04-24 11:49:41.288075640 +0200
++++ xbmc-imx6-13b4/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEResample.cpp 2014-04-24 11:50:14.007208425 +0200
+@@ -279,14 +279,16 @@
+ if (format == AE_FMT_U8) return AV_SAMPLE_FMT_U8;
+ else if (format == AE_FMT_S16NE) return AV_SAMPLE_FMT_S16;
+ else if (format == AE_FMT_S32NE) return AV_SAMPLE_FMT_S32;
+- else if (format == AE_FMT_S24NE4) return AV_SAMPLE_FMT_S32;
++ else if (format == AE_FMT_S24NE4H) return AV_SAMPLE_FMT_S32;
++ else if (format == AE_FMT_S24NE4L) return AV_SAMPLE_FMT_S32;
+ else if (format == AE_FMT_FLOAT) return AV_SAMPLE_FMT_FLT;
+ else if (format == AE_FMT_DOUBLE) return AV_SAMPLE_FMT_DBL;
+
+ else if (format == AE_FMT_U8P) return AV_SAMPLE_FMT_U8P;
+ else if (format == AE_FMT_S16NEP) return AV_SAMPLE_FMT_S16P;
+ else if (format == AE_FMT_S32NEP) return AV_SAMPLE_FMT_S32P;
+- else if (format == AE_FMT_S24NE4P) return AV_SAMPLE_FMT_S32P;
++ else if (format == AE_FMT_S24NE4HP) return AV_SAMPLE_FMT_S32P;
++ else if (format == AE_FMT_S24NE4LP) return AV_SAMPLE_FMT_S32P;
+ else if (format == AE_FMT_FLOATP) return AV_SAMPLE_FMT_FLTP;
+ else if (format == AE_FMT_DOUBLEP) return AV_SAMPLE_FMT_DBLP;
+
+@@ -298,14 +300,14 @@
+ if (format == AV_SAMPLE_FMT_U8) return AE_FMT_U8;
+ else if (format == AV_SAMPLE_FMT_S16) return AE_FMT_S16NE;
+ else if (format == AV_SAMPLE_FMT_S32 && bits == 32) return AE_FMT_S32NE;
+- else if (format == AV_SAMPLE_FMT_S32 && bits == 24) return AE_FMT_S24NE4;
++ else if (format == AV_SAMPLE_FMT_S32 && bits == 24) return AE_FMT_S24NE4H;
+ else if (format == AV_SAMPLE_FMT_FLT) return AE_FMT_FLOAT;
+ else if (format == AV_SAMPLE_FMT_DBL) return AE_FMT_DOUBLE;
+
+ else if (format == AV_SAMPLE_FMT_U8P) return AE_FMT_U8P;
+ else if (format == AV_SAMPLE_FMT_S16P) return AE_FMT_S16NEP;
+ else if (format == AV_SAMPLE_FMT_S32P && bits == 32) return AE_FMT_S32NEP;
+- else if (format == AV_SAMPLE_FMT_S32P && bits == 24) return AE_FMT_S24NE4P;
++ else if (format == AV_SAMPLE_FMT_S32P && bits == 24) return AE_FMT_S24NE4HP;
+ else if (format == AV_SAMPLE_FMT_FLTP) return AE_FMT_FLOATP;
+ else if (format == AV_SAMPLE_FMT_DBLP) return AE_FMT_DOUBLEP;
+
+diff -Naur xbmc-13b4/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAESink.cpp xbmc-imx6-13b4/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAESink.cpp
+--- xbmc-13b4/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAESink.cpp 2014-04-24 11:49:41.280075852 +0200
++++ xbmc-imx6-13b4/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAESink.cpp 2014-04-24 11:50:14.007208425 +0200
+@@ -796,6 +796,12 @@
+ }
+ }
+
++static inline void RShift8_32_buf(uint32_t *src, uint32_t *dst, uint32_t count)
++{
++ while (count--)
++ *dst++ = *src++ >> 8;
++}
++
+ unsigned int CActiveAESink::OutputSamples(CSampleBuffer* samples)
+ {
+ uint8_t *buffer = samples->pkt->data[0];
+@@ -816,14 +822,22 @@
+ case NEED_BYTESWAP:
+ Endian_Swap16_buf((uint16_t *)buffer, (uint16_t *)buffer, frames * samples->pkt->config.channels);
+ break;
++ case NEED_RSHIFT8:
++ RShift8_32_buf((uint32_t *)buffer, (uint32_t *)buffer, frames * samples->pkt->config.channels);
++ break;
+ case CHECK_CONVERT:
+ ConvertInit(samples);
+ if (m_convertState == NEED_CONVERT)
+ buffer = Convert(samples);
+ else if (m_convertState == NEED_BYTESWAP)
+ Endian_Swap16_buf((uint16_t *)buffer, (uint16_t *)buffer, frames * samples->pkt->config.channels);
++ else if (m_convertState == NEED_RSHIFT8)
++ RShift8_32_buf((uint32_t *)buffer, (uint32_t *)buffer, frames * samples->pkt->config.channels);
++ else if (m_convertState == SKIP_OUTPUT)
++ frames = 0;
+ break;
+- default:
++ case SKIP_OUTPUT:
++ frames = 0;
+ break;
+ }
+
+@@ -862,15 +876,38 @@
+
+ void CActiveAESink::ConvertInit(CSampleBuffer* samples)
+ {
+- if (CActiveAEResample::GetAESampleFormat(samples->pkt->config.fmt, samples->pkt->config.bits_per_sample) != m_sinkFormat.m_dataFormat)
++ AEDataFormat srcFmt = CActiveAEResample::GetAESampleFormat(samples->pkt->config.fmt, samples->pkt->config.bits_per_sample);
++
++ if (srcFmt != m_sinkFormat.m_dataFormat)
+ {
+- m_convertFn = CAEConvert::FrFloat(m_sinkFormat.m_dataFormat);
+- if (m_convertBuffer)
+- _aligned_free(m_convertBuffer);
+- m_convertBufferSampleSize = samples->pkt->max_nb_samples;
+- m_convertBuffer = (uint8_t*)_aligned_malloc(samples->pkt->max_nb_samples * m_sinkFormat.m_channelLayout.Count() * m_sinkFormat.m_frameSize, 16);
+- memset(m_convertBuffer, 0, samples->pkt->max_nb_samples * m_sinkFormat.m_channelLayout.Count() * m_sinkFormat.m_frameSize);
+- m_convertState = NEED_CONVERT;
++ switch (srcFmt)
++ {
++ case AE_FMT_FLOAT:
++ case AE_FMT_FLOATP:
++ m_convertFn = CAEConvert::FrFloat(m_sinkFormat.m_dataFormat);
++ if (m_convertBuffer)
++ _aligned_free(m_convertBuffer);
++ m_convertBufferSampleSize = samples->pkt->max_nb_samples;
++ m_convertBuffer = (uint8_t*)_aligned_malloc(samples->pkt->max_nb_samples * m_sinkFormat.m_channelLayout.Count() * m_sinkFormat.m_frameSize, 16);
++ memset(m_convertBuffer, 0, samples->pkt->max_nb_samples * m_sinkFormat.m_channelLayout.Count() * m_sinkFormat.m_frameSize);
++ m_convertState = NEED_CONVERT;
++ break;
++ case AE_FMT_S24NE4H:
++ m_convertState = (m_sinkFormat.m_dataFormat == AE_FMT_S24NE4L) ? NEED_RSHIFT8 : SKIP_OUTPUT;
++ break;
++ case AE_FMT_S24NE4HP:
++ m_convertState = (m_sinkFormat.m_dataFormat == AE_FMT_S24NE4LP) ? NEED_RSHIFT8 : SKIP_OUTPUT;
++ break;
++ default:
++ m_convertState = SKIP_OUTPUT;
++ break;
++ }
++
++ if (m_convertState == SKIP_OUTPUT)
++ {
++ CLog::Log(LOGERROR, "CActiveAESink::ConvertInit - cannot convert from %s to %s",
++ CAEUtil::DataFormatToStr(srcFmt), CAEUtil::DataFormatToStr(m_sinkFormat.m_dataFormat));
++ }
+ }
+ else if (AE_IS_RAW(m_requestedFormat.m_dataFormat) && CAEUtil::S16NeedsByteSwap(AE_FMT_S16NE, m_sinkFormat.m_dataFormat))
+ {
+diff -Naur xbmc-13b4/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAESink.h xbmc-imx6-13b4/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAESink.h
+--- xbmc-13b4/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAESink.h 2014-04-24 11:49:41.288075640 +0200
++++ xbmc-imx6-13b4/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAESink.h 2014-04-24 11:50:14.007208425 +0200
+@@ -139,6 +139,8 @@
+ NEED_CONVERT,
+ NEED_BYTESWAP,
+ SKIP_CONVERT,
++ NEED_RSHIFT8,
++ SKIP_OUTPUT
+ } m_convertState;
+
+ std::string m_deviceFriendlyName;
+diff -Naur xbmc-13b4/xbmc/cores/AudioEngine/Sinks/AESinkALSA.cpp xbmc-imx6-13b4/xbmc/cores/AudioEngine/Sinks/AESinkALSA.cpp
+--- xbmc-13b4/xbmc/cores/AudioEngine/Sinks/AESinkALSA.cpp 2014-04-24 11:49:41.256076488 +0200
++++ xbmc-imx6-13b4/xbmc/cores/AudioEngine/Sinks/AESinkALSA.cpp 2014-04-24 11:50:14.007208425 +0200
+@@ -268,7 +268,7 @@
+ case AE_FMT_S16NE : return SND_PCM_FORMAT_S16;
+ case AE_FMT_S16LE : return SND_PCM_FORMAT_S16_LE;
+ case AE_FMT_S16BE : return SND_PCM_FORMAT_S16_BE;
+- case AE_FMT_S24NE4: return SND_PCM_FORMAT_S24;
++ case AE_FMT_S24NE4L: return SND_PCM_FORMAT_S24;
+ #ifdef __BIG_ENDIAN__
+ case AE_FMT_S24NE3: return SND_PCM_FORMAT_S24_3BE;
+ #else
+@@ -343,7 +343,7 @@
+ {
+ /* if we opened in 32bit and only have 24bits, pack into 24 */
+ if (fmtBits == 32 && bits == 24)
+- i = AE_FMT_S24NE4;
++ i = AE_FMT_S24NE4L;
+ else
+ continue;
+ }
+@@ -720,7 +720,10 @@
+ * will automatically add "@" instead to enable surroundXX mangling.
+ * We don't want to do that if "default" can handle multichannel
+ * itself (e.g. in case of a pulseaudio server). */
+- EnumerateDevice(list, "default", "", config);
++
++ /* For Wandboard, we do not enurate default device as it will be grabbed
++ * as one of the sysdefault devices... */
++
+
+ void **hints;
+
+@@ -771,8 +774,8 @@
+ * found by the enumeration process. Skip them as well ("hw", "dmix",
+ * "plughw", "dsnoop"). */
+
++ /* For wandboard all devices are prefixed by sysdefault so do not ignore them */
+ else if (baseName != "default"
+- && baseName != "sysdefault"
+ && baseName != "surround40"
+ && baseName != "surround41"
+ && baseName != "surround50"
+@@ -881,6 +884,22 @@
+
+ AEDeviceType CAESinkALSA::AEDeviceTypeFromName(const std::string &name)
+ {
++ std::size_t found;
++
++ /* Hack : Check for specific wandboard sound device names */
++ found = name.find("imxspdif");
++ if (found!=std::string::npos)
++ return AE_DEVTYPE_IEC958;
++
++ found = name.find("imxhdmisoc");
++ if (found!=std::string::npos)
++ return AE_DEVTYPE_HDMI;
++
++ found = name.find("sgtl5000audio");
++ if (found!=std::string::npos)
++ return AE_DEVTYPE_PCM;
++
++
+ if (name.substr(0, 4) == "hdmi")
+ return AE_DEVTYPE_HDMI;
+ else if (name.substr(0, 6) == "iec958" || name.substr(0, 5) == "spdif")
+diff -Naur xbmc-13b4/xbmc/cores/AudioEngine/Sinks/AESinkPULSE.cpp xbmc-imx6-13b4/xbmc/cores/AudioEngine/Sinks/AESinkPULSE.cpp
+--- xbmc-13b4/xbmc/cores/AudioEngine/Sinks/AESinkPULSE.cpp 2014-04-24 11:49:41.268076170 +0200
++++ xbmc-imx6-13b4/xbmc/cores/AudioEngine/Sinks/AESinkPULSE.cpp 2014-04-24 11:50:14.007208425 +0200
+@@ -80,9 +80,9 @@
+ case AE_FMT_S24LE3: return PA_SAMPLE_S24LE;
+ case AE_FMT_S24BE3: return PA_SAMPLE_S24BE;
+ case AE_FMT_S24NE3: return PA_SAMPLE_S24NE;
+- case AE_FMT_S24LE4: return PA_SAMPLE_S24_32LE;
+- case AE_FMT_S24BE4: return PA_SAMPLE_S24_32BE;
+- case AE_FMT_S24NE4: return PA_SAMPLE_S24_32NE;
++ case AE_FMT_S24LE4L: return PA_SAMPLE_S24_32LE;
++ case AE_FMT_S24BE4L: return PA_SAMPLE_S24_32BE;
++ case AE_FMT_S24NE4L: return PA_SAMPLE_S24_32NE;
+ case AE_FMT_S32BE : return PA_SAMPLE_S32BE;
+ case AE_FMT_S32LE : return PA_SAMPLE_S32LE;
+ case AE_FMT_S32NE : return PA_SAMPLE_S32NE;
+@@ -119,9 +119,9 @@
+ AE_FMT_S24LE3,
+ AE_FMT_S24BE3,
+ AE_FMT_S24NE3,
+- AE_FMT_S24LE4,
+- AE_FMT_S24BE4,
+- AE_FMT_S24NE4,
++ AE_FMT_S24LE4L,
++ AE_FMT_S24BE4L,
++ AE_FMT_S24NE4L,
+ AE_FMT_S32BE,
+ AE_FMT_S32LE,
+ AE_FMT_S32NE,
+diff -Naur xbmc-13b4/xbmc/cores/AudioEngine/Sinks/AESinkWASAPI.cpp xbmc-imx6-13b4/xbmc/cores/AudioEngine/Sinks/AESinkWASAPI.cpp
+--- xbmc-13b4/xbmc/cores/AudioEngine/Sinks/AESinkWASAPI.cpp 2014-04-24 11:49:41.276075958 +0200
++++ xbmc-imx6-13b4/xbmc/cores/AudioEngine/Sinks/AESinkWASAPI.cpp 2014-04-24 11:50:14.007208425 +0200
+@@ -111,7 +111,7 @@
+ /* Sample formats go from float -> 32 bit int -> 24 bit int (packed in 32) -> -> 24 bit int -> 16 bit int */
+ static const sampleFormat testFormats[] = { {KSDATAFORMAT_SUBTYPE_IEEE_FLOAT, 32, 32, AE_FMT_FLOAT},
+ {KSDATAFORMAT_SUBTYPE_PCM, 32, 32, AE_FMT_S32NE},
+- {KSDATAFORMAT_SUBTYPE_PCM, 32, 24, AE_FMT_S24NE4},
++ {KSDATAFORMAT_SUBTYPE_PCM, 32, 24, AE_FMT_S24NE4H},
+ {KSDATAFORMAT_SUBTYPE_PCM, 24, 24, AE_FMT_S24NE3},
+ {KSDATAFORMAT_SUBTYPE_PCM, 16, 16, AE_FMT_S16NE} };
+
+@@ -758,7 +758,7 @@
+ wfxex.Format.wBitsPerSample = CAEUtil::DataFormatToBits((AEDataFormat) p);
+ wfxex.Format.nBlockAlign = wfxex.Format.nChannels * (wfxex.Format.wBitsPerSample >> 3);
+ wfxex.Format.nAvgBytesPerSec = wfxex.Format.nSamplesPerSec * wfxex.Format.nBlockAlign;
+- if (p <= AE_FMT_S24NE4 && p >= AE_FMT_S24BE4)
++ if (p <= AE_FMT_S24NE4H && p >= AE_FMT_S24BE4H)
+ {
+ wfxex.Samples.wValidBitsPerSample = 24;
+ }
+@@ -1149,7 +1149,7 @@
+ else if (wfxex.Samples.wValidBitsPerSample == 32)
+ format.m_dataFormat = AE_FMT_S32NE;
+ else
+- format.m_dataFormat = AE_FMT_S24NE4;
++ format.m_dataFormat = AE_FMT_S24NE4H;
+ }
+ else if (wfxex.Format.wBitsPerSample == 24)
+ format.m_dataFormat = AE_FMT_S24NE3;
+diff -Naur xbmc-13b4/xbmc/cores/AudioEngine/Utils/AEAudioFormat.h xbmc-imx6-13b4/xbmc/cores/AudioEngine/Utils/AEAudioFormat.h
+--- xbmc-13b4/xbmc/cores/AudioEngine/Utils/AEAudioFormat.h 2014-04-24 11:49:41.296075428 +0200
++++ xbmc-imx6-13b4/xbmc/cores/AudioEngine/Utils/AEAudioFormat.h 2014-04-24 11:50:14.011208319 +0200
+@@ -41,9 +41,13 @@
+ AE_FMT_S32LE,
+ AE_FMT_S32NE,
+
+- AE_FMT_S24BE4,
+- AE_FMT_S24LE4,
+- AE_FMT_S24NE4, /* S24 in 4 bytes */
++ AE_FMT_S24BE4H,
++ AE_FMT_S24LE4H,
++ AE_FMT_S24NE4H, /* S24 in upper 4 bytes */
++
++ AE_FMT_S24BE4L,
++ AE_FMT_S24LE4L,
++ AE_FMT_S24NE4L, /* S24 in lower 4 bytes */
+
+ AE_FMT_S24BE3,
+ AE_FMT_S24LE3,
+@@ -65,7 +69,8 @@
+ AE_FMT_U8P,
+ AE_FMT_S16NEP,
+ AE_FMT_S32NEP,
+- AE_FMT_S24NE4P,
++ AE_FMT_S24NE4HP,
++ AE_FMT_S24NE4LP,
+ AE_FMT_S24NE3P,
+ AE_FMT_DOUBLEP,
+ AE_FMT_FLOATP,
+diff -Naur xbmc-13b4/xbmc/cores/AudioEngine/Utils/AEConvert.cpp xbmc-imx6-13b4/xbmc/cores/AudioEngine/Utils/AEConvert.cpp
+--- xbmc-13b4/xbmc/cores/AudioEngine/Utils/AEConvert.cpp 2014-04-24 11:49:41.292075533 +0200
++++ xbmc-imx6-13b4/xbmc/cores/AudioEngine/Utils/AEConvert.cpp 2014-04-24 11:50:14.007208425 +0200
+@@ -69,18 +69,22 @@
+ #ifdef __BIG_ENDIAN__
+ case AE_FMT_S16NE : return &S16BE_Float;
+ case AE_FMT_S32NE : return &S32BE_Float;
+- case AE_FMT_S24NE4: return &S24BE4_Float;
++ case AE_FMT_S24NE4H: return &S24BE4H_Float;
++ case AE_FMT_S24NE4L: return &S24BE4L_Float;
+ case AE_FMT_S24NE3: return &S24BE3_Float;
+ #else
+ case AE_FMT_S16NE : return &S16LE_Float;
+ case AE_FMT_S32NE : return &S32LE_Float;
+- case AE_FMT_S24NE4: return &S24LE4_Float;
++ case AE_FMT_S24NE4H: return &S24LE4H_Float;
++ case AE_FMT_S24NE4L: return &S24LE4L_Float;
+ case AE_FMT_S24NE3: return &S24LE3_Float;
+ #endif
+ case AE_FMT_S16LE : return &S16LE_Float;
+ case AE_FMT_S16BE : return &S16BE_Float;
+- case AE_FMT_S24LE4: return &S24LE4_Float;
+- case AE_FMT_S24BE4: return &S24BE4_Float;
++ case AE_FMT_S24LE4H: return &S24LE4H_Float;
++ case AE_FMT_S24LE4L: return &S24LE4L_Float;
++ case AE_FMT_S24BE4H: return &S24BE4H_Float;
++ case AE_FMT_S24BE4L: return &S24BE4L_Float;
+ case AE_FMT_S24LE3: return &S24LE3_Float;
+ case AE_FMT_S24BE3: return &S24BE3_Float;
+ #if defined(__ARM_NEON__)
+@@ -112,7 +116,8 @@
+ #endif
+ case AE_FMT_S16LE : return &Float_S16LE;
+ case AE_FMT_S16BE : return &Float_S16BE;
+- case AE_FMT_S24NE4: return &Float_S24NE4;
++ case AE_FMT_S24NE4H: return &Float_S24NE4H;
++ case AE_FMT_S24NE4L: return &Float_S24NE4L;
+ case AE_FMT_S24NE3: return &Float_S24NE3;
+ #if defined(__ARM_NEON__)
+ case AE_FMT_S32LE : return &Float_S32LE_Neon;
+@@ -210,7 +215,17 @@
+ return samples;
+ }
+
+-unsigned int CAEConvert::S24LE4_Float(uint8_t *data, const unsigned int samples, float *dest)
++unsigned int CAEConvert::S24LE4H_Float(uint8_t *data, const unsigned int samples, float *dest)
++{
++ for (unsigned int i = 0; i < samples; ++i, data += 4)
++ {
++ int s = (data[3] << 24) | (data[2] << 16) | (data[1] << 8);
++ *dest++ = (float)s * INT32_SCALE;
++ }
++ return samples;
++}
++
++unsigned int CAEConvert::S24LE4L_Float(uint8_t *data, const unsigned int samples, float *dest)
+ {
+ for (unsigned int i = 0; i < samples; ++i, data += 4)
+ {
+@@ -220,7 +235,7 @@
+ return samples;
+ }
+
+-unsigned int CAEConvert::S24BE4_Float(uint8_t *data, const unsigned int samples, float *dest)
++unsigned int CAEConvert::S24BE4H_Float(uint8_t *data, const unsigned int samples, float *dest)
+ {
+ for (unsigned int i = 0; i < samples; ++i, data += 4)
+ {
+@@ -230,6 +245,16 @@
+ return samples;
+ }
+
++unsigned int CAEConvert::S24BE4L_Float(uint8_t *data, const unsigned int samples, float *dest)
++{
++ for (unsigned int i = 0; i < samples; ++i, data += 4)
++ {
++ int s = (data[1] << 24) | (data[2] << 16) | (data[3] << 8);
++ *dest++ = (float)s * INT32_SCALE;
++ }
++ return samples;
++}
++
+ unsigned int CAEConvert::S24LE3_Float(uint8_t *data, const unsigned int samples, float *dest)
+ {
+ for (unsigned int i = 0; i < samples; ++i, data += 3)
+@@ -244,7 +269,7 @@
+ {
+ for (unsigned int i = 0; i < samples; ++i, data += 3)
+ {
+- int s = (data[1] << 24) | (data[2] << 16) | (data[3] << 8);
++ int s = (data[0] << 24) | (data[1] << 16) | (data[2] << 8);
+ *dest++ = (float)s * INT32_SCALE;
+ }
+ return samples;
+@@ -786,7 +811,7 @@
+ return samples << 1;
+ }
+
+-unsigned int CAEConvert::Float_S24NE4(float *data, const unsigned int samples, uint8_t *dest)
++unsigned int CAEConvert::Float_S24NE4H(float *data, const unsigned int samples, uint8_t *dest)
+ {
+ int32_t *dst = (int32_t*)dest;
+ #ifdef __SSE2__
+@@ -797,7 +822,7 @@
+ /* work around invalid alignment */
+ while ((((uintptr_t)data & 0xF) || ((uintptr_t)dest & 0xF)) && count > 0)
+ {
+- dst[0] = (safeRound(data[0] * ((float)INT24_MAX+.5f)) & 0xFFFFFF) << 8;
++ dst[0] = safeRound(data[0] * ((float)INT24_MAX+.5f)) << 8;
+ ++data;
+ ++dst;
+ --count;
+@@ -816,7 +841,7 @@
+ {
+ const uint32_t odd = count - even;
+ if (odd == 1)
+- dst[0] = (safeRound(data[0] * ((float)INT24_MAX+.5f)) & 0xFFFFFF) << 8;
++ dst[0] = safeRound(data[0] * ((float)INT24_MAX+.5f)) << 8;
+ else
+ {
+ __m128 in;
+@@ -841,7 +866,69 @@
+ _mm_empty();
+ #else /* no SSE2 */
+ for (uint32_t i = 0; i < samples; ++i)
+- *dst++ = (safeRound(*data++ * ((float)INT24_MAX+.5f)) & 0xFFFFFF) << 8;
++ *dst++ = safeRound(*data++ * ((float)INT24_MAX+.5f)) << 8;
++ #endif
++
++ return samples << 2;
++}
++
++unsigned int CAEConvert::Float_S24NE4L(float *data, const unsigned int samples, uint8_t *dest)
++{
++ int32_t *dst = (int32_t*)dest;
++ #ifdef __SSE2__
++
++ const __m128i msk = _mm_set1_epi32(0xFFFFFF);
++ const __m128 mul = _mm_set_ps1((float)INT24_MAX+.5f);
++ unsigned int count = samples;
++
++ /* work around invalid alignment */
++ while ((((uintptr_t)data & 0xF) || ((uintptr_t)dest & 0xF)) && count > 0)
++ {
++ dst[0] = safeRound(data[0] * ((float)INT24_MAX+.5f)) & 0xFFFFFF;
++ ++data;
++ ++dst;
++ --count;
++ }
++
++ const uint32_t even = count & ~0x3;
++ for (uint32_t i = 0; i < even; i += 4, data += 4, dst += 4)
++ {
++ __m128 in = _mm_mul_ps(_mm_load_ps(data), mul);
++ __m128i con = _mm_cvtps_epi32(in);
++ con = _mm_and_si128(con, msk);
++ memcpy(dst, &con, sizeof(int32_t) * 4);
++ }
++
++ if (count != even)
++ {
++ const uint32_t odd = count - even;
++ if (odd == 1)
++ dst[0] = safeRound(data[0] * ((float)INT24_MAX+.5f)) & 0xFFFFFF;
++ else
++ {
++ __m128 in;
++ if (odd == 2)
++ {
++ in = _mm_setr_ps(data[0], data[1], 0, 0);
++ in = _mm_mul_ps(in, mul);
++ __m128i con = _mm_cvtps_epi32(in);
++ con = _mm_and_si128(con, msk);
++ memcpy(dst, &con, sizeof(int32_t) * 2);
++ }
++ else
++ {
++ in = _mm_setr_ps(data[0], data[1], data[2], 0);
++ in = _mm_mul_ps(in, mul);
++ __m128i con = _mm_cvtps_epi32(in);
++ con = _mm_and_si128(con, msk);
++ memcpy(dst, &con, sizeof(int32_t) * 3);
++ }
++ }
++ }
++ _mm_empty();
++ #else /* no SSE2 */
++ for (uint32_t i = 0; i < samples; ++i)
++ *dst++ = safeRound(*data++ * ((float)INT24_MAX+.5f)) & 0xFFFFFF;
+ #endif
+
+ return samples << 2;
+diff -Naur xbmc-13b4/xbmc/cores/AudioEngine/Utils/AEConvert.h xbmc-imx6-13b4/xbmc/cores/AudioEngine/Utils/AEConvert.h
+--- xbmc-13b4/xbmc/cores/AudioEngine/Utils/AEConvert.h 2014-04-24 11:49:41.292075533 +0200
++++ xbmc-imx6-13b4/xbmc/cores/AudioEngine/Utils/AEConvert.h 2014-04-24 11:50:14.007208425 +0200
+@@ -28,8 +28,10 @@
+ static unsigned int S8_Float (uint8_t *data, const unsigned int samples, float *dest);
+ static unsigned int S16LE_Float (uint8_t *data, const unsigned int samples, float *dest);
+ static unsigned int S16BE_Float (uint8_t *data, const unsigned int samples, float *dest);
+- static unsigned int S24LE4_Float(uint8_t *data, const unsigned int samples, float *dest);
+- static unsigned int S24BE4_Float(uint8_t *data, const unsigned int samples, float *dest);
++ static unsigned int S24LE4H_Float(uint8_t *data, const unsigned int samples, float *dest);
++ static unsigned int S24LE4L_Float(uint8_t *data, const unsigned int samples, float *dest);
++ static unsigned int S24BE4H_Float(uint8_t *data, const unsigned int samples, float *dest);
++ static unsigned int S24BE4L_Float(uint8_t *data, const unsigned int samples, float *dest);
+ static unsigned int S24LE3_Float(uint8_t *data, const unsigned int samples, float *dest);
+ static unsigned int S24BE3_Float(uint8_t *data, const unsigned int samples, float *dest);
+ static unsigned int S32LE_Float (uint8_t *data, const unsigned int samples, float *dest);
+@@ -41,7 +43,8 @@
+ static unsigned int Float_S8 (float *data, const unsigned int samples, uint8_t *dest);
+ static unsigned int Float_S16LE (float *data, const unsigned int samples, uint8_t *dest);
+ static unsigned int Float_S16BE (float *data, const unsigned int samples, uint8_t *dest);
+- static unsigned int Float_S24NE4(float *data, const unsigned int samples, uint8_t *dest);
++ static unsigned int Float_S24NE4H(float *data, const unsigned int samples, uint8_t *dest);
++ static unsigned int Float_S24NE4L(float *data, const unsigned int samples, uint8_t *dest);
+ static unsigned int Float_S24NE3(float *data, const unsigned int samples, uint8_t *dest);
+ static unsigned int Float_S32LE (float *data, const unsigned int samples, uint8_t *dest);
+ static unsigned int Float_S32BE (float *data, const unsigned int samples, uint8_t *dest);
+diff -Naur xbmc-13b4/xbmc/cores/AudioEngine/Utils/AEUtil.cpp xbmc-imx6-13b4/xbmc/cores/AudioEngine/Utils/AEUtil.cpp
+--- xbmc-13b4/xbmc/cores/AudioEngine/Utils/AEUtil.cpp 2014-04-24 11:49:41.296075428 +0200
++++ xbmc-imx6-13b4/xbmc/cores/AudioEngine/Utils/AEUtil.cpp 2014-04-24 11:50:14.007208425 +0200
+@@ -92,9 +92,13 @@
+ 32, /* S32LE */
+ 32, /* S32NE */
+
+- 32, /* S24BE */
+- 32, /* S24LE */
+- 32, /* S24NE */
++ 32, /* S24BE4H */
++ 32, /* S24LE4H */
++ 32, /* S24NE4H */
++
++ 32, /* S24BE4L */
++ 32, /* S24LE4L */
++ 32, /* S24NE4L */
+
+ 24, /* S24BE3 */
+ 24, /* S24LE3 */
+@@ -114,8 +118,9 @@
+ 8, /* U8P */
+ 16, /* S16NEP */
+ 32, /* S32NEP */
+- 32, /* S24NEP */
+- 24, /* S24NE3P*/
++ 32, /* S24NE4HP */
++ 32, /* S24NE4LP */
++ 24, /* S24NE3P */
+ sizeof(double) << 3, /* DOUBLEP */
+ sizeof(float ) << 3 /* FLOATP */
+ };
+@@ -125,7 +130,8 @@
+
+ const unsigned int CAEUtil::DataFormatToUsedBits(const enum AEDataFormat dataFormat)
+ {
+- if (dataFormat == AE_FMT_S24BE4 || dataFormat == AE_FMT_S24LE4 || dataFormat == AE_FMT_S24NE4)
++ if (dataFormat == AE_FMT_S24BE4H || dataFormat == AE_FMT_S24LE4H || dataFormat == AE_FMT_S24NE4H ||
++ dataFormat == AE_FMT_S24BE4L || dataFormat == AE_FMT_S24LE4L || dataFormat == AE_FMT_S24NE4L)
+ return 24;
+ else
+ return DataFormatToBits(dataFormat);
+@@ -149,9 +155,13 @@
+ "AE_FMT_S32LE",
+ "AE_FMT_S32NE",
+
+- "AE_FMT_S24BE4",
+- "AE_FMT_S24LE4",
+- "AE_FMT_S24NE4", /* S24 in 4 bytes */
++ "AE_FMT_S24BE4H",
++ "AE_FMT_S24LE4H",
++ "AE_FMT_S24NE4H", /* S24 in upper 4 bytes */
++
++ "AE_FMT_S24BE4L",
++ "AE_FMT_S24LE4L",
++ "AE_FMT_S24NE4L", /* S24 in lower 4 bytes */
+
+ "AE_FMT_S24BE3",
+ "AE_FMT_S24LE3",
+@@ -173,7 +183,8 @@
+ "AE_FMT_U8P",
+ "AE_FMT_S16NEP",
+ "AE_FMT_S32NEP",
+- "AE_FMT_S24NE4P",
++ "AE_FMT_S24NE4HP",
++ "AE_FMT_S24NE4LP",
+ "AE_FMT_S24NE3P",
+ "AE_FMT_DOUBLEP",
+ "AE_FMT_FLOATP"
+diff -Naur xbmc-13b4/xbmc/cores/dvdplayer/DVDCodecs/DVDFactoryCodec.cpp xbmc-imx6-13b4/xbmc/cores/dvdplayer/DVDCodecs/DVDFactoryCodec.cpp
+--- xbmc-13b4/xbmc/cores/dvdplayer/DVDCodecs/DVDFactoryCodec.cpp 2014-04-24 11:49:41.204077867 +0200
++++ xbmc-imx6-13b4/xbmc/cores/dvdplayer/DVDCodecs/DVDFactoryCodec.cpp 2014-04-24 11:50:14.007208425 +0200
+@@ -35,6 +35,9 @@
+ #include "Video/DVDVideoCodecFFmpeg.h"
+ #include "Video/DVDVideoCodecOpenMax.h"
+ #include "Video/DVDVideoCodecLibMpeg2.h"
++#if defined(HAS_IMXVPU)
++#include "Video/DVDVideoCodecIMX.h"
++#endif
+ #include "Video/DVDVideoCodecStageFright.h"
+ #if defined(HAVE_LIBCRYSTALHD)
+ #include "Video/DVDVideoCodecCrystalHD.h"
+@@ -191,7 +194,11 @@
+ #elif defined(TARGET_POSIX) && !defined(TARGET_DARWIN)
+ hwSupport += "VAAPI:no ";
+ #endif
+-
++#if defined(HAS_IMXVPU)
++ hwSupport += "iMXVPU:yes ";
++#else
++ hwSupport += "iMXVPU:no ";
++#endif
+ CLog::Log(LOGDEBUG, "CDVDFactoryCodec: compiled in hardware support: %s", hwSupport.c_str());
+ #if defined(HAS_LIBAMCODEC)
+ // amcodec can handle dvd playback.
+@@ -205,6 +212,15 @@
+ }
+ }
+
++/*#endif*/
++
++#if defined(HAS_IMXVPU)
++ if (!hint.software)
++ {
++ if ( (pCodec = OpenCodec(new CDVDVideoCodecIMX(), hint, options)) ) return pCodec;
++ }
++#endif
++
+ #if defined(TARGET_DARWIN_OSX)
+ if (!hint.software && CSettings::Get().GetBool("videoplayer.usevda"))
+ {
+diff -Naur xbmc-13b4/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodec.h xbmc-imx6-13b4/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodec.h
+--- xbmc-13b4/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodec.h 2014-04-24 11:49:41.200077973 +0200
++++ xbmc-imx6-13b4/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodec.h 2014-04-24 11:50:14.007208425 +0200
+@@ -27,6 +27,7 @@
+ #include
+ #include
+ #include "cores/VideoRenderers/RenderFormats.h"
++#include "DVDVideoCodecInfo.h"
+
+ struct DVDCodecAvailableType
+ {
+@@ -91,6 +92,11 @@
+ struct {
+ CDVDMediaCodecInfo *mediacodec;
+ };
++
++ struct {
++ CDVDVideoCodecBuffer *codecinfo;
++ };
++
+ };
+
+ unsigned int iFlags;
+diff -Naur xbmc-13b4/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp xbmc-imx6-13b4/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp
+--- xbmc-13b4/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp 1970-01-01 01:00:00.000000000 +0100
++++ xbmc-imx6-13b4/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp 2014-04-24 11:50:14.007208425 +0200
+@@ -0,0 +1,1501 @@
++/*
++ * Copyright (C) 2010-2013 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 "DVDVideoCodecIMX.h"
++
++#include
++#include
++#include
++#include
++#include
++#include
++#include
++#include
++#include "threads/SingleLock.h"
++#include "utils/log.h"
++#include "DVDClock.h"
++#include "threads/Atomics.h"
++
++
++// FIXME get rid of these defines properly
++#define FRAME_ALIGN 16
++#define MEDIAINFO 1
++#define _4CC(c1,c2,c3,c4) (((uint32_t)(c4)<<24)|((uint32_t)(c3)<<16)|((uint32_t)(c2)<<8)|(uint32_t)(c1))
++#define Align(ptr,align) (((unsigned int)ptr + (align) - 1)/(align)*(align))
++
++// Extrace physical and virtual addresses from CDVDVideoCodecBuffer pointers
++#define GET_PHYS_ADDR(buf) (buf)->data[1]
++#define GET_VIRT_ADDR(buf) (buf)->data[0]
++#define GET_DEINTERLACER(buf) (buf)->data[2]
++#define GET_FIELDTYPE(buf) (buf)->data[3]
++
++// Experiments show that we need at least one more (+1) V4L buffer than the min value returned by the VPU
++const int CDVDVideoCodecIMX::m_extraVpuBuffers = 6;
++const int CDVDVideoCodecIMX::m_maxVpuDecodeLoops = 5;
++CCriticalSection CDVDVideoCodecIMX::m_codecBufferLock;
++
++bool CDVDVideoCodecIMX::VpuAllocBuffers(VpuMemInfo *pMemBlock)
++{
++ int i, size;
++ void* ptr;
++ VpuMemDesc vpuMem;
++ VpuDecRetCode ret;
++
++ for(i=0; inSubBlockNum; i++)
++ {
++ size = pMemBlock->MemSubBlock[i].nAlignment + pMemBlock->MemSubBlock[i].nSize;
++ if (pMemBlock->MemSubBlock[i].MemType == VPU_MEM_VIRT)
++ { // Allocate standard virtual memory
++ ptr = malloc(size);
++ if(ptr == NULL)
++ {
++ CLog::Log(LOGERROR, "%s - Unable to malloc %d bytes.\n", __FUNCTION__, size);
++ goto AllocFailure;
++ }
++ pMemBlock->MemSubBlock[i].pVirtAddr = (unsigned char*)Align(ptr, pMemBlock->MemSubBlock[i].nAlignment);
++
++ m_decMemInfo.nVirtNum++;
++ m_decMemInfo.virtMem = (void**)realloc(m_decMemInfo.virtMem, m_decMemInfo.nVirtNum*sizeof(void*));
++ m_decMemInfo.virtMem[m_decMemInfo.nVirtNum-1] = ptr;
++ }
++ else
++ { // Allocate contigous mem for DMA
++ vpuMem.nSize = size;
++ ret = VPU_DecGetMem(&vpuMem);
++ if(ret != VPU_DEC_RET_SUCCESS)
++ {
++ CLog::Log(LOGERROR, "%s - Unable alloc %d bytes of physical memory (%d).\n", __FUNCTION__, size, ret);
++ goto AllocFailure;
++ }
++ pMemBlock->MemSubBlock[i].pVirtAddr = (unsigned char*)Align(vpuMem.nVirtAddr, pMemBlock->MemSubBlock[i].nAlignment);
++ pMemBlock->MemSubBlock[i].pPhyAddr = (unsigned char*)Align(vpuMem.nPhyAddr, pMemBlock->MemSubBlock[i].nAlignment);
++
++ m_decMemInfo.nPhyNum++;
++ m_decMemInfo.phyMem = (VpuMemDesc*)realloc(m_decMemInfo.phyMem, m_decMemInfo.nPhyNum*sizeof(VpuMemDesc));
++ m_decMemInfo.phyMem[m_decMemInfo.nPhyNum-1].nPhyAddr = vpuMem.nPhyAddr;
++ m_decMemInfo.phyMem[m_decMemInfo.nPhyNum-1].nVirtAddr = vpuMem.nVirtAddr;
++ m_decMemInfo.phyMem[m_decMemInfo.nPhyNum-1].nCpuAddr = vpuMem.nCpuAddr;
++ m_decMemInfo.phyMem[m_decMemInfo.nPhyNum-1].nSize = size;
++ }
++ }
++
++ return true;
++
++AllocFailure:
++ VpuFreeBuffers();
++ return false;
++}
++
++int CDVDVideoCodecIMX::VpuFindBuffer(void *frameAddr)
++{
++ for (int i=0; i1)
++ {
++ ySize=Align(ySize,nAlign);
++ uvSize=Align(uvSize,nAlign);
++ }
++
++ m_outputBuffers = new CDVDVideoCodecIMXBuffer*[m_vpuFrameBufferNum];
++
++ for (int i=0 ; i < m_vpuFrameBufferNum; i++)
++ {
++ totalSize=(ySize+uvSize+mvSize+nAlign)*1;
++
++ vpuMem.nSize=totalSize;
++ ret = VPU_DecGetMem(&vpuMem);
++ if(ret != VPU_DEC_RET_SUCCESS)
++ {
++ CLog::Log(LOGERROR, "%s: vpu malloc frame buf failure: ret=%d \r\n",__FUNCTION__,ret);
++ return false;
++ }
++
++ //record memory info for release
++ m_decMemInfo.nPhyNum++;
++ m_decMemInfo.phyMem = (VpuMemDesc*)realloc(m_decMemInfo.phyMem, m_decMemInfo.nPhyNum*sizeof(VpuMemDesc));
++ m_decMemInfo.phyMem[m_decMemInfo.nPhyNum-1].nPhyAddr = vpuMem.nPhyAddr;
++ m_decMemInfo.phyMem[m_decMemInfo.nPhyNum-1].nVirtAddr = vpuMem.nVirtAddr;
++ m_decMemInfo.phyMem[m_decMemInfo.nPhyNum-1].nCpuAddr = vpuMem.nCpuAddr;
++ m_decMemInfo.phyMem[m_decMemInfo.nPhyNum-1].nSize = vpuMem.nSize;
++
++ //fill frameBuf
++ ptr=(unsigned char*)vpuMem.nPhyAddr;
++ ptrVirt=(unsigned char*)vpuMem.nVirtAddr;
++
++ //align the base address
++ if(nAlign>1)
++ {
++ ptr=(unsigned char*)Align(ptr,nAlign);
++ ptrVirt=(unsigned char*)Align(ptrVirt,nAlign);
++ }
++
++ // fill stride info
++ m_vpuFrameBuffers[i].nStrideY=yStride;
++ m_vpuFrameBuffers[i].nStrideC=uvStride;
++
++ // fill phy addr
++ m_vpuFrameBuffers[i].pbufY=ptr;
++ m_vpuFrameBuffers[i].pbufCb=ptr+ySize;
++ m_vpuFrameBuffers[i].pbufCr=0;
++ m_vpuFrameBuffers[i].pbufMvCol=ptr+ySize+uvSize;
++ //ptr+=ySize+uSize+vSize+mvSize;
++ // fill virt addr
++ m_vpuFrameBuffers[i].pbufVirtY=ptrVirt;
++ m_vpuFrameBuffers[i].pbufVirtCb=ptrVirt+ySize;
++ m_vpuFrameBuffers[i].pbufVirtCr=0;
++ m_vpuFrameBuffers[i].pbufVirtMvCol=ptrVirt+ySize+uvSize;
++ //ptrVirt+=ySize+uSize+vSize+mvSize;
++
++ m_vpuFrameBuffers[i].pbufY_tilebot=0;
++ m_vpuFrameBuffers[i].pbufCb_tilebot=0;
++ m_vpuFrameBuffers[i].pbufVirtY_tilebot=0;
++ m_vpuFrameBuffers[i].pbufVirtCb_tilebot=0;
++
++#ifdef TRACE_FRAMES
++ m_outputBuffers[i] = new CDVDVideoCodecIMXBuffer(i);
++#else
++ m_outputBuffers[i] = new CDVDVideoCodecIMXBuffer();
++#endif
++ }
++
++ if (m_initInfo.nInterlace)
++ {
++ CLog::Log(LOGNOTICE, "IMX: Enable hardware deinterlacing\n");
++ if (!m_deinterlacer.Init(m_initInfo.nPicWidth, m_initInfo.nPicHeight, GetAllowedReferences()+1, nAlign))
++ {
++ CLog::Log(LOGWARNING, "IMX: Failed to initialize IPU buffers: deinterlacing disabled\n");
++ }
++ else
++ {
++ for (int i=0; iOpen(hints.codec, (uint8_t *)hints.extradata, hints.extrasize, true);
++ }
++ }
++ break;
++ case CODEC_ID_VC1:
++ m_decOpenParam.CodecFormat = VPU_V_VC1_AP;
++ m_pFormatName = "iMX-vc1";
++ break;
++/* FIXME TODO
++ * => for this type we have to set height, width, nChromaInterleave and nMapType
++ case CODEC_ID_MJPEG:
++ m_decOpenParam.CodecFormat = VPU_V_MJPG;
++ m_pFormatName = "iMX-mjpg";
++ break;*/
++ case CODEC_ID_CAVS:
++ case CODEC_ID_AVS:
++ m_decOpenParam.CodecFormat = VPU_V_AVS;
++ m_pFormatName = "iMX-AVS";
++ break;
++ case CODEC_ID_RV10:
++ case CODEC_ID_RV20:
++ case CODEC_ID_RV30:
++ case CODEC_ID_RV40:
++ m_decOpenParam.CodecFormat = VPU_V_RV;
++ m_pFormatName = "iMX-RV";
++ break;
++ case CODEC_ID_KMVC:
++ m_decOpenParam.CodecFormat = VPU_V_AVC_MVC;
++ m_pFormatName = "iMX-MVC";
++ break;
++ case CODEC_ID_VP8:
++ m_decOpenParam.CodecFormat = VPU_V_VP8;
++ m_pFormatName = "iMX-vp8";
++ break;
++ case CODEC_ID_MPEG4:
++ switch(m_hints.codec_tag)
++ {
++ case _4CC('D','I','V','X'):
++ m_decOpenParam.CodecFormat = VPU_V_XVID; // VPU_V_DIVX4
++ m_pFormatName = "iMX-divx4";
++ break;
++ case _4CC('D','X','5','0'):
++ case _4CC('D','I','V','5'):
++ m_decOpenParam.CodecFormat = VPU_V_XVID; // VPU_V_DIVX56
++ m_pFormatName = "iMX-divx5";
++ break;
++ case _4CC('X','V','I','D'):
++ case _4CC('M','P','4','V'):
++ case _4CC('P','M','P','4'):
++ case _4CC('F','M','P','4'):
++ m_decOpenParam.CodecFormat = VPU_V_XVID;
++ m_pFormatName = "iMX-xvid";
++ break;
++ default:
++ CLog::Log(LOGERROR, "iMX VPU : MPEG4 codec tag %d is not (yet) handled.\n", m_hints.codec_tag);
++ return false;
++ }
++ break;
++ default:
++ CLog::Log(LOGERROR, "iMX VPU : codecid %d is not (yet) handled.\n", m_hints.codec);
++ return false;
++ }
++
++ return true;
++}
++
++void CDVDVideoCodecIMX::Dispose(void)
++{
++ VpuDecRetCode ret;
++ bool VPU_loaded = m_vpuHandle;
++
++ // Block render thread from using that framebuffers
++ Enter();
++
++ // Release last buffer
++ if(m_lastBuffer)
++ SAFE_RELEASE(m_lastBuffer);
++
++ // Invalidate output buffers to prevent the renderer from mapping this memory
++ for (int i=0; iReleaseFramebuffer(&m_vpuHandle);
++ SAFE_RELEASE(m_outputBuffers[i]);
++ }
++
++ Leave();
++
++ if (m_vpuHandle)
++ {
++ ret = VPU_DecFlushAll(m_vpuHandle);
++ if (ret != VPU_DEC_RET_SUCCESS)
++ {
++ CLog::Log(LOGERROR, "%s - VPU flush failed with error code %d.\n", __FUNCTION__, ret);
++ }
++ ret = VPU_DecClose(m_vpuHandle);
++ if (ret != VPU_DEC_RET_SUCCESS)
++ {
++ CLog::Log(LOGERROR, "%s - VPU close failed with error code %d.\n", __FUNCTION__, ret);
++ }
++ m_vpuHandle = 0;
++ }
++
++ m_frameCounter = 0;
++ m_deinterlacer.Close();
++
++ // Clear memory
++ if (m_outputBuffers != NULL)
++ {
++ delete m_outputBuffers;
++ m_outputBuffers = NULL;
++ }
++
++ VpuFreeBuffers();
++ m_vpuFrameBufferNum = 0;
++
++ if (m_vpuFrameBuffers != NULL)
++ {
++ delete m_vpuFrameBuffers;
++ m_vpuFrameBuffers = NULL;
++ }
++
++ if (VPU_loaded)
++ {
++ ret = VPU_DecUnLoad();
++ if (ret != VPU_DEC_RET_SUCCESS)
++ {
++ CLog::Log(LOGERROR, "%s - VPU unload failed with error code %d.\n", __FUNCTION__, ret);
++ }
++ }
++
++ if (m_converter)
++ {
++ m_converter->Close();
++ SAFE_DELETE(m_converter);
++ }
++ return;
++}
++
++int CDVDVideoCodecIMX::Decode(BYTE *pData, int iSize, double dts, double pts)
++{
++ VpuDecFrameLengthInfo frameLengthInfo;
++ VpuBufferNode inData;
++ VpuDecRetCode ret;
++ int decRet = 0;
++ int retStatus = 0;
++ int demuxer_bytes = iSize;
++ uint8_t *demuxer_content = pData;
++ int retries = 0;
++ int idx;
++
++#ifdef IMX_PROFILE
++ static unsigned long long previous, current;
++ unsigned long long before_dec;
++#endif
++
++ if (!m_vpuHandle)
++ {
++ VpuOpen();
++ if (!m_vpuHandle)
++ return VC_ERROR;
++ }
++
++ for (int i=0; i < m_vpuFrameBufferNum; i++)
++ {
++ if (m_outputBuffers[i]->Rendered())
++ {
++ ret = m_outputBuffers[i]->ReleaseFramebuffer(&m_vpuHandle);
++ if(ret != VPU_DEC_RET_SUCCESS)
++ {
++ CLog::Log(LOGERROR, "%s: vpu clear frame display failure: ret=%d \r\n",__FUNCTION__,ret);
++ }
++ }
++ }
++
++#ifdef IMX_PROFILE
++ current = XbmcThreads::SystemClockMillis();
++ CLog::Log(LOGDEBUG, "%s - delta time decode : %llu - demux size : %d dts : %f - pts : %f\n", __FUNCTION__, current - previous, iSize, dts, pts);
++ previous = current;
++#endif
++
++ if ((pData && iSize) ||
++ (m_bytesToBeConsumed))
++ {
++ if ((m_convert_bitstream) && (iSize))
++ {
++ // convert demuxer packet from bitstream to bytestream (AnnexB)
++ if (m_converter->Convert(demuxer_content, demuxer_bytes))
++ {
++ demuxer_content = m_converter->GetConvertBuffer();
++ demuxer_bytes = m_converter->GetConvertSize();
++ }
++ else
++ CLog::Log(LOGERROR,"%s - bitstream_convert error", __FUNCTION__);
++ }
++
++ inData.nSize = demuxer_bytes;
++ inData.pPhyAddr = NULL;
++ inData.pVirAddr = demuxer_content;
++ // FIXME TODO VP8 & DivX3 require specific sCodecData values
++ if ((m_decOpenParam.CodecFormat == VPU_V_MPEG2) ||
++ (m_decOpenParam.CodecFormat == VPU_V_VC1_AP)||
++ (m_decOpenParam.CodecFormat == VPU_V_XVID))
++ {
++ inData.sCodecData.pData = (unsigned char *)m_hints.extradata;
++ inData.sCodecData.nSize = m_hints.extrasize;
++ }
++ else
++ {
++ inData.sCodecData.pData = NULL;
++ inData.sCodecData.nSize = 0;
++ }
++
++ while (true) // Decode as long as the VPU consumes data
++ {
++#ifdef IMX_PROFILE
++ before_dec = XbmcThreads::SystemClockMillis();
++#endif
++ if (m_frameReported)
++ m_bytesToBeConsumed += inData.nSize;
++ ret = VPU_DecDecodeBuf(m_vpuHandle, &inData, &decRet);
++#ifdef IMX_PROFILE
++ CLog::Log(LOGDEBUG, "%s - VPU dec 0x%x decode takes : %lld\n\n", __FUNCTION__, decRet, XbmcThreads::SystemClockMillis() - before_dec);
++#endif
++
++ if (ret != VPU_DEC_RET_SUCCESS)
++ {
++ CLog::Log(LOGERROR, "%s - VPU decode failed with error code %d.\n", __FUNCTION__, ret);
++ goto out_error;
++ }
++
++ if (decRet & VPU_DEC_INIT_OK)
++ // VPU decoding init OK : We can retrieve stream info
++ {
++ ret = VPU_DecGetInitialInfo(m_vpuHandle, &m_initInfo);
++ if (ret == VPU_DEC_RET_SUCCESS)
++ {
++ CLog::Log(LOGDEBUG, "%s - VPU Init Stream Info : %dx%d (interlaced : %d - Minframe : %d)"\
++ " - Align : %d bytes - crop : %d %d %d %d - Q16Ratio : %x\n", __FUNCTION__,
++ m_initInfo.nPicWidth, m_initInfo.nPicHeight, m_initInfo.nInterlace, m_initInfo.nMinFrameBufferCount,
++ m_initInfo.nAddressAlignment, m_initInfo.PicCropRect.nLeft, m_initInfo.PicCropRect.nTop,
++ m_initInfo.PicCropRect.nRight, m_initInfo.PicCropRect.nBottom, m_initInfo.nQ16ShiftWidthDivHeightRatio);
++ if (VpuAllocFrameBuffers())
++ {
++ ret = VPU_DecRegisterFrameBuffer(m_vpuHandle, m_vpuFrameBuffers, m_vpuFrameBufferNum);
++ if (ret != VPU_DEC_RET_SUCCESS)
++ {
++ CLog::Log(LOGERROR, "%s - VPU error while registering frame buffers (%d).\n", __FUNCTION__, ret);
++ goto out_error;
++ }
++ }
++ else
++ {
++ goto out_error;
++ }
++ }
++ else
++ {
++ CLog::Log(LOGERROR, "%s - VPU get initial info failed (%d).\n", __FUNCTION__, ret);
++ goto out_error;
++ }
++ } //VPU_DEC_INIT_OK
++
++ if (decRet & VPU_DEC_ONE_FRM_CONSUMED)
++ {
++ ret = VPU_DecGetConsumedFrameInfo(m_vpuHandle, &frameLengthInfo);
++ if (ret != VPU_DEC_RET_SUCCESS)
++ {
++ CLog::Log(LOGERROR, "%s - VPU error retireving info about consummed frame (%d).\n", __FUNCTION__, ret);
++ }
++ m_bytesToBeConsumed -= (frameLengthInfo.nFrameLength + frameLengthInfo.nStuffLength);
++ if (frameLengthInfo.pFrame)
++ {
++ idx = VpuFindBuffer(frameLengthInfo.pFrame->pbufY);
++ if (m_bytesToBeConsumed < 50)
++ m_bytesToBeConsumed = 0;
++ if (idx != -1)
++ {
++ if (m_previousPts != DVD_NOPTS_VALUE)
++ {
++ m_outputBuffers[idx]->SetPts(m_previousPts);
++ m_previousPts = DVD_NOPTS_VALUE;
++ }
++ else
++ m_outputBuffers[idx]->SetPts(pts);
++ }
++ else
++ CLog::Log(LOGERROR, "%s - could not find frame buffer\n", __FUNCTION__);
++ }
++ } //VPU_DEC_ONE_FRM_CONSUMED
++
++ if (decRet & VPU_DEC_OUTPUT_DIS)
++ // Frame ready to be displayed
++ {
++ if (retStatus & VC_PICTURE)
++ CLog::Log(LOGERROR, "%s - Second picture in the same decode call !\n", __FUNCTION__);
++
++ ret = VPU_DecGetOutputFrame(m_vpuHandle, &m_frameInfo);
++ if(ret != VPU_DEC_RET_SUCCESS)
++ {
++ CLog::Log(LOGERROR, "%s - VPU Cannot get output frame(%d).\n", __FUNCTION__, ret);
++ goto out_error;
++ }
++
++ // Some codecs (VC1?) lie about their frame size (mod 16). Adjust...
++ m_frameInfo.pExtInfo->nFrmWidth = (((m_frameInfo.pExtInfo->nFrmWidth) + 15) & ~15);
++ m_frameInfo.pExtInfo->nFrmHeight = (((m_frameInfo.pExtInfo->nFrmHeight) + 15) & ~15);
++
++ retStatus |= VC_PICTURE;
++ } //VPU_DEC_OUTPUT_DIS
++
++ // According to libfslvpuwrap: If this flag is set then the frame should
++ // be dropped. It is just returned to gather decoder information but not
++ // for display.
++ if (decRet & VPU_DEC_OUTPUT_MOSAIC_DIS)
++ {
++ ret = VPU_DecGetOutputFrame(m_vpuHandle, &m_frameInfo);
++ if(ret != VPU_DEC_RET_SUCCESS)
++ {
++ CLog::Log(LOGERROR, "%s - VPU Cannot get output frame(%d).\n", __FUNCTION__, ret);
++ goto out_error;
++ }
++
++ // Display frame
++ ret = VPU_DecOutFrameDisplayed(m_vpuHandle, m_frameInfo.pDisplayFrameBuf);
++ if(ret != VPU_DEC_RET_SUCCESS)
++ {
++ CLog::Log(LOGERROR, "%s: VPU Clear frame display failure(%d)\n",__FUNCTION__,ret);
++ goto out_error;
++ }
++ } //VPU_DEC_OUTPUT_MOSAIC_DIS
++
++ if (decRet & VPU_DEC_OUTPUT_REPEAT)
++ {
++ CLog::Log(LOGDEBUG, "%s - Frame repeat.\n", __FUNCTION__);
++ }
++ if (decRet & VPU_DEC_OUTPUT_DROPPED)
++ {
++ CLog::Log(LOGDEBUG, "%s - Frame dropped.\n", __FUNCTION__);
++ }
++ if (decRet & VPU_DEC_NO_ENOUGH_BUF)
++ {
++ CLog::Log(LOGERROR, "%s - No frame buffer available.\n", __FUNCTION__);
++ }
++ if (decRet & VPU_DEC_SKIP)
++ {
++ CLog::Log(LOGDEBUG, "%s - Frame skipped.\n", __FUNCTION__);
++ }
++ if (decRet & VPU_DEC_FLUSH)
++ {
++ CLog::Log(LOGNOTICE, "%s - VPU requires a flush.\n", __FUNCTION__);
++ Reset();
++ retStatus = VC_FLUSHED;
++ }
++ if (decRet & VPU_DEC_OUTPUT_EOS)
++ {
++ CLog::Log(LOGNOTICE, "%s - EOS encountered.\n", __FUNCTION__);
++ }
++ if ((decRet & VPU_DEC_NO_ENOUGH_INBUF) ||
++ (decRet & VPU_DEC_OUTPUT_DIS))
++ {
++ // We are done with VPU decoder that time
++ break;
++ }
++
++ retries++;
++ if (retries >= m_maxVpuDecodeLoops)
++ {
++ CLog::Log(LOGERROR, "%s - Leaving VPU decoding loop after %d iterations\n", __FUNCTION__, m_maxVpuDecodeLoops);
++ break;
++ }
++
++ if (!(decRet & VPU_DEC_INPUT_USED))
++ {
++ CLog::Log(LOGERROR, "%s - input not used : addr %p size :%d!\n", __FUNCTION__, inData.pVirAddr, inData.nSize);
++ }
++
++ // Let's process again as VPU_DEC_NO_ENOUGH_INBUF was not set
++ // and we don't have an image ready if we reach that point
++ inData.pVirAddr = NULL;
++ inData.nSize = 0;
++ } // Decode loop
++ } //(pData && iSize)
++
++ if (retStatus == 0)
++ {
++ retStatus |= VC_BUFFER;
++ }
++
++ if (m_bytesToBeConsumed > 0)
++ {
++ // Remember the current pts because the data which has just
++ // been sent to the VPU has not yet been consumed.
++ // This pts is related to the frame that will be consumed
++ // at next call...
++ m_previousPts = pts;
++ }
++ // Store current dts (will be used only if VC_PICTURE is set)
++ m_dts = dts;
++
++#ifdef IMX_PROFILE
++ CLog::Log(LOGDEBUG, "%s - returns %x - duration %lld\n", __FUNCTION__, retStatus, XbmcThreads::SystemClockMillis() - previous);
++#endif
++ return retStatus;
++
++out_error:
++ return VC_ERROR;
++}
++
++void CDVDVideoCodecIMX::Reset()
++{
++ int ret;
++
++ CLog::Log(LOGDEBUG, "%s - called\n", __FUNCTION__);
++
++ // Release last buffer
++ if(m_lastBuffer)
++ SAFE_RELEASE(m_lastBuffer);
++
++ // Invalidate all buffers
++ for(int i=0; i < m_vpuFrameBufferNum; i++)
++ m_outputBuffers[i]->ReleaseFramebuffer(&m_vpuHandle);
++
++ m_frameCounter = 0;
++ m_deinterlacer.Reset();
++ m_bytesToBeConsumed = 0;
++ m_previousPts = DVD_NOPTS_VALUE;
++
++ // Flush VPU
++ ret = VPU_DecFlushAll(m_vpuHandle);
++ if (ret != VPU_DEC_RET_SUCCESS)
++ {
++ CLog::Log(LOGERROR, "%s - VPU flush failed with error code %d.\n", __FUNCTION__, ret);
++ }
++
++}
++
++unsigned CDVDVideoCodecIMX::GetAllowedReferences()
++{
++ return 3;
++}
++
++bool CDVDVideoCodecIMX::ClearPicture(DVDVideoPicture* pDvdVideoPicture)
++{
++ if (pDvdVideoPicture)
++ {
++ SAFE_RELEASE(pDvdVideoPicture->codecinfo);
++ }
++
++ return true;
++}
++
++bool CDVDVideoCodecIMX::GetPicture(DVDVideoPicture* pDvdVideoPicture)
++{
++#ifdef IMX_PROFILE
++ static unsigned int previous = 0;
++ unsigned int current;
++
++ current = XbmcThreads::SystemClockMillis();
++ CLog::Log(LOGDEBUG, "%s tm:%03d\n", __FUNCTION__, current - previous);
++ previous = current;
++#endif
++
++ m_frameCounter++;
++
++ pDvdVideoPicture->iFlags = DVP_FLAG_ALLOCATED;
++ if (m_dropState)
++ pDvdVideoPicture->iFlags |= DVP_FLAG_DROPPED;
++ else
++ pDvdVideoPicture->iFlags &= ~DVP_FLAG_DROPPED;
++
++ pDvdVideoPicture->format = RENDER_FMT_IMXMAP;
++ pDvdVideoPicture->dts = DVD_NOPTS_VALUE;
++ pDvdVideoPicture->iWidth = m_frameInfo.pExtInfo->FrmCropRect.nRight - m_frameInfo.pExtInfo->FrmCropRect.nLeft;
++ pDvdVideoPicture->iHeight = m_frameInfo.pExtInfo->FrmCropRect.nBottom - m_frameInfo.pExtInfo->FrmCropRect.nTop;
++
++ pDvdVideoPicture->iDisplayWidth = ((pDvdVideoPicture->iWidth * m_frameInfo.pExtInfo->nQ16ShiftWidthDivHeightRatio) + 32767) >> 16;
++ pDvdVideoPicture->iDisplayHeight = pDvdVideoPicture->iHeight;
++
++ int idx = VpuFindBuffer(m_frameInfo.pDisplayFrameBuf->pbufY);
++ if (idx != -1)
++ {
++ CDVDVideoCodecIMXBuffer *buffer = m_outputBuffers[idx];
++
++ pDvdVideoPicture->pts = buffer->GetPts();
++ pDvdVideoPicture->dts = m_dts;
++ if (!m_usePTS)
++ {
++ pDvdVideoPicture->pts = DVD_NOPTS_VALUE;
++ pDvdVideoPicture->dts = DVD_NOPTS_VALUE;
++ }
++
++ buffer->Queue(&m_frameInfo, m_lastBuffer);
++
++#ifdef TRACE_FRAMES
++ CLog::Log(LOGDEBUG, "+ %02d dts %f pts %f (VPU)\n", idx, pDvdVideoPicture->dts, pDvdVideoPicture->pts);
++#endif
++
++ /*
++ // This does not work reliably since some streams do not report
++ // correctly if a frame is interlaced.
++ if (m_frameInfo.eFieldType != VPU_FIELD_NONE)
++ GET_DEINTERLACER(buffer) = (uint8_t*)&m_deinterlacer;
++ else
++ GET_DEINTERLACER(buffer) = NULL;
++ */
++
++ pDvdVideoPicture->codecinfo = buffer;
++ pDvdVideoPicture->codecinfo->Lock();
++
++ // Save last buffer
++ if (m_lastBuffer)
++ SAFE_RELEASE(m_lastBuffer);
++
++ m_lastBuffer = buffer;
++ m_lastBuffer->Lock();
++ }
++ else
++ {
++ CLog::Log(LOGERROR, "%s - could not find frame buffer\n", __FUNCTION__);
++ }
++
++ return true;
++}
++
++void CDVDVideoCodecIMX::SetDropState(bool bDrop)
++{
++
++ // We are fast enough to continue to really decode every frames
++ // and avoid artefacts...
++ // (Of course these frames won't be rendered but only decoded !)
++
++ if (m_dropState != bDrop)
++ {
++ m_dropState = bDrop;
++#ifdef TRACE_FRAMES
++ CLog::Log(LOGDEBUG, "%s : %d\n", __FUNCTION__, bDrop);
++#endif
++ }
++}
++
++void CDVDVideoCodecIMX::Enter()
++{
++ m_codecBufferLock.lock();
++}
++
++void CDVDVideoCodecIMX::Leave()
++{
++ m_codecBufferLock.unlock();
++}
++
++/*******************************************/
++
++#ifdef TRACE_FRAMES
++CDVDVideoCodecIMXBuffer::CDVDVideoCodecIMXBuffer(int idx)
++ : m_refs(1)
++ , m_idx(idx)
++#else
++CDVDVideoCodecIMXBuffer::CDVDVideoCodecIMXBuffer()
++ : m_refs(1)
++#endif
++ , m_frameBuffer(NULL)
++ , m_rendered(false)
++ , m_pts(DVD_NOPTS_VALUE)
++ , m_previousBuffer(NULL)
++{
++ GET_DEINTERLACER(this) = NULL;
++}
++
++void CDVDVideoCodecIMXBuffer::Lock()
++{
++#ifdef TRACE_FRAMES
++ long count = AtomicIncrement(&m_refs);
++ CLog::Log(LOGDEBUG, "R+ %02d - ref : %d (VPU)\n", m_idx, count);
++#else
++ AtomicIncrement(&m_refs);
++#endif
++}
++
++long CDVDVideoCodecIMXBuffer::Release()
++{
++ long count = AtomicDecrement(&m_refs);
++#ifdef TRACE_FRAMES
++ CLog::Log(LOGDEBUG, "R- %02d - ref : %d (VPU)\n", m_idx, count);
++#endif
++ if (count == 2)
++ {
++ // Only referenced by the coded and its next frame, release the previous
++ SAFE_RELEASE(m_previousBuffer);
++ }
++ if (count == 1)
++ {
++ // If count drops to 1 then the only reference is being held by the codec
++ // that it can be released in the next Decode call.
++ if(m_frameBuffer != NULL)
++ {
++ m_rendered = true;
++ SAFE_RELEASE(m_previousBuffer);
++#ifdef TRACE_FRAMES
++ CLog::Log(LOGDEBUG, "R %02d (VPU)\n", m_idx);
++#endif
++ }
++ }
++ else if (count == 0)
++ {
++ delete this;
++ }
++
++ return count;
++}
++
++bool CDVDVideoCodecIMXBuffer::IsValid()
++{
++ return m_frameBuffer != NULL;
++}
++
++bool CDVDVideoCodecIMXBuffer::Rendered() const
++{
++ return m_rendered;
++}
++
++void CDVDVideoCodecIMXBuffer::Queue(VpuDecOutFrameInfo *frameInfo,
++ CDVDVideoCodecIMXBuffer *previous)
++{
++ // No lock necessary because at this time there is definitely no
++ // thread still holding a reference
++ m_frameBuffer = frameInfo->pDisplayFrameBuf;
++ m_rendered = false;
++ m_previousBuffer = previous;
++ if (m_previousBuffer)
++ m_previousBuffer->Lock();
++
++ iWidth = frameInfo->pExtInfo->nFrmWidth;
++ iHeight = frameInfo->pExtInfo->nFrmHeight;
++ GET_VIRT_ADDR(this) = m_frameBuffer->pbufVirtY;
++ GET_PHYS_ADDR(this) = m_frameBuffer->pbufY;
++ GET_FIELDTYPE(this) = (uint8_t*)frameInfo->eFieldType;
++}
++
++VpuDecRetCode CDVDVideoCodecIMXBuffer::ReleaseFramebuffer(VpuDecHandle *handle)
++{
++ // Again no lock required because this is only issued after the last
++ // external reference was released
++ VpuDecRetCode ret = VPU_DEC_RET_FAILURE;
++
++ if((m_frameBuffer != NULL) && *handle)
++ {
++ ret = VPU_DecOutFrameDisplayed(*handle, m_frameBuffer);
++ if(ret != VPU_DEC_RET_SUCCESS)
++ CLog::Log(LOGERROR, "%s: vpu clear frame display failure: ret=%d \r\n",__FUNCTION__,ret);
++ }
++#ifdef TRACE_FRAMES
++ CLog::Log(LOGDEBUG, "- %02d (VPU)\n", m_idx);
++#endif
++ m_rendered = false;
++ m_frameBuffer = NULL;
++ m_pts = DVD_NOPTS_VALUE;
++ SAFE_RELEASE(m_previousBuffer);
++
++ return ret;
++}
++
++void CDVDVideoCodecIMXBuffer::SetPts(double pts)
++{
++ m_pts = pts;
++}
++
++double CDVDVideoCodecIMXBuffer::GetPts(void) const
++{
++ return m_pts;
++}
++
++CDVDVideoCodecIMXBuffer *CDVDVideoCodecIMXBuffer::GetPreviousBuffer() const
++{
++ return m_previousBuffer;
++}
++
++CDVDVideoCodecIMXBuffer::~CDVDVideoCodecIMXBuffer()
++{
++ assert(m_refs == 0);
++#ifdef TRACE_FRAMES
++ CLog::Log(LOGDEBUG, "~ %02d (VPU)\n", m_idx);
++#endif
++}
++
++#ifdef TRACE_FRAMES
++CDVDVideoCodecIPUBuffer::CDVDVideoCodecIPUBuffer(int idx)
++ : m_refs(1)
++ , m_idx(idx)
++#else
++CDVDVideoCodecIPUBuffer::CDVDVideoCodecIPUBuffer()
++ : m_refs(1)
++#endif
++ , m_source(NULL)
++ , m_pPhyAddr(NULL)
++ , m_pVirtAddr(NULL)
++ , m_nSize(0)
++{
++}
++
++CDVDVideoCodecIPUBuffer::~CDVDVideoCodecIPUBuffer()
++{
++ assert(m_refs == 0);
++#ifdef TRACE_FRAMES
++ CLog::Log(LOGDEBUG, "~ %02d (IPU)\n", m_idx);
++#endif
++}
++
++void CDVDVideoCodecIPUBuffer::Lock()
++{
++#ifdef TRACE_FRAMES
++ long count = AtomicIncrement(&m_refs);
++ CLog::Log(LOGDEBUG, "R+ %02d - ref : %d (IPU)\n", m_idx, count);
++#else
++ AtomicIncrement(&m_refs);
++#endif
++
++}
++
++long CDVDVideoCodecIPUBuffer::Release()
++{
++ long count = AtomicDecrement(&m_refs);
++#ifdef TRACE_FRAMES
++ CLog::Log(LOGDEBUG, "R- %02d - ref : %d (IPU)\n", m_idx, count);
++#endif
++ if (count == 1)
++ {
++ ReleaseFrameBuffer();
++ }
++ else if (count == 0)
++ {
++ delete this;
++ }
++
++ return count;
++}
++
++bool CDVDVideoCodecIPUBuffer::IsValid()
++{
++ return m_source && m_source->IsValid() && m_pPhyAddr;
++}
++
++bool CDVDVideoCodecIPUBuffer::Process(int fd, CDVDVideoCodecIMXBuffer *buffer,
++ VpuFieldType fieldType, int fieldFmt,
++ bool lowMotion)
++{
++ CDVDVideoCodecIMXBuffer *previousBuffer;
++ struct ipu_task task;
++ memset(&task, 0, sizeof(task));
++ task.priority = IPU_TASK_PRIORITY_HIGH;
++
++ if (lowMotion)
++ previousBuffer = buffer->GetPreviousBuffer();
++ else
++ previousBuffer = NULL;
++
++ SAFE_RELEASE(m_source);
++
++ iWidth = buffer->iWidth;
++ iHeight = buffer->iHeight;
++
++ // Input is the VPU decoded frame
++ task.input.width = iWidth;
++ task.input.height = iHeight;
++ task.input.format = IPU_PIX_FMT_NV12;
++
++ // Output is our IPU buffer
++ task.output.width = iWidth;
++ task.output.height = iHeight;
++ task.output.format = IPU_PIX_FMT_NV12;
++ task.output.paddr = (int)GET_PHYS_ADDR(this);
++
++ // Fill current and next buffer address
++ if (lowMotion && previousBuffer && previousBuffer->IsValid())
++ {
++ task.input.paddr = (int)GET_PHYS_ADDR(previousBuffer);
++ task.input.paddr_n = (int)GET_PHYS_ADDR(buffer);
++ task.input.deinterlace.motion = LOW_MOTION;
++ }
++ else
++ {
++ task.input.paddr = (int)GET_PHYS_ADDR(buffer);
++ task.input.deinterlace.motion = HIGH_MOTION;
++ }
++
++ task.input.deinterlace.enable = 1;
++ task.input.deinterlace.field_fmt = fieldFmt;
++
++ switch (fieldType)
++ {
++ case VPU_FIELD_TOP:
++ case VPU_FIELD_TB:
++ task.input.deinterlace.field_fmt |= IPU_DEINTERLACE_FIELD_TOP;
++ break;
++ case VPU_FIELD_BOTTOM:
++ case VPU_FIELD_BT:
++ task.input.deinterlace.field_fmt |= IPU_DEINTERLACE_FIELD_BOTTOM;
++ break;
++ default:
++ break;
++ }
++
++#ifdef IMX_PROFILE
++ unsigned int time = XbmcThreads::SystemClockMillis();
++#endif
++ int ret = ioctl(fd, IPU_QUEUE_TASK, &task);
++#ifdef IMX_PROFILE
++ CLog::Log(LOGDEBUG, "DEINT: tm:%d\n", XbmcThreads::SystemClockMillis() - time);
++#endif
++ if (ret < 0)
++ {
++ CLog::Log(LOGERROR, "IPU task failed: %s\n", strerror(errno));
++ return false;
++ }
++
++ buffer->Lock();
++
++ // Remember the source buffer. This is actually not necessary since the output
++ // buffer is the one that is used by the renderer. But keep it bound for now
++ // since this state is used in IsValid which then needs to become a flag in
++ // this class.
++ m_source = buffer;
++ m_source->Lock();
++
++ buffer->Release();
++
++ return true;
++}
++
++void CDVDVideoCodecIPUBuffer::ReleaseFrameBuffer()
++{
++#ifdef TRACE_FRAMES
++ CLog::Log(LOGDEBUG, "- %02d (IPU)\n", m_idx);
++#endif
++ CSingleLock lock(CDVDVideoCodecIMX::m_codecBufferLock);
++ SAFE_RELEASE(m_source);
++}
++
++bool CDVDVideoCodecIPUBuffer::Allocate(int fd, int width, int height, int nAlign)
++{
++ m_iWidth = Align(width,FRAME_ALIGN);
++ m_iHeight = Align(height,(2*FRAME_ALIGN));
++ // NV12 == 12 bpp
++ m_nSize = m_iWidth*m_iHeight*12/8;
++ m_pPhyAddr = m_nSize;
++
++ GET_PHYS_ADDR(this) = GET_VIRT_ADDR(this) = NULL;
++
++ int r = ioctl(fd, IPU_ALLOC, &m_pPhyAddr);
++ if (r < 0)
++ {
++ m_pPhyAddr = 0;
++ CLog::Log(LOGERROR, "ioctl IPU_ALLOC fail: disable deinterlacing: %s\n", strerror(errno));
++ return false;
++ }
++
++ CLog::Log(LOGNOTICE, "IPU: alloc %d bytes for frame of %dx%d at 0x%x\n",
++ m_nSize, m_iWidth, m_iHeight, m_pPhyAddr);
++
++ m_pVirtAddr = (uint8_t*)mmap(0, m_nSize, PROT_READ | PROT_WRITE, MAP_SHARED,
++ fd, m_pPhyAddr);
++ if (!m_pVirtAddr)
++ {
++ CLog::Log(LOGERROR, "IPU mmap failed: disable deinterlacing: %s\n", strerror(errno));
++ return false;
++ }
++
++ if (nAlign>1)
++ {
++ GET_PHYS_ADDR(this) = (uint8_t*)Align(m_pPhyAddr, nAlign);
++ GET_VIRT_ADDR(this) = (uint8_t*)Align(m_pVirtAddr, nAlign);
++ }
++ else
++ {
++ GET_PHYS_ADDR(this) = (uint8_t*)m_pPhyAddr;
++ GET_VIRT_ADDR(this) = (uint8_t*)m_pVirtAddr;
++ }
++
++ GET_DEINTERLACER(this) = NULL;
++
++ return true;
++}
++
++bool CDVDVideoCodecIPUBuffer::Free(int fd)
++{
++ CSingleLock lock(CDVDVideoCodecIMX::m_codecBufferLock);
++ bool ret = true;
++
++ // Unmap virtual memory
++ if (m_pVirtAddr != NULL)
++ {
++ if(munmap(m_pVirtAddr, m_nSize))
++ {
++ CLog::Log(LOGERROR, "IPU unmap failed: %s\n", strerror(errno));
++ ret = false;
++ }
++
++ m_pVirtAddr = NULL;
++ }
++
++ // Free IPU memory
++ if (m_pPhyAddr)
++ {
++ if (ioctl(fd, IPU_FREE, &m_pPhyAddr))
++ {
++ CLog::Log(LOGERROR, "IPU free buffer 0x%x failed: %s\n",
++ m_pPhyAddr, strerror(errno));
++ ret = false;
++ }
++
++ m_pPhyAddr = 0;
++ }
++
++ GET_PHYS_ADDR(this) = GET_VIRT_ADDR(this) = NULL;
++ SAFE_RELEASE(m_source);
++
++ return ret;
++}
++
++CDVDVideoCodecIPUBuffers::CDVDVideoCodecIPUBuffers()
++ : m_ipuHandle(0)
++ , m_bufferNum(0)
++ , m_buffers(NULL)
++ , m_currentFieldFmt(0)
++{
++}
++
++CDVDVideoCodecIPUBuffers::~CDVDVideoCodecIPUBuffers()
++{
++ Close();
++}
++
++bool CDVDVideoCodecIPUBuffers::Init(int width, int height, int numBuffers, int nAlign)
++{
++ if (numBuffers<=0)
++ {
++ CLog::Log(LOGERROR, "IPU Init: invalid number of buffers: %d\n", numBuffers);
++ return false;
++ }
++
++ m_ipuHandle = open("/dev/mxc_ipu", O_RDWR, 0);
++ if (m_ipuHandle<=0)
++ {
++ CLog::Log(LOGWARNING, "Failed to initialize IPU: deinterlacing disabled: %s\n",
++ strerror(errno));
++ m_ipuHandle = 0;
++ return false;
++ }
++
++ m_bufferNum = numBuffers;
++ m_buffers = new CDVDVideoCodecIPUBuffer*[m_bufferNum];
++ m_currentFieldFmt = 0;
++
++ for (int i=0; i < m_bufferNum; i++)
++ {
++#ifdef TRACE_FRAMES
++ m_buffers[i] = new CDVDVideoCodecIPUBuffer(i);
++#else
++ m_buffers[i] = new CDVDVideoCodecIPUBuffer;
++#endif
++ if (!m_buffers[i]->Allocate(m_ipuHandle, width, height, nAlign))
++ {
++ Close();
++ return false;
++ }
++ }
++
++ return true;
++}
++
++bool CDVDVideoCodecIPUBuffers::Reset()
++{
++ for (int i=0; i < m_bufferNum; i++)
++ m_buffers[i]->ReleaseFrameBuffer();
++ m_currentFieldFmt = 0;
++}
++
++bool CDVDVideoCodecIPUBuffers::Close()
++{
++ bool ret = true;
++
++ if (m_ipuHandle)
++ {
++ for (int i=0; i < m_bufferNum; i++)
++ {
++ if (m_buffers[i] == NULL ) continue;
++ if (!m_buffers[i]->Free(m_ipuHandle))
++ ret = false;
++ }
++
++ // Close IPU device
++ if (close(m_ipuHandle))
++ {
++ CLog::Log(LOGERROR, "IPU failed to close interface: %s\n", strerror(errno));
++ ret = false;
++ }
++
++ m_ipuHandle = 0;
++ }
++
++ if (m_buffers)
++ {
++ for (int i=0; i < m_bufferNum; i++)
++ SAFE_RELEASE(m_buffers[i]);
++
++ delete m_buffers;
++ m_buffers = NULL;
++ }
++
++ m_bufferNum = 0;
++ return true;
++}
++
++CDVDVideoCodecIPUBuffer *
++CDVDVideoCodecIPUBuffers::Process(CDVDVideoCodecBuffer *sourceBuffer,
++ VpuFieldType fieldType, bool lowMotion)
++{
++ CDVDVideoCodecIPUBuffer *target = NULL;
++ bool ret = true;
++
++ // TODO: Needs further checks on real streams
++ if (!m_bufferNum /*|| (fieldType == VPU_FIELD_NONE)*/)
++ return NULL;
++
++ for (int i=0; i < m_bufferNum; i++ )
++ {
++ if (!m_buffers[i]->Rendered()) continue;
++
++ // IPU process:
++ // SRC: Current VPU physical buffer address + last VPU buffer address
++ // DST: IPU buffer[i]
++ ret = m_buffers[i]->Process(m_ipuHandle, (CDVDVideoCodecIMXBuffer*)sourceBuffer,
++ fieldType, m_currentFieldFmt/* | IPU_DEINTERLACE_RATE_EN*/,
++ lowMotion);
++ if (ret)
++ {
++#ifdef TRACE_FRAMES
++ CLog::Log(LOGDEBUG, "+ %02d (IPU)\n", i);
++#endif
++ target = m_buffers[i];
++ }
++ break;
++ }
++
++ // Buffers are there but there is no free one, this is an error!
++ // Rendering will continue with unprocessed frames ...
++ if (ret && target==NULL)
++ {
++ CLog::Log(LOGERROR, "Deinterlacing: did not find free buffer, forward unprocessed frame\n");
++ }
++
++ // Toggle frame index bit
++ //m_currentFieldFmt ^= IPU_DEINTERLACE_RATE_FRAME1;
++
++ return target;
++}
+diff -Naur xbmc-13b4/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.h xbmc-imx6-13b4/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.h
+--- xbmc-13b4/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.h 1970-01-01 01:00:00.000000000 +0100
++++ xbmc-imx6-13b4/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.h 2014-04-24 11:50:14.007208425 +0200
+@@ -0,0 +1,215 @@
++#pragma once
++/*
++ * Copyright (C) 2010-2013 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
++#include
++#include "DVDVideoCodec.h"
++#include "DVDStreamInfo.h"
++#include "DVDVideoCodecInfo.h"
++#include "threads/CriticalSection.h"
++#include "utils/BitstreamConverter.h"
++
++
++//#define IMX_PROFILE
++//#define TRACE_FRAMES
++
++class CDecMemInfo
++{
++public:
++ CDecMemInfo()
++ : nVirtNum(0)
++ , virtMem(NULL)
++ , nPhyNum(0)
++ , phyMem(NULL)
++ {}
++
++ //virtual mem info
++ int nVirtNum;
++ void** virtMem;
++
++ //phy mem info
++ int nPhyNum;
++ VpuMemDesc* phyMem;
++};
++
++class CDVDVideoCodecIPUBuffer;
++
++class CDVDVideoCodecIMXBuffer : public CDVDVideoCodecBuffer
++{
++public:
++#ifdef TRACE_FRAMES
++ CDVDVideoCodecIMXBuffer(int idx);
++#else
++ CDVDVideoCodecIMXBuffer();
++#endif
++
++ // reference counting
++ virtual void Lock();
++ virtual long Release();
++ virtual bool IsValid();
++
++ bool Rendered() const;
++ void Queue(VpuDecOutFrameInfo *frameInfo,
++ CDVDVideoCodecIMXBuffer *previous);
++ VpuDecRetCode ReleaseFramebuffer(VpuDecHandle *handle);
++ void SetPts(double pts);
++ double GetPts(void) const;
++ CDVDVideoCodecIMXBuffer *GetPreviousBuffer() const;
++
++private:
++ // private because we are reference counted
++ virtual ~CDVDVideoCodecIMXBuffer();
++
++private:
++#ifdef TRACE_FRAMES
++ int m_idx;
++#endif
++ long m_refs;
++ VpuFrameBuffer *m_frameBuffer;
++ bool m_rendered;
++ double m_pts;
++ CDVDVideoCodecIMXBuffer *m_previousBuffer; // Holds a the reference counted
++ // previous buffer
++};
++
++// Shared buffer that holds an IPU allocated memory block and serves as target
++// for IPU operations such as deinterlacing, rotation or color conversion.
++class CDVDVideoCodecIPUBuffer : public CDVDVideoCodecBuffer
++{
++public:
++#ifdef TRACE_FRAMES
++ CDVDVideoCodecIPUBuffer(int idx);
++#else
++ CDVDVideoCodecIPUBuffer();
++#endif
++
++ // reference counting
++ virtual void Lock();
++ virtual long Release();
++ virtual bool IsValid();
++
++ // Returns whether the buffer is ready to be used
++ bool Rendered() const { return m_source == NULL; }
++ bool Process(int fd, CDVDVideoCodecIMXBuffer *buffer,
++ VpuFieldType fieldType, int fieldFmt,
++ bool lowMotion);
++ void ReleaseFrameBuffer();
++
++ bool Allocate(int fd, int width, int height, int nAlign);
++ bool Free(int fd);
++
++private:
++ virtual ~CDVDVideoCodecIPUBuffer();
++
++private:
++#ifdef TRACE_FRAMES
++ int m_idx;
++#endif
++ long m_refs;
++ CDVDVideoCodecBuffer *m_source;
++ int m_pPhyAddr;
++ uint8_t *m_pVirtAddr;
++ int m_iWidth;
++ int m_iHeight;
++ int m_nSize;
++};
++
++// Collection class that manages a pool of IPU buffers that are used for
++// deinterlacing. In future they can also serve rotation or color conversion
++// buffers.
++class CDVDVideoCodecIPUBuffers
++{
++ public:
++ CDVDVideoCodecIPUBuffers();
++ ~CDVDVideoCodecIPUBuffers();
++
++ bool Init(int width, int height, int numBuffers, int nAlign);
++ bool Reset();
++ bool Close();
++
++ CDVDVideoCodecIPUBuffer *Process(CDVDVideoCodecBuffer *sourceBuffer,
++ VpuFieldType fieldType, bool lowMotion);
++
++ private:
++ int m_ipuHandle;
++ int m_bufferNum;
++ CDVDVideoCodecIPUBuffer **m_buffers;
++ int m_currentFieldFmt;
++};
++
++
++class CDVDVideoCodecIMX : public CDVDVideoCodec
++{
++ friend class CDVDVideoCodecIMXBuffer;
++ friend class CDVDVideoCodecIPUBuffer;
++
++public:
++ CDVDVideoCodecIMX();
++ virtual ~CDVDVideoCodecIMX();
++
++ // Methods from CDVDVideoCodec which require overrides
++ virtual bool Open(CDVDStreamInfo &hints, CDVDCodecOptions &options);
++ virtual void Dispose(void);
++ virtual int Decode(BYTE *pData, int iSize, double dts, double pts);
++ virtual void Reset(void);
++ virtual bool ClearPicture(DVDVideoPicture *pDvdVideoPicture);
++ virtual bool GetPicture(DVDVideoPicture *pDvdVideoPicture);
++ virtual void SetDropState(bool bDrop);
++ virtual const char* GetName(void) { return (const char*)m_pFormatName; }
++ virtual unsigned GetAllowedReferences();
++
++ static void Enter();
++ static void Leave();
++
++protected:
++
++ bool VpuOpen();
++ bool VpuAllocBuffers(VpuMemInfo *);
++ bool VpuFreeBuffers();
++ bool VpuAllocFrameBuffers();
++ int VpuFindBuffer(void *frameAddr);
++
++ static const int m_extraVpuBuffers; // Number of additional buffers for VPU
++ static const int m_maxVpuDecodeLoops; // Maximum iterations in VPU decoding loop
++ static CCriticalSection m_codecBufferLock;
++
++ CDVDStreamInfo m_hints; // Hints from demuxer at stream opening
++ const char *m_pFormatName; // Current decoder format name
++ VpuDecOpenParam m_decOpenParam; // Parameters required to call VPU_DecOpen
++ CDecMemInfo m_decMemInfo; // VPU dedicated memory description
++ VpuDecHandle m_vpuHandle; // Handle for VPU library calls
++ VpuDecInitInfo m_initInfo; // Initial info returned from VPU at decoding start
++ bool m_dropState; // Current drop state
++ int m_vpuFrameBufferNum; // Total number of allocated frame buffers
++ VpuFrameBuffer *m_vpuFrameBuffers; // Table of VPU frame buffers description
++ CDVDVideoCodecIPUBuffers m_deinterlacer;
++ CDVDVideoCodecIMXBuffer **m_outputBuffers;
++ CDVDVideoCodecIMXBuffer *m_lastBuffer;
++ VpuMemDesc *m_extraMem; // Table of allocated extra Memory
++ int m_frameCounter; // Decoded frames counter
++ bool m_usePTS; // State whether pts out of decoding process should be used
++ VpuDecOutFrameInfo m_frameInfo;
++ CBitstreamConverter *m_converter;
++ bool m_convert_bitstream;
++ int m_bytesToBeConsumed; // Remaining bytes in VPU
++ double m_previousPts; // Enable to keep pts when needed
++ bool m_frameReported; // State whether the frame consumed event will be reported by libfslvpu
++ double m_dts; // Current dts
++};
+diff -Naur xbmc-13b4/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecInfo.h xbmc-imx6-13b4/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecInfo.h
+--- xbmc-13b4/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecInfo.h 1970-01-01 01:00:00.000000000 +0100
++++ xbmc-imx6-13b4/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecInfo.h 2014-04-24 11:50:14.007208425 +0200
+@@ -0,0 +1,38 @@
++/*
++ * Copyright (C) 2010-2013 Team XBMC
++ * http://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
++ * .
++ *
++ */
++
++#ifndef DVDVIDEOCODECINFO_H
++#define DVDVIDEOCODECINFO_H
++
++class CDVDVideoCodecBuffer
++{
++public:
++ // reference counting
++ virtual void Lock() = 0;
++ virtual long Release() = 0;
++ virtual bool IsValid() = 0;
++
++ uint32_t iWidth;
++ uint32_t iHeight;
++ uint8_t* data[4]; // [4] = alpha channel, currently not used
++ int iLineSize[4]; // [4] = alpha channel, currently not used
++};
++
++#endif // DVDVIDEOCODECINFO_H
+diff -Naur xbmc-13b4/xbmc/cores/dvdplayer/DVDCodecs/Video/Makefile.in xbmc-imx6-13b4/xbmc/cores/dvdplayer/DVDCodecs/Video/Makefile.in
+--- xbmc-13b4/xbmc/cores/dvdplayer/DVDCodecs/Video/Makefile.in 2014-04-24 11:49:41.192078185 +0200
++++ xbmc-imx6-13b4/xbmc/cores/dvdplayer/DVDCodecs/Video/Makefile.in 2014-04-24 11:50:14.007208425 +0200
+@@ -24,6 +24,9 @@
+ SRCS += OpenMaxVideo.cpp
+ SRCS += DVDVideoCodecOpenMax.cpp
+ endif
++ifeq (@USE_IMXVPU@,1)
++SRCS += DVDVideoCodecIMX.cpp
++endif
+ ifeq (@USE_LIBAMCODEC@,1)
+ SRCS += AMLCodec.cpp
+ SRCS += DVDVideoCodecAmlogic.cpp
+diff -Naur xbmc-13b4/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp xbmc-imx6-13b4/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp
+--- xbmc-13b4/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp 2014-04-24 11:49:41.128079881 +0200
++++ xbmc-imx6-13b4/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp 2014-04-24 11:50:14.003208531 +0200
+@@ -995,6 +995,8 @@
+ case RENDER_FMT_EGLIMG: return "EGLIMG";
+ case RENDER_FMT_BYPASS: return "BYPASS";
+ case RENDER_FMT_MEDIACODEC:return "MEDIACODEC";
++ case RENDER_FMT_YV12_BUFFER: return "YV12BUF";
++ case RENDER_FMT_IMXMAP: return "IMXMAP";
+ case RENDER_FMT_NONE: return "NONE";
+ }
+ return "UNKNOWN";
+diff -Naur xbmc-13b4/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp xbmc-imx6-13b4/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp
+--- xbmc-13b4/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp 2014-04-24 11:49:41.300075322 +0200
++++ xbmc-imx6-13b4/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp 2014-04-24 11:50:14.011208319 +0200
+@@ -75,6 +75,17 @@
+ static PFNGLEGLIMAGETARGETTEXTURE2DOESPROC glEGLImageTargetTexture2DOES;
+ #endif
+
++#ifdef HAS_IMXVPU
++#include "windowing/egl/EGLWrapper.h"
++#include "DVDCodecs/Video/DVDVideoCodecIMX.h"
++
++#define GL_VIV_NV12 0x8FC1
++typedef void (GL_APIENTRYP PFNGLTEXDIRECTVIVMAPPROC) (GLenum Target, GLsizei Width, GLsizei Height, GLenum Format, GLvoid ** Logical, const GLuint * Physical);
++typedef void (GL_APIENTRYP PFNGLTEXDIRECTINVALIDATEVIVPROC) (GLenum Target);
++static PFNGLTEXDIRECTVIVMAPPROC glTexDirectVIVMap;
++static PFNGLTEXDIRECTINVALIDATEVIVPROC glTexDirectInvalidateVIV;
++#endif
++
+ #if defined(TARGET_ANDROID)
+ #include "DVDCodecs/Video/DVDVideoCodecAndroidMediaCodec.h"
+ #endif
+@@ -99,6 +110,7 @@
+ #if defined(TARGET_ANDROID)
+ mediacodec = NULL;
+ #endif
++ codecinfo = NULL;
+ }
+
+ CLinuxRendererGLES::YUVBUFFER::~YUVBUFFER()
+@@ -150,6 +162,12 @@
+ if (!glEGLImageTargetTexture2DOES)
+ glEGLImageTargetTexture2DOES = (PFNGLEGLIMAGETARGETTEXTURE2DOESPROC) CEGLWrapper::GetProcAddress("glEGLImageTargetTexture2DOES");
+ #endif
++#ifdef HAS_IMXVPU
++ if (!glTexDirectVIVMap)
++ glTexDirectVIVMap = (PFNGLTEXDIRECTVIVMAPPROC) CEGLWrapper::GetProcAddress("glTexDirectVIVMap");
++ if (!glTexDirectInvalidateVIV)
++ glTexDirectInvalidateVIV = (PFNGLTEXDIRECTINVALIDATEVIVPROC) CEGLWrapper::GetProcAddress("glTexDirectInvalidateVIV");
++#endif
+ }
+
+ CLinuxRendererGLES::~CLinuxRendererGLES()
+@@ -278,6 +296,10 @@
+ {
+ return source;
+ }
++ if ( m_renderMethod & RENDER_IMXMAP )
++ {
++ return source;
++ }
+
+ #ifdef HAVE_VIDEOTOOLBOXDECODER
+ if (m_renderMethod & RENDER_CVREF )
+@@ -603,6 +625,10 @@
+ #if defined(TARGET_ANDROID)
+ m_formats.push_back(RENDER_FMT_MEDIACODEC);
+ #endif
++ m_formats.push_back(RENDER_FMT_YV12_BUFFER);
++#ifdef HAS_IMXVPU
++ m_formats.push_back(RENDER_FMT_IMXMAP);
++#endif
+
+ // setup the background colour
+ m_clearColour = (float)(g_advancedSettings.m_videoBlackBarColour & 0xff) / 0xff;
+@@ -713,6 +739,16 @@
+ m_renderMethod = RENDER_MEDIACODEC;
+ break;
+ }
++ else if (m_format == RENDER_FMT_YV12_BUFFER)
++ {
++ CLog::Log(LOGNOTICE, "GL: Using YV12 Buffer render method");
++ }
++ else if (m_format == RENDER_FMT_IMXMAP)
++ {
++ CLog::Log(LOGNOTICE, "GL: Using IMXMAP render method");
++ m_renderMethod = RENDER_IMXMAP;
++ break;
++ }
+ else if (m_format == RENDER_FMT_BYPASS)
+ {
+ CLog::Log(LOGNOTICE, "GL: Using BYPASS render method");
+@@ -805,6 +841,18 @@
+ m_textureCreate = &CLinuxRendererGLES::CreateNV12Texture;
+ m_textureDelete = &CLinuxRendererGLES::DeleteNV12Texture;
+ }
++ else if (m_format == RENDER_FMT_YV12_BUFFER)
++ {
++ m_textureUpload = &CLinuxRendererGLES::UploadYV12BufferTexture;
++ m_textureCreate = &CLinuxRendererGLES::CreateYV12Texture;
++ m_textureDelete = &CLinuxRendererGLES::DeleteYV12Texture;
++ }
++ else if (m_format == RENDER_FMT_IMXMAP)
++ {
++ m_textureUpload = &CLinuxRendererGLES::UploadIMXMAPTexture;
++ m_textureCreate = &CLinuxRendererGLES::CreateIMXMAPTexture;
++ m_textureDelete = &CLinuxRendererGLES::DeleteIMXMAPTexture;
++ }
+ else
+ {
+ // default to YV12 texture handlers
+@@ -956,6 +1004,10 @@
+ {
+ RenderSurfaceTexture(index, m_currentField);
+ }
++ else if (m_renderMethod & RENDER_IMXMAP)
++ {
++ RenderIMXMAPTexture(index, m_currentField);
++ }
+ else
+ {
+ RenderSoftware(index, m_currentField);
+@@ -1160,7 +1212,7 @@
+ // imgwidth *= planes[0].pixpertex_x;
+ // imgheight *= planes[0].pixpertex_y;
+ // }
+-//
++//
+ // glBegin(GL_QUADS);
+ //
+ // glMultiTexCoord2fARB(GL_TEXTURE0, planes[0].rect.x1, planes[0].rect.y1);
+@@ -1582,6 +1634,85 @@
+ #endif
+ }
+
++void CLinuxRendererGLES::RenderIMXMAPTexture(int index, int field)
++{
++#if defined(HAS_IMXVPU)
++#ifdef DEBUG_VERBOSE
++ unsigned int time = XbmcThreads::SystemClockMillis();
++#endif
++
++ YUVPLANE &plane = m_buffers[index].fields[field][0];
++ CDVDVideoCodecBuffer* codecinfo = m_buffers[index].codecinfo;
++
++ if(codecinfo == NULL) return;
++
++ CDVDVideoCodecIMX::Enter();
++
++ if(!codecinfo->IsValid())
++ {
++ CDVDVideoCodecIMX::Leave();
++ return;
++ }
++
++ glDisable(GL_DEPTH_TEST);
++
++ glActiveTexture(GL_TEXTURE0);
++ glBindTexture(m_textureTarget, plane.id);
++
++ g_Windowing.EnableGUIShader(SM_TEXTURE_RGBA);
++
++ GLubyte idx[4] = {0, 1, 3, 2}; //determines order of triangle strip
++ GLfloat ver[4][4];
++ GLfloat tex[4][2];
++ GLfloat col[3] = {1.0f, 1.0f, 1.0f};
++
++ GLint posLoc = g_Windowing.GUIShaderGetPos();
++ GLint texLoc = g_Windowing.GUIShaderGetCoord0();
++ GLint colLoc = g_Windowing.GUIShaderGetCol();
++
++ glVertexAttribPointer(posLoc, 4, GL_FLOAT, 0, 0, ver);
++ glVertexAttribPointer(texLoc, 2, GL_FLOAT, 0, 0, tex);
++ glVertexAttribPointer(colLoc, 3, GL_FLOAT, 0, 0, col);
++
++ glEnableVertexAttribArray(posLoc);
++ glEnableVertexAttribArray(texLoc);
++ glEnableVertexAttribArray(colLoc);
++
++ // Set vertex coordinates
++ for(int i = 0; i < 4; i++)
++ {
++ ver[i][0] = m_rotatedDestCoords[i].x;
++ ver[i][1] = m_rotatedDestCoords[i].y;
++ ver[i][2] = 0.0f;// set z to 0
++ ver[i][3] = 1.0f;
++ }
++
++ // Set texture coordinates
++ tex[0][0] = tex[3][0] = plane.rect.x1;
++ tex[0][1] = tex[1][1] = plane.rect.y1;
++ tex[1][0] = tex[2][0] = plane.rect.x2;
++ tex[2][1] = tex[3][1] = plane.rect.y2;
++
++ glDrawElements(GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_BYTE, idx);
++
++ glDisableVertexAttribArray(posLoc);
++ glDisableVertexAttribArray(texLoc);
++ glDisableVertexAttribArray(colLoc);
++
++ g_Windowing.DisableGUIShader();
++ VerifyGLState();
++
++ glBindTexture(m_textureTarget, 0);
++ VerifyGLState();
++
++ CDVDVideoCodecIMX::Leave();
++
++#ifdef DEBUG_VERBOSE
++ CLog::Log(LOGDEBUG, "RenderIMXMAPTexture %d: tm:%d\n", index, XbmcThreads::SystemClockMillis() - time);
++#endif
++#endif
++}
++
+ bool CLinuxRendererGLES::RenderCapture(CRenderCapture* capture)
+ {
+ if (!m_bValidated)
+@@ -2303,7 +2434,7 @@
+
+ glTexParameteri(m_textureTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri(m_textureTarget, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+- // This is necessary for non-power-of-two textures
++ // This is necessary for non-power-of-two textures
+ glTexParameteri(m_textureTarget, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameteri(m_textureTarget, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
+@@ -2409,7 +2540,7 @@
+
+ glTexParameteri(m_textureTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri(m_textureTarget, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+- // This is necessary for non-power-of-two textures
++ // This is necessary for non-power-of-two textures
+ glTexParameteri(m_textureTarget, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameteri(m_textureTarget, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+
+@@ -2483,6 +2614,84 @@
+ return true;
+ }
+
++//********************************************************************************************************
++// Buffer creation, deletion, copying + clearing
++//********************************************************************************************************
++void CLinuxRendererGLES::UploadYV12BufferTexture(int index)
++{
++ YUVBUFFER& buf = m_buffers[index];
++ YV12Image* im = &buf.image;
++ YUVFIELDS& fields = buf.fields;
++
++ if (!buf.codecinfo || !(im->flags & IMAGE_FLAG_READY))
++ return;
++
++ bool deinterlacing;
++ if (m_currentField == FIELD_FULL)
++ deinterlacing = false;
++ else
++ deinterlacing = true;
++
++ glEnable(m_textureTarget);
++ VerifyGLState();
++
++ glPixelStorei(GL_UNPACK_ALIGNMENT,1);
++
++ if (deinterlacing)
++ {
++ // Load Even Y Field
++ LoadPlane( fields[FIELD_TOP][0] , GL_LUMINANCE, buf.flipindex
++ , im->width, im->height >> 1
++ , buf.codecinfo->iLineSize[0]*2, im->bpp, buf.codecinfo->data[0] );
++
++ // Load Odd Y fields
++ LoadPlane( fields[FIELD_BOT][0], GL_LUMINANCE, buf.flipindex
++ , im->width, im->height >> 1
++ , buf.codecinfo->iLineSize[0]*2, im->bpp, buf.codecinfo->data[0] + buf.codecinfo->iLineSize[0]) ;
++
++ // Load Even U & V Fields
++ LoadPlane( fields[FIELD_TOP][1], GL_LUMINANCE, buf.flipindex
++ , im->width >> im->cshift_x, im->height >> (im->cshift_y + 1)
++ , buf.codecinfo->iLineSize[1]*2, im->bpp, buf.codecinfo->data[1] );
++
++ LoadPlane( fields[FIELD_TOP][2], GL_ALPHA, buf.flipindex
++ , im->width >> im->cshift_x, im->height >> (im->cshift_y + 1)
++ , buf.codecinfo->iLineSize[2]*2, im->bpp, buf.codecinfo->data[2] );
++
++ // Load Odd U & V Fields
++ LoadPlane( fields[FIELD_BOT][1], GL_LUMINANCE, buf.flipindex
++ , im->width >> im->cshift_x, im->height >> (im->cshift_y + 1)
++ , buf.codecinfo->iLineSize[1]*2, im->bpp, buf.codecinfo->data[1] + buf.codecinfo->iLineSize[1] );
++
++ LoadPlane( fields[FIELD_BOT][2], GL_ALPHA, buf.flipindex
++ , im->width >> im->cshift_x, im->height >> (im->cshift_y + 1)
++ , buf.codecinfo->iLineSize[2]*2, im->bpp, buf.codecinfo->data[2] + buf.codecinfo->iLineSize[2] );
++ }
++ else
++ {
++ // Load Y plane
++ LoadPlane( fields[FIELD_FULL][0], GL_LUMINANCE, buf.flipindex
++ , im->width, im->height
++ , buf.codecinfo->iLineSize[0], im->bpp, buf.codecinfo->data[0] );
++
++ //load U plane
++ LoadPlane( fields[FIELD_FULL][1], GL_LUMINANCE, buf.flipindex
++ , im->width >> im->cshift_x, im->height >> im->cshift_y
++ , buf.codecinfo->iLineSize[1], im->bpp, buf.codecinfo->data[1] );
++
++ //load V plane
++ LoadPlane( fields[FIELD_FULL][2], GL_ALPHA, buf.flipindex
++ , im->width >> im->cshift_x, im->height >> im->cshift_y
++ , buf.codecinfo->iLineSize[2], im->bpp, buf.codecinfo->data[2] );
++ }
++
++ VerifyGLState();
++
++ CalculateTextureSourceRects(index, 3);
++
++ glDisable(m_textureTarget);
++}
++
+ void CLinuxRendererGLES::SetTextureFilter(GLenum method)
+ {
+ for (int i = 0 ; iIsValid())
++ {
++ CDVDVideoCodecIMX::Leave();
++ return;
++ }
++
++ YUVPLANE &plane = m_buffers[index].fields[0][0];
++ CDVDVideoCodecIPUBuffers *deinterlacer = (CDVDVideoCodecIPUBuffers*)codecinfo->data[2];
++
++ if (deinterlacer)
++ {
++ EDEINTERLACEMODE deinterlacemode = CMediaSettings::Get().GetCurrentVideoSettings().m_DeinterlaceMode;
++
++ if (deinterlacemode != VS_DEINTERLACEMODE_OFF)
++ {
++ CDVDVideoCodecBuffer *deint;
++ EINTERLACEMETHOD interlacemethod = CMediaSettings::Get().GetCurrentVideoSettings().m_InterlaceMethod;
++ deint = deinterlacer->Process(codecinfo, (VpuFieldType)(int)codecinfo->data[3],
++ interlacemethod == VS_INTERLACEMETHOD_DEINTERLACE);
++ if (deint)
++ {
++ SAFE_RELEASE(buf.codecinfo);
++ buf.codecinfo = deint;
++ buf.codecinfo->Lock();
++ codecinfo = buf.codecinfo;
++ }
++ }
++ }
++
++ glActiveTexture(GL_TEXTURE0);
++ glBindTexture(m_textureTarget, plane.id);
++
++ GLuint physical = ~0U;
++ GLvoid *virt = (GLvoid*)codecinfo->data[0];
++ glTexDirectVIVMap(m_textureTarget, codecinfo->iWidth, codecinfo->iHeight, GL_VIV_NV12,
++ (GLvoid **)&virt, &physical);
++ glTexDirectInvalidateVIV(m_textureTarget);
++
++ glBindTexture(m_textureTarget, 0);
++
++ plane.flipindex = m_buffers[index].flipindex;
++ plane.texwidth = codecinfo->iWidth;
++ plane.texheight = codecinfo->iHeight;
++
++ CalculateTextureSourceRects(index, 1);
++
++ CDVDVideoCodecIMX::Leave();
++ }
++
++#endif
++}
++void CLinuxRendererGLES::DeleteIMXMAPTexture(int index)
++{
++ YUVBUFFER &buf = m_buffers[index];
++ YUVPLANE &plane = buf.fields[0][0];
++
++ if(plane.id && glIsTexture(plane.id))
++ glDeleteTextures(1, &plane.id);
++ plane.id = 0;
++
++ SAFE_RELEASE(buf.codecinfo);
++}
++bool CLinuxRendererGLES::CreateIMXMAPTexture(int index)
++{
++ YV12Image &im = m_buffers[index].image;
++ YUVFIELDS &fields = m_buffers[index].fields;
++ YUVPLANE &plane = fields[0][0];
++
++ DeleteEGLIMGTexture(index);
++
++ memset(&im , 0, sizeof(im));
++ memset(&fields, 0, sizeof(fields));
++
++ im.height = m_sourceHeight;
++ im.width = m_sourceWidth;
++
++ plane.texwidth = 0; // Must be actual frame width for pseudo-cropping
++ plane.texheight = 0; // Must be actual frame height for pseudo-cropping
++ plane.pixpertex_x = 1;
++ plane.pixpertex_y = 1;
++
++ glEnable(m_textureTarget);
++ glGenTextures(1, &plane.id);
++ VerifyGLState();
++
++ glBindTexture(m_textureTarget, plane.id);
++
++ glTexParameteri(m_textureTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
++ glTexParameteri(m_textureTarget, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
++
++ glDisable(m_textureTarget);
++ return true;
++}
++
++
+ bool CLinuxRendererGLES::Supports(ERENDERFEATURE feature)
+ {
+ // Player controls render, let it dictate available render features
+@@ -2578,9 +2895,14 @@
+ if(m_renderMethod & RENDER_CVREF)
+ return false;
+
++#ifdef HAS_IMXVPU
++ if(mode == VS_DEINTERLACEMODE_AUTO)
++ return true;
++#else
+ if(mode == VS_DEINTERLACEMODE_AUTO
+ || mode == VS_DEINTERLACEMODE_FORCE)
+ return true;
++#endif
+
+ return false;
+ }
+@@ -2609,6 +2931,15 @@
+ if(method == VS_INTERLACEMETHOD_AUTO)
+ return true;
+
++ if(m_renderMethod & RENDER_IMXMAP)
++ {
++ if(method == VS_INTERLACEMETHOD_DEINTERLACE
++ || method == VS_INTERLACEMETHOD_DEINTERLACE_HALF)
++ return true;
++ else
++ return false;
++ }
++
+ #if defined(__i386__) || defined(__x86_64__)
+ if(method == VS_INTERLACEMETHOD_DEINTERLACE
+ || method == VS_INTERLACEMETHOD_DEINTERLACE_HALF
+@@ -2657,6 +2988,9 @@
+ if(m_renderMethod & RENDER_CVREF)
+ return VS_INTERLACEMETHOD_NONE;
+
++ if(m_renderMethod & RENDER_IMXMAP)
++ return VS_INTERLACEMETHOD_DEINTERLACE_HALF;
++
+ #if defined(__i386__) || defined(__x86_64__)
+ return VS_INTERLACEMETHOD_DEINTERLACE_HALF;
+ #else
+@@ -2741,5 +3075,16 @@
+ }
+ #endif
+
++void CLinuxRendererGLES::AddProcessor(CDVDVideoCodecBuffer *codecinfo, int index)
++{
++ YUVBUFFER &buf = m_buffers[index];
++
++ SAFE_RELEASE(buf.codecinfo);
++ buf.codecinfo = codecinfo;
++
++ if (codecinfo)
++ codecinfo->Lock();
++}
++
+ #endif
+
+diff -Naur xbmc-13b4/xbmc/cores/VideoRenderers/LinuxRendererGLES.h xbmc-imx6-13b4/xbmc/cores/VideoRenderers/LinuxRendererGLES.h
+--- xbmc-13b4/xbmc/cores/VideoRenderers/LinuxRendererGLES.h 2014-04-24 11:49:41.304075216 +0200
++++ xbmc-imx6-13b4/xbmc/cores/VideoRenderers/LinuxRendererGLES.h 2014-04-24 11:50:14.011208319 +0200
+@@ -33,6 +33,7 @@
+ #include "guilib/GraphicContext.h"
+ #include "BaseRenderer.h"
+ #include "xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodec.h"
++#include "xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecInfo.h"
+
+ class CRenderCapture;
+
+@@ -89,7 +90,8 @@
+ RENDER_CVREF = 0x080,
+ RENDER_BYPASS = 0x100,
+ RENDER_EGLIMG = 0x200,
+- RENDER_MEDIACODEC = 0x400
++ RENDER_MEDIACODEC = 0x400,
++ RENDER_IMXMAP = 0x800
+ };
+
+ enum RenderQuality
+@@ -173,6 +175,7 @@
+ // mediaCodec
+ virtual void AddProcessor(CDVDMediaCodecInfo *mediacodec, int index);
+ #endif
++ virtual void AddProcessor(CDVDVideoCodecBuffer *codecinfo, int index);
+
+ protected:
+ virtual void Render(DWORD flags, int index);
+@@ -212,6 +215,12 @@
+ void DeleteSurfaceTexture(int index);
+ bool CreateSurfaceTexture(int index);
+
++ void UploadYV12BufferTexture(int index);
++
++ void UploadIMXMAPTexture(int index);
++ void DeleteIMXMAPTexture(int index);
++ bool CreateIMXMAPTexture(int index);
++
+ void CalculateTextureSourceRects(int source, int num_planes);
+
+ // renderers
+@@ -222,6 +231,7 @@
+ void RenderEglImage(int index, int field); // Android OES texture
+ void RenderCoreVideoRef(int index, int field); // CoreVideo reference
+ void RenderSurfaceTexture(int index, int field);// MediaCodec rendering using SurfaceTexture
++ void RenderIMXMAPTexture(int index, int field); // IMXMAP rendering
+
+ CFrameBufferObject m_fbo;
+
+@@ -288,6 +298,7 @@
+ // mediacodec
+ CDVDMediaCodecInfo *mediacodec;
+ #endif
++ CDVDVideoCodecBuffer *codecinfo;
+ };
+
+ typedef YUVBUFFER YUVBUFFERS[NUM_BUFFERS];
+diff -Naur xbmc-13b4/xbmc/cores/VideoRenderers/RenderFormats.h xbmc-imx6-13b4/xbmc/cores/VideoRenderers/RenderFormats.h
+--- xbmc-13b4/xbmc/cores/VideoRenderers/RenderFormats.h 2014-04-24 11:49:41.300075322 +0200
++++ xbmc-imx6-13b4/xbmc/cores/VideoRenderers/RenderFormats.h 2014-04-24 11:50:14.011208319 +0200
+@@ -37,6 +37,8 @@
+ RENDER_FMT_BYPASS,
+ RENDER_FMT_EGLIMG,
+ RENDER_FMT_MEDIACODEC,
++ RENDER_FMT_YV12_BUFFER,
++ RENDER_FMT_IMXMAP,
+ };
+
+ #endif
+diff -Naur xbmc-13b4/xbmc/cores/VideoRenderers/RenderManager.cpp xbmc-imx6-13b4/xbmc/cores/VideoRenderers/RenderManager.cpp
+--- xbmc-13b4/xbmc/cores/VideoRenderers/RenderManager.cpp 2014-04-24 11:49:41.308075110 +0200
++++ xbmc-imx6-13b4/xbmc/cores/VideoRenderers/RenderManager.cpp 2014-04-24 11:50:14.011208319 +0200
+@@ -928,6 +928,10 @@
+ else if(pic.format == RENDER_FMT_MEDIACODEC)
+ m_pRenderer->AddProcessor(pic.mediacodec, index);
+ #endif
++#ifdef HAS_IMXVPU
++ else if(pic.format == RENDER_FMT_YV12_BUFFER || pic.format == RENDER_FMT_IMXMAP)
++ m_pRenderer->AddProcessor(pic.codecinfo, index);
++#endif
+
+ m_pRenderer->ReleaseImage(index, false);
+
+diff -Naur xbmc-13b4/xbmc/cores/VideoRenderers/VideoShaders/YUV2RGBShader.cpp xbmc-imx6-13b4/xbmc/cores/VideoRenderers/VideoShaders/YUV2RGBShader.cpp
+--- xbmc-13b4/xbmc/cores/VideoRenderers/VideoShaders/YUV2RGBShader.cpp 2014-04-24 11:49:41.304075216 +0200
++++ xbmc-imx6-13b4/xbmc/cores/VideoRenderers/VideoShaders/YUV2RGBShader.cpp 2014-04-24 11:50:14.011208319 +0200
+@@ -39,12 +39,12 @@
+ //
+ // Transformation matrixes for different colorspaces.
+ //
+-static float yuv_coef_bt601[4][4] =
++static float yuv_coef_bt601[4][4] =
+ {
+ { 1.0f, 1.0f, 1.0f, 0.0f },
+ { 0.0f, -0.344f, 1.773f, 0.0f },
+ { 1.403f, -0.714f, 0.0f, 0.0f },
+- { 0.0f, 0.0f, 0.0f, 0.0f }
++ { 0.0f, 0.0f, 0.0f, 0.0f }
+ };
+
+ static float yuv_coef_bt709[4][4] =
+@@ -55,7 +55,7 @@
+ { 0.0f, 0.0f, 0.0f, 0.0f }
+ };
+
+-static float yuv_coef_ebu[4][4] =
++static float yuv_coef_ebu[4][4] =
+ {
+ { 1.0f, 1.0f, 1.0f, 0.0f },
+ { 0.0f, -0.3960f, 2.029f, 0.0f },
+@@ -74,19 +74,19 @@
+ static float** PickYUVConversionMatrix(unsigned flags)
+ {
+ // Pick the matrix.
+-
++
+ switch(CONF_FLAGS_YUVCOEF_MASK(flags))
+ {
+ case CONF_FLAGS_YUVCOEF_240M:
+ return (float**)yuv_coef_smtp240m; break;
+ case CONF_FLAGS_YUVCOEF_BT709:
+ return (float**)yuv_coef_bt709; break;
+- case CONF_FLAGS_YUVCOEF_BT601:
++ case CONF_FLAGS_YUVCOEF_BT601:
+ return (float**)yuv_coef_bt601; break;
+ case CONF_FLAGS_YUVCOEF_EBU:
+ return (float**)yuv_coef_ebu; break;
+ }
+-
++
+ return (float**)yuv_coef_bt601;
+ }
+
+@@ -228,7 +228,7 @@
+ m_hProj = -1;
+ m_hModel = -1;
+ m_hAlpha = -1;
+- if (m_format == RENDER_FMT_YUV420P)
++ if (m_format == RENDER_FMT_YUV420P || m_format == RENDER_FMT_YV12_BUFFER)
+ m_defines += "#define XBMC_YV12\n";
+ else if (m_format == RENDER_FMT_NV12)
+ m_defines += "#define XBMC_NV12\n";
+diff -Naur xbmc-13b4/xbmc/input/linux/LinuxInputDevices.cpp xbmc-imx6-13b4/xbmc/input/linux/LinuxInputDevices.cpp
+diff -Naur xbmc-13b4/xbmc/powermanagement/PowerManager.cpp xbmc-imx6-13b4/xbmc/powermanagement/PowerManager.cpp
+diff -Naur xbmc-13b4/xbmc/windowing/egl/EGLNativeTypeIMX.cpp xbmc-imx6-13b4/xbmc/windowing/egl/EGLNativeTypeIMX.cpp
+--- xbmc-13b4/xbmc/windowing/egl/EGLNativeTypeIMX.cpp 1970-01-01 01:00:00.000000000 +0100
++++ xbmc-imx6-13b4/xbmc/windowing/egl/EGLNativeTypeIMX.cpp 2014-04-24 11:50:14.019208107 +0200
+@@ -0,0 +1,321 @@
++/*
++ * Copyright (C) 2011-2013 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
++#include "system.h"
++#include
++
++#include "EGLNativeTypeIMX.h"
++#include
++#include
++#include
++#include "utils/log.h"
++#include "utils/RegExp.h"
++#include "utils/StringUtils.h"
++#include "utils/Environment.h"
++#include "guilib/gui3d.h"
++#include "windowing/WindowingFactory.h"
++#include "cores/AudioEngine/AEFactory.h"
++#include
++
++CEGLNativeTypeIMX::CEGLNativeTypeIMX()
++ : m_display(NULL)
++ , m_window(NULL)
++{
++}
++
++CEGLNativeTypeIMX::~CEGLNativeTypeIMX()
++{
++}
++
++bool CEGLNativeTypeIMX::CheckCompatibility()
++{
++ std::ifstream file("/sys/class/graphics/fb0/fsl_disp_dev_property");
++ return file;
++}
++
++void CEGLNativeTypeIMX::Initialize()
++{
++ int fd;
++
++ fd = open("/dev/fb0",O_RDWR);
++ if (fd < 0)
++ {
++ CLog::Log(LOGERROR, "%s - Error while opening /dev/fb0.\n", __FUNCTION__);
++ return;
++ }
++
++ // Unblank the fb
++ if (ioctl(fd, FBIOBLANK, 0) < 0)
++ {
++ CLog::Log(LOGERROR, "%s - Error while unblanking fb0.\n", __FUNCTION__);
++ }
++
++ close(fd);
++
++ // Check if we can change the framebuffer resolution
++ fd = open("/sys/class/graphics/fb0/mode", O_RDWR);
++ if (fd >= 0)
++ {
++ CLog::Log(LOGNOTICE, "%s - graphics sysfs is writable", __FUNCTION__);
++ m_readonly = false;
++ }
++ else
++ {
++ CLog::Log(LOGNOTICE, "%s - graphics sysfs is read-only", __FUNCTION__);
++ m_readonly = true;
++ }
++ close(fd);
++
++ return;
++}
++
++void CEGLNativeTypeIMX::Destroy()
++{
++ struct fb_fix_screeninfo fixed_info;
++ void *fb_buffer;
++ int fd;
++
++ fd = open("/dev/fb0",O_RDWR);
++ if (fd < 0)
++ {
++ CLog::Log(LOGERROR, "%s - Error while opening /dev/fb0.\n", __FUNCTION__);
++ return;
++ }
++
++ ioctl( fd, FBIOGET_FSCREENINFO, &fixed_info);
++ // Black fb0
++ fb_buffer = mmap(NULL, fixed_info.smem_len, PROT_WRITE, MAP_SHARED, fd, 0);
++ if (fb_buffer == MAP_FAILED)
++ {
++ CLog::Log(LOGERROR, "%s - fb mmap failed %s.\n", __FUNCTION__, strerror(errno));
++ }
++ else
++ {
++ memset(fb_buffer, 0x0, fixed_info.smem_len);
++ munmap(fb_buffer, fixed_info.smem_len);
++ }
++
++ close(fd);
++
++ return;
++}
++
++bool CEGLNativeTypeIMX::CreateNativeDisplay()
++{
++ // Force double-buffering
++ CEnvironment::setenv("FB_MULTI_BUFFER", "2", 0);
++
++ // EGL will be rendered on fb0
++ m_display = fbGetDisplayByIndex(0);
++ m_nativeDisplay = &m_display;
++ return true;
++}
++
++bool CEGLNativeTypeIMX::CreateNativeWindow()
++{
++ m_window = fbCreateWindow(m_display, 0, 0, 0, 0);
++ m_nativeWindow = &m_window;
++ return true;
++}
++
++bool CEGLNativeTypeIMX::GetNativeDisplay(XBNativeDisplayType **nativeDisplay) const
++{
++ if (!nativeDisplay)
++ return false;
++ if (!m_nativeDisplay)
++ return false;
++ *nativeDisplay = (XBNativeDisplayType*)m_nativeDisplay;
++ return true;
++}
++
++bool CEGLNativeTypeIMX::GetNativeWindow(XBNativeWindowType **nativeWindow) const
++{
++ if (!nativeWindow)
++ return false;
++ if (!m_nativeWindow || !m_window)
++ return false;
++ *nativeWindow = (XBNativeWindowType*)m_nativeWindow;
++ return true;
++}
++
++bool CEGLNativeTypeIMX::DestroyNativeDisplay()
++{
++ if (m_display)
++ fbDestroyDisplay(m_display);
++ m_display = NULL;
++ return true;
++}
++
++bool CEGLNativeTypeIMX::DestroyNativeWindow()
++{
++ if (m_window)
++ fbDestroyWindow(m_window);
++ m_window = NULL;
++ return true;
++}
++
++bool CEGLNativeTypeIMX::GetNativeResolution(RESOLUTION_INFO *res) const
++{
++ std::string mode;
++ get_sysfs_str("/sys/class/graphics/fb0/mode", mode);
++ return ModeToResolution(mode, res);
++}
++
++bool CEGLNativeTypeIMX::SetNativeResolution(const RESOLUTION_INFO &res)
++{
++ if (m_readonly)
++ return false;
++
++ std::string mode;
++ get_sysfs_str("/sys/class/graphics/fb0/mode", mode);
++ if (res.strId == mode)
++ return false;
++
++ DestroyNativeWindow();
++ DestroyNativeDisplay();
++
++ set_sysfs_str("/sys/class/graphics/fb0/mode", res.strId);
++
++ CreateNativeDisplay();
++
++ CLog::Log(LOGDEBUG, "%s: %s",__FUNCTION__, res.strId.c_str());
++
++ // Reset AE
++ CAEFactory::DeviceChange();
++
++ return true;
++}
++
++bool CEGLNativeTypeIMX::ProbeResolutions(std::vector &resolutions)
++{
++ if (m_readonly)
++ return false;
++
++ std::string valstr;
++ get_sysfs_str("/sys/class/graphics/fb0/modes", valstr);
++ std::vector probe_str;
++ StringUtils::SplitString(valstr, "\n", probe_str);
++
++ resolutions.clear();
++ RESOLUTION_INFO res;
++ for (size_t i = 0; i < probe_str.size(); i++)
++ {
++ if(!StringUtils::StartsWith(probe_str[i], "S:"))
++ continue;
++ if(ModeToResolution(probe_str[i], &res))
++ resolutions.push_back(res);
++ }
++ return resolutions.size() > 0;
++}
++
++bool CEGLNativeTypeIMX::GetPreferredResolution(RESOLUTION_INFO *res) const
++{
++ return GetNativeResolution(res);
++}
++
++bool CEGLNativeTypeIMX::ShowWindow(bool show)
++{
++ // Force vsync by default
++ eglSwapInterval(g_Windowing.GetEGLDisplay(), 1);
++ EGLint result = eglGetError();
++ if(result != EGL_SUCCESS)
++ CLog::Log(LOGERROR, "EGL error in %s: %x",__FUNCTION__, result);
++
++ return false;
++}
++
++int CEGLNativeTypeIMX::get_sysfs_str(std::string path, std::string& valstr) const
++{
++ int len;
++ char buf[256] = {0};
++
++ int fd = open(path.c_str(), O_RDONLY);
++ if (fd >= 0)
++ {
++ while ((len = read(fd, buf, 255)) > 0)
++ valstr.append(buf, len);
++ close(fd);
++ }
++ else
++ {
++ CLog::Log(LOGERROR, "%s: error reading %s",__FUNCTION__, path.c_str());
++ valstr = "fail";
++ return -1;
++ }
++ return 0;
++}
++
++int CEGLNativeTypeIMX::set_sysfs_str(std::string path, std::string val) const
++{
++ int fd = open(path.c_str(), O_WRONLY);
++ if (fd >= 0)
++ {
++ val += '\n';
++ write(fd, val.c_str(), val.size());
++ close(fd);
++ return 0;
++ }
++ CLog::Log(LOGERROR, "%s: error writing %s",__FUNCTION__, path.c_str());
++ return -1;
++}
++
++bool CEGLNativeTypeIMX::ModeToResolution(std::string mode, RESOLUTION_INFO *res) const
++{
++ if (!res)
++ return false;
++
++ res->iWidth = 0;
++ res->iHeight= 0;
++
++ if(mode.empty())
++ return false;
++
++ std::string fromMode = StringUtils::Mid(mode, 2);
++ StringUtils::Trim(fromMode);
++
++ CRegExp split(true);
++ split.RegComp("([0-9]+)x([0-9]+)([pi])-([0-9]+)");
++ if (split.RegFind(fromMode) < 0)
++ return false;
++
++ int w = atoi(split.GetMatch(1).c_str());
++ int h = atoi(split.GetMatch(2).c_str());
++ std::string p = split.GetMatch(3);
++ int r = atoi(split.GetMatch(4).c_str());
++
++ res->iWidth = w;
++ res->iHeight= h;
++ res->iScreenWidth = w;
++ res->iScreenHeight= h;
++ res->fRefreshRate = r;
++ res->dwFlags = p[0] == 'p' ? D3DPRESENTFLAG_PROGRESSIVE : D3DPRESENTFLAG_INTERLACED;
++
++ res->iScreen = 0;
++ res->bFullScreen = true;
++ res->iSubtitles = (int)(0.965 * res->iHeight);
++ res->fPixelRatio = 1.0f;
++ res->strMode = StringUtils::Format("%dx%d @ %.2f%s - Full Screen", res->iScreenWidth, res->iScreenHeight, res->fRefreshRate,
++ res->dwFlags & D3DPRESENTFLAG_INTERLACED ? "i" : "");
++ res->strId = mode;
++
++ return res->iWidth > 0 && res->iHeight> 0;
++}
++
+diff -Naur xbmc-13b4/xbmc/windowing/egl/EGLNativeTypeIMX.h xbmc-imx6-13b4/xbmc/windowing/egl/EGLNativeTypeIMX.h
+--- xbmc-13b4/xbmc/windowing/egl/EGLNativeTypeIMX.h 1970-01-01 01:00:00.000000000 +0100
++++ xbmc-imx6-13b4/xbmc/windowing/egl/EGLNativeTypeIMX.h 2014-04-24 11:50:14.019208107 +0200
+@@ -0,0 +1,60 @@
++#pragma once
++
++/*
++ * Copyright (C) 2011-2013 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
++#include "EGLNativeType.h"
++#include "EGL/eglvivante.h"
++
++class CEGLNativeTypeIMX : public CEGLNativeType
++{
++public:
++ CEGLNativeTypeIMX();
++ virtual ~CEGLNativeTypeIMX();
++ virtual std::string GetNativeName() const { return "iMX"; }
++ virtual bool CheckCompatibility();
++ virtual void Initialize();
++ virtual void Destroy();
++ virtual int GetQuirks() { return EGL_QUIRK_NONE; }
++
++ virtual bool CreateNativeDisplay();
++ virtual bool CreateNativeWindow();
++ virtual bool GetNativeDisplay(XBNativeDisplayType **nativeDisplay) const;
++ virtual bool GetNativeWindow(XBNativeWindowType **nativeWindow) const;
++
++ virtual bool DestroyNativeWindow();
++ virtual bool DestroyNativeDisplay();
++
++ virtual bool GetNativeResolution(RESOLUTION_INFO *res) const;
++ virtual bool SetNativeResolution(const RESOLUTION_INFO &res);
++ virtual bool ProbeResolutions(std::vector &resolutions);
++ virtual bool GetPreferredResolution(RESOLUTION_INFO *res) const;
++
++ virtual bool ShowWindow(bool show);
++
++protected:
++ bool m_readonly;
++ int get_sysfs_str(std::string path, std::string& valstr) const;
++ int set_sysfs_str(std::string path, std::string val) const;
++ bool ModeToResolution(std::string mode, RESOLUTION_INFO *res) const;
++
++ EGLNativeDisplayType m_display;
++ EGLNativeWindowType m_window;
++};
+diff -Naur xbmc-13b4/xbmc/windowing/egl/EGLWrapper.cpp xbmc-imx6-13b4/xbmc/windowing/egl/EGLWrapper.cpp
+--- xbmc-13b4/xbmc/windowing/egl/EGLWrapper.cpp 2014-04-24 11:49:41.748063448 +0200
++++ xbmc-imx6-13b4/xbmc/windowing/egl/EGLWrapper.cpp 2014-04-24 11:50:14.019208107 +0200
+@@ -17,16 +17,17 @@
+ * .
+ *
+ */
+-
+ #include "system.h"
+
+ #ifdef HAS_EGL
+-
+ #include "utils/log.h"
+ #include "EGLNativeTypeAndroid.h"
+ #include "EGLNativeTypeAmlogic.h"
+ #include "EGLNativeTypeRaspberryPI.h"
+ #include "EGLNativeTypeWayland.h"
++#ifdef HAS_IMXVPU
++#include "EGLNativeTypeIMX.h"
++#endif
+ #include "EGLWrapper.h"
+
+ #define CheckError() m_result = eglGetError(); if(m_result != EGL_SUCCESS) CLog::Log(LOGERROR, "EGL error in %s: %x",__FUNCTION__, m_result);
+@@ -83,7 +84,11 @@
+ if ((nativeGuess = CreateEGLNativeType(implementation)) ||
+ (nativeGuess = CreateEGLNativeType(implementation)) ||
+ (nativeGuess = CreateEGLNativeType(implementation)) ||
+- (nativeGuess = CreateEGLNativeType(implementation)))
++ (nativeGuess = CreateEGLNativeType(implementation))
++#ifdef HAS_IMXFB
++ || (nativeGuess = CreateEGLNativeType(implementation))
++#endif
++ )
+ {
+ m_nativeTypes = nativeGuess;
+
+diff -Naur xbmc-13b4/xbmc/windowing/egl/Makefile.in xbmc-imx6-13b4/xbmc/windowing/egl/Makefile.in
+--- xbmc-13b4/xbmc/windowing/egl/Makefile.in 2014-04-24 11:49:41.736063766 +0200
++++ xbmc-imx6-13b4/xbmc/windowing/egl/Makefile.in 2014-04-24 11:50:14.019208107 +0200
+@@ -24,6 +24,10 @@
+ wayland/XBMCSurface.cpp
+ endif
+
++ifeq (@USE_IMXFB@,1)
++SRCS+= EGLNativeTypeIMX.cpp
++endif
++
+ LIB = windowing_egl.a
+
+ include ../../../Makefile.include
diff --git a/tools/mkpkg/mkpkg_xbmc b/tools/mkpkg/mkpkg_xbmc-helix
similarity index 98%
rename from tools/mkpkg/mkpkg_xbmc
rename to tools/mkpkg/mkpkg_xbmc-helix
index 0f761a2664..87a71f6af0 100755
--- a/tools/mkpkg/mkpkg_xbmc
+++ b/tools/mkpkg/mkpkg_xbmc-helix
@@ -19,10 +19,10 @@
# http://www.gnu.org/copyleft/gpl.html
################################################################################
-PKG_NAME="xbmc"
+PKG_NAME="xbmc-master"
PKG_VERSION=""
GIT_REPO="-b master git://github.com/xbmc/xbmc.git"
-DEST_DIR="$PKG_NAME-master"
+DEST_DIR="$PKG_NAME"
echo "getting sources..."
if [ ! -d $DEST_DIR-latest ]; then