From cf404a610b3aca20e1417aeaf0ccad41ae0d56ac Mon Sep 17 00:00:00 2001 From: Peter Vicman Date: Sat, 3 Sep 2016 10:45:19 +0200 Subject: [PATCH] projects/imx6: small fixes for kodi master --- .../kodi/kodi-100-krypton-from-mk01.patch | 18593 ---------------- .../patches/kodi/kodi-100-master-fixes.patch | 26 + 2 files changed, 26 insertions(+), 18593 deletions(-) delete mode 100644 projects/imx6/patches/kodi/kodi-100-krypton-from-mk01.patch create mode 100644 projects/imx6/patches/kodi/kodi-100-master-fixes.patch diff --git a/projects/imx6/patches/kodi/kodi-100-krypton-from-mk01.patch b/projects/imx6/patches/kodi/kodi-100-krypton-from-mk01.patch deleted file mode 100644 index 1f7217bd06..0000000000 --- a/projects/imx6/patches/kodi/kodi-100-krypton-from-mk01.patch +++ /dev/null @@ -1,18593 +0,0 @@ -From 37a1a171c6a6bf1a42e8c0b02882f5213c878485 Mon Sep 17 00:00:00 2001 -From: Peter Vicman -Date: Tue, 12 Jul 2016 19:03:46 +0200 -Subject: [PATCH] patch for kodi krypton from mk01 - -kodi base: f3ca4eaf9a803f0ae195854f088341b84f9253c9 -kodi mk01: - https://github.com/mk01/xbmc/tree/treeKrypton 0b3954d54c41c494e30143794ccfba0b690f926d - -+ small adaptions for kodi-17.0-alpha3-fc46cf2 (2 Aug 2016) ---- - Makefile.in | 1 + - .../resource.language.en_gb/resources/strings.po | 154 +- - configure.ac | 94 +- - project/cmake/addons/CMakeLists.txt | 3 +- - system/peripherals.xml | 13 +- - system/settings/imx6.xml | 28 +- - system/settings/settings.xml | 84 + - tools/EventClients/Clients/WiiRemote/Makefile | 2 +- - ...-data-before-VO-VOL-in-mpeg-4-over-mpegts.patch | 69 + - .../0001-Squashed-commit-of-the-following.patch | 2180 +++++++++++++ - ...vcodec-add-h264_mvc-codec-id-and-profiles.patch | 67 + - ...er-add-support-for-parsing-h264-mvc-NALUs.patch | 113 + - ...Signal-unsupported-GMC-with-more-than-one.patch | 48 + - .../73fde6f9f3d01f7fc0f3ae4b66f6c725f9fb1105.patch | 24 + - tools/depends/target/ffmpeg/Makefile | 45 +- - .../added_ARM_NEON_optimized_SAO_patches.patch | 3328 ++++++++++++++++++++ - tools/depends/target/ffmpeg/autobuild.sh | 9 +- - ...arsing_of_mvc_slices_in_some_corner_cases.patch | 66 + - ...hevcdsp_ARM_NEON_optimized_epel_functions.patch | 409 +++ - xbmc/Application.cpp | 119 +- - xbmc/Application.h | 11 +- - xbmc/PlayListPlayer.cpp | 3 - - xbmc/URL.cpp | 2 + - xbmc/Util.cpp | 14 +- - .../AudioEngine/Engines/ActiveAE/ActiveAE.cpp | 16 +- - .../AudioEngine/Engines/ActiveAE/ActiveAESink.cpp | 21 +- - .../Engines/ActiveAE/ActiveAEStream.cpp | 15 +- - xbmc/cores/AudioEngine/Sinks/AESinkALSA.cpp | 45 +- - xbmc/cores/AudioEngine/Sinks/AESinkALSA.h | 2 +- - xbmc/cores/IPlayer.h | 4 + - .../VideoPlayer/DVDCodecs/Video/DVDVideoCodec.h | 2 + - .../DVDCodecs/Video/DVDVideoCodecIMX.cpp | 1947 ++++++------ - .../VideoPlayer/DVDCodecs/Video/DVDVideoCodecIMX.h | 376 ++- - .../VideoPlayer/DVDDemuxers/DVDDemuxFFmpeg.cpp | 2 +- - xbmc/cores/VideoPlayer/VideoPlayerAudio.cpp | 2 + - xbmc/cores/VideoPlayer/VideoPlayerVideo.cpp | 7 + - .../VideoPlayer/VideoRenderers/BaseRenderer.cpp | 10 + - .../VideoRenderers/HwDecRender/RendererIMX.cpp | 63 +- - .../VideoRenderers/HwDecRender/RendererIMX.h | 2 + - .../VideoPlayer/VideoRenderers/RenderFlags.cpp | 5 + - .../cores/VideoPlayer/VideoRenderers/RenderFlags.h | 5 +- - .../VideoPlayer/VideoRenderers/RenderManager.cpp | 42 +- - xbmc/dbwrappers/Database.cpp | 3 + - xbmc/filesystem/CurlFile.cpp | 6 +- - xbmc/filesystem/DirectoryFactory.cpp | 8 +- - xbmc/filesystem/FileFactory.cpp | 8 +- - xbmc/guilib/Resolution.cpp | 113 +- - xbmc/guilib/Resolution.h | 9 +- - xbmc/input/linux/LinuxInputDevices.cpp | 11 + - xbmc/input/linux/LinuxInputDevices.h | 1 + - xbmc/interfaces/IAnnouncer.h | 7 +- - xbmc/interfaces/builtins/SystemBuiltins.cpp | 9 +- - xbmc/linux/RBP.cpp | 14 + - xbmc/linux/RBP.h | 3 + - xbmc/linux/imx/IMX.h | 135 +- - xbmc/messaging/ApplicationMessenger.h | 3 + - xbmc/music/MusicDatabase.cpp | 2 +- - xbmc/network/DNSNameCache.cpp | 86 +- - xbmc/network/DNSNameCache.h | 6 + - xbmc/network/Makefile.in | 1 + - xbmc/network/Network.cpp | 365 ++- - xbmc/network/Network.h | 271 +- - xbmc/network/NetworkServices.cpp | 7 +- - xbmc/network/TCPServer.cpp | 7 +- - xbmc/network/WakeOnAccess.cpp | 34 +- - xbmc/network/linux/Makefile | 1 + - xbmc/network/linux/NetworkLinux.cpp | 447 +-- - xbmc/network/linux/NetworkLinux.h | 59 +- - xbmc/network/linux/android-ifaddrs/Makefile | 6 + - xbmc/network/linux/android-ifaddrs/README.md | 6 + - xbmc/network/linux/android-ifaddrs/ifaddrs.c | 663 ++++ - xbmc/network/linux/android-ifaddrs/ifaddrs.h | 54 + - xbmc/network/osx/priv_netlink.h | 120 + - xbmc/peripherals/PeripheralTypes.h | 24 + - xbmc/peripherals/Peripherals.cpp | 12 + - xbmc/peripherals/Peripherals.h | 2 + - xbmc/peripherals/bus/Makefile.in | 1 + - xbmc/peripherals/bus/PeripheralBus.cpp | 16 + - xbmc/peripherals/bus/PeripheralBus.h | 3 + - .../bus/linux/PeripheralBusPLATFORMLibUdev.cpp | 142 + - .../bus/linux/PeripheralBusPLATFORMLibUdev.h | 47 + - .../bus/linux/PeripheralBusUSBLibUdev.cpp | 12 +- - .../bus/linux/PeripheralBusUSBLibUdev.h | 2 +- - xbmc/peripherals/bus/virtual/PeripheralBusCEC.cpp | 4 + - xbmc/peripherals/devices/Makefile.in | 1 + - xbmc/peripherals/devices/Peripheral.h | 12 + - xbmc/peripherals/devices/PeripheralCecAdapter.cpp | 121 +- - xbmc/peripherals/devices/PeripheralCecAdapter.h | 7 +- - xbmc/peripherals/devices/PeripheralVideo.cpp | 121 + - xbmc/peripherals/devices/PeripheralVideo.h | 62 + - xbmc/platform/xbmc.cpp | 16 +- - xbmc/powermanagement/linux/LogindUPowerSyscall.cpp | 10 +- - xbmc/powermanagement/linux/UPowerSyscall.cpp | 11 +- - xbmc/settings/DisplaySettings.cpp | 16 +- - xbmc/settings/Settings.cpp | 8 + - xbmc/settings/Settings.h | 7 + - xbmc/threads/platform/pthreads/ThreadImpl.cpp | 4 + - xbmc/utils/CPUInfo.cpp | 32 +- - xbmc/utils/CPUInfo.h | 1 + - xbmc/utils/Makefile.in | 1 + - xbmc/utils/RssReader.cpp | 2 +- - xbmc/utils/Screen.cpp | 147 + - xbmc/utils/Screen.h | 52 + - xbmc/utils/URIUtils.cpp | 72 +- - xbmc/utils/URIUtils.h | 5 + - xbmc/utils/Weather.cpp | 2 +- - xbmc/utils/log.cpp | 30 +- - xbmc/video/VideoReferenceClock.cpp | 3 +- - xbmc/video/dialogs/GUIDialogVideoOSD.cpp | 2 +- - xbmc/video/dialogs/GUIDialogVideoSettings.cpp | 4 + - xbmc/windowing/WinEvents.cpp | 19 + - xbmc/windowing/WinEvents.h | 1 + - xbmc/windowing/WinEventsLinux.cpp | 5 + - xbmc/windowing/WinEventsLinux.h | 1 + - xbmc/windowing/WinSystem.cpp | 4 +- - xbmc/windowing/egl/EGLEdid.cpp | 94 + - xbmc/windowing/egl/EGLEdid.h | 71 + - xbmc/windowing/egl/EGLNativeTypeIMX.cpp | 247 +- - xbmc/windowing/egl/EGLNativeTypeIMX.h | 20 +- - xbmc/windowing/egl/EGLWrapper.cpp | 1 + - xbmc/windowing/egl/Makefile.in | 1 + - xbmc/windowing/egl/WinSystemEGL.cpp | 64 +- - xbmc/windowing/egl/vc_hdmi.h | 565 ++++ - xbmc/windows/GUIMediaWindow.cpp | 4 +- - xbmc/windows/GUIWindowSystemInfo.cpp | 2 + - 125 files changed, 12150 insertions(+), 1880 deletions(-) - create mode 100644 tools/depends/target/ffmpeg/0001-Discard-data-before-VO-VOL-in-mpeg-4-over-mpegts.patch - create mode 100644 tools/depends/target/ffmpeg/0001-Squashed-commit-of-the-following.patch - create mode 100644 tools/depends/target/ffmpeg/0001-avcodec-add-h264_mvc-codec-id-and-profiles.patch - create mode 100644 tools/depends/target/ffmpeg/0001-h264_parser-add-support-for-parsing-h264-mvc-NALUs.patch - create mode 100644 tools/depends/target/ffmpeg/0001-mpeg4video-Signal-unsupported-GMC-with-more-than-one.patch - create mode 100644 tools/depends/target/ffmpeg/73fde6f9f3d01f7fc0f3ae4b66f6c725f9fb1105.patch - create mode 100644 tools/depends/target/ffmpeg/added_ARM_NEON_optimized_SAO_patches.patch - create mode 100644 tools/depends/target/ffmpeg/h264_parser_fix_parsing_of_mvc_slices_in_some_corner_cases.patch - create mode 100644 tools/depends/target/ffmpeg/hevcdsp_ARM_NEON_optimized_epel_functions.patch - create mode 100644 xbmc/network/linux/android-ifaddrs/Makefile - create mode 100644 xbmc/network/linux/android-ifaddrs/README.md - create mode 100644 xbmc/network/linux/android-ifaddrs/ifaddrs.c - create mode 100644 xbmc/network/linux/android-ifaddrs/ifaddrs.h - create mode 100644 xbmc/network/osx/priv_netlink.h - create mode 100644 xbmc/peripherals/bus/linux/PeripheralBusPLATFORMLibUdev.cpp - create mode 100644 xbmc/peripherals/bus/linux/PeripheralBusPLATFORMLibUdev.h - create mode 100644 xbmc/peripherals/devices/PeripheralVideo.cpp - create mode 100644 xbmc/peripherals/devices/PeripheralVideo.h - create mode 100644 xbmc/utils/Screen.cpp - create mode 100644 xbmc/utils/Screen.h - create mode 100644 xbmc/windowing/egl/EGLEdid.cpp - create mode 100644 xbmc/windowing/egl/EGLEdid.h - create mode 100644 xbmc/windowing/egl/vc_hdmi.h - -diff --git a/Makefile.in b/Makefile.in -index 957fb92..6f4ce9f 100644 ---- a/Makefile.in -+++ b/Makefile.in -@@ -171,6 +171,7 @@ DIRECTORY_ARCHIVES += xbmc/network/linux/network_linux.a - DIRECTORY_ARCHIVES += xbmc/powermanagement/android/powermanagement_android.a - DIRECTORY_ARCHIVES += xbmc/storage/android/storage_android.a - DIRECTORY_ARCHIVES += xbmc/windowing/X11/windowing_X11.a -+DIRECTORY_ARCHIVES += xbmc/network/linux/android-ifaddrs/android-ifaddrs.a - else - DIRECTORY_ARCHIVES += xbmc/input/joysticks/input_joysticks.a - DIRECTORY_ARCHIVES += xbmc/input/joysticks/generic/input_joysticks_generic.a -diff --git a/addons/resource.language.en_gb/resources/strings.po b/addons/resource.language.en_gb/resources/strings.po -index 028aa8f..d4ee85e 100644 ---- a/addons/resource.language.en_gb/resources/strings.po -+++ b/addons/resource.language.en_gb/resources/strings.po -@@ -5088,7 +5088,12 @@ msgctxt "#10524" - msgid "Movie information" - msgstr "" - --#empty strings from id 10525 to 11999 -+#: xbmc/settings/AdvancedSettings.cpp -+msgctxt "#10525" -+msgid "Verbose logging for the [B]PVR[/B] component" -+msgstr "" -+ -+#empty strings from id 10526 to 11999 - - #: xbmc/guilib/WindowIDs.h - msgctxt "#12000" -@@ -5579,7 +5584,12 @@ msgctxt "#13005" - msgid "Shutdown" - msgstr "" - --#empty strings from id 13006 to 13007 -+#empty strings from id 13006 -+ -+#: system/peripherals.xml -+msgctxt "#13007" -+msgid "Same as \"switching source\"" -+msgstr "" - - #: system/settings/settings.xml - msgctxt "#13008" -@@ -6083,7 +6093,12 @@ msgctxt "#13287" - msgid "Screen resolution:" - msgstr "" - --#empty strings from id 13288 to 13291 -+#: peripheral/devices/PeripheralVideo.cpp -+msgctxt "#13288" -+msgid "Probing available resolutions" -+msgstr "Probing available resolutions" -+ -+#empty strings from id 13289 to 13291 - - msgctxt "#13292" - msgid "A/V cable:" -@@ -6860,7 +6875,17 @@ msgctxt "#13557" - msgid "Skip delay" - msgstr "" - --#empty strings from id 13558 to 13599 -+#: system/settings/settings.xml -+msgctxt "#13558" -+msgid "Adjust display resolution" -+msgstr "" -+ -+#: system/settings/settings.xml -+msgctxt "#13559" -+msgid "Include interlaced modes" -+msgstr "" -+ -+#empty strings from id 13560 to 13599 - - #: system/settings/darwin.xml - msgctxt "#13600" -@@ -8745,16 +8770,40 @@ msgstr "" - #. Description of OSD video settings for deinterlace method with label #16334 - #: xbmc/video/dialogs/GUIDialogVideoSettings.cpp - msgctxt "#16334" --msgid "IMX - Fast motion" -+msgid "IMX - Bob (half)" - msgstr "" - - #. Description of OSD video settings for deinterlace method with label #16335 - #: xbmc/video/dialogs/GUIDialogVideoSettings.cpp - msgctxt "#16335" --msgid "IMX - Fast motion (double)" -+msgid "IMX - Bob" - msgstr "" - --#empty strings from id 16336 to 16399 -+#. Description of OSD video settings for deinterlace method with label #16336 -+#: xbmc/video/dialogs/GUIDialogVideoSettings.cpp -+msgctxt "#16336" -+msgid "IMX - Bob (inverted)" -+msgstr "" -+ -+#. Description of OSD video settings for deinterlace method with label #16337 -+#: xbmc/video/dialogs/GUIDialogVideoSettings.cpp -+msgctxt "#16337" -+msgid "IMX - Advanced (half)" -+msgstr "" -+ -+#. Description of OSD video settings for deinterlace method with label #16337 -+#: xbmc/video/dialogs/GUIDialogVideoSettings.cpp -+msgctxt "#16338" -+msgid "IMX - Advanced" -+msgstr "" -+ -+#. Description of OSD video settings for deinterlace method with label #16337 -+#: xbmc/video/dialogs/GUIDialogVideoSettings.cpp -+msgctxt "#16339" -+msgid "IMX - Weave" -+msgstr "" -+ -+#empty strings from id 16340 to 16399 - - #: xbmc/video/dialogs/GUIDialogVideoSettings.cpp - msgctxt "#16400" -@@ -11679,7 +11728,10 @@ msgctxt "#20260" - msgid "Secure Shell (SSH / SFTP)" - msgstr "" - --#empty string with id 20261 -+#: xbmc/network/GUIDialogNetworkSetup.cpp -+msgctxt "#20261" -+msgid "Apple Filing Protocol (AFP)" -+msgstr "" - - #: xbmc/storage/MediaManager.cpp - msgctxt "#20262" -@@ -16703,7 +16755,11 @@ msgctxt "#36171" - msgid "Select the zoom level that 4:3 videos are shown on widescreen displays." - msgstr "" - --#empty string with id 36172 -+#. Description of setting "Videos -> Playback -> Adjust display resolution" with label #13558 -+#: system/settings/settings.xml -+msgctxt "#36172" -+msgid "Allow the resolution of the display to be changed so that it best matches the video resolution." -+msgstr "" - - #. Description of setting with label #14109 "Short date format" - #: system/settings/settings.xml -@@ -16959,7 +17015,11 @@ msgctxt "#36218" - msgid "This category contains the electronic programming guide (EPG) settings." - msgstr "" - --#empty string with id 36219 -+#. Description of setting "Videos -> Playback -> Include interlaced modes" with label #13559 -+#: system/settings/settings.xml -+msgctxt "#36219" -+msgid "Interlaced modes will be used for interlaced content (deinterlacing will be deactivated)." -+msgstr "" - - #: system/settings/settings.xml - msgctxt "#36220" -@@ -19456,3 +19515,76 @@ msgstr "" - msgstr "" - - -+#. Label of setting "System -> Video output -> Refresh resolutions" -+#: system/settings/settings.xml -+msgctxt "#40000" -+msgid "Update available resolutions on Display device changes" -+msgstr "" -+ -+#. Description of setting "System -> Video output -> Refresh resolutions" -+#: system/settings/settings.xml -+msgctxt "#40001" -+msgid "Available resolutions will be updated on HDMI hotplug events. Currently active resolution will be matched agains new mode list. If new mode list doesn't provide same mode, closest mode will be used and changed to" -+msgstr "" -+ -+#. Label of "System -> Input devices -> HDMI Video -> Enable hotplug events be passed to Kodi" -+#: system/peripherals.xml -+msgctxt "#40002" -+msgid "Detect hotplug events" -+msgstr "" -+ -+#. Label of setting "System -> Video output -> Blank framebuffer" -+#: system/settings/settings.xml -+msgctxt "#40003" -+msgid "Intelligently power off/on GPU to save power" -+msgstr "" -+ -+#. Description of setting "System -> Video output -> Blank framebuffer" -+#: system/settings/settings.xml -+msgctxt "#40004" -+msgid "Kodi will powerdown the GPU (when not in use), thus provide significant powersavings. TV being powered OFF, Kodi no longer active source (CEC) or start of BlackScreensaver will trigger this action (HDMI Audio will be powered down too)" -+msgstr "" -+ -+#. Label of setting "System -> Network -> Restart services" -+#: system/settings/settings.xml -+msgctxt "#40005" -+msgid "Restart services on network change" -+msgstr "" -+ -+#. Description of setting "System -> Network -> Restart services" -+#: system/settings/settings.xml -+msgctxt "#40006" -+msgid "If physical network parameters change (add/remove of network card or interface), automatically restart all Kodi services (sevices will re-read network settings and use new network parameters)" -+msgstr "" -+ -+msgctxt "#40007" -+msgid "480p" -+msgstr "" -+ -+msgctxt "#40008" -+msgid "576p" -+msgstr "" -+ -+msgctxt "#40009" -+msgid "720p" -+msgstr "" -+ -+msgctxt "#40010" -+msgid "900" -+msgstr "" -+ -+msgctxt "#40011" -+msgid "1080p" -+msgstr "" -+ -+#. Label of setting "Settings -> Videos -> Minimum vertical resolution" -+#: system/settings/settings.xml -+msgctxt "#40012" -+msgid "Only modes having higher vertical resolution" -+msgstr "" -+ -+#. Label of setting "Settings -> Videos -> Allow non-CEA" -+#: system/settings/settings.xml -+msgctxt "#40013" -+msgid "Allow changing to non-CEA modes" -+msgstr "" -diff --git a/configure.ac b/configure.ac -index 8b330b0..f70ebb8 100644 ---- a/configure.ac -+++ b/configure.ac -@@ -190,6 +190,8 @@ librtmp_not_found="== Could not find libRTMP. RTMP support disabled. ==" - librtmp_disabled="== RTMP support disabled. ==" - libnfs_not_found="== Could not find libnfs. NFS client support disabled. ==" - libnfs_disabled="== NFS support disabled. ==" -+libafpclient_not_found="== Could not find libafpclient. AFP client support disabled. ==" -+libafpclient_disabled="== AFP support disabled. ==" - libshairplay_not_found="== Could not find libshairplay. ==" - samba_disabled="== SAMBA support disabled. ==" - libplist_not_found="== Could not find libplist. AirPlay support disabled. ==" -@@ -241,9 +243,9 @@ AC_ARG_WITH([platform], - - AC_ARG_ENABLE([optimizations], - [AS_HELP_STRING([--enable-optimizations], -- [enable optimization (default is yes)])], -+ [enable optimization (default is no)])], - [use_optimizations=$enableval], -- [use_optimizations=yes]) -+ [use_optimizations=no]) - - AC_ARG_ENABLE([gl], - [AS_HELP_STRING([--enable-gl], -@@ -341,6 +343,12 @@ AC_ARG_ENABLE([nfs], - [use_libnfs=$enableval], - [use_libnfs=auto]) - -+AC_ARG_ENABLE([afpclient], -+ [AS_HELP_STRING([--enable-afpclient], -+ [enable AFP support via libafpclient (default is auto)])], -+ [use_libafpclient=$enableval], -+ [use_libafpclient=auto]) -+ - AC_ARG_ENABLE([airplay], - [AS_HELP_STRING([--enable-airplay], - [enable AirPlay support(default is auto)])], -@@ -672,16 +680,38 @@ case $use_platform in - target_platform=target_raspberry_pi - use_neon=no - use_cpu=arm1176jzf-s -+ extrarpiflags=rpi1 -+ CFLAGS="$CFLAGS -pipe -O3 -mcpu=arm1176jzf-s -mtune=arm1176jzf-s -mfloat-abi=hard -mfpu=vfp -mabi=aapcs-linux -Wno-psabi -Wa,-mno-warn-deprecated -Wno-deprecated-declarations " -+ CXXFLAGS="$CXXFLAGS -pipe -O3 -mcpu=arm1176jzf-s -mtune=arm1176jzf-s -mfloat-abi=hard -mfpu=vfp -mabi=aapcs-linux -Wno-psabi -Wa,-mno-warn-deprecated -Wno-deprecated-declarations " -+ FFMPEG_EXTRACFLAGS="$FFMPEG_EXTRACFLAGS -pipe -O3 -mcpu=arm1176jzf-s -mtune=arm1176jzf-s -mfloat-abi=hard -mfpu=vfp -mabi=aapcs-linux -Wno-psabi -Wa,-mno-warn-deprecated -Wno-deprecated-declarations " -+ use_arch="arm" -+ ;; -+ cubox-i) -+ use_arch=armv7-a -+ target_platform="cubox-i" -+ use_static_ffmpeg=yes -+ use_joystick=no -+ use_sdl=no -+ use_hardcoded_tables="yes" -+ CFLAGS="$CFLAGS -pipe -O3 -march=armv7-a -mtune=cortex-a9 -mcpu=cortex-a9 -mfloat-abi=hard -mfpu=neon -mabi=aapcs-linux -Wno-psabi -Wa,-mno-warn-deprecated -Wno-deprecated-declarations " -+ CXXFLAGS="$CXXFLAGS -pipe -O3 -march=armv7-a -mtune=cortex-a9 -mcpu=cortex-a9 -mfloat-abi=hard -mfpu=neon -mabi=aapcs-linux -Wno-psabi -Wa,-mno-warn-deprecated -Wno-deprecated-declarations " -+ use_cpu=cortex-a9 -+ use_x11=no -+ use_neon=yes -+ ARCH=arm - ;; - raspberry-pi2) -+ use_arch=armv7-a - target_platform=target_raspberry_pi - use_neon=yes - use_cpu=cortex-a7 -+ extrarpiflags=rpi2 -+ CFLAGS="$CFLAGS -pipe -O3 -march=armv7-a -mfloat-abi=hard -mfpu=neon -mabi=aapcs-linux -Wno-psabi -Wa,-mno-warn-deprecated -Wno-deprecated-declarations " -+ CXXFLAGS="$CXXFLAGS -pipe -O3 -march=armv7-a -mfloat-abi=hard -mfpu=neon -mabi=aapcs-linux -Wno-psabi -Wa,-mno-warn-deprecated -Wno-deprecated-declarations " - ;; - esac - - if test "$target_platform" = "target_raspberry_pi" ; then -- use_arch="arm" - use_hardcoded_tables="yes" - use_openmax=no - CORE_SYSTEM_NAME=rbpi -@@ -785,10 +815,7 @@ if test "$host_vendor" = "apple" ; then - #arm/ios - LIBS="$LIBS -framework CoreFoundation" - fi --elif test "$target_platform" = "target_raspberry_pi"; then -- ARCH="arm" -- use_arch="arm" --elif test "$use_arch" = "arm"; then -+elif test "$use_arch" = "arm" || test "$ARCH" = "arm"; then - CFLAGS="$CFLAGS -mno-apcs-stack-check" - CXXFLAGS="$CXXFLAGS -mno-apcs-stack-check" - if test "$use_tegra" = "yes"; then -@@ -909,6 +936,17 @@ else - AC_MSG_NOTICE([Using Python $PYTHON_VERSION]) - fi - -+# i.MX6 -+if test "$target_platform" = "cubox-i"; then -+ 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 -+fi -+ - # Checks for platforms libraries. - if test "$use_gles" = "yes"; then - use_gl="no" -@@ -922,7 +960,12 @@ if test "$use_gles" = "yes"; then - AC_DEFINE([HAVE_LIBEGL],[1],["Define to 1 if you have the `EGL' library (-lEGL)."]) - AC_DEFINE([HAVE_LIBGLESV2],[1],["Define to 1 if you have the `GLESv2' library (-lGLESv2)."]) - AC_MSG_RESULT(== WARNING: OpenGLES support is assumed.) -- LIBS="$LIBS -lEGL -lGLESv2 -lbcm_host -lvcos -lvchiq_arm -lmmal -lmmal_core -lmmal_util -lvcsm" -+ INCLUDES="-I/opt/vc/include -I/opt/vc/include/interface/vmcs_host/linux/ -I/opt/vc/include/interface/vcos/pthreads $INCLUDES" -+ LIBS="$LIBS -L/opt/vc/lib -lEGL -lGLESv2 -lbcm_host -lvcos -lvchiq_arm -lmmal -lmmal_core -lmmal_util -lvcsm" -+ elif test "$target_platform" = "cubox-i"; then -+ AC_DEFINE([HAVE_LIBEGL],[1],["Define to 1 if you have the `EGL' library (-lEGL)."]) -+ AC_DEFINE([HAVE_LIBGLESV2],[1],["Define to 1 if you have the `GLESv2' library (-lGLESv2)."]) -+ LIBS="$LIBS -lEGL -lGLESv2 -lGAL " - else - AC_CHECK_LIB([EGL], [main],, AC_MSG_ERROR($missing_library)) - AC_CHECK_LIB([GLESv2],[main],, AC_MSG_ERROR($missing_library)) -@@ -1029,7 +1072,8 @@ int main() { - )]) - AC_LANG_POP([C++]) - --if test "${target_platform}" = "target_linux" || test "${target_platform}" = "target_raspberry_pi" || test "${target_platform}" = "target_android"; then -+if test "${target_platform}" = "target_linux" || test "${target_platform}" = "target_raspberry_pi" || test "${target_platform}" = "target_android" || \ -+ test "${target_platform}" = "cubox-i"; then - PKG_CHECK_MODULES([UUID], [uuid],, AC_MSG_ERROR(libuuid not found)) - fi - -@@ -1350,6 +1394,26 @@ else - AC_MSG_NOTICE($libnfs_disabled) - fi - -+# libafpclient -+USE_LIBAFPCLIENT=0 -+if test "x$use_libafpclient" != "xno"; then -+ AC_CHECK_HEADERS([afpfs-ng/libafpclient.h],, -+ [if test "x$use_libafpclient" = "xyes"; then -+ AC_MSG_ERROR($libafpclient_not_found) -+ elif test "x$use_libafpclient" != "xno"; then -+ AC_MSG_NOTICE($libafpclient_not_found) -+ use_libafpclient="no" -+ fi -+ ]) -+ if test "x$use_libafpclient" != "xno"; then -+ XB_FIND_SONAME([AFPCLIENT], [afpclient], [use_libafpclient]) -+ AC_DEFINE([HAVE_LIBAFPCLIENT], [1], [Whether to use libafpclient library.]) -+ USE_LIBAFPCLIENT=1 -+ fi -+else -+ AC_MSG_NOTICE($libafpclient_disabled) -+fi -+ - # libplist for airplay feature - USE_AIRPLAY=0 - if test "$use_airplay" != "no"; then -@@ -1535,6 +1599,8 @@ if test "${USE_STATIC_FFMPEG}" = "1"; then - FFMPEG_OPTS="${FFMPEG_OPTS} --disable-optimizations" - fi - -+ FFMPEG_OPTS="${FFMPEG_OPTS} --cpu=${use_cpu} --arch=${use_arch}" -+ - if test "$with_ffmpeg" = "auto" || test "$with_ffmpeg" = "yes"; then - SAVE_INCLUDES="$INCLUDES" - SAVE_LIBS="$LIBS" -@@ -1616,9 +1682,6 @@ final_message="$final_message\n SWIG Available:\tYes" - - echo "Checking for a jre installation" - AC_PATH_PROG(JAVA_EXE, java, "none") --if test "$JAVA_EXE" = "none"; then -- AC_MSG_ERROR($missing_program) --fi - final_message="$final_message\n JRE Available:\tYes" - - echo "Checking for doxygen installation" -@@ -2043,6 +2106,12 @@ else - final_message="$final_message\n libnfs client support:No" - fi - -+if test "x$use_libafpclient" != "xno"; then -+ final_message="$final_message\n libafpclient support:\tYes" -+else -+ final_message="$final_message\n libafpclient support:\tNo" -+fi -+ - if test "$use_airplay" != "no"; then - final_message="$final_message\n AirPlay support:\tYes" - else -@@ -2280,6 +2349,7 @@ AC_SUBST(USE_VDPAU) - AC_SUBST(USE_VAAPI) - AC_SUBST(USE_LIBSMBCLIENT) - AC_SUBST(USE_LIBNFS) -+AC_SUBST(USE_LIBAFPCLIENT) - AC_SUBST(USE_AIRPLAY) - AC_SUBST(USE_OPENMAX) - AC_SUBST(USE_PULSE) -diff --git a/project/cmake/addons/CMakeLists.txt b/project/cmake/addons/CMakeLists.txt -index d0f166f..f7c781a 100644 ---- a/project/cmake/addons/CMakeLists.txt -+++ b/project/cmake/addons/CMakeLists.txt -@@ -127,7 +127,6 @@ if(NOT ADDONS_TO_BUILD) - else() - string(STRIP "${ADDONS_TO_BUILD}" ADDONS_TO_BUILD) - message(STATUS "Building following addons: ${ADDONS_TO_BUILD}") -- separate_arguments(ADDONS_TO_BUILD) - endif() - - if(NOT ADDONS_DEFINITION_DIR) -@@ -230,6 +229,8 @@ endif() - # error either in ADDONS_TO_BUILD or in the directory configuration. - set(SUPPORTED_ADDON_FOUND FALSE) - -+separate_arguments(ADDONS_TO_BUILD) -+ - foreach(addon ${addons}) - if(NOT (addon MATCHES platforms.txt)) - file(STRINGS ${addon} def) -diff --git a/system/peripherals.xml b/system/peripherals.xml -index 67f6b7a..ea2b245 100644 ---- a/system/peripherals.xml -+++ b/system/peripherals.xml -@@ -16,11 +16,11 @@ - - - -- -- -- -+ -+ -+ -+ - -- - - - -@@ -44,4 +44,9 @@ - - - -+ -+ -+ -+ -+ - -diff --git a/system/settings/imx6.xml b/system/settings/imx6.xml -index b8c90a5..52e60e3 100644 ---- a/system/settings/imx6.xml -+++ b/system/settings/imx6.xml -@@ -2,10 +2,34 @@ - -
- -- -+ -+ -+ true -+ -+ -+ false -+ -+ -+ true -+ -+ -+ -+
-+
-+ -+ -+ -+ true -+ -+ -+ -+
-+
-+ -+ - - 2 -- 10 -+ 5 - - 0 - 5 -diff --git a/system/settings/settings.xml b/system/settings/settings.xml -index 5ba7bdb..8ef5874 100644 ---- a/system/settings/settings.xml -+++ b/system/settings/settings.xml -@@ -46,6 +46,67 @@ - - - -+ -+ 2 -+ 0 -+ -+ refreshchangedelays -+ -+ -+ 0 -+ -+ -+ -+ -+ 2 -+ false -+ true -+ -+ 0 -+ -+ -+ -+ -+ 2 -+ false -+ true -+ -+ true -+ -+ -+ -+ -+ 2 -+ false -+ true -+ -+ true -+ -+ -+ -+ -+ 2 -+ 720 -+ true -+ -+ true -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ 2 -+ false -+ -+ - - 1 - false -@@ -1953,6 +2014,15 @@ - - - -+ -+ 1 -+ false -+ false -+ -+ -+ -+ -+ - - - -@@ -2035,6 +2105,13 @@ - - - -+ -+ -+ 2 -+ true -+ -+ -+ - - - -@@ -3054,6 +3131,13 @@ - - - -+ -+ -+ 3 -+ false -+ -+ -+ - - - -diff --git a/tools/EventClients/Clients/WiiRemote/Makefile b/tools/EventClients/Clients/WiiRemote/Makefile -index eba0f1e..8bb41a5 100644 ---- a/tools/EventClients/Clients/WiiRemote/Makefile -+++ b/tools/EventClients/Clients/WiiRemote/Makefile -@@ -7,7 +7,7 @@ VERSION = v0.12 - - all: - @$(MAKE) -C wiiuse_$(VERSION)/src $@ -- $(CXX) $(CFLAGS) -I./wiiuse_$(VERSION)/src WiiUse_WiiRemote.cpp $(OBJS) -o $(BIN) -+ $(CXX) $(CFLAGS) -I./wiiuse_$(VERSION)/src WiiUse_WiiRemote.cpp $(OBJS) -o $(BIN) -l bluetooth - wiiuse: - @$(MAKE) -C wiiuse_$(VERSION)/src - clean: -diff --git a/tools/depends/target/ffmpeg/0001-Discard-data-before-VO-VOL-in-mpeg-4-over-mpegts.patch b/tools/depends/target/ffmpeg/0001-Discard-data-before-VO-VOL-in-mpeg-4-over-mpegts.patch -new file mode 100644 -index 0000000..eef7385 ---- /dev/null -+++ b/tools/depends/target/ffmpeg/0001-Discard-data-before-VO-VOL-in-mpeg-4-over-mpegts.patch -@@ -0,0 +1,69 @@ -+From ff289b3678b3b102f76c0fc0ffc802e3c8026fdb Mon Sep 17 00:00:00 2001 -+From: Deborah Crook -+Date: Thu, 5 Mar 2015 19:48:43 +0000 -+Subject: [PATCH] Discard data before VO/VOL in mpeg-4 over mpegts -+ -+--- -+ libavcodec/mpeg4video_parser.c | 26 ++++++++++++++++++++++---- -+ 1 file changed, 22 insertions(+), 4 deletions(-) -+ -+diff --git a/libavcodec/mpeg4video_parser.c b/libavcodec/mpeg4video_parser.c -+index aa5e87a..0d8b15a 100644 -+--- a/libavcodec/mpeg4video_parser.c -++++ b/libavcodec/mpeg4video_parser.c -+@@ -43,18 +43,32 @@ int ff_mpeg4_find_frame_end(ParseContext *pc, const uint8_t *buf, int buf_size) -+ state = pc->state; -+ -+ i = 0; -+- if (!vop_found) { -++ if (vop_found < 0) { -++ for (i = 0; i < buf_size; i++) { -++ state = (state << 8) | buf[i]; -++ if (state >= 0x100 && state <= 0x12f) { -++ i++; -++ vop_found = 0; -++ break; -++ } -++ } -++ } -++ -++ if (vop_found == 0) -++ vop_found = 1; -++ -++ if (vop_found == 1) { -+ for (i = 0; i < buf_size; i++) { -+ state = (state << 8) | buf[i]; -+ if (state == 0x1B6) { -+ i++; -+- vop_found = 1; -++ vop_found = 2; -+ break; -+ } -+ } -+ } -+ -+- if (vop_found) { -++ if (vop_found == 2) { -+ /* EOF considered as end of frame */ -+ if (buf_size == 0) -+ return 0; -+@@ -133,12 +147,16 @@ static int mpeg4video_parse(AVCodecParserContext *s, -+ ParseContext *pc = s->priv_data; -+ int next; -+ -++ if (pc->frame_start_found == 0 && !avctx->extradata) -++ pc->frame_start_found = -1; -++ -+ if (s->flags & PARSER_FLAG_COMPLETE_FRAMES) { -+ next = buf_size; -+ } else { -+ next = ff_mpeg4_find_frame_end(pc, buf, buf_size); -+ -+- if (ff_combine_frame(pc, next, &buf, &buf_size) < 0) { -++ if (pc->frame_start_found < 0 || -++ ff_combine_frame(pc, next, &buf, &buf_size) < 0) { -+ *poutbuf = NULL; -+ *poutbuf_size = 0; -+ return buf_size; -+-- -+2.1.4 -diff --git a/tools/depends/target/ffmpeg/0001-Squashed-commit-of-the-following.patch b/tools/depends/target/ffmpeg/0001-Squashed-commit-of-the-following.patch -new file mode 100644 -index 0000000..88adfab ---- /dev/null -+++ b/tools/depends/target/ffmpeg/0001-Squashed-commit-of-the-following.patch -@@ -0,0 +1,2180 @@ -+From ccb1eff2e6dd1259c6a8ca262076553875c5abe2 Mon Sep 17 00:00:00 2001 -+From: John Cox -+Date: Wed, 13 Jan 2016 16:13:33 +0000 -+Subject: [PATCH] H.265 residual decode rework (v2) -+ -+Rework the cabac decode functions -+Simplify the code flow and variable usage where possible -+ -+(Remove profiling and other spurious deltas that were in v1) -+--- -+ libavcodec/arm/cabac.h | 155 ++++- -+ libavcodec/arm/hevc_cabac.h | 491 +++++++++++++++ -+ libavcodec/arm/hevcdsp_deblock_neon.S | 13 +- -+ libavcodec/arm/hevcdsp_epel_neon.S | 9 +- -+ libavcodec/cabac.h | 9 +- -+ libavcodec/hevc_cabac.c | 1098 +++++++++++++++++++++++++-------- -+ 6 files changed, 1510 insertions(+), 265 deletions(-) -+ create mode 100644 libavcodec/arm/hevc_cabac.h -+ -+diff --git a/libavcodec/arm/cabac.h b/libavcodec/arm/cabac.h -+index fdbf86b..0a3980a 100644 -+--- a/libavcodec/arm/cabac.h -++++ b/libavcodec/arm/cabac.h -+@@ -26,13 +26,34 @@ -+ #include "libavutil/internal.h" -+ #include "libavcodec/cabac.h" -+ -++ -++#if UNCHECKED_BITSTREAM_READER -++#define LOAD_16BITS_BEHI\ -++ "ldrh %[tmp] , [%[ptr]] , #2 \n\t"\ -++ "rev %[tmp] , %[tmp] \n\t" -++#elif CONFIG_THUMB -++#define LOAD_16BITS_BEHI\ -++ "ldr %[tmp] , [%[c], %[end]] \n\t"\ -++ "cmp %[tmp] , %[ptr] \n\t"\ -++ "it cs \n\t"\ -++ "ldrhcs %[tmp] , [%[ptr]] , #2 \n\t"\ -++ "rev %[tmp] , %[tmp] \n\t" -++#else -++#define LOAD_16BITS_BEHI\ -++ "ldr %[tmp] , [%[c], %[end]] \n\t"\ -++ "cmp %[tmp] , %[ptr] \n\t"\ -++ "ldrcsh %[tmp] , [%[ptr]] , #2 \n\t"\ -++ "rev %[tmp] , %[tmp] \n\t" -++#endif -++ -++ -+ #define get_cabac_inline get_cabac_inline_arm -+ static av_always_inline int get_cabac_inline_arm(CABACContext *c, -+ uint8_t *const state) -+ { -+ int bit; -++#if 0 -+ void *reg_b, *reg_c, *tmp; -+- -+ __asm__ volatile( -+ "ldrb %[bit] , [%[state]] \n\t" -+ "add %[r_b] , %[tables] , %[lps_off] \n\t" -+@@ -100,9 +121,141 @@ static av_always_inline int get_cabac_inline_arm(CABACContext *c, -+ [mlps_off]"I"(H264_MLPS_STATE_OFFSET + 128) -+ : "memory", "cc" -+ ); -++#else -++ // *** Not thumb compatible yet -++ unsigned int reg_b, tmp; -++ __asm__ ( -++ "ldrb %[bit] , [%[state]] \n\t" -++ "sub %[r_b] , %[mlps_tables], %[lps_off] \n\t" -++ "and %[tmp] , %[range] , #0xC0 \n\t" -++ "add %[r_b] , %[r_b] , %[bit] \n\t" -++ "ldrb %[tmp] , [%[r_b] , %[tmp], lsl #1] \n\t" -++// %bit = *state -++// %range = range -++// %tmp = RangeLPS -++ "sub %[range] , %[range] , %[tmp] \n\t" -++ -++ "cmp %[low] , %[range] , lsl #17 \n\t" -++ "ittt ge \n\t" -++ "subge %[low] , %[low] , %[range], lsl #17 \n\t" -++ "mvnge %[bit] , %[bit] \n\t" -++ "movge %[range] , %[tmp] \n\t" -++ -++ "clz %[tmp] , %[range] \n\t" -++ "sub %[tmp] , #23 \n\t" -++ -++ "ldrb %[r_b] , [%[mlps_tables], %[bit]] \n\t" -++ "lsl %[low] , %[low] , %[tmp] \n\t" -++ "lsl %[range] , %[range] , %[tmp] \n\t" -++ -++ "strb %[r_b] , [%[state]] \n\t" -++ "lsls %[tmp] , %[low] , #16 \n\t" -++ -++ "bne 2f \n\t" -++ LOAD_16BITS_BEHI -++ "lsr %[tmp] , %[tmp] , #15 \n\t" -++ "movw %[r_b] , #0xFFFF \n\t" -++ "sub %[tmp] , %[tmp] , %[r_b] \n\t" -++ -++ "rbit %[r_b] , %[low] \n\t" -++ "clz %[r_b] , %[r_b] \n\t" -++ "sub %[r_b] , %[r_b] , #16 \n\t" -++#if CONFIG_THUMB -++ "lsl %[tmp] , %[tmp] , %[r_b] \n\t" -++ "add %[low] , %[low] , %[tmp] \n\t" -++#else -++ "add %[low] , %[low] , %[tmp], lsl %[r_b] \n\t" -++#endif -++ "2: \n\t" -++ : [bit]"=&r"(bit), -++ [low]"+&r"(c->low), -++ [range]"+&r"(c->range), -++ [r_b]"=&r"(reg_b), -++ [ptr]"+&r"(c->bytestream), -++ [tmp]"=&r"(tmp) -++ : [state]"r"(state), -++ [mlps_tables]"r"(ff_h264_cabac_tables + H264_MLPS_STATE_OFFSET + 128), -++ [byte]"M"(offsetof(CABACContext, bytestream)), -++#if !UNCHECKED_BITSTREAM_READER -++ [c]"r"(c), -++ [end]"M"(offsetof(CABACContext, bytestream_end)), -++#endif -++ [lps_off]"I"((H264_MLPS_STATE_OFFSET + 128) - H264_LPS_RANGE_OFFSET) -++ : "memory", "cc" -++ ); -++#endif -+ -+ return bit & 1; -+ } -++ -++#define get_cabac_bypass get_cabac_bypass_arm -++static inline int get_cabac_bypass_arm(CABACContext * const c) -++{ -++ int rv = 0; -++ unsigned int tmp; -++ __asm ( -++ "lsl %[low] , #1 \n\t" -++ "cmp %[low] , %[range] , lsl #17 \n\t" -++ "adc %[rv] , %[rv] , #0 \n\t" -++ "it cs \n\t" -++ "subcs %[low] , %[low] , %[range], lsl #17 \n\t" -++ "lsls %[tmp] , %[low] , #16 \n\t" -++ "bne 1f \n\t" -++ LOAD_16BITS_BEHI -++ "add %[low] , %[low] , %[tmp], lsr #15 \n\t" -++ "movw %[tmp] , #0xFFFF \n\t" -++ "sub %[low] , %[low] , %[tmp] \n\t" -++ "1: \n\t" -++ : // Outputs -++ [rv]"+&r"(rv), -++ [low]"+&r"(c->low), -++ [tmp]"=&r"(tmp), -++ [ptr]"+&r"(c->bytestream) -++ : // Inputs -++#if !UNCHECKED_BITSTREAM_READER -++ [c]"r"(c), -++ [end]"M"(offsetof(CABACContext, bytestream_end)), -++#endif -++ [range]"r"(c->range) -++ : "cc" -++ ); -++ return rv; -++} -++ -++ -++#define get_cabac_bypass_sign get_cabac_bypass_sign_arm -++static inline int get_cabac_bypass_sign_arm(CABACContext * const c, int rv) -++{ -++ unsigned int tmp; -++ __asm ( -++ "lsl %[low] , #1 \n\t" -++ "cmp %[low] , %[range] , lsl #17 \n\t" -++ "ite cc \n\t" -++ "rsbcc %[rv] , %[rv] , #0 \n\t" -++ "subcs %[low] , %[low] , %[range], lsl #17 \n\t" -++ "lsls %[tmp] , %[low] , #16 \n\t" -++ "bne 1f \n\t" -++ LOAD_16BITS_BEHI -++ "add %[low] , %[low] , %[tmp], lsr #15 \n\t" -++ "movw %[tmp] , #0xFFFF \n\t" -++ "sub %[low] , %[low] , %[tmp] \n\t" -++ "1: \n\t" -++ : // Outputs -++ [rv]"+&r"(rv), -++ [low]"+&r"(c->low), -++ [tmp]"=&r"(tmp), -++ [ptr]"+&r"(c->bytestream) -++ : // Inputs -++#if !UNCHECKED_BITSTREAM_READER -++ [c]"r"(c), -++ [end]"M"(offsetof(CABACContext, bytestream_end)), -++#endif -++ [range]"r"(c->range) -++ : "cc" -++ ); -++ return rv; -++} -++ -+ #endif /* HAVE_ARMV6T2_INLINE */ -+ -+ #endif /* AVCODEC_ARM_CABAC_H */ -+diff --git a/libavcodec/arm/hevc_cabac.h b/libavcodec/arm/hevc_cabac.h -+new file mode 100644 -+index 0000000..31d3c59 -+--- /dev/null -++++ b/libavcodec/arm/hevc_cabac.h -+@@ -0,0 +1,491 @@ -++/* -++ * This file is part of FFmpeg. -++ * -++ * FFmpeg is free software; you can redistribute it and/or -++ * modify it under the terms of the GNU Lesser General Public -++ * License as published by the Free Software Foundation; either -++ * version 2.1 of the License, or (at your option) any later version. -++ * -++ * FFmpeg is distributed in the hope that it will be useful, -++ * but WITHOUT ANY WARRANTY; without even the implied warranty of -++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -++ * Lesser General Public License for more details. -++ * -++ * You should have received a copy of the GNU Lesser General Public -++ * License along with FFmpeg; if not, write to the Free Software -++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -++ */ -++ -++#ifndef AVCODEC_ARM_HEVC_CABAC_H -++#define AVCODEC_ARM_HEVC_CABAC_H -++ -++#include "config.h" -++#if HAVE_ARMV6T2_INLINE -++ -++#define hevc_mem_bits32 hevc_mem_bits32_arm -++static inline uint32_t hevc_mem_bits32_arm(const void * p, const unsigned int bits) -++{ -++ unsigned int n; -++ __asm__ ( -++ "rev %[n], %[x] \n\t" -++ : [n]"=r"(n) -++ : [x]"r"(*(const uint32_t *)((const uint8_t *)p + (bits >> 3))) -++ : -++ ); -++ return n << (bits & 7); -++} -++ -++ -++// --------------------------------------------------------------------------- -++// -++// Helper fns - little bits of code where ARM has an instraction that the -++// compiler doesn't know about / use -++ -++#define trans_scale_sat trans_scale_sat_arm -++static inline int trans_scale_sat_arm(const int level, const unsigned int scale, const unsigned int scale_m, const unsigned int shift) -++{ -++ int rv; -++ int t = ((level * (int)(scale * scale_m)) >> shift) + 1; -++ -++ __asm__ ( -++ "ssat %[rv], #16, %[t], ASR #1 \n\t" -++ : [rv]"=r"(rv) -++ : [t]"r"(t) -++ : -++ ); -++ return rv; -++} -++ -++#define update_rice update_rice_arm -++static inline void update_rice_arm(uint8_t * const stat_coeff, -++ const unsigned int last_coeff_abs_level_remaining, -++ const unsigned int c_rice_param) -++{ -++ int t; -++ __asm__ ( -++ "lsl %[t], %[coeff], #1 \n\t" -++ "lsrs %[t], %[t], %[shift] \n\t" -++ "it eq \n\t" -++ "subeq %[stat], %[stat], #1 \n\t" -++ "cmp %[t], #6 \n\t" -++ "adc %[stat], %[stat], #0 \n\t" -++ "usat %[stat], #8, %[stat] \n\t" -++ : [stat]"+&r"(*stat_coeff), -++ [t]"=&r"(t) -++ : [coeff]"r"(last_coeff_abs_level_remaining), -++ [shift]"r"(c_rice_param) -++ : "cc" -++ ); -++} -++ -++// --------------------------------------------------------------------------- -++// -++// CABAC get loops -++// -++// Where the loop is simple enough we can normally do 10-30% better than the -++// compiler -++ -++// Get the residual greater than 1 bits -++ -++#define get_cabac_greater1_bits get_cabac_greater1_bits_arm -++static inline unsigned int get_cabac_greater1_bits_arm(CABACContext * const c, const unsigned int n, -++ uint8_t * const state0) -++{ -++ unsigned int i, reg_b, st, tmp, bit, rv; -++ __asm__ ( -++ "mov %[i] , #0 \n\t" -++ "mov %[rv] , #0 \n\t" -++ "1: \n\t" -++ "add %[i] , %[i] , #1 \n\t" -++ "cmp %[rv] , #0 \n\t" -++ "ite eq \n\t" -++ "usateq %[st] , #2 , %[i] \n\t" -++ "movne %[st] , #0 \n\t" -++ -++ "ldrb %[bit] , [%[state0], %[st]] \n\t" -++ "sub %[r_b] , %[mlps_tables], %[lps_off] \n\t" -++ "and %[tmp] , %[range] , #0xC0 \n\t" -++ "add %[r_b] , %[r_b] , %[bit] \n\t" -++ "ldrb %[tmp] , [%[r_b], %[tmp], lsl #1] \n\t" -++ "sub %[range] , %[range] , %[tmp] \n\t" -++ -++ "cmp %[low] , %[range], lsl #17 \n\t" -++ "ittt ge \n\t" -++ "subge %[low] , %[low] , %[range], lsl #17 \n\t" -++ "mvnge %[bit] , %[bit] \n\t" -++ "movge %[range] , %[tmp] \n\t" -++ -++ "ldrb %[r_b] , [%[mlps_tables], %[bit]] \n\t" -++ "and %[bit] , %[bit] , #1 \n\t" -++ "orr %[rv] , %[bit] , %[rv], lsl #1 \n\t" -++ -++ "clz %[tmp] , %[range] \n\t" -++ "sub %[tmp] , #23 \n\t" -++ -++ "lsl %[low] , %[low] , %[tmp] \n\t" -++ "lsl %[range] , %[range] , %[tmp] \n\t" -++ -++ "strb %[r_b] , [%[state0], %[st]] \n\t" -++// There is a small speed gain from combining both conditions, using a single -++// branch and then working out what that meant later -++ "lsls %[tmp] , %[low] , #16 \n\t" -++ "it ne \n\t" -++ "cmpne %[n] , %[i] \n\t" -++ "bne 1b \n\t" -++ -++// If reload is not required then we must have run out of flags to decode -++ "tst %[tmp] , %[tmp] \n\t" -++ "bne 2f \n\t" -++ -++// Do reload -++ "ldrh %[tmp] , [%[bptr]] , #2 \n\t" -++ "movw %[r_b] , #0xFFFF \n\t" -++ "rev %[tmp] , %[tmp] \n\t" -++ "rsb %[tmp] , %[r_b] , %[tmp], lsr #15 \n\t" -++ -++ "rbit %[r_b] , %[low] \n\t" -++ "clz %[r_b] , %[r_b] \n\t" -++ "sub %[r_b] , %[r_b] , #16 \n\t" -++ -++#if CONFIG_THUMB -++ "lsl %[tmp] , %[tmp] , %[r_b] \n\t" -++ "add %[low] , %[low] , %[tmp] \n\t" -++#else -++ "add %[low] , %[low] , %[tmp], lsl %[r_b] \n\t" -++#endif -++ -++ "cmp %[n] , %[i] \n\t" -++ "bne 1b \n\t" -++ "2: \n\t" -++ : [bit]"=&r"(bit), -++ [low]"+&r"(c->low), -++ [range]"+&r"(c->range), -++ [r_b]"=&r"(reg_b), -++ [bptr]"+&r"(c->bytestream), -++ [i]"=&r"(i), -++ [tmp]"=&r"(tmp), -++ [st]"=&r"(st), -++ [rv]"=&r"(rv) -++ : [state0]"r"(state0), -++ [n]"r"(n), -++ [mlps_tables]"r"(ff_h264_cabac_tables + H264_MLPS_STATE_OFFSET + 128), -++ [byte]"M"(offsetof(CABACContext, bytestream)), -++ [lps_off]"I"((H264_MLPS_STATE_OFFSET + 128) - H264_LPS_RANGE_OFFSET) -++ : "memory", "cc" -++ ); -++ return rv; -++} -++ -++ -++// n must be > 0 on entry -++#define get_cabac_sig_coeff_flag_idxs get_cabac_sig_coeff_flag_idxs_arm -++static inline uint8_t * get_cabac_sig_coeff_flag_idxs_arm(CABACContext * const c, uint8_t * const state0, -++ unsigned int n, -++ const uint8_t const * ctx_map, -++ uint8_t * p) -++{ -++ unsigned int reg_b, tmp, st, bit; -++ __asm__ ( -++ "1: \n\t" -++// Get bin from map -++ "ldrb %[st] , [%[ctx_map], %[n]] \n\t" -++ -++// Load state & ranges -++ "sub %[r_b] , %[mlps_tables], %[lps_off] \n\t" -++ "ldrb %[bit] , [%[state0], %[st]] \n\t" -++ "and %[tmp] , %[range] , #0xC0 \n\t" -++ "add %[r_b] , %[r_b] , %[tmp], lsl #1 \n\t" -++ "ldrb %[tmp] , [%[r_b], %[bit]] \n\t" -++ "sub %[range] , %[range] , %[tmp] \n\t" -++ -++ "cmp %[low] , %[range], lsl #17 \n\t" -++ "ittt ge \n\t" -++ "subge %[low] , %[low] , %[range], lsl #17 \n\t" -++ "mvnge %[bit] , %[bit] \n\t" -++ "movge %[range] , %[tmp] \n\t" -++ -++ "ldrb %[r_b] , [%[mlps_tables], %[bit]] \n\t" -++ "tst %[bit] , #1 \n\t" -++// GCC asm seems to need strbne written differently for thumb and arm -++#if CONFIG_THUMB -++ "it ne \n\t" -++ "strbne %[n] , [%[idx]] , #1 \n\t" -++#else -++ "strneb %[n] , [%[idx]] , #1 \n\t" -++#endif -++ -++// Renorm -++ "clz %[tmp] , %[range] \n\t" -++ "sub %[tmp] , #23 \n\t" -++ "lsl %[low] , %[low] , %[tmp] \n\t" -++ "lsl %[range] , %[range] , %[tmp] \n\t" -++ -++ "strb %[r_b] , [%[state0], %[st]] \n\t" -++// There is a small speed gain from combining both conditions, using a single -++// branch and then working out what that meant later -++ "subs %[n] , %[n] , #1 \n\t" -++#if CONFIG_THUMB -++ "itt ne \n\t" -++ "lslsne %[tmp] , %[low] , #16 \n\t" -++ "bne 1b \n\t" -++#else -++ "lslnes %[tmp] , %[low] , #16 \n\t" -++ "bne 1b \n\t" -++#endif -++ -++// If we have bits left then n must be 0 so give up now -++ "lsls %[tmp] , %[low] , #16 \n\t" -++ "bne 2f \n\t" -++ -++// Do reload -++ "ldrh %[tmp] , [%[bptr]] , #2 \n\t" -++ "movw %[r_b] , #0xFFFF \n\t" -++ "rev %[tmp] , %[tmp] \n\t" -++ "rsb %[tmp] , %[r_b] , %[tmp], lsr #15 \n\t" -++ -++ "rbit %[r_b] , %[low] \n\t" -++ "clz %[r_b] , %[r_b] \n\t" -++ "sub %[r_b] , %[r_b] , #16 \n\t" -++ -++#if CONFIG_THUMB -++ "lsl %[tmp] , %[tmp] , %[r_b] \n\t" -++ "add %[low] , %[low] , %[tmp] \n\t" -++#else -++ "add %[low] , %[low] , %[tmp], lsl %[r_b] \n\t" -++#endif -++ -++// Check to see if we still have more to do -++ "cmp %[n] , #0 \n\t" -++ "bne 1b \n\t" -++ "2: \n\t" -++ : [bit]"=&r"(bit), -++ [low]"+&r"(c->low), -++ [range]"+&r"(c->range), -++ [r_b]"=&r"(reg_b), -++ [bptr]"+&r"(c->bytestream), -++ [idx]"+&r"(p), -++ [n]"+&r"(n), -++ [tmp]"=&r"(tmp), -++ [st]"=&r"(st) -++ : [state0]"r"(state0), -++ [ctx_map]"r"(ctx_map), -++ [mlps_tables]"r"(ff_h264_cabac_tables + H264_MLPS_STATE_OFFSET + 128), -++ [byte]"M"(offsetof(CABACContext, bytestream)), -++ [lps_off]"I"((H264_MLPS_STATE_OFFSET + 128) - H264_LPS_RANGE_OFFSET) -++ : "memory", "cc" -++ ); -++ -++ return p; -++} -++ -++// --------------------------------------------------------------------------- -++// -++// CABAC_BY22 functions -++// -++// By and large these are (at best) no faster than their C equivalents - the -++// only one worth having is _peek where we do a slightly better job than the -++// compiler -++// -++// The others have been stashed here for reference in case larger scale asm -++// is attempted in which case they might be a useful base -++ -++ -++#define get_cabac_by22_peek get_cabac_by22_peek_arm -++static inline uint32_t get_cabac_by22_peek_arm(const CABACContext *const c) -++{ -++ uint32_t rv, tmp; -++ __asm__ ( -++ "bic %[rv] , %[low], #1 \n\t" -++ "cmp %[inv] , #0 \n\t" -++ "it ne \n\t" -++ "umullne %[tmp] , %[rv] , %[inv], %[rv] \n\t" -++ : // Outputs -++ [rv]"=&r"(rv), -++ [tmp]"=r"(tmp) -++ : // Inputs -++ [low]"r"(c->low), -++ [inv]"r"(c->range) -++ : // Clobbers -++ "cc" -++ ); -++ return rv << 1; -++} -++ -++#if 0 -++ -++// ***** Slower than the C :-( -++#define get_cabac_by22_flush get_cabac_by22_flush_arm -++static inline void get_cabac_by22_flush_arm(CABACContext *const c, const unsigned int n, const uint32_t val) -++{ -++ uint32_t m, tmp; -++ __asm__ ( -++ "add %[bits], %[bits], %[n] \n\t" -++ "ldr %[m], [%[ptr], %[bits], lsr #3] \n\t" -++ -++ "rsb %[tmp], %[n], #32 \n\t" -++ "lsr %[tmp], %[val], %[tmp] \n\t" -++ "mul %[tmp], %[range], %[tmp] \n\t" -++ -++ "rev %[m], %[m] \n\t" -++ -++ "lsl %[tmp], %[tmp], #23 \n\t" -++ "rsb %[low], %[tmp], %[low], lsl %[n] \n\t" -++ -++ "and %[tmp], %[bits], #7 \n\t" -++ "lsl %[m], %[m], %[tmp] \n\t" -++ -++ "orr %[low], %[low], %[m], lsr #9 \n\t" -++ : // Outputs -++ [m]"=&r"(m), -++ [tmp]"=&r"(tmp), -++ [bits]"+&r"(c->by22.bits), -++ [low]"+&r"(c->low) -++ : // Inputs -++ [n]"r"(n), -++ [val]"r"(val), -++ [inv]"r"(c->range), -++ [range]"r"(c->by22.range), -++ [ptr]"r"(c->bytestream) -++ : // Clobbers -++ ); -++} -++ -++ -++// Works but slower than C -++#define coeff_abs_level_remaining_decode_by22(c,r) coeff_abs_level_remaining_decode_by22_arm(c, r) -++static int coeff_abs_level_remaining_decode_by22_arm(CABACContext * const c, const unsigned int c_rice_param) -++{ -++ uint32_t n, val, tmp, level; -++ -++// PROFILE_START(); -++ -++ __asm__ ( -++ // Peek -++ "bic %[val], %[low], #1 \n\t" -++ "cmp %[inv], #0 \n\t" -++ "umullne %[tmp], %[val], %[inv], %[val] \n\t" -++ "lsl %[val], %[val], #1 \n\t" -++ -++ // Count bits (n = prefix) -++ "mvn %[n], %[val] \n\t" -++ "clz %[n], %[n] \n\t" -++ -++ "lsl %[level], %[val], %[n] \n\t" -++ "subs %[tmp], %[n], #3 \n\t" -++ "blo 2f \n\t" -++ -++ // prefix >= 3 -++ // < tmp = prefix - 3 -++ // > tmp = prefix + rice - 3 -++ "add %[tmp], %[tmp], %[rice] \n\t" -++ // > n = prefix * 2 + rice - 3 -++ "add %[n], %[tmp], %[n] \n\t" -++ "cmp %[n], #21 \n\t" -++ "bhi 3f \n\t" -++ -++ "orr %[level], %[level], #0x80000000 \n\t" -++ "rsb %[tmp], %[tmp], #31 \n\t" -++ "lsr %[level], %[level], %[tmp] \n\t" -++ -++ "mov %[tmp], #2 \n\t" -++ "add %[level], %[level], %[tmp], lsl %[rice] \n\t" -++ "b 1f \n\t" -++ -++ // > 22 bits used in total - need reload -++ "3: \n\t" -++ -++ // Stash prefix + rice - 3 in level (only spare reg) -++ "mov %[level], %[tmp] \n\t" -++ // Restore n to flush value (prefix) -++ "sub %[n], %[n], %[tmp] \n\t" -++ -++ // Flush + reload -++ -++// "rsb %[tmp], %[n], #32 \n\t" -++// "lsr %[tmp], %[val], %[tmp] \n\t" -++// "mul %[tmp], %[range], %[tmp] \n\t" -++ -++ // As it happens we know that all the bits we are flushing are 1 -++ // so we can cheat slightly -++ "rsb %[tmp], %[range], %[range], lsl %[n] \n\t" -++ "lsl %[tmp], %[tmp], #23 \n\t" -++ "rsb %[low], %[tmp], %[low], lsl %[n] \n\t" -++ -++ "add %[bits], %[bits], %[n] \n\t" -++ "ldr %[n], [%[ptr], %[bits], lsr #3] \n\t" -++ "rev %[n], %[n] \n\t" -++ "and %[tmp], %[bits], #7 \n\t" -++ "lsl %[n], %[n], %[tmp] \n\t" -++ -++ "orr %[low], %[low], %[n], lsr #9 \n\t" -++ -++ // (reload) -++ -++ "bic %[val], %[low], #1 \n\t" -++ "cmp %[inv], #0 \n\t" -++ "umullne %[tmp], %[val], %[inv], %[val] \n\t" -++ "lsl %[val], %[val], #1 \n\t" -++ -++ // Build value -++ -++ "mov %[n], %[level] \n\t" -++ -++ "orr %[tmp], %[val], #0x80000000 \n\t" -++ "rsb %[level], %[level], #31 \n\t" -++ "lsr %[level], %[tmp], %[level] \n\t" -++ -++ "mov %[tmp], #2 \n\t" -++ "add %[level], %[level], %[tmp], lsl %[rice] \n\t" -++ "b 1f \n\t" -++ -++ // prefix < 3 -++ "2: \n\t" -++ "rsb %[tmp], %[rice], #31 \n\t" -++ "lsr %[level], %[level], %[tmp] \n\t" -++ "orr %[level], %[level], %[n], lsl %[rice] \n\t" -++ "add %[n], %[n], %[rice] \n\t" -++ -++ "1: \n\t" -++ // Flush -++ "add %[n], %[n], #1 \n\t" -++ -++ "rsb %[tmp], %[n], #32 \n\t" -++ "lsr %[tmp], %[val], %[tmp] \n\t" -++ -++ "add %[bits], %[bits], %[n] \n\t" -++ "ldr %[val], [%[ptr], %[bits], lsr #3] \n\t" -++ -++ "mul %[tmp], %[range], %[tmp] \n\t" -++ "lsl %[tmp], %[tmp], #23 \n\t" -++ "rsb %[low], %[tmp], %[low], lsl %[n] \n\t" -++ -++ "rev %[val], %[val] \n\t" -++ "and %[tmp], %[bits], #7 \n\t" -++ "lsl %[val], %[val], %[tmp] \n\t" -++ -++ "orr %[low], %[low], %[val], lsr #9 \n\t" -++ : // Outputs -++ [level]"=&r"(level), -++ [n]"=&r"(n), -++ [val]"=&r"(val), -++ [tmp]"=&r"(tmp), -++ [bits]"+&r"(c->by22.bits), -++ [low]"+&r"(c->low) -++ : // Inputs -++ [rice]"r"(c_rice_param), -++ [inv]"r"(c->range), -++ [range]"r"(c->by22.range), -++ [ptr]"r"(c->bytestream) -++ : // Clobbers -++ "cc" -++ ); -++ -++// PROFILE_ACC(residual_abs); -++ -++ return level; -++} -++#endif -++ -++#endif /* HAVE_ARMV6T2_INLINE */ -++ -++#endif /* AVCODEC_ARM_HEVC_CABAC_H */ -+diff --git a/libavcodec/arm/hevcdsp_deblock_neon.S b/libavcodec/arm/hevcdsp_deblock_neon.S -+index bad4589..a088cc3 100644 -+--- a/libavcodec/arm/hevcdsp_deblock_neon.S -++++ b/libavcodec/arm/hevcdsp_deblock_neon.S -+@@ -409,10 +409,12 @@ function ff_hevc_deblocking_boundary_strengths_neon, export=1 -+ beq 90f -+ -+ tst a3, #1 -++ itee ne -+ ldrne a3, [v5, #0] @ curr->mv[0] -+ ldreq a3, [v5, #4] @ curr->mv[1] -+ moveq v1, v2 -+ tst v8, #1 -++ itee ne -+ ldrne v8, [v6, #0] @ neigh->mv[0] -+ ldreq v8, [v6, #4] @ neigh->mv[1] -+ moveq v3, v4 -+@@ -424,9 +426,14 @@ function ff_hevc_deblocking_boundary_strengths_neon, export=1 -+ sel a3, a3, ip -+ ands a3, a3, lr -+ @ drop through -+-10: movne a3, #1 -++10: it ne -++ movne a3, #1 -+ 11: subs a2, a2, #1 -+-12: strbhs a3, [v7], a4 -++12: -++A strbhs a3, [v7], a4 -++T itt hs -++T strbhs a3, [v7] -++T addhs v7, v7, a4 -+ subs a2, a2, #1 -+ bhs 12b -+ -+@@ -442,6 +449,7 @@ function ff_hevc_deblocking_boundary_strengths_neon, export=1 -+ bne 10b -+ -+ teq v1, v3 -++ it eq -+ teqeq v2, v4 -+ bne 40f -+ teq v1, v2 -+@@ -487,6 +495,7 @@ function ff_hevc_deblocking_boundary_strengths_neon, export=1 -+ b 10b -+ -+ 40: teq v1, v4 -++ ite eq -+ teqeq v2, v3 -+ bne 10b -+ -+diff --git a/libavcodec/arm/hevcdsp_epel_neon.S b/libavcodec/arm/hevcdsp_epel_neon.S -+index 516ae5b..00eab9e 100644 -+--- a/libavcodec/arm/hevcdsp_epel_neon.S -++++ b/libavcodec/arm/hevcdsp_epel_neon.S -+@@ -110,7 +110,9 @@ function ff_hevc_put_epel_h_neon_8, export=1 -+ sub r7, #1 -+ lsl r7, #2 -+ vpush {d8-d15} -+- adrl r12, epel_coeffs -++@ adr reaches if we are in thumb mode but not in arm -++T adr r12, epel_coeffs -++A adrl r12, epel_coeffs -+ add r7, r12 -+ sub r1, #1 -+ lsl r4, #1 -+@@ -170,7 +172,8 @@ function ff_hevc_put_epel_v_neon_8, export=1 -+ sub r7, #1 -+ lsl r7, #2 -+ vpush {d8-d15} -+- adrl r12, epel_coeffs -++T adr r12, epel_coeffs -++A adrl r12, epel_coeffs -+ add r7, r12 -+ load_coeffs_16b r7 -+ sub r1, r2 -+@@ -246,7 +249,7 @@ function ff_hevc_put_epel_hv_neon_8, export=1 -+ sub r7, #1 -+ lsl r7, #2 -+ vpush {d8-d15} -+- adrl r12, epel_coeffs -++ adr r12, epel_coeffs -+ sub r6, #1 -+ lsl r6, #2 -+ add r6, r12 // mx epel coeff offset -+diff --git a/libavcodec/cabac.h b/libavcodec/cabac.h -+index 1bf1c62..ccfa991 100644 -+--- a/libavcodec/cabac.h -++++ b/libavcodec/cabac.h -+@@ -43,7 +43,14 @@ extern const uint8_t ff_h264_cabac_tables[512 + 4*2*64 + 4*64 + 63]; -+ typedef struct CABACContext{ -+ int low; -+ int range; -+- int outstanding_count; -++ union -++ { -++ int outstanding_count; -++ struct { -++ uint16_t bits; -++ uint16_t range; -++ } by22; -++ }; -+ const uint8_t *bytestream_start; -+ const uint8_t *bytestream; -+ const uint8_t *bytestream_end; -+diff --git a/libavcodec/hevc_cabac.c b/libavcodec/hevc_cabac.c -+index 271e17a..4caf720 100644 -+--- a/libavcodec/hevc_cabac.c -++++ b/libavcodec/hevc_cabac.c -+@@ -21,14 +21,72 @@ -+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -+ */ -+ -++#define UNCHECKED_BITSTREAM_READER 1 -++ -+ #include "libavutil/attributes.h" -+ #include "libavutil/common.h" -+ -+-#include "cabac_functions.h" -+ #include "hevc.h" -++#include "cabac_functions.h" -++ -++// BY22 is probably faster than simple bypass if the processor has -++// either a fast 32-bit divide or a fast 32x32->64[63:32] instruction -++// x86 has fast int divide -++// Arm doesn't have divide or general fast 64 bit, but does have the multiply -++// * Beware: ARCH_xxx isn't set if configure --disable-asm is used -++#define USE_BY22 (HAVE_FAST_64BIT || ARCH_ARM || ARCH_X86) -++// Use native divide if we have a fast one - otherwise use mpy 1/x -++// x86 has a fast integer divide - arm doesn't - unsure about other -++// architectures -++#define USE_BY22_DIV ARCH_X86 -++ -++// Special case blocks with a single significant ceoff -++// Decreases the complexity of the code for a common case but increases the -++// code size. -++#define USE_N_END_1 1 -++ -++#if ARCH_ARM -++#include "arm/hevc_cabac.h" -++#endif -+ -+ #define CABAC_MAX_BIN 31 -+ -++ -++#if USE_BY22 && !USE_BY22_DIV -++#define I(x) (uint32_t)((0x10000000000ULL / (uint64_t)(x)) + 1ULL) -++ -++static const uint32_t cabac_by22_inv_range[256] = { -++ 0, I(257), I(258), I(259), -++ I(260), I(261), I(262), I(263), I(264), I(265), I(266), I(267), I(268), I(269), -++ I(270), I(271), I(272), I(273), I(274), I(275), I(276), I(277), I(278), I(279), -++ I(280), I(281), I(282), I(283), I(284), I(285), I(286), I(287), I(288), I(289), -++ I(290), I(291), I(292), I(293), I(294), I(295), I(296), I(297), I(298), I(299), -++ I(300), I(301), I(302), I(303), I(304), I(305), I(306), I(307), I(308), I(309), -++ I(310), I(311), I(312), I(313), I(314), I(315), I(316), I(317), I(318), I(319), -++ I(320), I(321), I(322), I(323), I(324), I(325), I(326), I(327), I(328), I(329), -++ I(330), I(331), I(332), I(333), I(334), I(335), I(336), I(337), I(338), I(339), -++ I(340), I(341), I(342), I(343), I(344), I(345), I(346), I(347), I(348), I(349), -++ I(350), I(351), I(352), I(353), I(354), I(355), I(356), I(357), I(358), I(359), -++ I(360), I(361), I(362), I(363), I(364), I(365), I(366), I(367), I(368), I(369), -++ I(370), I(371), I(372), I(373), I(374), I(375), I(376), I(377), I(378), I(379), -++ I(380), I(381), I(382), I(383), I(384), I(385), I(386), I(387), I(388), I(389), -++ I(390), I(391), I(392), I(393), I(394), I(395), I(396), I(397), I(398), I(399), -++ I(400), I(401), I(402), I(403), I(404), I(405), I(406), I(407), I(408), I(409), -++ I(410), I(411), I(412), I(413), I(414), I(415), I(416), I(417), I(418), I(419), -++ I(420), I(421), I(422), I(423), I(424), I(425), I(426), I(427), I(428), I(429), -++ I(430), I(431), I(432), I(433), I(434), I(435), I(436), I(437), I(438), I(439), -++ I(440), I(441), I(442), I(443), I(444), I(445), I(446), I(447), I(448), I(449), -++ I(450), I(451), I(452), I(453), I(454), I(455), I(456), I(457), I(458), I(459), -++ I(460), I(461), I(462), I(463), I(464), I(465), I(466), I(467), I(468), I(469), -++ I(470), I(471), I(472), I(473), I(474), I(475), I(476), I(477), I(478), I(479), -++ I(480), I(481), I(482), I(483), I(484), I(485), I(486), I(487), I(488), I(489), -++ I(490), I(491), I(492), I(493), I(494), I(495), I(496), I(497), I(498), I(499), -++ I(500), I(501), I(502), I(503), I(504), I(505), I(506), I(507), I(508), I(509), -++ I(510), I(511) -++}; -++#undef I -++#endif // USE_BY22 -++ -+ /** -+ * number of bin by SyntaxElement. -+ */ -+@@ -445,6 +503,211 @@ static const uint8_t diag_scan8x8_inv[8][8] = { -+ { 28, 36, 43, 49, 54, 58, 61, 63, }, -+ }; -+ -++ -++typedef struct -++{ -++ uint16_t coeff; -++ uint16_t scale; -++} xy_off_t; -++ -++#define XYT_C(x,y,t) ((x) + ((y) << (t))) -++#define SCALE_TRAFO(t) ((t) > 3 ? 3 : (t)) -++#define SCALE_SHR(t) ((t) - SCALE_TRAFO(t)) -++#define XYT_S(x,y,t) (((x) >> SCALE_SHR(t)) + (((y) >> SCALE_SHR(t)) << SCALE_TRAFO(t))) -++ -++#define XYT(x,y,t) {XYT_C(x,y,t), XYT_S(x,y,t)} -++ -++#define OFF_DIAG(t) {\ -++ XYT(0,0,t), XYT(0,1,t), XYT(1,0,t), XYT(0,2,t),\ -++ XYT(1,1,t), XYT(2,0,t), XYT(0,3,t), XYT(1,2,t),\ -++ XYT(2,1,t), XYT(3,0,t), XYT(1,3,t), XYT(2,2,t),\ -++ XYT(3,1,t), XYT(2,3,t), XYT(3,2,t), XYT(3,3,t)\ -++} -++ -++#define OFF_HORIZ(t) {\ -++ XYT(0,0,t), XYT(1,0,t), XYT(2,0,t), XYT(3,0,t),\ -++ XYT(0,1,t), XYT(1,1,t), XYT(2,1,t), XYT(3,1,t),\ -++ XYT(0,2,t), XYT(1,2,t), XYT(2,2,t), XYT(3,2,t),\ -++ XYT(0,3,t), XYT(1,3,t), XYT(2,3,t), XYT(3,3,t)\ -++} -++ -++#define OFF_VERT(t) {\ -++ XYT(0,0,t), XYT(0,1,t), XYT(0,2,t), XYT(0,3,t),\ -++ XYT(1,0,t), XYT(1,1,t), XYT(1,2,t), XYT(1,3,t),\ -++ XYT(2,0,t), XYT(2,1,t), XYT(2,2,t), XYT(2,3,t),\ -++ XYT(3,0,t), XYT(3,1,t), XYT(3,2,t), XYT(3,3,t)\ -++} -++ -++static const xy_off_t off_xys[3][4][16] = -++{ -++ {OFF_DIAG(2), OFF_DIAG(3), OFF_DIAG(4), OFF_DIAG(5)}, -++ {OFF_HORIZ(2), OFF_HORIZ(3), OFF_HORIZ(4), OFF_HORIZ(5)}, -++ {OFF_VERT(2), OFF_VERT(3), OFF_VERT(4), OFF_VERT(5)} -++}; -++ -++ -++// Helper fns -++#ifndef hevc_mem_bits32 -++static av_always_inline uint32_t hevc_mem_bits32(const void * buf, const unsigned int offset) -++{ -++ return AV_RB32((const uint8_t *)buf + (offset >> 3)) << (offset & 7); -++} -++#endif -++ -++#if AV_GCC_VERSION_AT_LEAST(3,4) && !defined(hevc_clz32) -++#define hevc_clz32 hevc_clz32_builtin -++static av_always_inline unsigned int hevc_clz32_builtin(const uint32_t x) -++{ -++ // __builtin_clz says it works on ints - so adjust if int is >32 bits long -++ return __builtin_clz(x) - (sizeof(int) * 8 - 32); -++} -++#endif -++ -++// It is unlikely that we will ever need this but include for completeness -++#ifndef hevc_clz32 -++static inline unsigned int hevc_clz32(unsigned int x) -++{ -++ unsigned int n = 1; -++ if ((x & 0xffff0000) == 0) { -++ n += 16; -++ x <<= 16; -++ } -++ if ((x & 0xff000000) == 0) { -++ n += 8; -++ x <<= 8; -++ } -++ if ((x & 0xf0000000) == 0) { -++ n += 4; -++ x <<= 4; -++ } -++ if ((x & 0xc0000000) == 0) { -++ n += 2; -++ x <<= 2; -++ } -++ return n - ((x >> 31) & 1); -++} -++#endif -++ -++ -++#if !USE_BY22 -++// If no by22 then _by22 functions will revert to normal and so _peek/_flush -++// will no longer be called but the setup calls will still exist and we want -++// to null them out -++#define bypass_start(s) -++#define bypass_finish(s) -++#else -++// Use BY22 for residual bypass block -++ -++#define bypass_start(s) get_cabac_by22_start(&s->HEVClc->cc) -++#define bypass_finish(s) get_cabac_by22_finish(&s->HEVClc->cc) -++ -++// BY22 notes that bypass is simply a divide into the bitstream and so we -++// can peek out large quantities of bits at one and treat the result as if -++// it was VLC. In many cases this will lead to O(1) processing rather than -++// O(n) though the setup and teardown is sufficiently expensive that it is -++// only worth using if we expect to be dealing with more than a few bits -++// The definition of "a few bits" will vary from platform to platform but -++// tests on ARM show that it probably isn't worth it for a single coded -++// residual, but is for >1 - this is probaly reinforced that if there are -++// more residuals then they are likely to be bigger and this will make the -++// O(1) nature of the code more worthwhile. -++ -++ -++#if !USE_BY22_DIV -++// * 1/x @ 32 bits gets us 22 bits of accuracy -++#define CABAC_BY22_PEEK_BITS 22 -++#else -++// A real 32-bit divide gets us another bit -++// If we have a 64 bit int & a unit time divider then we should get a lot -++// of bits (55) but that is untested and it is unclear if it would give -++// us a large advantage -++#define CABAC_BY22_PEEK_BITS 23 -++#endif -++ -++// Bypass block start -++// Must be called before _by22_peek is used as it sets the CABAC environment -++// into the correct state. _by22_finish must be called to return to 'normal' -++// (i.e. non-bypass) cabac decoding -++static inline void get_cabac_by22_start(CABACContext * const c) -++{ -++ const unsigned int bits = __builtin_ctz(c->low); -++ const uint32_t m = hevc_mem_bits32(c->bytestream, 0); -++ uint32_t x = (c->low << (22 - CABAC_BITS)) ^ ((m ^ 0x80000000U) >> (9 + CABAC_BITS - bits)); -++#if !USE_BY22_DIV -++ const uint32_t inv = cabac_by22_inv_range[c->range & 0xff]; -++#endif -++ -++ c->bytestream -= (CABAC_BITS / 8); -++ c->by22.bits = bits; -++#if !USE_BY22_DIV -++ c->by22.range = c->range; -++ c->range = inv; -++#endif -++ c->low = x; -++} -++ -++// Bypass block finish -++// Must be called at the end of the bypass block to return to normal operation -++static inline void get_cabac_by22_finish(CABACContext * const c) -++{ -++ unsigned int used = c->by22.bits; -++ unsigned int bytes_used = (used / CABAC_BITS) * (CABAC_BITS / 8); -++ unsigned int bits_used = used & (CABAC_BITS == 16 ? 15 : 7); -++ -++ c->bytestream += bytes_used + (CABAC_BITS / 8); -++ c->low = (((uint32_t)c->low >> (22 - CABAC_BITS + bits_used)) | 1) << bits_used; -++#if !USE_BY22_DIV -++ c->range = c->by22.range; -++#endif -++} -++ -++// Peek bypass bits -++// _by22_start must be called before _by22_peek is called and _by22_flush -++// must be called afterwards to flush any used bits -++// The actual number of valid bits returned is -++// min(, CABAC_BY22_PEEK_BITS). CABAC_BY22_PEEK_BITS -++// will be at least 22 which should be long enough for any prefix or suffix -++// though probably not long enough for the worst case combination -++#ifndef get_cabac_by22_peek -++static inline uint32_t get_cabac_by22_peek(const CABACContext * const c) -++{ -++#if USE_BY22_DIV -++ return ((unsigned int)c->low / (unsigned int)c->range) << 9; -++#else -++ uint32_t x = c->low & ~1U; -++ const uint32_t inv = c->range; -++ -++ if (inv != 0) -++ x = (uint32_t)(((uint64_t)x * (uint64_t)inv) >> 32); -++ -++ return x << 1; -++#endif -++} -++#endif -++ -++// Flush bypass bits peeked by _by22_peek -++// Flush n bypass bits. n must be >= 1 to guarantee correct operation -++// val is an unmodified copy of whatever _by22_peek returned -++#ifndef get_cabac_by22_flush -++static inline void get_cabac_by22_flush(CABACContext * c, const unsigned int n, const uint32_t val) -++{ -++ // Subtract the bits used & reshift up to the top of the word -++#if USE_BY22_DIV -++ const uint32_t low = (((unsigned int)c->low << n) - (((val >> (32 - n)) * (unsigned int)c->range) << 23)); -++#else -++ const uint32_t low = (((uint32_t)c->low << n) - (((val >> (32 - n)) * c->by22.range) << 23)); -++#endif -++ -++ // and refill lower bits -++ // We will probably OR over some existing bits but that doesn't matter -++ c->by22.bits += n; -++ c->low = low | (hevc_mem_bits32(c->bytestream, c->by22.bits) >> 9); -++} -++#endif -++ -++#endif // USE_BY22 -++ -++ -+ void ff_hevc_save_states(HEVCContext *s, int ctb_addr_ts) -+ { -+ if (s->ps.pps->entropy_coding_sync_enabled_flag && -+@@ -863,19 +1126,19 @@ int ff_hevc_cbf_luma_decode(HEVCContext *s, int trafo_depth) -+ return GET_CABAC(elem_offset[CBF_LUMA] + !trafo_depth); -+ } -+ -+-static int hevc_transform_skip_flag_decode(HEVCContext *s, int c_idx) -++static int hevc_transform_skip_flag_decode(HEVCContext *s, int c_idx_nz) -+ { -+- return GET_CABAC(elem_offset[TRANSFORM_SKIP_FLAG] + !!c_idx); -++ return GET_CABAC(elem_offset[TRANSFORM_SKIP_FLAG] + c_idx_nz); -+ } -+ -+-static int explicit_rdpcm_flag_decode(HEVCContext *s, int c_idx) -++static int explicit_rdpcm_flag_decode(HEVCContext *s, int c_idx_nz) -+ { -+- return GET_CABAC(elem_offset[EXPLICIT_RDPCM_FLAG] + !!c_idx); -++ return GET_CABAC(elem_offset[EXPLICIT_RDPCM_FLAG] + c_idx_nz); -+ } -+ -+-static int explicit_rdpcm_dir_flag_decode(HEVCContext *s, int c_idx) -++static int explicit_rdpcm_dir_flag_decode(HEVCContext *s, int c_idx_nz) -+ { -+- return GET_CABAC(elem_offset[EXPLICIT_RDPCM_DIR_FLAG] + !!c_idx); -++ return GET_CABAC(elem_offset[EXPLICIT_RDPCM_DIR_FLAG] + c_idx_nz); -+ } -+ -+ int ff_hevc_log2_res_scale_abs(HEVCContext *s, int idx) { -+@@ -891,14 +1154,14 @@ int ff_hevc_res_scale_sign_flag(HEVCContext *s, int idx) { -+ return GET_CABAC(elem_offset[RES_SCALE_SIGN_FLAG] + idx); -+ } -+ -+-static av_always_inline void last_significant_coeff_xy_prefix_decode(HEVCContext *s, int c_idx, -++static av_always_inline void last_significant_coeff_xy_prefix_decode(HEVCContext *s, int c_idx_nz, -+ int log2_size, int *last_scx_prefix, int *last_scy_prefix) -+ { -+ int i = 0; -+ int max = (log2_size << 1) - 1; -+ int ctx_offset, ctx_shift; -+ -+- if (!c_idx) { -++ if (!c_idx_nz) { -+ ctx_offset = 3 * (log2_size - 2) + ((log2_size - 1) >> 2); -+ ctx_shift = (log2_size + 1) >> 2; -+ } else { -+@@ -929,22 +1192,16 @@ static av_always_inline int last_significant_coeff_suffix_decode(HEVCContext *s, -+ return value; -+ } -+ -+-static av_always_inline int significant_coeff_group_flag_decode(HEVCContext *s, int c_idx, int ctx_cg) -++static av_always_inline int significant_coeff_group_flag_decode(HEVCContext *s, int c_idx_nz, int ctx_cg) -+ { -+ int inc; -+ -+- inc = FFMIN(ctx_cg, 1) + (c_idx>0 ? 2 : 0); -++ inc = (ctx_cg != 0) + (c_idx_nz << 1); -+ -+ return GET_CABAC(elem_offset[SIGNIFICANT_COEFF_GROUP_FLAG] + inc); -+ } -+-static av_always_inline int significant_coeff_flag_decode(HEVCContext *s, int x_c, int y_c, -+- int offset, const uint8_t *ctx_idx_map) -+-{ -+- int inc = ctx_idx_map[(y_c << 2) + x_c] + offset; -+- return GET_CABAC(elem_offset[SIGNIFICANT_COEFF_FLAG] + inc); -+-} -+ -+-static av_always_inline int significant_coeff_flag_decode_0(HEVCContext *s, int c_idx, int offset) -++static av_always_inline int significant_coeff_flag_decode_0(HEVCContext *s, int offset) -+ { -+ return GET_CABAC(elem_offset[SIGNIFICANT_COEFF_FLAG] + offset); -+ } -+@@ -966,65 +1223,305 @@ static av_always_inline int coeff_abs_level_greater2_flag_decode(HEVCContext *s, -+ return GET_CABAC(elem_offset[COEFF_ABS_LEVEL_GREATER2_FLAG] + inc); -+ } -+ -+-static av_always_inline int coeff_abs_level_remaining_decode(HEVCContext *s, int rc_rice_param) -++ -++#if !USE_BY22 -++#define coeff_abs_level_remaining_decode_bypass(s,r) coeff_abs_level_remaining_decode(s, r) -++#endif -++ -++ -++#ifndef coeff_abs_level_remaining_decode_bypass -++static int coeff_abs_level_remaining_decode_bypass(HEVCContext * const s, const unsigned int rice_param) -++{ -++ CABACContext * const c = &s->HEVClc->cc; -++ uint32_t y; -++ unsigned int prefix; -++ unsigned int last_coeff_abs_level_remaining; -++ unsigned int n; -++ -++ y = get_cabac_by22_peek(c); -++ prefix = hevc_clz32(~y); -++ // y << prefix will always have top bit 0 -++ -++ if (prefix < 3) { -++ const unsigned int suffix = (y << prefix) >> (31 - rice_param); -++ last_coeff_abs_level_remaining = (prefix << rice_param) + suffix; -++ n = prefix + 1 + rice_param; -++ } -++ else if (prefix * 2 + rice_param <= CABAC_BY22_PEEK_BITS + 2) -++ { -++ const uint32_t suffix = ((y << prefix) | 0x80000000) >> (34 - (prefix + rice_param)); -++ -++ last_coeff_abs_level_remaining = (2 << rice_param) + suffix; -++ n = prefix * 2 + rice_param - 2; -++ } -++ else { -++ unsigned int suffix; -++ -++ get_cabac_by22_flush(c, prefix, y); -++ y = get_cabac_by22_peek(c); -++ -++ suffix = (y | 0x80000000) >> (34 - (prefix + rice_param)); -++ last_coeff_abs_level_remaining = (2 << rice_param) + suffix; -++ n = prefix + rice_param - 2; -++ } -++ -++ get_cabac_by22_flush(c, n, y); -++ -++ return last_coeff_abs_level_remaining; -++} -++#endif -++ -++static int coeff_abs_level_remaining_decode(HEVCContext * const s, int rc_rice_param) -+ { -++ CABACContext * const c = &s->HEVClc->cc; -+ int prefix = 0; -+ int suffix = 0; -+ int last_coeff_abs_level_remaining; -+ int i; -+ -+- while (prefix < CABAC_MAX_BIN && get_cabac_bypass(&s->HEVClc->cc)) -++ while (prefix < CABAC_MAX_BIN && get_cabac_bypass(c)) -+ prefix++; -+ if (prefix == CABAC_MAX_BIN) { -+ av_log(s->avctx, AV_LOG_ERROR, "CABAC_MAX_BIN : %d\n", prefix); -+ return 0; -+ } -++ -+ if (prefix < 3) { -+ for (i = 0; i < rc_rice_param; i++) -+- suffix = (suffix << 1) | get_cabac_bypass(&s->HEVClc->cc); -++ suffix = (suffix << 1) | get_cabac_bypass(c); -+ last_coeff_abs_level_remaining = (prefix << rc_rice_param) + suffix; -+ } else { -+ int prefix_minus3 = prefix - 3; -+ for (i = 0; i < prefix_minus3 + rc_rice_param; i++) -+- suffix = (suffix << 1) | get_cabac_bypass(&s->HEVClc->cc); -++ suffix = (suffix << 1) | get_cabac_bypass(c); -+ last_coeff_abs_level_remaining = (((1 << prefix_minus3) + 3 - 1) -+ << rc_rice_param) + suffix; -+ } -++ -+ return last_coeff_abs_level_remaining; -+ } -+ -+-static av_always_inline int coeff_sign_flag_decode(HEVCContext *s, uint8_t nb) -++#if !USE_BY22 -++#define coeff_sign_flag_decode_bypass coeff_sign_flag_decode -++static inline uint32_t coeff_sign_flag_decode(HEVCContext * const s, const unsigned int nb) -+ { -+- int i; -+- int ret = 0; -++ CABACContext * const c = &s->HEVClc->cc; -++ unsigned int i; -++ uint32_t ret = 0; -+ -+ for (i = 0; i < nb; i++) -+- ret = (ret << 1) | get_cabac_bypass(&s->HEVClc->cc); -+- return ret; -++ ret = (ret << 1) | get_cabac_bypass(c); -++ -++ return ret << (32 - nb); -+ } -++#endif -++ -++#ifndef coeff_sign_flag_decode_bypass -++static inline uint32_t coeff_sign_flag_decode_bypass(HEVCContext * const s, const unsigned int nb) -++{ -++ CABACContext * const c = &s->HEVClc->cc; -++ uint32_t y; -++ y = get_cabac_by22_peek(c); -++ get_cabac_by22_flush(c, nb, y); -++ return y & ~(0xffffffffU >> nb); -++} -++#endif -++ -++ -++#ifndef get_cabac_greater1_bits -++static inline unsigned int get_cabac_greater1_bits(CABACContext * const c, const unsigned int n, -++ uint8_t * const state0) -++{ -++ unsigned int i; -++ unsigned int rv = 0; -++ for (i = 0; i != n; ++i) { -++ const unsigned int idx = rv != 0 ? 0 : i < 3 ? i + 1 : 3; -++ const unsigned int b = get_cabac(c, state0 + idx); -++ rv = (rv << 1) | b; -++ } -++ return rv; -++} -++#endif -++ -++ -++// N.B. levels returned are the values assuming coeff_abs_level_remaining -++// is uncoded, so 1 must be added if it is coded. sum_abs also reflects -++// this version of events. -++static inline uint32_t get_greaterx_bits(HEVCContext * const s, const unsigned int n_end, int * const levels, -++ int * const pprev_subset_coded, int * const psum, -++ const unsigned int idx0_gt1, const unsigned int idx_gt2) -++{ -++ CABACContext * const c = &s->HEVClc->cc; -++ uint8_t * const state0 = s->HEVClc->cabac_state + idx0_gt1; -++ uint8_t * const state_gt2 = s->HEVClc->cabac_state + idx_gt2; -++ unsigned int rv; -++ unsigned int i; -++ const unsigned int n = FFMIN(n_end, 8); -++ -++ // Really this is i != n but the simple unconditional loop is cheaper -++ // and faster -++ for (i = 0; i != 8; ++i) -++ levels[i] = 1; -++ -++ rv = get_cabac_greater1_bits(c, n, state0); -++ -++ *pprev_subset_coded = 0; -++ *psum = n; -++ -++ rv <<= (32 - n); -++ if (rv != 0) -++ { -++ *pprev_subset_coded = 1; -++ *psum = n + 1; -++ i = hevc_clz32(rv); -++ levels[i] = 2; -++ if (get_cabac(c, state_gt2) == 0) -++ { -++ // Unset first coded bit -++ rv &= ~(0x80000000U >> i); -++ } -++ } -++ -++ if (n_end > 8) { -++ const unsigned int g8 = n_end - 8; -++ rv |= ((1 << g8) - 1) << (24 - g8); -++ for (i = 0; i != g8; ++i) { -++ levels[i + 8] = 0; -++ } -++ } -++ -++ return rv; -++} -++ -++// extended_precision_processing_flag must be false given we are -++// putting the result into a 16-bit array -++// So trans_coeff_level must fit in 16 bits too (7.4.9.1 definition of coeff_abs_level_remaining) -++// scale_m is uint8_t -++// -++// scale is [40 - 72] << [0..12] based on qp- worst case is (45 << 12) -++// or it can be 2 (if we have transquant_bypass) -++// shift is set to one less than we really want but would normally be -++// s->ps.sps->bit_depth (max 16, min 8) + log2_trafo_size (max 5, min 2?) - 5 = max 16 min 5? -++// however the scale shift is substracted from shift to a min 0 so scale_m worst = 45 << 6 -++// This can still theoretically lead to overflow but the coding would have to be very odd (& inefficient) -++// to achieve it -++ -++#ifndef trans_scale_sat -++static inline int trans_scale_sat(const int level, const unsigned int scale, const unsigned int scale_m, const unsigned int shift) -++{ -++ return av_clip_int16((((level * (int)(scale * scale_m)) >> shift) + 1) >> 1); -++} -++#endif -++ -++ -++#ifndef update_rice -++static inline void update_rice(uint8_t * const stat_coeff, -++ const unsigned int last_coeff_abs_level_remaining, -++ const unsigned int c_rice_param) -++{ -++ const unsigned int x = (last_coeff_abs_level_remaining << 1) >> c_rice_param; -++ if (x >= 6) -++ (*stat_coeff)++; -++ else if (x == 0 && *stat_coeff > 0) -++ (*stat_coeff)--; -++} -++#endif -++ -++ -++// n must be > 0 on entry -++#ifndef get_cabac_sig_coeff_flag_idxs -++static inline uint8_t * get_cabac_sig_coeff_flag_idxs(CABACContext * const c, uint8_t * const state0, -++ unsigned int n, -++ const uint8_t const * ctx_map, -++ uint8_t * p) -++{ -++ do { -++ if (get_cabac(c, state0 + ctx_map[n])) -++ *p++ = n; -++ } while (--n != 0); -++ return p; -++} -++#endif -++ -++ -++static int get_sig_coeff_flag_idxs(CABACContext * const c, uint8_t * const state0, -++ unsigned int n, -++ const uint8_t const * ctx_map, -++ uint8_t * const flag_idx) -++{ -++ int rv; -++ -++ rv = get_cabac_sig_coeff_flag_idxs(c, state0, n, ctx_map, flag_idx) - flag_idx; -++ -++ return rv; -++} -++ -++#define H4x4(x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15) {\ -++ x0, x1, x2, x3,\ -++ x4, x5, x6, x7,\ -++ x8, x9, x10, x11,\ -++ x12, x13, x14, x15} -++ -++#define V4x4(x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15) {\ -++ x0, x4, x8, x12,\ -++ x1, x5, x9, x13,\ -++ x2, x6, x10, x14,\ -++ x3, x7, x11, x15} -++ -++#define D4x4(x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15) {\ -++ x0, x4, x1, x8,\ -++ x5, x2, x12, x9,\ -++ x6, x3, x13, x10,\ -++ x7, x14, x11, x15} -++ -++ -++static inline int next_subset(HEVCContext * const s, int i, const int c_idx_nz, -++ uint8_t * const significant_coeff_group_flag, -++ const uint8_t * const scan_x_cg, const uint8_t * const scan_y_cg, -++ int * const pPrev_sig) -++{ -++ while (--i >= 0) { -++ unsigned int x_cg = scan_x_cg[i]; -++ unsigned int y_cg = scan_y_cg[i]; -++ -++ // For the flag decode we only care about Z/NZ but -++ // we use the full Right + Down * 2 when calculating -++ // significant coeff flags so we obtain it here -++ //. -++ // The group flag array is one longer than it needs to -++ // be so we don't need to check for y_cg limits -++ unsigned int prev_sig = ((significant_coeff_group_flag[y_cg] >> (x_cg + 1)) & 1) | -++ (((significant_coeff_group_flag[y_cg + 1] >> x_cg) & 1) << 1); -++ -++ if (i == 0 || -++ significant_coeff_group_flag_decode(s, c_idx_nz, prev_sig)) -++ { -++ significant_coeff_group_flag[y_cg] |= (1 << x_cg); -++ *pPrev_sig = prev_sig; -++ break; -++ } -++ } -++ -++ return i; -++} -++ -+ -+ void ff_hevc_hls_residual_coding(HEVCContext *s, int x0, int y0, -+ int log2_trafo_size, enum ScanType scan_idx, -+ int c_idx) -+ { -+-#define GET_COORD(offset, n) \ -+- do { \ -+- x_c = (x_cg << 2) + scan_x_off[n]; \ -+- y_c = (y_cg << 2) + scan_y_off[n]; \ -+- } while (0) -+- HEVCLocalContext *lc = s->HEVClc; -+- int transform_skip_flag = 0; -++ HEVCLocalContext * const lc = s->HEVClc; -++ int trans_skip_or_bypass = lc->cu.cu_transquant_bypass_flag; -+ -+ int last_significant_coeff_x, last_significant_coeff_y; -+- int last_scan_pos; -+- int n_end; -+ int num_coeff = 0; -+- int greater1_ctx = 1; -++ int prev_subset_coded = 0; -+ -+ int num_last_subset; -+ int x_cg_last_sig, y_cg_last_sig; -+ -+- const uint8_t *scan_x_cg, *scan_y_cg, *scan_x_off, *scan_y_off; -++ const uint8_t *scan_x_cg, *scan_y_cg; -++ const xy_off_t * scan_xy_off; -+ -+ ptrdiff_t stride = s->frame->linesize[c_idx]; -+ int hshift = s->ps.sps->hshift[c_idx]; -+@@ -1032,21 +1529,28 @@ void ff_hevc_hls_residual_coding(HEVCContext *s, int x0, int y0, -+ uint8_t *dst = &s->frame->data[c_idx][(y0 >> vshift) * stride + -+ ((x0 >> hshift) << s->ps.sps->pixel_shift)]; -+ #ifdef RPI -+- int use_vpu = s->enable_rpi && !lc->cu.cu_transquant_bypass_flag && !transform_skip_flag && !lc->tu.cross_pf && log2_trafo_size>=4; -++ //***** transform_skip_flag decoded later! -++ int use_vpu = s->enable_rpi && !lc->cu.cu_transquant_bypass_flag /* && !transform_skip_flag*/ && !lc->tu.cross_pf && log2_trafo_size>=4; -+ #endif -+ int16_t *coeffs = (int16_t*)(c_idx ? lc->edge_emu_buffer2 : lc->edge_emu_buffer); -+- uint8_t significant_coeff_group_flag[8][8] = {{0}}; -++ uint8_t significant_coeff_group_flag[9] = {0}; // Allow 1 final byte that is always zero -+ int explicit_rdpcm_flag = 0; -+ int explicit_rdpcm_dir_flag; -+ -+ int trafo_size = 1 << log2_trafo_size; -+ int i; -+- int qp,shift,add,scale,scale_m; -+- const uint8_t level_scale[] = { 40, 45, 51, 57, 64, 72 }; -++ int qp,shift,scale; -++ static const uint8_t level_scale[] = { 40, 45, 51, 57, 64, 72 }; -+ const uint8_t *scale_matrix = NULL; -+ uint8_t dc_scale; -+ int pred_mode_intra = (c_idx == 0) ? lc->tu.intra_pred_mode : -+ lc->tu.intra_pred_mode_c; -++ -++ int prev_sig = 0; -++ const int c_idx_nz = (c_idx != 0); -++ -++ int may_hide_sign; -++ -+ #ifdef RPI -+ if (s->enable_rpi) { -+ int n = trafo_size * trafo_size; -+@@ -1078,7 +1582,7 @@ void ff_hevc_hls_residual_coding(HEVCContext *s, int x0, int y0, -+ -+ // Derive QP for dequant -+ if (!lc->cu.cu_transquant_bypass_flag) { -+- static const int qp_c[] = { 29, 30, 31, 32, 33, 33, 34, 34, 35, 35, 36, 36, 37, 37 }; -++ static const uint8_t qp_c[] = { 29, 30, 31, 32, 33, 33, 34, 34, 35, 35, 36, 36, 37, 37 }; -+ static const uint8_t rem6[51 + 4 * 6 + 1] = { -+ 0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5, 0, 1, 2, -+ 3, 4, 5, 0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5, -+@@ -1094,9 +1598,19 @@ void ff_hevc_hls_residual_coding(HEVCContext *s, int x0, int y0, -+ }; -+ int qp_y = lc->qp_y; -+ -++ may_hide_sign = s->ps.pps->sign_data_hiding_flag; -++ -+ if (s->ps.pps->transform_skip_enabled_flag && -+ log2_trafo_size <= s->ps.pps->log2_max_transform_skip_block_size) { -+- transform_skip_flag = hevc_transform_skip_flag_decode(s, c_idx); -++ int transform_skip_flag = hevc_transform_skip_flag_decode(s, c_idx_nz); -++ if (transform_skip_flag) { -++ trans_skip_or_bypass = 1; -++ if (lc->cu.pred_mode == MODE_INTRA && -++ s->ps.sps->implicit_rdpcm_enabled_flag && -++ (pred_mode_intra == 10 || pred_mode_intra == 26)) { -++ may_hide_sign = 0; -++ } -++ } -+ } -+ -+ if (c_idx == 0) { -+@@ -1129,39 +1643,73 @@ void ff_hevc_hls_residual_coding(HEVCContext *s, int x0, int y0, -+ qp += s->ps.sps->qp_bd_offset; -+ } -+ -+- shift = s->ps.sps->bit_depth + log2_trafo_size - 5; -+- add = 1 << (shift-1); -+- scale = level_scale[rem6[qp]] << (div6[qp]); -+- scale_m = 16; // default when no custom scaling lists. -+- dc_scale = 16; -++ // Shift is set to one less than will actually occur as the scale -++ // and saturate step adds 1 and then shifts right again -++ shift = s->ps.sps->bit_depth + log2_trafo_size - 6; -++ scale = level_scale[rem6[qp]]; -++ if (div6[qp] >= shift) { -++ scale <<= (div6[qp] - shift); -++ shift = 0; -++ } else { -++ shift -= div6[qp]; -++ } -+ -+- if (s->ps.sps->scaling_list_enable_flag && !(transform_skip_flag && log2_trafo_size > 2)) { -++ if (s->ps.sps->scaling_list_enable_flag && !(trans_skip_or_bypass && log2_trafo_size > 2)) { -+ const ScalingList *sl = s->ps.pps->scaling_list_data_present_flag ? -+- &s->ps.pps->scaling_list : &s->ps.sps->scaling_list; -++ &s->ps.pps->scaling_list : &s->ps.sps->scaling_list; -+ int matrix_id = lc->cu.pred_mode != MODE_INTRA; -+ -+ matrix_id = 3 * matrix_id + c_idx; -+ -+ scale_matrix = sl->sl[log2_trafo_size - 2][matrix_id]; -++ dc_scale = scale_matrix[0]; -+ if (log2_trafo_size >= 4) -+ dc_scale = sl->sl_dc[log2_trafo_size - 4][matrix_id]; -+ } -++ else -++ { -++ static const uint8_t sixteen_scale[64] = { -++ 16, 16, 16, 16, 16, 16, 16, 16, -++ 16, 16, 16, 16, 16, 16, 16, 16, -++ 16, 16, 16, 16, 16, 16, 16, 16, -++ 16, 16, 16, 16, 16, 16, 16, 16, -++ 16, 16, 16, 16, 16, 16, 16, 16, -++ 16, 16, 16, 16, 16, 16, 16, 16, -++ 16, 16, 16, 16, 16, 16, 16, 16, -++ 16, 16, 16, 16, 16, 16, 16, 16 -++ }; -++ scale_matrix = sixteen_scale; -++ dc_scale = 16; -++ } -+ } else { -++ static const uint8_t unit_scale[64] = { -++ 1, 1, 1, 1, 1, 1, 1, 1, -++ 1, 1, 1, 1, 1, 1, 1, 1, -++ 1, 1, 1, 1, 1, 1, 1, 1, -++ 1, 1, 1, 1, 1, 1, 1, 1, -++ 1, 1, 1, 1, 1, 1, 1, 1, -++ 1, 1, 1, 1, 1, 1, 1, 1, -++ 1, 1, 1, 1, 1, 1, 1, 1, -++ 1, 1, 1, 1, 1, 1, 1, 1, -++ }; -++ scale_matrix = unit_scale; -+ shift = 0; -+- add = 0; -+- scale = 0; -+- dc_scale = 0; -++ scale = 2; // We will shift right to kill this -++ dc_scale = 1; -++ -++ may_hide_sign = 0; -+ } -+ -+ if (lc->cu.pred_mode == MODE_INTER && s->ps.sps->explicit_rdpcm_enabled_flag && -+- (transform_skip_flag || lc->cu.cu_transquant_bypass_flag)) { -+- explicit_rdpcm_flag = explicit_rdpcm_flag_decode(s, c_idx); -++ trans_skip_or_bypass) { -++ explicit_rdpcm_flag = explicit_rdpcm_flag_decode(s, c_idx_nz); -+ if (explicit_rdpcm_flag) { -+- explicit_rdpcm_dir_flag = explicit_rdpcm_dir_flag_decode(s, c_idx); -++ may_hide_sign = 0; -++ explicit_rdpcm_dir_flag = explicit_rdpcm_dir_flag_decode(s, c_idx_nz); -+ } -+ } -+ -+- last_significant_coeff_xy_prefix_decode(s, c_idx, log2_trafo_size, -++ last_significant_coeff_xy_prefix_decode(s, c_idx_nz, log2_trafo_size, -+ &last_significant_coeff_x, &last_significant_coeff_y); -+ -+ if (last_significant_coeff_x > 3) { -+@@ -1189,119 +1737,113 @@ void ff_hevc_hls_residual_coding(HEVCContext *s, int x0, int y0, -+ int last_x_c = last_significant_coeff_x & 3; -+ int last_y_c = last_significant_coeff_y & 3; -+ -+- scan_x_off = ff_hevc_diag_scan4x4_x; -+- scan_y_off = ff_hevc_diag_scan4x4_y; -+ num_coeff = diag_scan4x4_inv[last_y_c][last_x_c]; -+- if (trafo_size == 4) { -++ -++ switch (log2_trafo_size) { -++ case 2: -+ scan_x_cg = scan_1x1; -+ scan_y_cg = scan_1x1; -+- } else if (trafo_size == 8) { -++ break; -++ case 3: -+ num_coeff += diag_scan2x2_inv[y_cg_last_sig][x_cg_last_sig] << 4; -+ scan_x_cg = diag_scan2x2_x; -+ scan_y_cg = diag_scan2x2_y; -+- } else if (trafo_size == 16) { -++ break; -++ case 4: -+ num_coeff += diag_scan4x4_inv[y_cg_last_sig][x_cg_last_sig] << 4; -+ scan_x_cg = ff_hevc_diag_scan4x4_x; -+ scan_y_cg = ff_hevc_diag_scan4x4_y; -+- } else { // trafo_size == 32 -++ break; -++ case 5: -++ default: -+ num_coeff += diag_scan8x8_inv[y_cg_last_sig][x_cg_last_sig] << 4; -+ scan_x_cg = ff_hevc_diag_scan8x8_x; -+ scan_y_cg = ff_hevc_diag_scan8x8_y; -++ break; -+ } -+ break; -+ } -+ case SCAN_HORIZ: -+ scan_x_cg = horiz_scan2x2_x; -+ scan_y_cg = horiz_scan2x2_y; -+- scan_x_off = horiz_scan4x4_x; -+- scan_y_off = horiz_scan4x4_y; -+ num_coeff = horiz_scan8x8_inv[last_significant_coeff_y][last_significant_coeff_x]; -+ break; -+ default: //SCAN_VERT -+ scan_x_cg = horiz_scan2x2_y; -+ scan_y_cg = horiz_scan2x2_x; -+- scan_x_off = horiz_scan4x4_y; -+- scan_y_off = horiz_scan4x4_x; -+ num_coeff = horiz_scan8x8_inv[last_significant_coeff_x][last_significant_coeff_y]; -+ break; -+ } -+ num_coeff++; -+ num_last_subset = (num_coeff - 1) >> 4; -+ -+- for (i = num_last_subset; i >= 0; i--) { -+- int n, m; -+- int x_cg, y_cg, x_c, y_c, pos; -+- int implicit_non_zero_coeff = 0; -+- int64_t trans_coeff_level; -+- int prev_sig = 0; -+- int offset = i << 4; -+- int rice_init = 0; -+- -+- uint8_t significant_coeff_flag_idx[16]; -+- uint8_t nb_significant_coeff_flag = 0; -++ significant_coeff_group_flag[y_cg_last_sig] = 1 << x_cg_last_sig; // 1st subset always significant -+ -+- x_cg = scan_x_cg[i]; -+- y_cg = scan_y_cg[i]; -++ scan_xy_off = off_xys[scan_idx][log2_trafo_size - 2]; -+ -+- if ((i < num_last_subset) && (i > 0)) { -+- int ctx_cg = 0; -+- if (x_cg < (1 << (log2_trafo_size - 2)) - 1) -+- ctx_cg += significant_coeff_group_flag[x_cg + 1][y_cg]; -+- if (y_cg < (1 << (log2_trafo_size - 2)) - 1) -+- ctx_cg += significant_coeff_group_flag[x_cg][y_cg + 1]; -+- -+- significant_coeff_group_flag[x_cg][y_cg] = -+- significant_coeff_group_flag_decode(s, c_idx, ctx_cg); -+- implicit_non_zero_coeff = 1; -+- } else { -+- significant_coeff_group_flag[x_cg][y_cg] = -+- ((x_cg == x_cg_last_sig && y_cg == y_cg_last_sig) || -+- (x_cg == 0 && y_cg == 0)); -+- } -++ i = num_last_subset; -++ do { -++ int implicit_non_zero_coeff = 0; -++ int n_end; -+ -+- last_scan_pos = num_coeff - offset - 1; -++ uint8_t significant_coeff_flag_idx[16]; -++ unsigned int nb_significant_coeff_flag = 0; -+ -+ if (i == num_last_subset) { -++ // First time through -++ int last_scan_pos = num_coeff - (i << 4) - 1; -+ n_end = last_scan_pos - 1; -+ significant_coeff_flag_idx[0] = last_scan_pos; -+ nb_significant_coeff_flag = 1; -+ } else { -+ n_end = 15; -++ implicit_non_zero_coeff = (i != 0); -+ } -+ -+- if (x_cg < ((1 << log2_trafo_size) - 1) >> 2) -+- prev_sig = !!significant_coeff_group_flag[x_cg + 1][y_cg]; -+- if (y_cg < ((1 << log2_trafo_size) - 1) >> 2) -+- prev_sig += (!!significant_coeff_group_flag[x_cg][y_cg + 1] << 1); -+- -+- if (significant_coeff_group_flag[x_cg][y_cg] && n_end >= 0) { -+- static const uint8_t ctx_idx_map[] = { -+- 0, 1, 4, 5, 2, 3, 4, 5, 6, 6, 8, 8, 7, 7, 8, 8, // log2_trafo_size == 2 -+- 1, 1, 1, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, // prev_sig == 0 -+- 2, 2, 2, 2, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, // prev_sig == 1 -+- 2, 1, 0, 0, 2, 1, 0, 0, 2, 1, 0, 0, 2, 1, 0, 0, // prev_sig == 2 -+- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 // default -++ if (n_end >= 0) { -++ static const uint8_t ctx_idx_maps_ts2[3][16] = { -++ D4x4(0, 1, 4, 5, 2, 3, 4, 5, 6, 6, 8, 8, 7, 7, 8, 8), // log2_trafo_size == 2 -++ H4x4(0, 1, 4, 5, 2, 3, 4, 5, 6, 6, 8, 8, 7, 7, 8, 8), // log2_trafo_size == 2 -++ V4x4(0, 1, 4, 5, 2, 3, 4, 5, 6, 6, 8, 8, 7, 7, 8, 8) // log2_trafo_size == 2 -++ }; -++ static const uint8_t ctx_idx_maps[3][4][16] = { -++ { -++ D4x4(1, 1, 1, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0), // prev_sig == 0 -++ D4x4(2, 2, 2, 2, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0), // prev_sig == 1 -++ D4x4(2, 1, 0, 0, 2, 1, 0, 0, 2, 1, 0, 0, 2, 1, 0, 0), // prev_sig == 2 -++ D4x4(2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2) // prev_sig == 3, default -++ }, -++ { -++ H4x4(1, 1, 1, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0), // prev_sig == 0 -++ H4x4(2, 2, 2, 2, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0), // prev_sig == 1 -++ H4x4(2, 1, 0, 0, 2, 1, 0, 0, 2, 1, 0, 0, 2, 1, 0, 0), // prev_sig == 2 -++ H4x4(2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2) // prev_sig == 3, default -++ }, -++ { -++ V4x4(1, 1, 1, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0), // prev_sig == 0 -++ V4x4(2, 2, 2, 2, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0), // prev_sig == 1 -++ V4x4(2, 1, 0, 0, 2, 1, 0, 0, 2, 1, 0, 0, 2, 1, 0, 0), // prev_sig == 2 -++ V4x4(2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2) // prev_sig == 3, default -++ } -+ }; -+ const uint8_t *ctx_idx_map_p; -+ int scf_offset = 0; -+- if (s->ps.sps->transform_skip_context_enabled_flag && -+- (transform_skip_flag || lc->cu.cu_transquant_bypass_flag)) { -+- ctx_idx_map_p = (uint8_t*) &ctx_idx_map[4 * 16]; -+- if (c_idx == 0) { -+- scf_offset = 40; -+- } else { -+- scf_offset = 14 + 27; -+- } -++ -++ if (s->ps.sps->transform_skip_context_enabled_flag && trans_skip_or_bypass) { -++ ctx_idx_map_p = ctx_idx_maps[0][3]; -++ scf_offset = 40 + c_idx_nz; -+ } else { -+- if (c_idx != 0) -++ if (c_idx_nz != 0) -+ scf_offset = 27; -++ -+ if (log2_trafo_size == 2) { -+- ctx_idx_map_p = (uint8_t*) &ctx_idx_map[0]; -++ ctx_idx_map_p = ctx_idx_maps_ts2[scan_idx]; -+ } else { -+- ctx_idx_map_p = (uint8_t*) &ctx_idx_map[(prev_sig + 1) << 4]; -+- if (c_idx == 0) { -+- if ((x_cg > 0 || y_cg > 0)) -++ ctx_idx_map_p = ctx_idx_maps[scan_idx][prev_sig]; -++ if (!c_idx_nz) { -++ if (i != 0) -+ scf_offset += 3; -++ -+ if (log2_trafo_size == 3) { -+ scf_offset += (scan_idx == SCAN_DIAG) ? 9 : 15; -+ } else { -+@@ -1315,34 +1857,30 @@ void ff_hevc_hls_residual_coding(HEVCContext *s, int x0, int y0, -+ } -+ } -+ } -+- for (n = n_end; n > 0; n--) { -+- x_c = scan_x_off[n]; -+- y_c = scan_y_off[n]; -+- if (significant_coeff_flag_decode(s, x_c, y_c, scf_offset, ctx_idx_map_p)) { -+- significant_coeff_flag_idx[nb_significant_coeff_flag] = n; -+- nb_significant_coeff_flag++; -++ -++ if (n_end > 0) { -++ int cnt = get_sig_coeff_flag_idxs(&s->HEVClc->cc, -++ s->HEVClc->cabac_state + elem_offset[SIGNIFICANT_COEFF_FLAG] + scf_offset, -++ n_end, ctx_idx_map_p, -++ significant_coeff_flag_idx + nb_significant_coeff_flag); -++ -++ nb_significant_coeff_flag += cnt; -++ if (cnt != 0) { -+ implicit_non_zero_coeff = 0; -+ } -+ } -++ -+ if (implicit_non_zero_coeff == 0) { -+- if (s->ps.sps->transform_skip_context_enabled_flag && -+- (transform_skip_flag || lc->cu.cu_transquant_bypass_flag)) { -+- if (c_idx == 0) { -+- scf_offset = 42; -+- } else { -+- scf_offset = 16 + 27; -+- } -++ if (s->ps.sps->transform_skip_context_enabled_flag && trans_skip_or_bypass) { -++ scf_offset = 42 + c_idx_nz; -+ } else { -+ if (i == 0) { -+- if (c_idx == 0) -+- scf_offset = 0; -+- else -+- scf_offset = 27; -++ scf_offset = c_idx_nz ? 27 : 0; -+ } else { -+ scf_offset = 2 + scf_offset; -+ } -+ } -+- if (significant_coeff_flag_decode_0(s, c_idx, scf_offset) == 1) { -++ if (significant_coeff_flag_decode_0(s, scf_offset) == 1) { -+ significant_coeff_flag_idx[nb_significant_coeff_flag] = 0; -+ nb_significant_coeff_flag++; -+ } -+@@ -1352,141 +1890,185 @@ void ff_hevc_hls_residual_coding(HEVCContext *s, int x0, int y0, -+ } -+ } -+ -+- n_end = nb_significant_coeff_flag; -+- -++ if (nb_significant_coeff_flag != 0) { -++ const unsigned int gt1_idx_delta = (c_idx_nz << 2) | -++ ((i != 0 && !c_idx_nz) ? 2 : 0) | -++ prev_subset_coded; -++ const unsigned int idx0_gt1 = elem_offset[COEFF_ABS_LEVEL_GREATER1_FLAG] + -++ (gt1_idx_delta << 2); -++ const unsigned int idx_gt2 = elem_offset[COEFF_ABS_LEVEL_GREATER2_FLAG] + -++ gt1_idx_delta; -++ -++ const unsigned int x_cg = scan_x_cg[i]; -++ const unsigned int y_cg = scan_y_cg[i]; -++ int16_t * const blk_coeffs = coeffs + -++ ((x_cg + (y_cg << log2_trafo_size)) << 2); -++ // This calculation is 'wrong' for log2_traffo_size == 2 -++ // but that doesn't mattor as in this case x_cg & y_cg -++ // are always 0 so result is correct (0) anyway -++ const uint8_t * const blk_scale = scale_matrix + -++ (((x_cg + (y_cg << 3)) << (5 - log2_trafo_size))); -++ -++ // * THe following code block doesn't deal with these flags: -++ // (nor did the one it replaces) -++ // -++ // cabac_bypass_alignment_enabled_flag -++ // This should be easy but I can't find a test case -++ // extended_precision_processing_flag -++ // This can extend the required precision past 16bits -++ // so is probably tricky - also no example found yet -++ -++#if USE_N_END_1 -++ if (nb_significant_coeff_flag == 1) { -++ // There is a small gain to be had from special casing the single -++ // transform coefficient case. The reduction in complexity -++ // makes up for the code duplicatioon. -++ -++ int trans_coeff_level = 1; -++ int coeff_sign_flag; -++ int coded_val = 0; -++ -++ // initialize first elem of coeff_bas_level_greater1_flag -++ prev_subset_coded = 0; -++ -++ if (get_cabac(&s->HEVClc->cc, s->HEVClc->cabac_state + idx0_gt1 + 1)) { -++ trans_coeff_level = 2; -++ prev_subset_coded = 1; -++ coded_val = get_cabac(&s->HEVClc->cc, s->HEVClc->cabac_state + idx_gt2); -++ } -+ -+- if (n_end) { -+- int first_nz_pos_in_cg; -+- int last_nz_pos_in_cg; -+- int c_rice_param = 0; -+- int first_greater1_coeff_idx = -1; -+- uint8_t coeff_abs_level_greater1_flag[8]; -+- uint16_t coeff_sign_flag; -+- int sum_abs = 0; -+- int sign_hidden; -+- int sb_type; -++ // Probably not worth the overhead of starting by22 for just one value -++ coeff_sign_flag = get_cabac_bypass(&s->HEVClc->cc); -+ -++ if (coded_val) -++ { -++ if (!s->ps.sps->persistent_rice_adaptation_enabled_flag) { -++ trans_coeff_level = 3 + coeff_abs_level_remaining_decode(s, 0); -++ } else { -++ uint8_t * const stat_coeff = -++ lc->stat_coeff + trans_skip_or_bypass + 2 - ((c_idx_nz) << 1); -++ const unsigned int c_rice_param = *stat_coeff >> 2; -++ const int last_coeff_abs_level_remaining = coeff_abs_level_remaining_decode(s, c_rice_param); -+ -+- // initialize first elem of coeff_bas_level_greater1_flag -+- int ctx_set = (i > 0 && c_idx == 0) ? 2 : 0; -++ trans_coeff_level = 3 + last_coeff_abs_level_remaining; -++ update_rice(stat_coeff, last_coeff_abs_level_remaining, c_rice_param); -++ } -++ } -+ -+- if (s->ps.sps->persistent_rice_adaptation_enabled_flag) { -+- if (!transform_skip_flag && !lc->cu.cu_transquant_bypass_flag) -+- sb_type = 2 * (c_idx == 0 ? 1 : 0); -+- else -+- sb_type = 2 * (c_idx == 0 ? 1 : 0) + 1; -+- c_rice_param = lc->stat_coeff[sb_type] / 4; -+- } -++ { -++ const xy_off_t * const xy_off = scan_xy_off + significant_coeff_flag_idx[0]; -++ const int k = (int32_t)(coeff_sign_flag << 31) >> 31; -++ const unsigned int scale_m = blk_scale[xy_off->scale]; -+ -+- if (!(i == num_last_subset) && greater1_ctx == 0) -+- ctx_set++; -+- greater1_ctx = 1; -+- last_nz_pos_in_cg = significant_coeff_flag_idx[0]; -+- -+- for (m = 0; m < (n_end > 8 ? 8 : n_end); m++) { -+- int inc = (ctx_set << 2) + greater1_ctx; -+- coeff_abs_level_greater1_flag[m] = -+- coeff_abs_level_greater1_flag_decode(s, c_idx, inc); -+- if (coeff_abs_level_greater1_flag[m]) { -+- greater1_ctx = 0; -+- if (first_greater1_coeff_idx == -1) -+- first_greater1_coeff_idx = m; -+- } else if (greater1_ctx > 0 && greater1_ctx < 3) { -+- greater1_ctx++; -++ blk_coeffs[xy_off->coeff] = trans_scale_sat( -++ (trans_coeff_level ^ k) - k, // Apply sign -++ scale, -++ i == 0 && xy_off->coeff == 0 ? dc_scale : scale_m, -++ shift); -+ } -+ } -+- first_nz_pos_in_cg = significant_coeff_flag_idx[n_end - 1]; -+- -+- if (lc->cu.cu_transquant_bypass_flag || -+- (lc->cu.pred_mode == MODE_INTRA && -+- s->ps.sps->implicit_rdpcm_enabled_flag && transform_skip_flag && -+- (pred_mode_intra == 10 || pred_mode_intra == 26 )) || -+- explicit_rdpcm_flag) -+- sign_hidden = 0; -+ else -+- sign_hidden = (last_nz_pos_in_cg - first_nz_pos_in_cg >= 4); -++#endif -++ { -++ int sign_hidden = may_hide_sign; -++ int levels[16]; // Should be able to get away with int16_t but that fails some tests -++ uint32_t coeff_sign_flags; -++ uint32_t coded_vals = 0; -++ // Sum(abs(level[])) -++ // In fact we only need the bottom bit and in some future -++ // version that may be all we calculate -++ unsigned int sum_abs; -++ -++ coded_vals = get_greaterx_bits(s, nb_significant_coeff_flag, levels, -++ &prev_subset_coded, &sum_abs, idx0_gt1, idx_gt2); -++ -++ if (significant_coeff_flag_idx[0] - significant_coeff_flag_idx[nb_significant_coeff_flag - 1] <= 3) -++ sign_hidden = 0; -++ -++ // -- Start bypass block -++ -++ bypass_start(s); -++ -++ coeff_sign_flags = coeff_sign_flag_decode_bypass(s, nb_significant_coeff_flag - sign_hidden); -++ -++ if (coded_vals != 0) -++ { -++ const int rice_adaptation_enabled = s->ps.sps->persistent_rice_adaptation_enabled_flag; -++ uint8_t * stat_coeff = !rice_adaptation_enabled ? NULL : -++ lc->stat_coeff + trans_skip_or_bypass + 2 - ((c_idx_nz) << 1); -++ int c_rice_param = !rice_adaptation_enabled ? 0 : *stat_coeff >> 2; -++ int * level = levels - 1; -++ -++ do { -++ { -++ const unsigned int z = hevc_clz32(coded_vals) + 1; -++ level += z; -++ coded_vals <<= z; -++ } -+ -+- if (first_greater1_coeff_idx != -1) { -+- coeff_abs_level_greater1_flag[first_greater1_coeff_idx] += coeff_abs_level_greater2_flag_decode(s, c_idx, ctx_set); -+- } -+- if (!s->ps.pps->sign_data_hiding_flag || !sign_hidden ) { -+- coeff_sign_flag = coeff_sign_flag_decode(s, nb_significant_coeff_flag) << (16 - nb_significant_coeff_flag); -+- } else { -+- coeff_sign_flag = coeff_sign_flag_decode(s, nb_significant_coeff_flag - 1) << (16 - (nb_significant_coeff_flag - 1)); -+- } -++ { -++ const int last_coeff_abs_level_remaining = coeff_abs_level_remaining_decode_bypass(s, c_rice_param); -++ const int trans_coeff_level = *level + last_coeff_abs_level_remaining + 1; -++ -++ sum_abs += last_coeff_abs_level_remaining + 1; -++ *level = trans_coeff_level; -+ -+- for (m = 0; m < n_end; m++) { -+- n = significant_coeff_flag_idx[m]; -+- GET_COORD(offset, n); -+- if (m < 8) { -+- trans_coeff_level = 1 + coeff_abs_level_greater1_flag[m]; -+- if (trans_coeff_level == ((m == first_greater1_coeff_idx) ? 3 : 2)) { -+- int last_coeff_abs_level_remaining = coeff_abs_level_remaining_decode(s, c_rice_param); -+- -+- trans_coeff_level += last_coeff_abs_level_remaining; -+- if (trans_coeff_level > (3 << c_rice_param)) -+- c_rice_param = s->ps.sps->persistent_rice_adaptation_enabled_flag ? c_rice_param + 1 : FFMIN(c_rice_param + 1, 4); -+- if (s->ps.sps->persistent_rice_adaptation_enabled_flag && !rice_init) { -+- int c_rice_p_init = lc->stat_coeff[sb_type] / 4; -+- if (last_coeff_abs_level_remaining >= (3 << c_rice_p_init)) -+- lc->stat_coeff[sb_type]++; -+- else if (2 * last_coeff_abs_level_remaining < (1 << c_rice_p_init)) -+- if (lc->stat_coeff[sb_type] > 0) -+- lc->stat_coeff[sb_type]--; -+- rice_init = 1; -++ if (stat_coeff != NULL) -++ update_rice(stat_coeff, last_coeff_abs_level_remaining, c_rice_param); -++ stat_coeff = NULL; -++ -++ if (trans_coeff_level > (3 << c_rice_param) && -++ (c_rice_param < 4 || rice_adaptation_enabled)) -++ ++c_rice_param; -+ } -+- } -+- } else { -+- int last_coeff_abs_level_remaining = coeff_abs_level_remaining_decode(s, c_rice_param); -+- -+- trans_coeff_level = 1 + last_coeff_abs_level_remaining; -+- if (trans_coeff_level > (3 << c_rice_param)) -+- c_rice_param = s->ps.sps->persistent_rice_adaptation_enabled_flag ? c_rice_param + 1 : FFMIN(c_rice_param + 1, 4); -+- if (s->ps.sps->persistent_rice_adaptation_enabled_flag && !rice_init) { -+- int c_rice_p_init = lc->stat_coeff[sb_type] / 4; -+- if (last_coeff_abs_level_remaining >= (3 << c_rice_p_init)) -+- lc->stat_coeff[sb_type]++; -+- else if (2 * last_coeff_abs_level_remaining < (1 << c_rice_p_init)) -+- if (lc->stat_coeff[sb_type] > 0) -+- lc->stat_coeff[sb_type]--; -+- rice_init = 1; -+- } -++ } while (coded_vals != 0); -+ } -+- if (s->ps.pps->sign_data_hiding_flag && sign_hidden) { -+- sum_abs += trans_coeff_level; -+- if (n == first_nz_pos_in_cg && (sum_abs&1)) -+- trans_coeff_level = -trans_coeff_level; -++ -++ // sign_hidden = 0 or 1 so we can combine the tests -++ if ((sign_hidden & sum_abs) != 0) { -++ levels[nb_significant_coeff_flag - 1] = -levels[nb_significant_coeff_flag - 1]; -+ } -+- if (coeff_sign_flag >> 15) -+- trans_coeff_level = -trans_coeff_level; -+- coeff_sign_flag <<= 1; -+- if(!lc->cu.cu_transquant_bypass_flag) { -+- if (s->ps.sps->scaling_list_enable_flag && !(transform_skip_flag && log2_trafo_size > 2)) { -+- if(y_c || x_c || log2_trafo_size < 4) { -+- switch(log2_trafo_size) { -+- case 3: pos = (y_c << 3) + x_c; break; -+- case 4: pos = ((y_c >> 1) << 3) + (x_c >> 1); break; -+- case 5: pos = ((y_c >> 2) << 3) + (x_c >> 2); break; -+- default: pos = (y_c << 2) + x_c; break; -+- } -+- scale_m = scale_matrix[pos]; -+- } else { -+- scale_m = dc_scale; -+- } -++ -++ bypass_finish(s); -++ -++ // -- Finish bypass block -++ -++ // Scale loop -++ { -++ int m = nb_significant_coeff_flag - 1; -++ -++ // Deal with DC component (if any) first -++ if (i == 0 && significant_coeff_flag_idx[m] == 0) -++ { -++ const int k = (int32_t)(coeff_sign_flags << m) >> 31; -++ blk_coeffs[0] = trans_scale_sat( -++ (levels[m] ^ k) - k, scale, dc_scale, shift); -++ --m; -+ } -+- trans_coeff_level = (trans_coeff_level * (int64_t)scale * (int64_t)scale_m + add) >> shift; -+- if(trans_coeff_level < 0) { -+- if((~trans_coeff_level) & 0xFffffffffff8000) -+- trans_coeff_level = -32768; -+- } else { -+- if(trans_coeff_level & 0xffffffffffff8000) -+- trans_coeff_level = 32767; -++ -++#if !USE_N_END_1 -++ // If N_END_! set then m was at least 1 initially -++ if (m >= 0) -++#endif -++ { -++ do { -++ const xy_off_t * const xy_off = scan_xy_off + -++ significant_coeff_flag_idx[m]; -++ const int k = (int32_t)(coeff_sign_flags << m) >> 31; -++ -++ blk_coeffs[xy_off->coeff] = trans_scale_sat( -++ (levels[m] ^ k) - k, -++ scale, -++ blk_scale[xy_off->scale], -++ shift); -++ } while (--m >= 0); -+ } -+ } -+- coeffs[y_c * trafo_size + x_c] = trans_coeff_level; -++ -+ } -+ } -+- } -++ } while ((i = next_subset(s, i, c_idx_nz, -++ significant_coeff_group_flag, scan_x_cg, scan_y_cg, &prev_sig)) >= 0); -+ -+ if (lc->cu.cu_transquant_bypass_flag) { -+ if (explicit_rdpcm_flag || (s->ps.sps->implicit_rdpcm_enabled_flag && -+@@ -1496,7 +2078,7 @@ void ff_hevc_hls_residual_coding(HEVCContext *s, int x0, int y0, -+ s->hevcdsp.transform_rdpcm(coeffs, log2_trafo_size, mode); -+ } -+ } else { -+- if (transform_skip_flag) { -++ if (trans_skip_or_bypass) { // Must be trans_skip as we've already dealt with bypass -+ int rot = s->ps.sps->transform_skip_rotation_enabled_flag && -+ log2_trafo_size == 2 && -+ lc->cu.pred_mode == MODE_INTRA; -+-- -+2.5.0 -+ -diff --git a/tools/depends/target/ffmpeg/0001-avcodec-add-h264_mvc-codec-id-and-profiles.patch b/tools/depends/target/ffmpeg/0001-avcodec-add-h264_mvc-codec-id-and-profiles.patch -new file mode 100644 -index 0000000..c191dd1 ---- /dev/null -+++ b/tools/depends/target/ffmpeg/0001-avcodec-add-h264_mvc-codec-id-and-profiles.patch -@@ -0,0 +1,67 @@ -+From f2e011c656b3579b6ede184bb5c56a7b97fad0f3 Mon Sep 17 00:00:00 2001 -+From: Hendrik Leppkes -+Date: Sat, 9 Jan 2016 15:34:09 +0100 -+Subject: [PATCH] avcodec: add h264_mvc codec id and profiles -+ -+avcodec: add h264_mvc codec id and profiles -+--- -+ libavcodec/avcodec.h | 5 +++++ -+ libavcodec/codec_desc.c | 7 +++++++ -+ libavcodec/profiles.c | 3 +++ -+ libavformat/mpegts.c | 2 +- -+ 4 files changed, 16 insertions(+), 1 deletion(-) -+ -+diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h -+index f365775..8498921 100644 -+--- a/libavcodec/avcodec.h -++++ b/libavcodec/avcodec.h -+@@ -316,6 +316,8 @@ enum AVCodecID { -+ AV_CODEC_ID_APNG, -+ AV_CODEC_ID_DAALA, -+ -++ AV_CODEC_ID_H264_MVC, -++ -+ /* various PCM "codecs" */ -+ AV_CODEC_ID_FIRST_AUDIO = 0x10000, ///< A dummy id pointing at the start of audio codecs -+ AV_CODEC_ID_PCM_S16LE = 0x10000, -+@@ -3086,6 +3088,9 @@ typedef struct AVCodecContext { -+ #define FF_PROFILE_H264_HIGH_444_PREDICTIVE 244 -+ #define FF_PROFILE_H264_HIGH_444_INTRA (244|FF_PROFILE_H264_INTRA) -+ #define FF_PROFILE_H264_CAVLC_444 44 -++#define FF_PROFILE_H264_MULTIVIEW_HIGH 118 -++#define FF_PROFILE_H264_STEREO_HIGH 128 -++#define FF_PROFILE_H264_MULTIVIEW_HIGH_DEPTH 138 -+ -+ #define FF_PROFILE_VC1_SIMPLE 0 -+ #define FF_PROFILE_VC1_MAIN 1 -+diff --git a/libavcodec/codec_desc.c b/libavcodec/codec_desc.c -+index 5fbe624..9431bd8 100644 -+--- a/libavcodec/codec_desc.c -++++ b/libavcodec/codec_desc.c -+@@ -1521,6 +1521,13 @@ static const AVCodecDescriptor codec_descriptors[] = { -+ .props = AV_CODEC_PROP_LOSSLESS, -+ .mime_types= MT("image/png"), -+ }, -++ { -++ .id = AV_CODEC_ID_H264_MVC, -++ .type = AVMEDIA_TYPE_VIDEO, -++ .name = "h264_mvc", -++ .long_name = NULL_IF_CONFIG_SMALL("H264 MVC"), -++ .props = AV_CODEC_PROP_LOSSY, -++ }, -+ -+ /* various PCM "codecs" */ -+ { -+diff --git a/libavformat/mpegts.c b/libavformat/mpegts.c -+index 22874e6..34b6987 100644 -+--- a/libavformat/mpegts.c -++++ b/libavformat/mpegts.c -+@@ -698,7 +698,7 @@ static const StreamType ISO_types[] = { -+ { 0x11, AVMEDIA_TYPE_AUDIO, AV_CODEC_ID_AAC_LATM }, /* LATM syntax */ -+ #endif -+ { 0x1b, AVMEDIA_TYPE_VIDEO, AV_CODEC_ID_H264 }, -+- { 0x20, AVMEDIA_TYPE_VIDEO, AV_CODEC_ID_H264 }, -++ { 0x20, AVMEDIA_TYPE_VIDEO, AV_CODEC_ID_H264_MVC }, -+ { 0x21, AVMEDIA_TYPE_VIDEO, AV_CODEC_ID_JPEG2000 }, -+ { 0x24, AVMEDIA_TYPE_VIDEO, AV_CODEC_ID_HEVC }, -+ { 0x42, AVMEDIA_TYPE_VIDEO, AV_CODEC_ID_CAVS }, -diff --git a/tools/depends/target/ffmpeg/0001-h264_parser-add-support-for-parsing-h264-mvc-NALUs.patch b/tools/depends/target/ffmpeg/0001-h264_parser-add-support-for-parsing-h264-mvc-NALUs.patch -new file mode 100644 -index 0000000..06e4347 ---- /dev/null -+++ b/tools/depends/target/ffmpeg/0001-h264_parser-add-support-for-parsing-h264-mvc-NALUs.patch -@@ -0,0 +1,113 @@ -+From 0b857974bc3f2f48800526efbe02b9e72fdeb266 Mon Sep 17 00:00:00 2001 -+From: Hendrik Leppkes -+Date: Sat, 9 Jan 2016 16:34:40 +0100 -+Subject: [PATCH] h264_parser: add support for parsing h264 mvc NALUs -+ -+--- -+ libavcodec/allcodecs.c | 1 + -+ libavcodec/h264.h | 2 ++ -+ libavcodec/h264_parser.c | 34 ++++++++++++++++++++++++++++++---- -+ 3 files changed, 33 insertions(+), 4 deletions(-) -+ -+diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c -+index 2097db0..66eb571 100644 -+--- a/libavcodec/allcodecs.c -++++ b/libavcodec/allcodecs.c -+@@ -633,6 +633,7 @@ void avcodec_register_all(void) -+ REGISTER_PARSER(H261, h261); -+ REGISTER_PARSER(H263, h263); -+ REGISTER_PARSER(H264, h264); -++ REGISTER_PARSER(H264_MVC, h264_mvc); -+ REGISTER_PARSER(HEVC, hevc); -+ REGISTER_PARSER(MJPEG, mjpeg); -+ REGISTER_PARSER(MLP, mlp); -+diff --git a/libavcodec/h264.h b/libavcodec/h264.h -+index 78f4eed..9e1d377 100644 -+--- a/libavcodec/h264.h -++++ b/libavcodec/h264.h -+@@ -123,7 +123,9 @@ enum { -+ NAL_END_STREAM = 11, -+ NAL_FILLER_DATA = 12, -+ NAL_SPS_EXT = 13, -++ NAL_SPS_SUBSET = 15, -+ NAL_AUXILIARY_SLICE = 19, -++ NAL_SLICE_EXT = 20, -+ NAL_FF_IGNORE = 0xff0f001, -+ }; -+ -+diff --git a/libavcodec/h264_parser.c b/libavcodec/h264_parser.c -+index 12d6397..4337c8c 100644 -+--- a/libavcodec/h264_parser.c -++++ b/libavcodec/h264_parser.c -+@@ -38,6 +38,7 @@ typedef struct H264ParseContext { -+ H264Context h; -+ ParseContext pc; -+ int got_first; -++ int is_mvc; -+ } H264ParseContext; -+ -+ -+@@ -86,14 +87,18 @@ static int h264_find_frame_end(H264ParseContext *p, const uint8_t *buf, -+ } else if (state <= 5) { -+ int nalu_type = buf[i] & 0x1F; -+ if (nalu_type == NAL_SEI || nalu_type == NAL_SPS || -+- nalu_type == NAL_PPS || nalu_type == NAL_AUD) { -++ nalu_type == NAL_PPS || nalu_type == NAL_AUD || -++ nalu_type == NAL_SPS_SUBSET) { -+ if (pc->frame_start_found) { -+ i++; -+ goto found; -+ } -+ } else if (nalu_type == NAL_SLICE || nalu_type == NAL_DPA || -+- nalu_type == NAL_IDR_SLICE) { -++ nalu_type == NAL_IDR_SLICE || (p->is_mvc && nalu_type == NAL_SLICE_EXT)) { -+ state += 8; -++ -++ if (nalu_type == NAL_SLICE_EXT) -++ i += 3; // skip mvc extension -+ continue; -+ } -+ state = 7; -+@@ -532,7 +537,8 @@ static int h264_parse(AVCodecParserContext *s, -+ } -+ } -+ -+- parse_nal_units(s, avctx, buf, buf_size); -++ if (!p->is_mvc) -++ parse_nal_units(s, avctx, buf, buf_size); -+ -+ if (avctx->framerate.num) -+ avctx->time_base = av_inv_q(av_mul_q(avctx->framerate, (AVRational){avctx->ticks_per_frame, 1})); -+@@ -569,7 +575,7 @@ static int h264_split(AVCodecContext *avctx, -+ if ((state & 0xFFFFFF00) != 0x100) -+ break; -+ nalu_type = state & 0x1F; -+- if (nalu_type == NAL_SPS) { -++ if (nalu_type == NAL_SPS || nalu_type == NAL_SPS_SUBSET) { -+ has_sps = 1; -+ } else if (nalu_type == NAL_PPS) -+ has_pps = 1; -+@@ -625,3 +631,23 @@ AVCodecParser ff_h264_parser = { -+ .parser_close = h264_close, -+ .split = h264_split, -+ }; -++ -++static av_cold int init_mvc(AVCodecParserContext *s) -++{ -++ H264ParseContext *p = s->priv_data; -++ int ret = init(s); -++ if (ret < 0) -++ return ret; -++ -++ p->is_mvc = 1; -++ return 0; -++} -++ -++AVCodecParser ff_h264_mvc_parser = { -++ .codec_ids = { AV_CODEC_ID_H264_MVC }, -++ .priv_data_size = sizeof(H264ParseContext), -++ .parser_init = init_mvc, -++ .parser_parse = h264_parse, -++ .parser_close = h264_close, -++ .split = h264_split, -++}; -diff --git a/tools/depends/target/ffmpeg/0001-mpeg4video-Signal-unsupported-GMC-with-more-than-one.patch b/tools/depends/target/ffmpeg/0001-mpeg4video-Signal-unsupported-GMC-with-more-than-one.patch -new file mode 100644 -index 0000000..4cb8dd8 ---- /dev/null -+++ b/tools/depends/target/ffmpeg/0001-mpeg4video-Signal-unsupported-GMC-with-more-than-one.patch -@@ -0,0 +1,48 @@ -+From 84e9a1784bbd3182b68cefa5e5feae8da8b9e184 Mon Sep 17 00:00:00 2001 -+From: popcornmix -+Date: Fri, 5 Jun 2015 22:48:33 +0100 -+Subject: [PATCH] mpeg4video: Signal unsupported GMC with more than one warp -+ point -+ -+--- -+ libavcodec/avcodec.h | 1 + -+ libavcodec/mpeg4videodec.c | 4 ++++ -+ 2 files changed, 5 insertions(+) -+ -+diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h -+index 8c7c420..e63dc2d 100644 -+--- a/libavcodec/avcodec.h -++++ b/libavcodec/avcodec.h -+@@ -2527,6 +2527,7 @@ typedef struct AVCodecContext { -+ #define FF_BUG_DC_CLIP 4096 -+ #define FF_BUG_MS 8192 ///< Work around various bugs in Microsoft's broken decoders. -+ #define FF_BUG_TRUNCATED 16384 -++#define FF_BUG_GMC_UNSUPPORTED 32768 -+ -+ /** -+ * strictly follow the standard (MPEG4, ...). -+diff --git a/libavcodec/mpeg4videodec.c b/libavcodec/mpeg4videodec.c -+index 9bf33dd..0b5d3b9 100644 -+--- a/libavcodec/mpeg4videodec.c -++++ b/libavcodec/mpeg4videodec.c -+@@ -2179,6 +2179,9 @@ int ff_mpeg4_workaround_bugs(AVCodecContext *avctx) -+ -+ if (ctx->divx_version >= 0) -+ s->workaround_bugs |= FF_BUG_HPEL_CHROMA; -++ -++ if (ctx->num_sprite_warping_points > 1) -++ s->workaround_bugs |= FF_BUG_GMC_UNSUPPORTED; -+ } -+ -+ if (s->workaround_bugs & FF_BUG_STD_QPEL) { -+@@ -2203,6 +2206,7 @@ int ff_mpeg4_workaround_bugs(AVCodecContext *avctx) -+ s->workaround_bugs, ctx->lavc_build, ctx->xvid_build, -+ ctx->divx_version, ctx->divx_build, s->divx_packed ? "p" : ""); -+ -++ avctx->workaround_bugs = s->workaround_bugs; -+ if (CONFIG_MPEG4_DECODER && ctx->xvid_build >= 0 && -+ s->codec_id == AV_CODEC_ID_MPEG4 && -+ avctx->idct_algo == FF_IDCT_AUTO) { -+-- -+1.9.1 -+ -diff --git a/tools/depends/target/ffmpeg/73fde6f9f3d01f7fc0f3ae4b66f6c725f9fb1105.patch b/tools/depends/target/ffmpeg/73fde6f9f3d01f7fc0f3ae4b66f6c725f9fb1105.patch -new file mode 100644 -index 0000000..5240cf5 ---- /dev/null -+++ b/tools/depends/target/ffmpeg/73fde6f9f3d01f7fc0f3ae4b66f6c725f9fb1105.patch -@@ -0,0 +1,24 @@ -+From 73fde6f9f3d01f7fc0f3ae4b66f6c725f9fb1105 Mon Sep 17 00:00:00 2001 -+From: Hendrik Leppkes -+Date: Mon, 1 Sep 2014 11:39:09 +0200 -+Subject: [PATCH] h264_parser: force grabing a new timestamp until a frame -+ start was found -+ -+--- -+ libavcodec/h264_parser.c | 3 +++ -+ 1 file changed, 3 insertions(+) -+ -+diff --git a/libavcodec/h264_parser.c b/libavcodec/h264_parser.c -+index 2fd3f2b..7165652 100644 -+--- a/libavcodec/h264_parser.c -++++ b/libavcodec/h264_parser.c -+@@ -525,6 +525,9 @@ static int h264_parse(AVCodecParserContext *s, -+ } else { -+ next = h264_find_frame_end(p, buf, buf_size); -+ -++ if (next == END_NOT_FOUND && pc->frame_start_found == 0) -++ s->fetch_timestamp = 1; -++ -+ if (ff_combine_frame(pc, next, &buf, &buf_size) < 0) { -+ *poutbuf = NULL; -+ *poutbuf_size = 0; -diff --git a/tools/depends/target/ffmpeg/Makefile b/tools/depends/target/ffmpeg/Makefile -index 09e4193..5b2f19c 100644 ---- a/tools/depends/target/ffmpeg/Makefile -+++ b/tools/depends/target/ffmpeg/Makefile -@@ -1,10 +1,24 @@ --include ../../Makefile.include - include FFMPEG-VERSION --DEPS= ../../Makefile.include FFMPEG-VERSION Makefile -+ -+PLATFORM = ffmpeg-$(VERSION) -+RETRIEVE_TOOL = curl -+TARBALLS_LOCATION = $(shell pwd) -+ARCHIVE_TOOL = tar -+ARCHIVE_TOOL_FLAGS = --strip-components=1 -xf -+ -+DEPS= ../../Makefile.include FFMPEG-VERSION Makefile \ -+ 0001-mpeg4video-Signal-unsupported-GMC-with-more-than-one.patch \ -+ hevcdsp_ARM_NEON_optimized_epel_functions.patch added_ARM_NEON_optimized_SAO_patches.patch \ -+ pfcd_hevc_optimisations.patch \ -+ 0001-Squashed-commit-of-the-following.patch \ -+ 0001-avcodec-add-h264_mvc-codec-id-and-profiles.patch 0001-h264_parser-add-support-for-parsing-h264-mvc-NALUs.patch \ -+ h264_parser_fix_parsing_of_mvc_slices_in_some_corner_cases.patch \ -+ 73fde6f9f3d01f7fc0f3ae4b66f6c725f9fb1105.patch \ -+ 0001-Discard-data-before-VO-VOL-in-mpeg-4-over-mpegts.patch - - # set to "yes" to enable patching - # we don't apply patches until we move to a vanilla ffmpeg tarball --APPLY_PATCHES=no -+APPLY_PATCHES=yes - - # configuration settings - ffmpg_config = --prefix=$(PREFIX) --extra-version="kodi-$(VERSION)" -@@ -12,12 +26,14 @@ ffmpg_config += --cc=$(CC) --cxx=$(CXX) --ar=$(AR) --ranlib=$(RANLIB) - ffmpg_config += --disable-devices --disable-doc - ffmpg_config += --disable-ffplay --disable-ffmpeg --disable-sdl - ffmpg_config += --disable-ffprobe --disable-ffserver --ffmpg_config += --enable-gpl --enable-runtime-cpudetect -+ffmpg_config += --enable-gpl -+###--enable-runtime-cpudetect - ffmpg_config += --enable-postproc --enable-pthreads - ffmpg_config += --enable-muxer=spdif --enable-muxer=adts - ffmpg_config += --enable-muxer=asf --enable-muxer=ipod - ffmpg_config += --enable-encoder=ac3 --enable-encoder=aac - ffmpg_config += --enable-encoder=wmav2 --enable-protocol=http -+ffmpg_config += --pkg-config=/usr/bin/pkg-config - ffmpg_config += --enable-gnutls - ffmpg_config += --enable-encoder=png --enable-encoder=mjpeg - -@@ -48,7 +64,6 @@ ifeq ($(OS), osx) - ffmpg_config += --disable-outdev=sdl - ffmpg_config += --disable-decoder=mpeg_xvmc --disable-vda --disable-crystalhd --enable-videotoolbox - ffmpg_config += --target-os=darwin -- ffmpg_config += --disable-securetransport - endif - ifeq ($(findstring arm, $(CPU)), arm) - ffmpg_config += --enable-pic --disable-armv5te --disable-armv6t2 -@@ -60,10 +75,11 @@ ifeq ($(Configuration), Release) - ffmpg_config += --disable-debug - endif - -+ffmpg_config += $(CONFFLAGS) - - CLEAN_FILES=$(ARCHIVE) $(PLATFORM) - --all: .installed-$(PLATFORM) -+all: .ffmpeg-installed - - $(TARBALLS_LOCATION)/$(ARCHIVE): - cd $(TARBALLS_LOCATION); $(RETRIEVE_TOOL) -Ls --create-dirs -f -o $(TARBALLS_LOCATION)/$(ARCHIVE) $(BASE_URL)/$(VERSION).tar.gz -@@ -72,6 +88,16 @@ $(PLATFORM): $(TARBALLS_LOCATION)/$(ARCHIVE) $(DEPS) - rm -rf $(PLATFORM); mkdir -p $(PLATFORM) - cd $(PLATFORM); $(ARCHIVE_TOOL) $(ARCHIVE_TOOL_FLAGS) $(TARBALLS_LOCATION)/$(ARCHIVE) - cd $(PLATFORM); sed -i".bak" -e "s%pkg_config_default=pkg-config%export PKG_CONFIG_LIBDIR=$(PREFIX)/lib/pkgconfig \&\& pkg_config_default=$(NATIVEPREFIX)/bin/pkg-config%" configure -+ cd $(PLATFORM); patch -p1 < ../../0001-mpeg4video-Signal-unsupported-GMC-with-more-than-one.patch -+ cd $(PLATFORM); patch -p1 < ../../hevcdsp_ARM_NEON_optimized_epel_functions.patch -+ cd $(PLATFORM); patch -p1 < ../../added_ARM_NEON_optimized_SAO_patches.patch -+ cd $(PLATFORM); patch -p1 < ../../pfcd_hevc_optimisations.patch -+ cd $(PLATFORM); patch -p1 < ../../0001-Squashed-commit-of-the-following.patch -+ cd $(PLATFORM); patch -p1 < ../../0001-avcodec-add-h264_mvc-codec-id-and-profiles.patch -+ cd $(PLATFORM); patch -p1 < ../../0001-h264_parser-add-support-for-parsing-h264-mvc-NALUs.patch -+ cd $(PLATFORM); patch -p1 < ../../h264_parser_fix_parsing_of_mvc_slices_in_some_corner_cases.patch -+ cd $(PLATFORM); patch -p1 < ../../73fde6f9f3d01f7fc0f3ae4b66f6c725f9fb1105.patch -+ cd $(PLATFORM); patch -p1 < ../../0001-Discard-data-before-VO-VOL-in-mpeg-4-over-mpegts.patch - cd $(PLATFORM);\ - CFLAGS="$(CFLAGS)" CXXFLAGS="$(CXXFLAGS)" CPPFLAGS="$(CPPFLAGS)" LDFLAGS="$(LDFLAGS)" \ - ./configure $(ffmpg_config) -@@ -79,13 +105,14 @@ $(PLATFORM): $(TARBALLS_LOCATION)/$(ARCHIVE) $(DEPS) - build: $(PLATFORM) - $(MAKE) -C $(PLATFORM) - --.installed-$(PLATFORM): build -+.ffmpeg-installed: build - $(MAKE) -C $(PLATFORM) install - touch $@ - - clean: - $(MAKE) -C $(PLATFORM) clean -- rm -f .installed-$(PLATFORM) -+ rm -f .ffmpeg-installed - - distclean:: -- rm -rf $(PLATFORM) .installed-$(PLATFORM) -+ rm -rf $(PLATFORM) .ffmpeg-installed -+ -diff --git a/tools/depends/target/ffmpeg/added_ARM_NEON_optimized_SAO_patches.patch b/tools/depends/target/ffmpeg/added_ARM_NEON_optimized_SAO_patches.patch -new file mode 100644 -index 0000000..792b5fe ---- /dev/null -+++ b/tools/depends/target/ffmpeg/added_ARM_NEON_optimized_SAO_patches.patch -@@ -0,0 +1,3328 @@ -+From b0cb307c253d2c9f4b94a54dfc74ddb83af984cc Mon Sep 17 00:00:00 2001 -+From: Seppo Tomperi -+Date: Mon, 8 Dec 2014 13:24:40 +0200 -+Subject: [PATCH 1/9] added ARM NEON optimized SAO band offset -+ -+--- -+ libavcodec/arm/Makefile | 3 +- -+ libavcodec/arm/hevcdsp_init_neon.c | 47 +++++++++ -+ libavcodec/arm/hevcdsp_sao_neon.S | 204 +++++++++++++++++++++++++++++++++++++ -+ 3 files changed, 253 insertions(+), 1 deletion(-) -+ create mode 100644 libavcodec/arm/hevcdsp_sao_neon.S -+ -+diff --git a/libavcodec/arm/Makefile b/libavcodec/arm/Makefile -+index 6051ec8..093a2e8 100644 -+--- a/libavcodec/arm/Makefile -++++ b/libavcodec/arm/Makefile -+@@ -133,7 +133,8 @@ NEON-OBJS-$(CONFIG_HEVC_DECODER) += arm/hevcdsp_init_neon.o \ -+ arm/hevcdsp_deblock_neon.o \ -+ arm/hevcdsp_epel_neon.o \ -+ arm/hevcdsp_idct_neon.o \ -+- arm/hevcdsp_qpel_neon.o -++ arm/hevcdsp_qpel_neon.o \ -++ arm/hevcdsp_sao_neon.o -+ NEON-OBJS-$(CONFIG_RV30_DECODER) += arm/rv34dsp_neon.o -+ NEON-OBJS-$(CONFIG_RV40_DECODER) += arm/rv34dsp_neon.o \ -+ arm/rv40dsp_neon.o -+diff --git a/libavcodec/arm/hevcdsp_init_neon.c b/libavcodec/arm/hevcdsp_init_neon.c -+index 733ff08..69e2b2c 100644 -+--- a/libavcodec/arm/hevcdsp_init_neon.c -++++ b/libavcodec/arm/hevcdsp_init_neon.c -+@@ -22,6 +22,7 @@ -+ #include "libavutil/arm/cpu.h" -+ #include "libavcodec/hevcdsp.h" -+ #include "hevcdsp_arm.h" -++#include "../bit_depth_template.c" -+ -+ void ff_hevc_v_loop_filter_luma_neon(uint8_t *_pix, ptrdiff_t _stride, int _beta, int *_tc, uint8_t *_no_p, uint8_t *_no_q); -+ void ff_hevc_h_loop_filter_luma_neon(uint8_t *_pix, ptrdiff_t _stride, int _beta, int *_tc, uint8_t *_no_p, uint8_t *_no_q); -+@@ -43,6 +44,11 @@ void ff_hevc_transform_add_16x16_neon_8(uint8_t *_dst, int16_t *coeffs, -+ void ff_hevc_transform_add_32x32_neon_8(uint8_t *_dst, int16_t *coeffs, -+ ptrdiff_t stride); -+ -++void ff_hevc_sao_band_w8_neon_8(uint8_t *_dst, uint8_t *_src, ptrdiff_t stride_dst, ptrdiff_t stride_src, int height, int8_t * offset_table); -++void ff_hevc_sao_band_w16_neon_8(uint8_t *_dst, uint8_t *_src, ptrdiff_t stride_dst, ptrdiff_t stride_src, int height, int8_t * offset_table); -++void ff_hevc_sao_band_w32_neon_8(uint8_t *_dst, uint8_t *_src, ptrdiff_t stride_dst, ptrdiff_t stride_src, int height, int8_t * offset_table); -++void ff_hevc_sao_band_w64_neon_8(uint8_t *_dst, uint8_t *_src, ptrdiff_t stride_dst, ptrdiff_t stride_src, int height, int8_t * offset_table); -++ -+ #define PUT_PIXELS(name) \ -+ void name(int16_t *dst, uint8_t *src, \ -+ ptrdiff_t srcstride, int height, \ -+@@ -151,6 +157,44 @@ void ff_hevc_put_qpel_bi_neon_wrapper(uint8_t *dst, ptrdiff_t dststride, uint8_t -+ put_hevc_qpel_uw_neon[my][mx](dst, dststride, src, srcstride, width, height, src2, MAX_PB_SIZE); -+ } -+ -++static void ff_hevc_sao_band_neon_wrapper(uint8_t *_dst, uint8_t *_src, ptrdiff_t stride_dst, ptrdiff_t stride_src, -++ int16_t *sao_offset_val, int sao_left_class, int width, int height) -++{ -++ pixel *dst = (pixel *)_dst; -++ pixel *src = (pixel *)_src; -++ int8_t offset_table[32] = { 0 }; -++ int k, y, x; -++ int shift = 3; // BIT_DEPTH - 5 -++ -++ stride_src /= sizeof(pixel); -++ stride_dst /= sizeof(pixel); -++ -++ for (k = 0; k < 4; k++) -++ offset_table[(k + sao_left_class) & 31] = sao_offset_val[k + 1]; -++ -++ switch(width){ -++ case 8: -++ ff_hevc_sao_band_w8_neon_8(_dst, _src, stride_dst, stride_src, height, offset_table); -++ break; -++ case 16: -++ ff_hevc_sao_band_w16_neon_8(_dst, _src, stride_dst, stride_src, height, offset_table); -++ break; -++ case 32: -++ ff_hevc_sao_band_w32_neon_8(_dst, _src, stride_dst, stride_src, height, offset_table); -++ break; -++ case 64: -++ ff_hevc_sao_band_w64_neon_8(_dst, _src, stride_dst, stride_src, height, offset_table); -++ break; -++ default: -++ for (y = 0; y < height; y++) { -++ for (x = 0; x < width; x++) -++ dst[x] = av_clip_pixel(src[x] + offset_table[src[x] >> shift]); -++ dst += stride_dst; -++ src += stride_src; -++ } -++ } -++} -++ -+ av_cold void ff_hevcdsp_init_neon(HEVCDSPContext *c, const int bit_depth) -+ { -+ if (bit_depth == 8) { -+@@ -170,6 +214,9 @@ av_cold void ff_hevcdsp_init_neon(HEVCDSPContext *c, const int bit_depth) -+ c->transform_add[2] = ff_hevc_transform_add_16x16_neon_8; -+ c->transform_add[3] = ff_hevc_transform_add_32x32_neon_8; -+ c->idct_4x4_luma = ff_hevc_transform_luma_4x4_neon_8; -++ for (x = 0; x < sizeof c->sao_band_filter / sizeof *c->sao_band_filter; x++) { -++ c->sao_band_filter[x] = ff_hevc_sao_band_neon_wrapper; -++ } -+ put_hevc_qpel_neon[1][0] = ff_hevc_put_qpel_v1_neon_8; -+ put_hevc_qpel_neon[2][0] = ff_hevc_put_qpel_v2_neon_8; -+ put_hevc_qpel_neon[3][0] = ff_hevc_put_qpel_v3_neon_8; -+diff --git a/libavcodec/arm/hevcdsp_sao_neon.S b/libavcodec/arm/hevcdsp_sao_neon.S -+new file mode 100644 -+index 0000000..1f0ad64 -+--- /dev/null -++++ b/libavcodec/arm/hevcdsp_sao_neon.S -+@@ -0,0 +1,204 @@ -++/* -++ * Copyright (c) 2014 Seppo Tomperi -++ * -++ * This file is part of FFmpeg. -++ * -++ * FFmpeg is free software; you can redistribute it and/or -++ * modify it under the terms of the GNU Lesser General Public -++ * License as published by the Free Software Foundation; either -++ * version 2.1 of the License, or (at your option) any later version. -++ * -++ * FFmpeg is distributed in the hope that it will be useful, -++ * but WITHOUT ANY WARRANTY; without even the implied warranty of -++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -++ * Lesser General Public License for more details. -++ * -++ * You should have received a copy of the GNU Lesser General Public -++ * License along with FFmpeg; if not, write to the Free Software -++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -++ */ -++ -++#include "libavutil/arm/asm.S" -++#include "neon.S" -++ -++function ff_hevc_sao_band_w8_neon_8, export=1 -++ push {r4-r8} -++ ldr r4, [sp, #20] // height -++ ldr r5, [sp, #24] // offset_table -++ vpush {d8-d15} -++ vld1.8 {q0, q1}, [r5] // offset table -++ -++1: subs r4, #1 -++ vld1.8 {d24}, [r1], r3 -++ vshr.u8 d16, d24, #3 -++ vtbl.8 d16, {q0, q1}, d16 -++ vmovl.s8 q2, d16 -++ vmovl.u8 q6, d24 -++ vadd.s16 q2, q6 -++ vqmovun.s16 d4, q2 -++ vst1.8 {d4}, [r0], r2 -++ bne 1b -++ -++ vpop {d8-d15} -++ pop {r4-r8} -++ bx lr -++endfunc -++ -++function ff_hevc_sao_band_w16_neon_8, export=1 -++ push {r4-r8} -++ ldr r4, [sp, #20] // height -++ ldr r5, [sp, #24] // offset_table -++ vpush {d8-d15} -++ vld1.8 {q0, q1}, [r5] // offset table -++ -++1: subs r4, #1 -++ vld1.8 {q12}, [r1], r3 -++ -++ vshr.u8 q8, q12, #3 -++ -++ vtbl.8 d16, {q0, q1}, d16 -++ vtbl.8 d17, {q0, q1}, d17 -++ -++ vmovl.s8 q2, d16 -++ vmovl.s8 q3, d17 -++ -++ vmovl.u8 q6, d24 -++ vmovl.u8 q7, d25 -++ -++ vadd.s16 q2, q6 -++ vadd.s16 q3, q7 -++ -++ vqmovun.s16 d4, q2 -++ vqmovun.s16 d5, q3 -++ -++ vstm.8 r0, {q2} -++ add r0, r2 -++ bne 1b -++ -++ vpop {d8-d15} -++ pop {r4-r8} -++ bx lr -++endfunc -++ -++function ff_hevc_sao_band_w32_neon_8, export=1 -++ push {r4-r8} -++ ldr r4, [sp, #20] // height -++ ldr r5, [sp, #24] // offset_table -++ vpush {d8-d15} -++ vld1.8 {q0, q1}, [r5] // offset table -++ -++1: subs r4, #1 -++ vld1.8 {q12-q13}, [r1], r3 -++ -++ vshr.u8 q8, q12, #3 -++ vshr.u8 q9, q13, #3 -++ -++ vtbl.8 d16, {q0, q1}, d16 -++ vtbl.8 d17, {q0, q1}, d17 -++ vtbl.8 d18, {q0, q1}, d18 -++ vtbl.8 d19, {q0, q1}, d19 -++ -++ vmovl.s8 q2, d16 -++ vmovl.s8 q3, d17 // q8 free -++ vmovl.s8 q4, d18 -++ vmovl.s8 q5, d19 // q9 free -++ -++ vmovl.u8 q6, d24 -++ vmovl.u8 q7, d25 // q12 free -++ vmovl.u8 q8, d26 -++ vmovl.u8 q9, d27 // q13 free -++ -++ vadd.s16 q2, q6 -++ vadd.s16 q3, q7 -++ vadd.s16 q4, q8 -++ vadd.s16 q5, q9 -++ -++ vqmovun.s16 d4, q2 -++ vqmovun.s16 d5, q3 -++ vqmovun.s16 d6, q4 // q4 free -++ vqmovun.s16 d7, q5 // q5 free -++ -++ vst1.8 {q2-q3}, [r0], r2 -++ bne 1b -++ -++ vpop {d8-d15} -++ pop {r4-r8} -++ bx lr -++endfunc -++ -++function ff_hevc_sao_band_w64_neon_8, export=1 -++ push {r4-r8} -++ ldr r4, [sp, #20] // height -++ ldr r5, [sp, #24] // offset_table -++ vpush {d8-d15} -++ vld1.8 {q0, q1}, [r5] // offset table -++ -++1: subs r4, #1 -++ vld1.8 {q12-q13}, [r1]! -++ vld1.8 {q14-q15}, [r1], r3 -++ sub r1, #32 -++ -++ vshr.u8 q8, q12, #3 -++ vshr.u8 q9, q13, #3 -++ vshr.u8 q10, q14, #3 -++ vshr.u8 q11, q15, #3 -++ -++ vtbl.8 d16, {q0, q1}, d16 -++ vtbl.8 d17, {q0, q1}, d17 -++ vtbl.8 d18, {q0, q1}, d18 -++ vtbl.8 d19, {q0, q1}, d19 -++ vtbl.8 d20, {q0, q1}, d20 -++ vtbl.8 d21, {q0, q1}, d21 -++ vtbl.8 d22, {q0, q1}, d22 -++ vtbl.8 d23, {q0, q1}, d23 -++ -++ vmovl.s8 q2, d16 -++ vmovl.s8 q3, d17 // q8 free -++ vmovl.s8 q4, d18 -++ vmovl.s8 q5, d19 // q9 free -++ -++ vmovl.u8 q6, d24 -++ vmovl.u8 q7, d25 // q12 free -++ vmovl.u8 q8, d26 -++ vmovl.u8 q9, d27 // q13 free -++ -++ vadd.s16 q2, q6 -++ vadd.s16 q3, q7 -++ vadd.s16 q4, q8 -++ vadd.s16 q5, q9 -++ -++ vqmovun.s16 d4, q2 -++ vqmovun.s16 d5, q3 -++ vqmovun.s16 d6, q4 // q4 free -++ vqmovun.s16 d7, q5 // q5 free -++ -++ // free q4 -q9, q12 - q13 -++ vmovl.s8 q4, d20 -++ vmovl.s8 q5, d21 // q10 free -++ vmovl.s8 q6, d22 -++ vmovl.s8 q7, d23 // q11 free -++ -++ vmovl.u8 q8, d28 -++ vmovl.u8 q9, d29 // q14 free -++ vmovl.u8 q10, d30 -++ vmovl.u8 q11, d31 // q15 free -++ -++ vadd.s16 q4, q8 -++ vadd.s16 q5, q9 -++ vadd.s16 q6, q10 -++ vadd.s16 q7, q11 -++ -++ vqmovun.s16 d8, q4 -++ vqmovun.s16 d9, q5 -++ vqmovun.s16 d10, q6 -++ vqmovun.s16 d11, q7 -++ -++ vstm.8 r0, {q2-q5} -++ add r0, r2 -++ bne 1b -++ -++ vpop {d8-d15} -++ pop {r4-r8} -++ bx lr -++endfunc -++ -+-- -+2.5.0 -+ -+ -+From 8429b1de64bb871d57651ecfe3b084e2dfe0af51 Mon Sep 17 00:00:00 2001 -+From: Seppo Tomperi -+Date: Wed, 27 May 2015 18:10:20 +0100 -+Subject: [PATCH 2/9] added NEON optimized sao edge for eo1 width 64 -+ -+--- -+ libavcodec/arm/hevcdsp_init_neon.c | 47 ++++++++++++ -+ libavcodec/arm/hevcdsp_sao_neon.S | 147 +++++++++++++++++++++++++++++++++++++ -+ 2 files changed, 194 insertions(+) -+ -+diff --git a/libavcodec/arm/hevcdsp_init_neon.c b/libavcodec/arm/hevcdsp_init_neon.c -+index 69e2b2c..c7b5404 100644 -+--- a/libavcodec/arm/hevcdsp_init_neon.c -++++ b/libavcodec/arm/hevcdsp_init_neon.c -+@@ -22,6 +22,7 @@ -+ #include "libavutil/arm/cpu.h" -+ #include "libavcodec/hevcdsp.h" -+ #include "hevcdsp_arm.h" -++#include "libavcodec/avcodec.h" -+ #include "../bit_depth_template.c" -+ -+ void ff_hevc_v_loop_filter_luma_neon(uint8_t *_pix, ptrdiff_t _stride, int _beta, int *_tc, uint8_t *_no_p, uint8_t *_no_q); -+@@ -48,6 +49,7 @@ void ff_hevc_sao_band_w8_neon_8(uint8_t *_dst, uint8_t *_src, ptrdiff_t stride_d -+ void ff_hevc_sao_band_w16_neon_8(uint8_t *_dst, uint8_t *_src, ptrdiff_t stride_dst, ptrdiff_t stride_src, int height, int8_t * offset_table); -+ void ff_hevc_sao_band_w32_neon_8(uint8_t *_dst, uint8_t *_src, ptrdiff_t stride_dst, ptrdiff_t stride_src, int height, int8_t * offset_table); -+ void ff_hevc_sao_band_w64_neon_8(uint8_t *_dst, uint8_t *_src, ptrdiff_t stride_dst, ptrdiff_t stride_src, int height, int8_t * offset_table); -++void ff_hevc_sao_edge_eo1_w64_neon_8(uint8_t *_dst, uint8_t *_src, ptrdiff_t stride_dst, ptrdiff_t stride_src, int height, int8_t *sao_offset_table); -+ -+ #define PUT_PIXELS(name) \ -+ void name(int16_t *dst, uint8_t *src, \ -+@@ -195,6 +197,50 @@ static void ff_hevc_sao_band_neon_wrapper(uint8_t *_dst, uint8_t *_src, ptrdiff_ -+ } -+ } -+ -++#define CMP(a, b) ((a) > (b) ? 1 : ((a) == (b) ? 0 : -1)) -++static void ff_hevc_sao_edge_neon_wrapper(uint8_t *_dst /* align 16 */, uint8_t *_src /* align 32 */, ptrdiff_t stride_dst, -++ int16_t *_sao_offset_val, int eo, int width, int height) -++{ -++ static const uint8_t edge_idx[] = { 1, 2, 0, 3, 4 }; -++ static const int8_t pos[4][2][2] = { -++ { { -1, 0 }, { 1, 0 } }, // horizontal -++ { { 0, -1 }, { 0, 1 } }, // vertical -++ { { -1, -1 }, { 1, 1 } }, // 45 degree -++ { { 1, -1 }, { -1, 1 } }, // 135 degree -++ }; -++ int8_t sao_offset_val[8]; // padding of 3 for vld -++ ptrdiff_t stride_src = (2*MAX_PB_SIZE + FF_INPUT_BUFFER_PADDING_SIZE); -++ pixel *dst = (pixel *)_dst; -++ pixel *src = (pixel *)_src; -++ int a_stride, b_stride; -++ int x, y; -++ -++ for (x = 0; x < 5; x++) { -++ sao_offset_val[x] = _sao_offset_val[x]; -++ } -++ -++ stride_src /= sizeof(pixel); -++ stride_dst /= sizeof(pixel); -++ -++ if (eo == 1 && width == 64) { -++ ff_hevc_sao_edge_eo1_w64_neon_8(dst, src, stride_dst, stride_src, height, sao_offset_val); -++ } else { -++ a_stride = pos[eo][0][0] + pos[eo][0][1] * stride_src; -++ b_stride = pos[eo][1][0] + pos[eo][1][1] * stride_src; -++ for (y = 0; y < height; y++) { -++ for (x = 0; x < width; x++) { -++ int diff0 = CMP(src[x], src[x + a_stride]); -++ int diff1 = CMP(src[x], src[x + b_stride]); -++ int offset_val = edge_idx[2 + diff0 + diff1]; -++ dst[x] = av_clip_pixel(src[x] + sao_offset_val[offset_val]); -++ } -++ src += stride_src; -++ dst += stride_dst; -++ } -++ } -++} -++#undef CMP -++ -+ av_cold void ff_hevcdsp_init_neon(HEVCDSPContext *c, const int bit_depth) -+ { -+ if (bit_depth == 8) { -+@@ -216,6 +262,7 @@ av_cold void ff_hevcdsp_init_neon(HEVCDSPContext *c, const int bit_depth) -+ c->idct_4x4_luma = ff_hevc_transform_luma_4x4_neon_8; -+ for (x = 0; x < sizeof c->sao_band_filter / sizeof *c->sao_band_filter; x++) { -+ c->sao_band_filter[x] = ff_hevc_sao_band_neon_wrapper; -++ c->sao_edge_filter[x] = ff_hevc_sao_edge_neon_wrapper; -+ } -+ put_hevc_qpel_neon[1][0] = ff_hevc_put_qpel_v1_neon_8; -+ put_hevc_qpel_neon[2][0] = ff_hevc_put_qpel_v2_neon_8; -+diff --git a/libavcodec/arm/hevcdsp_sao_neon.S b/libavcodec/arm/hevcdsp_sao_neon.S -+index 1f0ad64..5ec2de9 100644 -+--- a/libavcodec/arm/hevcdsp_sao_neon.S -++++ b/libavcodec/arm/hevcdsp_sao_neon.S -+@@ -202,3 +202,150 @@ function ff_hevc_sao_band_w64_neon_8, export=1 -+ bx lr -+ endfunc -+ -++function ff_hevc_sao_edge_eo1_w64_neon_8, export=1 -++ push {r4-r8} -++ ldr r4, [sp, #20] // height -++ ldr r5, [sp, #24] // sao_offset_val_table -++ ldr r6, =0x02 -++ vpush {d8-d15} -++1: subs r4, #1 -++ // load a -++ sub r1, r3 -++ vld1.8 {q0-q1}, [r1]! -++ vld1.8 {q2-q3}, [r1], r3 -++ sub r1, #32 -++ // load c -++ vld1.8 {q4-q5}, [r1]! -++ vld1.8 {q6-q7}, [r1], r3 -++ sub r1, #32 -++ // load b -++ vld1.8 {q8-q9}, [r1]! -++ vld1.8 {q10-q11}, [r1], r3 -++ sub r1, #32 -++ -++ vcgt.u8 q12, q4, q0 // c > a -> -1 , otherwise 0 -++ vcgt.u8 q0, q0, q4 // a > c -> -1 , otherwise 0 -++ vcgt.u8 q13, q5, q1 -++ vcgt.u8 q1, q1, q5 -++ vcgt.u8 q14, q6, q2 -++ vcgt.u8 q2, q2, q6 -++ vcgt.u8 q15, q7, q3 -++ vcgt.u8 q3, q3, q7 -++ -++ vsub.s8 q12, q0, q12 // diff0 -++ vsub.s8 q13, q1, q13 -++ vsub.s8 q14, q2, q14 -++ vsub.s8 q15, q3, q15 -++ -++ vcgt.u8 q0, q4, q8 // c > b -++ vcgt.u8 q8, q8, q4 // b > c -++ vcgt.u8 q1, q5, q9 -++ vcgt.u8 q9, q9, q5 -++ vcgt.u8 q2, q6, q10 -++ vcgt.u8 q10, q10, q6 -++ vcgt.u8 q3, q7, q11 -++ vcgt.u8 q11, q11, q7 -++ -++ vsub.s8 q0, q8, q0 // diff1 -++ vsub.s8 q1, q9, q1 -++ vsub.s8 q2, q10, q2 -++ vsub.s8 q3, q11, q3 -++ -++ veor.u8 q8, q8 // zero register -++ vdup.s8 q9, r6 // 2 to all elements -++ add r6, #1 -++ vdup.s8 q10, r6 // 3 to all elements -++ sub r6, #1 -++ -++ vadd.s8 q0, q12 //diff0 + diff1 -++ vadd.s8 q1, q13 -++ vadd.s8 q2, q14 -++ vadd.s8 q3, q15 -++ -++ vcgt.s8 q4, q0, q8 // diff0 + diff1 > 0 -++ vcgt.s8 q5, q1, q8 -++ vcgt.s8 q6, q2, q8 -++ vcgt.s8 q7, q3, q8 -++ -++ vclt.s8 q11, q0, q8 // diff0 + diff1 < 0 -++ vclt.s8 q12, q1, q8 -++ vclt.s8 q13, q2, q8 -++ vclt.s8 q14, q3, q8 -++ -++ vadd.s8 q8, q0, q9 // diff0 + diff1 + 2 -++ vand.8 q15, q8, q4 -++ vadd.s8 q8, q0, q10 // diff0 + diff1 + 3 -++ vand.8 q8, q8, q11 -++ vadd.s8 q0, q15, q8 // offset_idx -++ -++ vadd.s8 q8, q1, q9 // diff0 + diff1 + 2 -++ vand.8 q15, q8, q5 -++ vadd.s8 q8, q1, q10 // diff0 + diff1 + 3 -++ vand.8 q8, q8, q12 -++ vadd.s8 q1, q15, q8 // offset_idx -++ -++ vadd.s8 q8, q2, q9 // diff0 + diff1 + 2 + 2 -++ vand.8 q15, q8, q6 -++ vadd.s8 q8, q2, q10 // diff0 + diff1 + 2 + 3 -++ vand.8 q8, q8, q13 -++ vadd.s8 q2, q15, q8 // offset_idx -++ -++ vadd.s8 q8, q3, q9 // diff0 + diff1 + 2 + 2 -++ vand.8 q15, q8, q7 -++ vadd.s8 q8, q3, q10 // diff0 + diff1 + 2 + 3 -++ vand.8 q8, q8, q14 -++ vadd.s8 q3, q15, q8 // offset_idx -++ // TODO: load only once -++ vld1.8 d16, [r5] -++ -++ vtbl.8 d0, {d16}, d0 -++ vtbl.8 d1, {d16}, d1 -++ vtbl.8 d2, {d16}, d2 -++ vtbl.8 d3, {d16}, d3 -++ vtbl.8 d4, {d16}, d4 -++ vtbl.8 d5, {d16}, d5 -++ vtbl.8 d6, {d16}, d6 -++ vtbl.8 d7, {d16}, d7 -++ -++ // TODO: load only once -++ // load c again -++ sub r1, r3 -++ sub r1, r3 -++ vld1.8 {q4-q5}, [r1]! -++ vld1.8 {q6-q7}, [r1], r3 -++ sub r1, #32 -++ -++ vmovl.u8 q8, d8 -++ vmovl.u8 q9, d9 -++ vmovl.u8 q10, d10 -++ vmovl.u8 q11, d11 -++ vmovl.u8 q12, d12 -++ vmovl.u8 q13, d13 -++ vmovl.u8 q14, d14 -++ vmovl.u8 q15, d15 -++ -++ vaddw.s8 q8, d0 -++ vaddw.s8 q9, d1 -++ vaddw.s8 q10, d2 -++ vaddw.s8 q11, d3 -++ vaddw.s8 q12, d4 -++ vaddw.s8 q13, d5 -++ vaddw.s8 q14, d6 -++ vaddw.s8 q15, d7 -++ -++ vqmovun.s16 d0, q8 -++ vqmovun.s16 d1, q9 -++ vqmovun.s16 d2, q10 -++ vqmovun.s16 d3, q11 -++ vqmovun.s16 d4, q12 -++ vqmovun.s16 d5, q13 -++ vqmovun.s16 d6, q14 -++ vqmovun.s16 d7, q15 -++ -++ vstm r0, {q0-q3} -++ add r0, r2 -++ bne 1b -++ vpop {d8-d15} -++ pop {r4-r8} -++ bx lr -++endfunc -+-- -+2.5.0 -+ -+ -+From 402e2bd1c5ad659c757bf9734abe6331904fb9e2 Mon Sep 17 00:00:00 2001 -+From: Seppo Tomperi -+Date: Tue, 16 Dec 2014 16:28:25 +0200 -+Subject: [PATCH 3/9] Added SAO edge offset for ARM NEON w32 and w64 -+ -+--- -+ libavcodec/arm/hevcdsp_init_neon.c | 46 +++- -+ libavcodec/arm/hevcdsp_sao_neon.S | 510 +++++++++++++++++++++++++++++++------ -+ 2 files changed, 474 insertions(+), 82 deletions(-) -+ -+diff --git a/libavcodec/arm/hevcdsp_init_neon.c b/libavcodec/arm/hevcdsp_init_neon.c -+index c7b5404..c32940e 100644 -+--- a/libavcodec/arm/hevcdsp_init_neon.c -++++ b/libavcodec/arm/hevcdsp_init_neon.c -+@@ -49,7 +49,16 @@ void ff_hevc_sao_band_w8_neon_8(uint8_t *_dst, uint8_t *_src, ptrdiff_t stride_d -+ void ff_hevc_sao_band_w16_neon_8(uint8_t *_dst, uint8_t *_src, ptrdiff_t stride_dst, ptrdiff_t stride_src, int height, int8_t * offset_table); -+ void ff_hevc_sao_band_w32_neon_8(uint8_t *_dst, uint8_t *_src, ptrdiff_t stride_dst, ptrdiff_t stride_src, int height, int8_t * offset_table); -+ void ff_hevc_sao_band_w64_neon_8(uint8_t *_dst, uint8_t *_src, ptrdiff_t stride_dst, ptrdiff_t stride_src, int height, int8_t * offset_table); -++ -++void ff_hevc_sao_edge_eo0_w32_neon_8(uint8_t *_dst, uint8_t *_src, ptrdiff_t stride_dst, ptrdiff_t stride_src, int height, int8_t *sao_offset_table); -++void ff_hevc_sao_edge_eo1_w32_neon_8(uint8_t *_dst, uint8_t *_src, ptrdiff_t stride_dst, ptrdiff_t stride_src, int height, int8_t *sao_offset_table); -++void ff_hevc_sao_edge_eo2_w32_neon_8(uint8_t *_dst, uint8_t *_src, ptrdiff_t stride_dst, ptrdiff_t stride_src, int height, int8_t *sao_offset_table); -++void ff_hevc_sao_edge_eo3_w32_neon_8(uint8_t *_dst, uint8_t *_src, ptrdiff_t stride_dst, ptrdiff_t stride_src, int height, int8_t *sao_offset_table); -++ -++void ff_hevc_sao_edge_eo0_w64_neon_8(uint8_t *_dst, uint8_t *_src, ptrdiff_t stride_dst, ptrdiff_t stride_src, int height, int8_t *sao_offset_table); -+ void ff_hevc_sao_edge_eo1_w64_neon_8(uint8_t *_dst, uint8_t *_src, ptrdiff_t stride_dst, ptrdiff_t stride_src, int height, int8_t *sao_offset_table); -++void ff_hevc_sao_edge_eo2_w64_neon_8(uint8_t *_dst, uint8_t *_src, ptrdiff_t stride_dst, ptrdiff_t stride_src, int height, int8_t *sao_offset_table); -++void ff_hevc_sao_edge_eo3_w64_neon_8(uint8_t *_dst, uint8_t *_src, ptrdiff_t stride_dst, ptrdiff_t stride_src, int height, int8_t *sao_offset_table); -+ -+ #define PUT_PIXELS(name) \ -+ void name(int16_t *dst, uint8_t *src, \ -+@@ -222,9 +231,40 @@ static void ff_hevc_sao_edge_neon_wrapper(uint8_t *_dst /* align 16 */, uint8_t -+ stride_src /= sizeof(pixel); -+ stride_dst /= sizeof(pixel); -+ -+- if (eo == 1 && width == 64) { -+- ff_hevc_sao_edge_eo1_w64_neon_8(dst, src, stride_dst, stride_src, height, sao_offset_val); -+- } else { -++ switch (width) { -++ case 32: -++ switch(eo) { -++ case 0: -++ ff_hevc_sao_edge_eo0_w32_neon_8(dst, src, stride_dst, stride_src, height, sao_offset_val); -++ break; -++ case 1: -++ ff_hevc_sao_edge_eo1_w32_neon_8(dst, src, stride_dst, stride_src, height, sao_offset_val); -++ break; -++ case 2: -++ ff_hevc_sao_edge_eo2_w32_neon_8(dst, src, stride_dst, stride_src, height, sao_offset_val); -++ break; -++ case 3: -++ ff_hevc_sao_edge_eo3_w32_neon_8(dst, src, stride_dst, stride_src, height, sao_offset_val); -++ break; -++ } -++ break; -++ case 64: -++ switch(eo) { -++ case 0: -++ ff_hevc_sao_edge_eo0_w64_neon_8(dst, src, stride_dst, stride_src, height, sao_offset_val); -++ break; -++ case 1: -++ ff_hevc_sao_edge_eo1_w64_neon_8(dst, src, stride_dst, stride_src, height, sao_offset_val); -++ break; -++ case 2: -++ ff_hevc_sao_edge_eo2_w64_neon_8(dst, src, stride_dst, stride_src, height, sao_offset_val); -++ break; -++ case 3: -++ ff_hevc_sao_edge_eo3_w64_neon_8(dst, src, stride_dst, stride_src, height, sao_offset_val); -++ break; -++ } -++ break; -++ default: -+ a_stride = pos[eo][0][0] + pos[eo][0][1] * stride_src; -+ b_stride = pos[eo][1][0] + pos[eo][1][1] * stride_src; -+ for (y = 0; y < height; y++) { -+diff --git a/libavcodec/arm/hevcdsp_sao_neon.S b/libavcodec/arm/hevcdsp_sao_neon.S -+index 5ec2de9..4687012 100644 -+--- a/libavcodec/arm/hevcdsp_sao_neon.S -++++ b/libavcodec/arm/hevcdsp_sao_neon.S -+@@ -202,27 +202,7 @@ function ff_hevc_sao_band_w64_neon_8, export=1 -+ bx lr -+ endfunc -+ -+-function ff_hevc_sao_edge_eo1_w64_neon_8, export=1 -+- push {r4-r8} -+- ldr r4, [sp, #20] // height -+- ldr r5, [sp, #24] // sao_offset_val_table -+- ldr r6, =0x02 -+- vpush {d8-d15} -+-1: subs r4, #1 -+- // load a -+- sub r1, r3 -+- vld1.8 {q0-q1}, [r1]! -+- vld1.8 {q2-q3}, [r1], r3 -+- sub r1, #32 -+- // load c -+- vld1.8 {q4-q5}, [r1]! -+- vld1.8 {q6-q7}, [r1], r3 -+- sub r1, #32 -+- // load b -+- vld1.8 {q8-q9}, [r1]! -+- vld1.8 {q10-q11}, [r1], r3 -+- sub r1, #32 -+- -++.macro edge_w64_body -+ vcgt.u8 q12, q4, q0 // c > a -> -1 , otherwise 0 -+ vcgt.u8 q0, q0, q4 // a > c -> -1 , otherwise 0 -+ vcgt.u8 q13, q5, q1 -+@@ -251,69 +231,61 @@ function ff_hevc_sao_edge_eo1_w64_neon_8, export=1 -+ vsub.s8 q2, q10, q2 -+ vsub.s8 q3, q11, q3 -+ -+- veor.u8 q8, q8 // zero register -+- vdup.s8 q9, r6 // 2 to all elements -+- add r6, #1 -+- vdup.s8 q10, r6 // 3 to all elements -+- sub r6, #1 -+- -+ vadd.s8 q0, q12 //diff0 + diff1 -+ vadd.s8 q1, q13 -+ vadd.s8 q2, q14 -+ vadd.s8 q3, q15 -+ -+- vcgt.s8 q4, q0, q8 // diff0 + diff1 > 0 -+- vcgt.s8 q5, q1, q8 -+- vcgt.s8 q6, q2, q8 -+- vcgt.s8 q7, q3, q8 -+- -+- vclt.s8 q11, q0, q8 // diff0 + diff1 < 0 -+- vclt.s8 q12, q1, q8 -+- vclt.s8 q13, q2, q8 -+- vclt.s8 q14, q3, q8 -+- -+- vadd.s8 q8, q0, q9 // diff0 + diff1 + 2 -+- vand.8 q15, q8, q4 -+- vadd.s8 q8, q0, q10 // diff0 + diff1 + 3 -+- vand.8 q8, q8, q11 -+- vadd.s8 q0, q15, q8 // offset_idx -+- -+- vadd.s8 q8, q1, q9 // diff0 + diff1 + 2 -+- vand.8 q15, q8, q5 -+- vadd.s8 q8, q1, q10 // diff0 + diff1 + 3 -+- vand.8 q8, q8, q12 -+- vadd.s8 q1, q15, q8 // offset_idx -+- -+- vadd.s8 q8, q2, q9 // diff0 + diff1 + 2 + 2 -+- vand.8 q15, q8, q6 -+- vadd.s8 q8, q2, q10 // diff0 + diff1 + 2 + 3 -+- vand.8 q8, q8, q13 -+- vadd.s8 q2, q15, q8 // offset_idx -+- -+- vadd.s8 q8, q3, q9 // diff0 + diff1 + 2 + 2 -+- vand.8 q15, q8, q7 -+- vadd.s8 q8, q3, q10 // diff0 + diff1 + 2 + 3 -+- vand.8 q8, q8, q14 -+- vadd.s8 q3, q15, q8 // offset_idx -+- // TODO: load only once -+- vld1.8 d16, [r5] -+- -+- vtbl.8 d0, {d16}, d0 -+- vtbl.8 d1, {d16}, d1 -+- vtbl.8 d2, {d16}, d2 -+- vtbl.8 d3, {d16}, d3 -+- vtbl.8 d4, {d16}, d4 -+- vtbl.8 d5, {d16}, d5 -+- vtbl.8 d6, {d16}, d6 -+- vtbl.8 d7, {d16}, d7 -+- -+- // TODO: load only once -+- // load c again -+- sub r1, r3 -+- sub r1, r3 -+- vld1.8 {q4-q5}, [r1]! -+- vld1.8 {q6-q7}, [r1], r3 -+- sub r1, #32 -++ vdup.s8 q9, r6 // 3 to all elements -++ sub r6, #1 -++ -++ vclt.s8 q12, q0, #0 // diff0 + diff1 < 0 -++ vclt.s8 q13, q1, #0 -++ vclt.s8 q14, q2, #0 -++ vclt.s8 q15, q3, #0 -++ -++ vadd.s8 q8, q0, q9 // diff0 + diff1 + 3 -++ vadd.s8 q10, q1, q9 -++ vand.8 q12, q8, q12 // if (diff0 + diff1 < 0) then (diff0 + diff1 + 3) else 0 -++ vand.8 q13, q10, q13 -++ vadd.s8 q8, q2, q9 -++ vadd.s8 q10, q3, q9 -++ vand.8 q14, q8, q14 -++ vand.8 q15, q10, q15 -++ -++ vdup.s8 q9, r6 // 2 to all elements -++ add r6, #1 -++ -++ vcgt.s8 q10, q0, #0 // diff0 + diff1 > 0 -++ vadd.s8 q8, q0, q9 // diff0 + diff1 + 2 -++ vand.8 q11, q8, q10 // if (diff0 + diff1 > 0) then (diff0 + diff1 + 2) else 0 -++ vcgt.s8 q10, q1, #0 -++ vadd.s8 q0, q11, q12 // offset_idx -++ -++ vadd.s8 q8, q1, q9 // diff0 + diff1 + 2 -++ vcgt.s8 q12, q2, #0 -++ vand.8 q11, q8, q10 // if (diff0 + diff1 > 0) then (diff0 + diff1 + 2) else 0 -++ vadd.s8 q8, q2, q9 // diff0 + diff1 + 2 -++ vadd.s8 q1, q11, q13 -++ -++ vand.8 q11, q8, q12 // if (diff0 + diff1 > 0) then (diff0 + diff1 + 2) else 0 -++ vcgt.s8 q10, q3, #0 -++ vadd.s8 q2, q11, q14 -++ -++ vadd.s8 q8, q3, q9 // diff0 + diff1 + 2 -++ vmov.32 d18[0], r7 // load offset table from general registers -++ vand.8 q11, q8, q10 // if (diff0 + diff1 > 0) then (diff0 + diff1 + 2) else 0 -++ vmov.32 d18[1], r5 // load rest of offset table -++ vadd.s8 q3, q11, q15 -++ -++ vtbl.8 d0, {d18}, d0 -++ vtbl.8 d1, {d18}, d1 -++ vtbl.8 d2, {d18}, d2 -++ vtbl.8 d3, {d18}, d3 -++ vtbl.8 d4, {d18}, d4 -++ vtbl.8 d5, {d18}, d5 -++ vtbl.8 d6, {d18}, d6 -++ vtbl.8 d7, {d18}, d7 -+ -+ vmovl.u8 q8, d8 -+ vmovl.u8 q9, d9 -+@@ -344,8 +316,388 @@ function ff_hevc_sao_edge_eo1_w64_neon_8, export=1 -+ -+ vstm r0, {q0-q3} -+ add r0, r2 -++.endm -++ -++.macro edge_w32_body -++ vcgt.u8 q12, q4, q0 // c > a -> -1 , otherwise 0 -++ vcgt.u8 q0, q0, q4 // a > c -> -1 , otherwise 0 -++ vcgt.u8 q13, q5, q1 -++ vcgt.u8 q1, q1, q5 -++ -++ vsub.s8 q12, q0, q12 // diff0 -++ vcgt.u8 q0, q4, q8 // c > b -++ vsub.s8 q13, q1, q13 // diff0 part 2 -++ -++ vcgt.u8 q6, q8, q4 // b > c -++ vcgt.u8 q1, q5, q9 -++ vcgt.u8 q7, q9, q5 -++ -++ vsub.s8 q0, q6, q0 // diff1 -++ vsub.s8 q1, q7, q1 // diff1 part 2 -++ vadd.s8 q0, q12 //diff0 + diff1 -++ -++ vdup.s8 q7, r6 // 3 to all elements -++ sub r6, #1 -++ vadd.s8 q1, q13 -++ -++ vclt.s8 q12, q0, #0 // diff0 + diff1 < 0 -++ vclt.s8 q13, q1, #0 -++ -++ vadd.s8 q6, q0, q7 // diff0 + diff1 + 3 -++ vadd.s8 q10, q1, q7 -++ vdup.s8 q7, r6 // 2 to all elements -++ add r6, #1 -++ vand.8 q12, q6, q12 // if (diff0 + diff1 < 0) then (diff0 + diff1 + 3) else 0 -++ vand.8 q13, q10, q13 -++ -++ -++ vcgt.s8 q10, q0, #0 // diff0 + diff1 > 0 -++ vadd.s8 q6, q0, q7 // diff0 + diff1 + 2 -++ vand.8 q11, q6, q10 // if (diff0 + diff1 > 0) then (diff0 + diff1 + 2) else 0 -++ vcgt.s8 q10, q1, #0 -++ vadd.s8 q0, q11, q12 // offset_idx -++ -++ vadd.s8 q6, q1, q7 // diff0 + diff1 + 2 -++ vmov.32 d14[0], r7 // load offset table from general registers -++ vand.8 q11, q6, q10 // if (diff0 + diff1 > 0) then (diff0 + diff1 + 2) else 0 -++ vmov.32 d14[1], r5 // load rest of offset table -++ vadd.s8 q1, q11, q13 -++ -++ vtbl.8 d0, {d14}, d0 -++ vtbl.8 d1, {d14}, d1 -++ vtbl.8 d2, {d14}, d2 -++ vtbl.8 d3, {d14}, d3 -++ -++ vmovl.u8 q6, d8 -++ vmovl.u8 q7, d9 -++ vmovl.u8 q10, d10 -++ vmovl.u8 q11, d11 -++ -++ vaddw.s8 q6, d0 -++ vaddw.s8 q7, d1 -++ vaddw.s8 q10, d2 -++ vaddw.s8 q11, d3 -++ -++ vqmovun.s16 d0, q6 -++ vqmovun.s16 d1, q7 -++ vqmovun.s16 d2, q10 -++ vqmovun.s16 d3, q11 -++ -++ vstm r0, {q0-q1} -++ add r0, r2 -++.endm -++ -++function ff_hevc_sao_edge_eo0_w64_neon_8, export=1 -++ push {r4-r8} -++ ldr r4, [sp, #20] // height -++ ldr r5, [sp, #24] // sao_offset_val_table -++ ldr r6, =0x03 -++ ldr r7, [r5] -++ add r5, #4 -++ ldr r5, [r5] -++ vpush {d8-d15} -++ sub r1, #8 -++1: subs r4, #1 -++ vld1.64 {q10-q11}, [r1]! -++ vld1.64 {q12-q13}, [r1]! -++ vld1.64 {q14}, [r1], r3 -++ sub r1, #64 -++ // load a -++ vext.8 q0, q10, q11, #7 -++ vext.8 q1, q11, q12, #7 -++ vext.8 q2, q12, q13, #7 -++ vext.8 q3, q13, q14, #7 -++ // load c -++ vext.8 q4, q10, q11, #8 -++ vext.8 q5, q11, q12, #8 -++ vext.8 q6, q12, q13, #8 -++ vext.8 q7, q13, q14, #8 -++ // load b -++ vext.8 q8, q10, q11, #9 -++ vext.8 q9, q11, q12, #9 -++ vext.8 q10, q12, q13, #9 -++ vext.8 q11, q13, q14, #9 -++ edge_w64_body -++ bne 1b -++ vpop {d8-d15} -++ pop {r4-r8} -++ bx lr -++endfunc -++ -++function ff_hevc_sao_edge_eo1_w64_neon_8, export=1 -++ push {r4-r8} -++ ldr r4, [sp, #20] // height -++ ldr r5, [sp, #24] // sao_offset_val_table -++ ldr r6, =0x03 -++ ldr r7, [r5] -++ add r5, #4 -++ ldr r5, [r5] -++ vpush {d8-d15} -++ sub r1, r3 -++ // load a -++ vld1.8 {q0-q1}, [r1]! -++ vld1.8 {q2-q3}, [r1], r3 -++ sub r1, #32 -++1: subs r4, #1 -++ // load c -++ vld1.8 {q4-q5}, [r1]! -++ vld1.8 {q6-q7}, [r1], r3 -++ sub r1, #32 -++ // load b -++ vld1.8 {q8-q9}, [r1]! -++ vld1.8 {q10-q11}, [r1] -++ sub r1, #32 -++ edge_w64_body -++ // copy c to a -++ vmov.64 q0, q4 -++ vmov.64 q1, q5 -++ vmov.64 q2, q6 -++ vmov.64 q3, q7 -+ bne 1b -+ vpop {d8-d15} -+ pop {r4-r8} -+ bx lr -+ endfunc -++ -++function ff_hevc_sao_edge_eo2_w64_neon_8, export=1 -++ push {r4-r8} -++ ldr r4, [sp, #20] // height -++ ldr r5, [sp, #24] // sao_offset_val_table -++ ldr r6, =0x03 -++ ldr r7, [r5] -++ add r5, #4 -++ ldr r5, [r5] -++ vpush {d8-d15} -++1: sub r1, r3 -++ // load a -++ // TODO: fix unaligned load -++ // don't reload a like in eo1 -++ sub r1, #1 -++ vld1.8 {q0-q1}, [r1]! -++ vld1.8 {q2-q3}, [r1], r3 -++ sub r1, #31 -++ subs r4, #1 -++ // load c -++ vld1.8 {q4-q5}, [r1]! -++ vld1.8 {q6-q7}, [r1], r3 -++ sub r1, #32 -++ // load b -++ add r1, #1 -++ vld1.8 {q8-q9}, [r1]! -++ vld1.8 {q10-q11}, [r1] -++ sub r1, #33 -++ edge_w64_body -++ // copy c to a -++ vmov.64 q0, q4 -++ vmov.64 q1, q5 -++ vmov.64 q2, q6 -++ vmov.64 q3, q7 -++ bne 1b -++ vpop {d8-d15} -++ pop {r4-r8} -++ bx lr -++endfunc -++ -++function ff_hevc_sao_edge_eo3_w64_neon_8, export=1 -++ push {r4-r8} -++ ldr r4, [sp, #20] // height -++ ldr r5, [sp, #24] // sao_offset_val_table -++ ldr r6, =0x03 -++ ldr r7, [r5] -++ add r5, #4 -++ ldr r5, [r5] -++ vpush {d8-d15} -++1: sub r1, r3 -++ // load a -++ // TODO: fix unaligned load -++ // don't reload a like in eo1 -++ add r1, #1 -++ vld1.8 {q0-q1}, [r1]! -++ vld1.8 {q2-q3}, [r1], r3 -++ sub r1, #33 -++ subs r4, #1 -++ // load c -++ vld1.8 {q4-q5}, [r1]! -++ vld1.8 {q6-q7}, [r1], r3 -++ sub r1, #32 -++ // load b -++ sub r1, #1 -++ vld1.8 {q8-q9}, [r1]! -++ vld1.8 {q10-q11}, [r1] -++ sub r1, #31 -++ edge_w64_body -++ // copy c to a -++ vmov.64 q0, q4 -++ vmov.64 q1, q5 -++ vmov.64 q2, q6 -++ vmov.64 q3, q7 -++ bne 1b -++ vpop {d8-d15} -++ pop {r4-r8} -++ bx lr -++endfunc -++ -++function ff_hevc_sao_edge_eo0_w32_neon_8, export=1 -++ push {r4-r8} -++ ldr r4, [sp, #20] // height -++ ldr r5, [sp, #24] // sao_offset_val_table -++ ldr r6, =0x03 -++ ldr r7, [r5] -++ add r5, #4 -++ ldr r5, [r5] -++ vpush {d8-d15} -++ sub r1, #8 // load 8 extra bytes -++1: subs r4, #1 -++ vld1.8 {q10-q11}, [r1] -++ add r1, #32 -++ vld1.8 {q12}, [r1], r3 // only first 9 bytes are used -++ sub r1, #32 -++ // a -++ vext.8 q0, q10, q11, #7 -++ vext.8 q1, q11, q12, #7 -++ // c -++ vext.8 q4, q10, q11, #8 -++ vext.8 q5, q11, q12, #8 -++ // b -++ vext.8 q8, q10, q11, #9 -++ vext.8 q9, q11, q12, #9 -++ edge_w32_body -++ bne 1b -++ vpop {d8-d15} -++ pop {r4-r8} -++ bx lr -++endfunc -++ -++function ff_hevc_sao_edge_eo1_w32_neon_8, export=1 -++ push {r4-r8} -++ ldr r4, [sp, #20] // height -++ ldr r5, [sp, #24] // sao_offset_val_table -++ ldr r6, =0x03 -++ ldr r7, [r5] -++ add r5, #4 -++ ldr r5, [r5] -++ vpush {d8-d15} -++ // load a -++ sub r1, r3 -++ vld1.8 {q0-q1}, [r1], r3 -++ // load c -++ vld1.8 {q4-q5}, [r1], r3 -++1: subs r4, #1 -++ // load b -++ vld1.8 {q8-q9}, [r1], r3 -++ edge_w32_body -++ // inputs for next loop iteration -++ // a -++ vmov.64 q0, q4 -++ vmov.64 q1, q5 -++ // c -++ vmov.64 q4, q8 -++ vmov.64 q5, q9 -++ bne 1b -++ vpop {d8-d15} -++ pop {r4-r8} -++ bx lr -++endfunc -++ -++function ff_hevc_sao_edge_eo2_w32_neon_8, export=1 -++ push {r4-r8} -++ ldr r4, [sp, #20] // height -++ ldr r5, [sp, #24] // sao_offset_val_table -++ ldr r6, =0x03 -++ ldr r7, [r5] -++ add r5, #4 -++ ldr r5, [r5] -++ vpush {d8-d15} -++ // load a -++ sub r1, r3 -++ sub r1, #8 -++ vld1.8 {q10-q11}, [r1] -++ add r1, #32 -++ vld1.8 {q12}, [r1], r3 -++ sub r1, #32 -++ vext.8 q0, q10, q11, #7 -++ vext.8 q1, q11, q12, #7 -++ // load c -++ vld1.8 {q10-q11}, [r1] -++ add r1, #32 -++ vld1.8 {q12}, [r1], r3 -++ sub r1, #32 -++ vext.8 q4, q10, q11, #8 -++ vext.8 q5, q11, q12, #8 -++ vext.8 q2, q10, q11, #7 -++1: subs r4, #1 -++ // load b -++ vld1.8 {q10-q11}, [r1] -++ add r1, #32 -++ vld1.8 {q12}, [r1], r3 -++ sub r1, #32 -++ vext.8 q8, q10, q11, #9 -++ vext.8 q9, q11, q12, #9 -++ vext.8 q14, q10, q11, #8 -++ vext.8 q15, q11, q12, #8 -++ vext.8 q3, q10, q11, #7 -++ edge_w32_body -++ // inputs for next loop iteration -++ // a -++ vmov.8 q0, q2 -++ vext.8 q1, q4, q5, #15 -++ // c -++ vmov.8 q4, q14 -++ vmov.8 q5, q15 -++ vmov.8 q2, q3 -++ bne 1b -++ vpop {d8-d15} -++ pop {r4-r8} -++ bx lr -++endfunc -++ -++function ff_hevc_sao_edge_eo3_w32_neon_8, export=1 -++ push {r4-r8} -++ ldr r4, [sp, #20] // height -++ ldr r5, [sp, #24] // sao_offset_val_table -++ ldr r6, =0x03 -++ ldr r7, [r5] -++ add r5, #4 -++ sub r1, r3 -++ ldr r5, [r5] -++ sub r1, #8 -++ vpush {d8-d15} -++ // load a -++ vld1.8 {q10-q11}, [r1] -++ add r1, #32 -++ vld1.8 {q12}, [r1], r3 -++ sub r1, #32 -++ vext.8 q0, q10, q11, #9 -++ vext.8 q1, q11, q12, #9 -++ // load c -++ vld1.8 {q10-q11}, [r1] -++ add r1, #32 -++ vld1.8 {q12}, [r1], r3 -++ sub r1, #32 -++ vext.8 q4, q10, q11, #8 -++ vext.8 q5, q11, q12, #8 -++ vext.8 q2, q12, q11, #8 -++1: subs r4, #1 -++ // load b -++ vld1.8 {q10-q11}, [r1] -++ add r1, #32 -++ vld1.8 {q12}, [r1], r3 -++ sub r1, #32 -++ vext.8 q8, q10, q11, #7 -++ vext.8 q9, q11, q12, #7 -++ vext.8 q3, q12, q10, #7 -++ edge_w32_body -++ // inputs for next loop iteration -++ // a -++ vext.8 q0, q4, q5, #1 -++ vext.8 q1, q5, q2, #1 -++ // c -++ vext.8 q4, q8, q9, #1 -++ vext.8 q5, q9, q3, #1 -++ vext.8 q2, q3, q1, #1 -++ bne 1b -++ vpop {d8-d15} -++ pop {r4-r8} -++ bx lr -++endfunc -++ -+-- -+2.5.0 -+ -+ -+From 1898d052a73370166d57e17cc7c52b7275887df3 Mon Sep 17 00:00:00 2001 -+From: Seppo Tomperi -+Date: Fri, 19 Dec 2014 09:44:10 +0200 -+Subject: [PATCH 4/9] Improved SAO band NEON opimizations made SAO buffer 16 -+ byte aligned added alignment hints to loads and stores optimized register -+ usage in SAO band neon assembly -+ -+--- -+ libavcodec/arm/hevcdsp_sao_neon.S | 212 +++++++++++++++----------------------- -+ 1 file changed, 82 insertions(+), 130 deletions(-) -+ -+diff --git a/libavcodec/arm/hevcdsp_sao_neon.S b/libavcodec/arm/hevcdsp_sao_neon.S -+index 4687012..ac21013 100644 -+--- a/libavcodec/arm/hevcdsp_sao_neon.S -++++ b/libavcodec/arm/hevcdsp_sao_neon.S -+@@ -22,120 +22,84 @@ -+ #include "neon.S" -+ -+ function ff_hevc_sao_band_w8_neon_8, export=1 -+- push {r4-r8} -+- ldr r4, [sp, #20] // height -+- ldr r5, [sp, #24] // offset_table -+- vpush {d8-d15} -+- vld1.8 {q0, q1}, [r5] // offset table -++ ldr r12, [sp, #4] // offset_table address -++ vld1.8 {q0, q1}, [r12] // offset table -++ ldr r12, [sp, #0] // height -+ -+-1: subs r4, #1 -+- vld1.8 {d24}, [r1], r3 -++1: subs r12, #1 -++ vld1.8 {d24}, [r1,:64], r3 -+ vshr.u8 d16, d24, #3 -+ vtbl.8 d16, {q0, q1}, d16 -+- vmovl.s8 q2, d16 -+ vmovl.u8 q6, d24 -+- vadd.s16 q2, q6 -++ vaddw.s8 q6, d16 -+ vqmovun.s16 d4, q2 -+- vst1.8 {d4}, [r0], r2 -++ vst1.8 {d4}, [r0,:64], r2 -+ bne 1b -+ -+- vpop {d8-d15} -+- pop {r4-r8} -+ bx lr -+ endfunc -+ -+ function ff_hevc_sao_band_w16_neon_8, export=1 -+- push {r4-r8} -+- ldr r4, [sp, #20] // height -+- ldr r5, [sp, #24] // offset_table -+- vpush {d8-d15} -+- vld1.8 {q0, q1}, [r5] // offset table -+- -+-1: subs r4, #1 -+- vld1.8 {q12}, [r1], r3 -++ ldr r12, [sp, #4] // offset_table address -++ vld1.8 {q0, q1}, [r12] // offset table -++ ldr r12, [sp, #0] // height -+ -++1: subs r12, #1 -++ vld1.8 {q12}, [r1,:128], r3 -+ vshr.u8 q8, q12, #3 -+- -+ vtbl.8 d16, {q0, q1}, d16 -+ vtbl.8 d17, {q0, q1}, d17 -+- -+- vmovl.s8 q2, d16 -+- vmovl.s8 q3, d17 -+- -+- vmovl.u8 q6, d24 -+- vmovl.u8 q7, d25 -+- -+- vadd.s16 q2, q6 -+- vadd.s16 q3, q7 -+- -+- vqmovun.s16 d4, q2 -+- vqmovun.s16 d5, q3 -+- -+- vstm.8 r0, {q2} -+- add r0, r2 -++ vmovl.u8 q10, d24 -++ vmovl.u8 q11, d25 -++ vaddw.s8 q10, d16 -++ vaddw.s8 q11, d17 -++ vqmovun.s16 d4, q10 -++ vqmovun.s16 d5, q11 -++ vst1.8 {q2}, [r0,:128], r2 -+ bne 1b -+ -+- vpop {d8-d15} -+- pop {r4-r8} -+ bx lr -+ endfunc -+ -+ function ff_hevc_sao_band_w32_neon_8, export=1 -+- push {r4-r8} -+- ldr r4, [sp, #20] // height -+- ldr r5, [sp, #24] // offset_table -+- vpush {d8-d15} -+- vld1.8 {q0, q1}, [r5] // offset table -+- -+-1: subs r4, #1 -+- vld1.8 {q12-q13}, [r1], r3 -+- -+- vshr.u8 q8, q12, #3 -+- vshr.u8 q9, q13, #3 -+- -+- vtbl.8 d16, {q0, q1}, d16 -+- vtbl.8 d17, {q0, q1}, d17 -+- vtbl.8 d18, {q0, q1}, d18 -+- vtbl.8 d19, {q0, q1}, d19 -+- -+- vmovl.s8 q2, d16 -+- vmovl.s8 q3, d17 // q8 free -+- vmovl.s8 q4, d18 -+- vmovl.s8 q5, d19 // q9 free -+- -+- vmovl.u8 q6, d24 -+- vmovl.u8 q7, d25 // q12 free -+- vmovl.u8 q8, d26 -+- vmovl.u8 q9, d27 // q13 free -+- -+- vadd.s16 q2, q6 -+- vadd.s16 q3, q7 -+- vadd.s16 q4, q8 -+- vadd.s16 q5, q9 -+- -+- vqmovun.s16 d4, q2 -+- vqmovun.s16 d5, q3 -+- vqmovun.s16 d6, q4 // q4 free -+- vqmovun.s16 d7, q5 // q5 free -+- -+- vst1.8 {q2-q3}, [r0], r2 -+- bne 1b -+- -+- vpop {d8-d15} -+- pop {r4-r8} -+- bx lr -++ ldr r12, [sp, #4] // offset_table address -++ vld1.8 {q0, q1}, [r12] // offset table -++ ldr r12, [sp, #0] // height -++ -++1: subs r12, #1 -++ vld1.8 {q2-q3}, [r1,:128], r3 -++ vshr.u8 q8, q2, #3 -++ vshr.u8 q9, q3, #3 -++ vtbl.8 d16, {q0, q1}, d16 -++ vtbl.8 d17, {q0, q1}, d17 -++ vtbl.8 d18, {q0, q1}, d18 -++ vtbl.8 d19, {q0, q1}, d19 -++ vmovl.u8 q12, d4 -++ vmovl.u8 q13, d5 -++ vmovl.u8 q14, d6 -++ vmovl.u8 q15, d7 -++ vaddw.s8 q12, d16 -++ vaddw.s8 q13, d17 -++ vaddw.s8 q14, d18 -++ vaddw.s8 q15, d19 -++ vqmovun.s16 d4, q12 -++ vqmovun.s16 d5, q13 -++ vqmovun.s16 d6, q14 -++ vqmovun.s16 d7, q15 -++ vst1.8 {q2-q3}, [r0,:128], r2 -++ bne 1b -++ -++ bx lr -+ endfunc -+ -+ function ff_hevc_sao_band_w64_neon_8, export=1 -+- push {r4-r8} -+- ldr r4, [sp, #20] // height -+- ldr r5, [sp, #24] // offset_table -+- vpush {d8-d15} -+- vld1.8 {q0, q1}, [r5] // offset table -++ ldr r12, [sp, #4] // offset_table address -++ vld1.8 {q0, q1}, [r12] // offset table -++ ldr r12, [sp, #0] // height -+ -+-1: subs r4, #1 -+- vld1.8 {q12-q13}, [r1]! -+- vld1.8 {q14-q15}, [r1], r3 -++1: subs r12, #1 -++ vld1.8 {q12-q13}, [r1,:128]! -++ vld1.8 {q14-q15}, [r1,:128], r3 -+ sub r1, #32 -+ -+ vshr.u8 q8, q12, #3 -+@@ -152,53 +116,41 @@ function ff_hevc_sao_band_w64_neon_8, export=1 -+ vtbl.8 d22, {q0, q1}, d22 -+ vtbl.8 d23, {q0, q1}, d23 -+ -+- vmovl.s8 q2, d16 -+- vmovl.s8 q3, d17 // q8 free -+- vmovl.s8 q4, d18 -+- vmovl.s8 q5, d19 // q9 free -++ vmovl.u8 q2, d24 -++ vmovl.u8 q3, d25 -++ vmovl.u8 q12, d26 -++ vmovl.u8 q13, d27 -+ -+- vmovl.u8 q6, d24 -+- vmovl.u8 q7, d25 // q12 free -+- vmovl.u8 q8, d26 -+- vmovl.u8 q9, d27 // q13 free -+- -+- vadd.s16 q2, q6 -+- vadd.s16 q3, q7 -+- vadd.s16 q4, q8 -+- vadd.s16 q5, q9 -++ vaddw.s8 q2, d16 -++ vaddw.s8 q3, d17 -++ vaddw.s8 q12, d18 -++ vaddw.s8 q13, d19 -+ -+ vqmovun.s16 d4, q2 -+ vqmovun.s16 d5, q3 -+- vqmovun.s16 d6, q4 // q4 free -+- vqmovun.s16 d7, q5 // q5 free -+- -+- // free q4 -q9, q12 - q13 -+- vmovl.s8 q4, d20 -+- vmovl.s8 q5, d21 // q10 free -+- vmovl.s8 q6, d22 -+- vmovl.s8 q7, d23 // q11 free -+- -+- vmovl.u8 q8, d28 -+- vmovl.u8 q9, d29 // q14 free -+- vmovl.u8 q10, d30 -+- vmovl.u8 q11, d31 // q15 free -+- -+- vadd.s16 q4, q8 -+- vadd.s16 q5, q9 -+- vadd.s16 q6, q10 -+- vadd.s16 q7, q11 -+- -+- vqmovun.s16 d8, q4 -+- vqmovun.s16 d9, q5 -+- vqmovun.s16 d10, q6 -+- vqmovun.s16 d11, q7 -+- -+- vstm.8 r0, {q2-q5} -+- add r0, r2 -++ vqmovun.s16 d6, q12 -++ vqmovun.s16 d7, q13 -++ -++ vmovl.u8 q12, d28 -++ vmovl.u8 q13, d29 -++ vmovl.u8 q14, d30 -++ vmovl.u8 q15, d31 -++ -++ vaddw.s8 q12, d20 -++ vaddw.s8 q13, d21 -++ vaddw.s8 q14, d22 -++ vaddw.s8 q15, d23 -++ -++ vqmovun.s16 d8, q12 -++ vqmovun.s16 d9, q13 -++ vqmovun.s16 d10, q14 -++ vqmovun.s16 d11, q15 -++ -++ vst1.8 {q2-q3}, [r0,:128]! -++ vst1.8 {q4-q5}, [r0,:128], r2 -++ sub r0, #32 -+ bne 1b -+ -+- vpop {d8-d15} -+- pop {r4-r8} -+ bx lr -+ endfunc -+ -+-- -+2.5.0 -+ -+ -+From 26bd536800db2f50ff6a021e1fda0d0394d1ea01 Mon Sep 17 00:00:00 2001 -+From: Seppo Tomperi -+Date: Mon, 29 Dec 2014 15:00:49 +0200 -+Subject: [PATCH 5/9] better code reuse in NEON SAO band -+ -+--- -+ libavcodec/arm/hevcdsp_init_neon.c | 16 ++-- -+ libavcodec/arm/hevcdsp_sao_neon.S | 155 +++++++++++++------------------------ -+ 2 files changed, 61 insertions(+), 110 deletions(-) -+ -+diff --git a/libavcodec/arm/hevcdsp_init_neon.c b/libavcodec/arm/hevcdsp_init_neon.c -+index c32940e..6379810 100644 -+--- a/libavcodec/arm/hevcdsp_init_neon.c -++++ b/libavcodec/arm/hevcdsp_init_neon.c -+@@ -45,10 +45,10 @@ void ff_hevc_transform_add_16x16_neon_8(uint8_t *_dst, int16_t *coeffs, -+ void ff_hevc_transform_add_32x32_neon_8(uint8_t *_dst, int16_t *coeffs, -+ ptrdiff_t stride); -+ -+-void ff_hevc_sao_band_w8_neon_8(uint8_t *_dst, uint8_t *_src, ptrdiff_t stride_dst, ptrdiff_t stride_src, int height, int8_t * offset_table); -+-void ff_hevc_sao_band_w16_neon_8(uint8_t *_dst, uint8_t *_src, ptrdiff_t stride_dst, ptrdiff_t stride_src, int height, int8_t * offset_table); -+-void ff_hevc_sao_band_w32_neon_8(uint8_t *_dst, uint8_t *_src, ptrdiff_t stride_dst, ptrdiff_t stride_src, int height, int8_t * offset_table); -+-void ff_hevc_sao_band_w64_neon_8(uint8_t *_dst, uint8_t *_src, ptrdiff_t stride_dst, ptrdiff_t stride_src, int height, int8_t * offset_table); -++void ff_hevc_sao_band_w8_neon_8(uint8_t *_dst, uint8_t *_src, ptrdiff_t stride_dst, ptrdiff_t stride_src, int8_t * offset_table, int height); -++void ff_hevc_sao_band_w16_neon_8(uint8_t *_dst, uint8_t *_src, ptrdiff_t stride_dst, ptrdiff_t stride_src, int8_t * offset_table, int height); -++void ff_hevc_sao_band_w32_neon_8(uint8_t *_dst, uint8_t *_src, ptrdiff_t stride_dst, ptrdiff_t stride_src, int8_t * offset_table, int height); -++void ff_hevc_sao_band_w64_neon_8(uint8_t *_dst, uint8_t *_src, ptrdiff_t stride_dst, ptrdiff_t stride_src, int8_t * offset_table, int height); -+ -+ void ff_hevc_sao_edge_eo0_w32_neon_8(uint8_t *_dst, uint8_t *_src, ptrdiff_t stride_dst, ptrdiff_t stride_src, int height, int8_t *sao_offset_table); -+ void ff_hevc_sao_edge_eo1_w32_neon_8(uint8_t *_dst, uint8_t *_src, ptrdiff_t stride_dst, ptrdiff_t stride_src, int height, int8_t *sao_offset_table); -+@@ -185,16 +185,16 @@ static void ff_hevc_sao_band_neon_wrapper(uint8_t *_dst, uint8_t *_src, ptrdiff_ -+ -+ switch(width){ -+ case 8: -+- ff_hevc_sao_band_w8_neon_8(_dst, _src, stride_dst, stride_src, height, offset_table); -++ ff_hevc_sao_band_w8_neon_8(_dst, _src, stride_dst, stride_src, offset_table, height); -+ break; -+ case 16: -+- ff_hevc_sao_band_w16_neon_8(_dst, _src, stride_dst, stride_src, height, offset_table); -++ ff_hevc_sao_band_w16_neon_8(_dst, _src, stride_dst, stride_src, offset_table, height); -+ break; -+ case 32: -+- ff_hevc_sao_band_w32_neon_8(_dst, _src, stride_dst, stride_src, height, offset_table); -++ ff_hevc_sao_band_w32_neon_8(_dst, _src, stride_dst, stride_src, offset_table, height); -+ break; -+ case 64: -+- ff_hevc_sao_band_w64_neon_8(_dst, _src, stride_dst, stride_src, height, offset_table); -++ ff_hevc_sao_band_w64_neon_8(_dst, _src, stride_dst, stride_src, offset_table, height); -+ break; -+ default: -+ for (y = 0; y < height; y++) { -+diff --git a/libavcodec/arm/hevcdsp_sao_neon.S b/libavcodec/arm/hevcdsp_sao_neon.S -+index ac21013..8852550 100644 -+--- a/libavcodec/arm/hevcdsp_sao_neon.S -++++ b/libavcodec/arm/hevcdsp_sao_neon.S -+@@ -21,53 +21,13 @@ -+ #include "libavutil/arm/asm.S" -+ #include "neon.S" -+ -+-function ff_hevc_sao_band_w8_neon_8, export=1 -+- ldr r12, [sp, #4] // offset_table address -++.macro init_sao_band -++ ldr r12, [sp, #0] // offset_table address -+ vld1.8 {q0, q1}, [r12] // offset table -+- ldr r12, [sp, #0] // height -+- -+-1: subs r12, #1 -+- vld1.8 {d24}, [r1,:64], r3 -+- vshr.u8 d16, d24, #3 -+- vtbl.8 d16, {q0, q1}, d16 -+- vmovl.u8 q6, d24 -+- vaddw.s8 q6, d16 -+- vqmovun.s16 d4, q2 -+- vst1.8 {d4}, [r0,:64], r2 -+- bne 1b -+- -+- bx lr -+-endfunc -+- -+-function ff_hevc_sao_band_w16_neon_8, export=1 -+- ldr r12, [sp, #4] // offset_table address -+- vld1.8 {q0, q1}, [r12] // offset table -+- ldr r12, [sp, #0] // height -+- -+-1: subs r12, #1 -+- vld1.8 {q12}, [r1,:128], r3 -+- vshr.u8 q8, q12, #3 -+- vtbl.8 d16, {q0, q1}, d16 -+- vtbl.8 d17, {q0, q1}, d17 -+- vmovl.u8 q10, d24 -+- vmovl.u8 q11, d25 -+- vaddw.s8 q10, d16 -+- vaddw.s8 q11, d17 -+- vqmovun.s16 d4, q10 -+- vqmovun.s16 d5, q11 -+- vst1.8 {q2}, [r0,:128], r2 -+- bne 1b -+- -+- bx lr -+-endfunc -+- -+-function ff_hevc_sao_band_w32_neon_8, export=1 -+- ldr r12, [sp, #4] // offset_table address -+- vld1.8 {q0, q1}, [r12] // offset table -+- ldr r12, [sp, #0] // height -++ ldr r12, [sp, #4] // height -++.endm -+ -+-1: subs r12, #1 -+- vld1.8 {q2-q3}, [r1,:128], r3 -++.macro sao_band_32 -+ vshr.u8 q8, q2, #3 -+ vshr.u8 q9, q3, #3 -+ vtbl.8 d16, {q0, q1}, d16 -+@@ -86,6 +46,43 @@ function ff_hevc_sao_band_w32_neon_8, export=1 -+ vqmovun.s16 d5, q13 -+ vqmovun.s16 d6, q14 -+ vqmovun.s16 d7, q15 -++.endm -++ -++function ff_hevc_sao_band_w8_neon_8, export=1 -++ init_sao_band -++1: subs r12, #4 -++ vld1.8 {d4}, [r1,:64], r3 -++ vld1.8 {d5}, [r1,:64], r3 -++ vld1.8 {d6}, [r1,:64], r3 -++ vld1.8 {d7}, [r1,:64], r3 -++ sao_band_32 -++ vst1.8 {d4}, [r0,:64], r2 -++ vst1.8 {d5}, [r0,:64], r2 -++ vst1.8 {d6}, [r0,:64], r2 -++ vst1.8 {d7}, [r0,:64], r2 -++ bne 1b -++ -++ bx lr -++endfunc -++ -++function ff_hevc_sao_band_w16_neon_8, export=1 -++ init_sao_band -++1: subs r12, #2 -++ vld1.8 {q2}, [r1,:128], r3 -++ vld1.8 {q3}, [r1,:128], r3 -++ sao_band_32 -++ vst1.8 {q2}, [r0,:128], r2 -++ vst1.8 {q3}, [r0,:128], r2 -++ bne 1b -++ -++ bx lr -++endfunc -++ -++function ff_hevc_sao_band_w32_neon_8, export=1 -++ init_sao_band -++1: subs r12, #1 -++ vld1.8 {q2-q3}, [r1,:128], r3 -++ sao_band_32 -+ vst1.8 {q2-q3}, [r0,:128], r2 -+ bne 1b -+ -+@@ -93,63 +90,17 @@ function ff_hevc_sao_band_w32_neon_8, export=1 -+ endfunc -+ -+ function ff_hevc_sao_band_w64_neon_8, export=1 -+- ldr r12, [sp, #4] // offset_table address -+- vld1.8 {q0, q1}, [r12] // offset table -+- ldr r12, [sp, #0] // height -+- -+-1: subs r12, #1 -+- vld1.8 {q12-q13}, [r1,:128]! -+- vld1.8 {q14-q15}, [r1,:128], r3 -+- sub r1, #32 -+- -+- vshr.u8 q8, q12, #3 -+- vshr.u8 q9, q13, #3 -+- vshr.u8 q10, q14, #3 -+- vshr.u8 q11, q15, #3 -+- -+- vtbl.8 d16, {q0, q1}, d16 -+- vtbl.8 d17, {q0, q1}, d17 -+- vtbl.8 d18, {q0, q1}, d18 -+- vtbl.8 d19, {q0, q1}, d19 -+- vtbl.8 d20, {q0, q1}, d20 -+- vtbl.8 d21, {q0, q1}, d21 -+- vtbl.8 d22, {q0, q1}, d22 -+- vtbl.8 d23, {q0, q1}, d23 -+- -+- vmovl.u8 q2, d24 -+- vmovl.u8 q3, d25 -+- vmovl.u8 q12, d26 -+- vmovl.u8 q13, d27 -+- -+- vaddw.s8 q2, d16 -+- vaddw.s8 q3, d17 -+- vaddw.s8 q12, d18 -+- vaddw.s8 q13, d19 -+- -+- vqmovun.s16 d4, q2 -+- vqmovun.s16 d5, q3 -+- vqmovun.s16 d6, q12 -+- vqmovun.s16 d7, q13 -+- -+- vmovl.u8 q12, d28 -+- vmovl.u8 q13, d29 -+- vmovl.u8 q14, d30 -+- vmovl.u8 q15, d31 -+- -+- vaddw.s8 q12, d20 -+- vaddw.s8 q13, d21 -+- vaddw.s8 q14, d22 -+- vaddw.s8 q15, d23 -+- -+- vqmovun.s16 d8, q12 -+- vqmovun.s16 d9, q13 -+- vqmovun.s16 d10, q14 -+- vqmovun.s16 d11, q15 -+- -+- vst1.8 {q2-q3}, [r0,:128]! -+- vst1.8 {q4-q5}, [r0,:128], r2 -+- sub r0, #32 -+- bne 1b -++ init_sao_band -++1: subs r12, #1 -++ vld1.8 {q2-q3}, [r1,:128]! -++ sao_band_32 -++ vst1.8 {q2-q3}, [r0,:128]! -++ vld1.8 {q2-q3}, [r1,:128], r3 -++ sub r1, #32 -++ sao_band_32 -++ vst1.8 {q2-q3}, [r0,:128], r2 -++ sub r0, #32 -++ bne 1b -+ -+ bx lr -+ endfunc -+-- -+2.5.0 -+ -+ -+From f93646a97bc885b81759e774d04be3781916a3e7 Mon Sep 17 00:00:00 2001 -+From: Seppo Tomperi -+Date: Wed, 7 Jan 2015 15:27:38 +0200 -+Subject: [PATCH 6/9] More SAO NEON optimizations Now uses only 8 bit integers -+ for SAO calculations -+ -+--- -+ libavcodec/arm/hevcdsp_init_neon.c | 7 +- -+ libavcodec/arm/hevcdsp_sao_neon.S | 664 +++++++++++++++---------------------- -+ 2 files changed, 272 insertions(+), 399 deletions(-) -+ -+diff --git a/libavcodec/arm/hevcdsp_init_neon.c b/libavcodec/arm/hevcdsp_init_neon.c -+index 6379810..8d6e863 100644 -+--- a/libavcodec/arm/hevcdsp_init_neon.c -++++ b/libavcodec/arm/hevcdsp_init_neon.c -+@@ -225,7 +225,7 @@ static void ff_hevc_sao_edge_neon_wrapper(uint8_t *_dst /* align 16 */, uint8_t -+ int x, y; -+ -+ for (x = 0; x < 5; x++) { -+- sao_offset_val[x] = _sao_offset_val[x]; -++ sao_offset_val[x] = _sao_offset_val[edge_idx[x]]; -+ } -+ -+ stride_src /= sizeof(pixel); -+@@ -271,8 +271,9 @@ static void ff_hevc_sao_edge_neon_wrapper(uint8_t *_dst /* align 16 */, uint8_t -+ for (x = 0; x < width; x++) { -+ int diff0 = CMP(src[x], src[x + a_stride]); -+ int diff1 = CMP(src[x], src[x + b_stride]); -+- int offset_val = edge_idx[2 + diff0 + diff1]; -+- dst[x] = av_clip_pixel(src[x] + sao_offset_val[offset_val]); -++ int idx = diff0 + diff1; -++ if (idx) -++ dst[x] = av_clip_pixel(src[x] + sao_offset_val[idx+2]); -+ } -+ src += stride_src; -+ dst += stride_dst; -+diff --git a/libavcodec/arm/hevcdsp_sao_neon.S b/libavcodec/arm/hevcdsp_sao_neon.S -+index 8852550..5fc482b 100644 -+--- a/libavcodec/arm/hevcdsp_sao_neon.S -++++ b/libavcodec/arm/hevcdsp_sao_neon.S -+@@ -1,5 +1,5 @@ -+ /* -+- * Copyright (c) 2014 Seppo Tomperi -++ * Copyright (c) 2014 - 2015 Seppo Tomperi -+ * -+ * This file is part of FFmpeg. -+ * -+@@ -23,6 +23,7 @@ -+ -+ .macro init_sao_band -+ ldr r12, [sp, #0] // offset_table address -++ pld [r1] -+ vld1.8 {q0, q1}, [r12] // offset table -+ ldr r12, [sp, #4] // height -+ .endm -+@@ -30,36 +31,31 @@ -+ .macro sao_band_32 -+ vshr.u8 q8, q2, #3 -+ vshr.u8 q9, q3, #3 -++ vmov.u8 q14, #128 -+ vtbl.8 d16, {q0, q1}, d16 -+ vtbl.8 d17, {q0, q1}, d17 -+ vtbl.8 d18, {q0, q1}, d18 -+ vtbl.8 d19, {q0, q1}, d19 -+- vmovl.u8 q12, d4 -+- vmovl.u8 q13, d5 -+- vmovl.u8 q14, d6 -+- vmovl.u8 q15, d7 -+- vaddw.s8 q12, d16 -+- vaddw.s8 q13, d17 -+- vaddw.s8 q14, d18 -+- vaddw.s8 q15, d19 -+- vqmovun.s16 d4, q12 -+- vqmovun.s16 d5, q13 -+- vqmovun.s16 d6, q14 -+- vqmovun.s16 d7, q15 -++ vadd.s8 q2, q14 -++ vadd.s8 q3, q14 -++ vqadd.s8 q2, q8 -++ vqadd.s8 q3, q9 -++ vsub.s8 q2, q14 -++ vsub.s8 q3, q14 -+ .endm -+ -+ function ff_hevc_sao_band_w8_neon_8, export=1 -+ init_sao_band -+ 1: subs r12, #4 -+- vld1.8 {d4}, [r1,:64], r3 -+- vld1.8 {d5}, [r1,:64], r3 -+- vld1.8 {d6}, [r1,:64], r3 -+- vld1.8 {d7}, [r1,:64], r3 -++ vld1.8 {d4}, [r1, :64], r3 -++ vld1.8 {d5}, [r1, :64], r3 -++ vld1.8 {d6}, [r1, :64], r3 -++ vld1.8 {d7}, [r1, :64], r3 -+ sao_band_32 -+- vst1.8 {d4}, [r0,:64], r2 -+- vst1.8 {d5}, [r0,:64], r2 -+- vst1.8 {d6}, [r0,:64], r2 -+- vst1.8 {d7}, [r0,:64], r2 -++ vst1.8 {d4}, [r0, :64], r2 -++ vst1.8 {d5}, [r0, :64], r2 -++ vst1.8 {d6}, [r0, :64], r2 -++ vst1.8 {d7}, [r0, :64], r2 -+ bne 1b -+ -+ bx lr -+@@ -68,11 +64,11 @@ endfunc -+ function ff_hevc_sao_band_w16_neon_8, export=1 -+ init_sao_band -+ 1: subs r12, #2 -+- vld1.8 {q2}, [r1,:128], r3 -+- vld1.8 {q3}, [r1,:128], r3 -++ vld1.8 {q2}, [r1, :128], r3 -++ vld1.8 {q3}, [r1, :128], r3 -+ sao_band_32 -+- vst1.8 {q2}, [r0,:128], r2 -+- vst1.8 {q3}, [r0,:128], r2 -++ vst1.8 {q2}, [r0, :128], r2 -++ vst1.8 {q3}, [r0, :128], r2 -+ bne 1b -+ -+ bx lr -+@@ -81,9 +77,9 @@ endfunc -+ function ff_hevc_sao_band_w32_neon_8, export=1 -+ init_sao_band -+ 1: subs r12, #1 -+- vld1.8 {q2-q3}, [r1,:128], r3 -++ vld1.8 {q2-q3}, [r1, :128], r3 -+ sao_band_32 -+- vst1.8 {q2-q3}, [r0,:128], r2 -++ vst1.8 {q2-q3}, [r0, :128], r2 -+ bne 1b -+ -+ bx lr -+@@ -92,263 +88,153 @@ endfunc -+ function ff_hevc_sao_band_w64_neon_8, export=1 -+ init_sao_band -+ 1: subs r12, #1 -+- vld1.8 {q2-q3}, [r1,:128]! -++ pld [r1, r3] -++ vld1.8 {q2-q3}, [r1, :128]! -+ sao_band_32 -+- vst1.8 {q2-q3}, [r0,:128]! -+- vld1.8 {q2-q3}, [r1,:128], r3 -++ vst1.8 {q2-q3}, [r0, :128]! -++ vld1.8 {q2-q3}, [r1, :128], r3 -+ sub r1, #32 -+ sao_band_32 -+- vst1.8 {q2-q3}, [r0,:128], r2 -++ vst1.8 {q2-q3}, [r0, :128], r2 -+ sub r0, #32 -+ bne 1b -+ -+ bx lr -+ endfunc -+- -++// input -++// a in q0 - q3 -++// c in q4 - q7 -++// b in q8 - q11 -++// offset table in r7 and r5 -++// output in q0 - q3 -++// clobbers q12 - q15 -+ .macro edge_w64_body -+- vcgt.u8 q12, q4, q0 // c > a -> -1 , otherwise 0 -+- vcgt.u8 q0, q0, q4 // a > c -> -1 , otherwise 0 -+- vcgt.u8 q13, q5, q1 -+- vcgt.u8 q1, q1, q5 -+- vcgt.u8 q14, q6, q2 -+- vcgt.u8 q2, q2, q6 -+- vcgt.u8 q15, q7, q3 -+- vcgt.u8 q3, q3, q7 -+- -+- vsub.s8 q12, q0, q12 // diff0 -+- vsub.s8 q13, q1, q13 -+- vsub.s8 q14, q2, q14 -+- vsub.s8 q15, q3, q15 -+- -++ vcgt.u8 q12, q4, q0 // c > a -> -1 , otherwise 0 -++ vcgt.u8 q0, q0, q4 // a > c -> -1 , otherwise 0 -++ vcgt.u8 q13, q5, q1 -++ vcgt.u8 q1, q1, q5 -++ vsub.s8 q12, q0, q12 // diff0 -+ vcgt.u8 q0, q4, q8 // c > b -+- vcgt.u8 q8, q8, q4 // b > c -++ vsub.s8 q13, q1, q13 -++ -++ vcgt.u8 q14, q8, q4 // b > c -+ vcgt.u8 q1, q5, q9 -+- vcgt.u8 q9, q9, q5 -+- vcgt.u8 q2, q6, q10 -+- vcgt.u8 q10, q10, q6 -+- vcgt.u8 q3, q7, q11 -+- vcgt.u8 q11, q11, q7 -++ vcgt.u8 q15, q9, q5 -++ vsub.s8 q0, q14, q0 // diff1 -+ -+- vsub.s8 q0, q8, q0 // diff1 -+- vsub.s8 q1, q9, q1 -+- vsub.s8 q2, q10, q2 -+- vsub.s8 q3, q11, q3 -++ vsub.s8 q1, q15, q1 -+ -+- vadd.s8 q0, q12 //diff0 + diff1 -+- vadd.s8 q1, q13 -+- vadd.s8 q2, q14 -+- vadd.s8 q3, q15 -+- -+- vdup.s8 q9, r6 // 3 to all elements -+- sub r6, #1 -+- -+- vclt.s8 q12, q0, #0 // diff0 + diff1 < 0 -+- vclt.s8 q13, q1, #0 -+- vclt.s8 q14, q2, #0 -+- vclt.s8 q15, q3, #0 -+- -+- vadd.s8 q8, q0, q9 // diff0 + diff1 + 3 -+- vadd.s8 q10, q1, q9 -+- vand.8 q12, q8, q12 // if (diff0 + diff1 < 0) then (diff0 + diff1 + 3) else 0 -+- vand.8 q13, q10, q13 -+- vadd.s8 q8, q2, q9 -+- vadd.s8 q10, q3, q9 -+- vand.8 q14, q8, q14 -+- vand.8 q15, q10, q15 -+- -+- vdup.s8 q9, r6 // 2 to all elements -+- add r6, #1 -+- -+- vcgt.s8 q10, q0, #0 // diff0 + diff1 > 0 -+- vadd.s8 q8, q0, q9 // diff0 + diff1 + 2 -+- vand.8 q11, q8, q10 // if (diff0 + diff1 > 0) then (diff0 + diff1 + 2) else 0 -+- vcgt.s8 q10, q1, #0 -+- vadd.s8 q0, q11, q12 // offset_idx -+- -+- vadd.s8 q8, q1, q9 // diff0 + diff1 + 2 -+- vcgt.s8 q12, q2, #0 -+- vand.8 q11, q8, q10 // if (diff0 + diff1 > 0) then (diff0 + diff1 + 2) else 0 -+- vadd.s8 q8, q2, q9 // diff0 + diff1 + 2 -+- vadd.s8 q1, q11, q13 -+- -+- vand.8 q11, q8, q12 // if (diff0 + diff1 > 0) then (diff0 + diff1 + 2) else 0 -+- vcgt.s8 q10, q3, #0 -+- vadd.s8 q2, q11, q14 -+- -+- vadd.s8 q8, q3, q9 // diff0 + diff1 + 2 -+- vmov.32 d18[0], r7 // load offset table from general registers -+- vand.8 q11, q8, q10 // if (diff0 + diff1 > 0) then (diff0 + diff1 + 2) else 0 -+- vmov.32 d18[1], r5 // load rest of offset table -+- vadd.s8 q3, q11, q15 -+- -+- vtbl.8 d0, {d18}, d0 -+- vtbl.8 d1, {d18}, d1 -+- vtbl.8 d2, {d18}, d2 -+- vtbl.8 d3, {d18}, d3 -+- vtbl.8 d4, {d18}, d4 -+- vtbl.8 d5, {d18}, d5 -+- vtbl.8 d6, {d18}, d6 -+- vtbl.8 d7, {d18}, d7 -+- -+- vmovl.u8 q8, d8 -+- vmovl.u8 q9, d9 -+- vmovl.u8 q10, d10 -+- vmovl.u8 q11, d11 -+- vmovl.u8 q12, d12 -+- vmovl.u8 q13, d13 -+- vmovl.u8 q14, d14 -+- vmovl.u8 q15, d15 -+- -+- vaddw.s8 q8, d0 -+- vaddw.s8 q9, d1 -+- vaddw.s8 q10, d2 -+- vaddw.s8 q11, d3 -+- vaddw.s8 q12, d4 -+- vaddw.s8 q13, d5 -+- vaddw.s8 q14, d6 -+- vaddw.s8 q15, d7 -+- -+- vqmovun.s16 d0, q8 -+- vqmovun.s16 d1, q9 -+- vqmovun.s16 d2, q10 -+- vqmovun.s16 d3, q11 -+- vqmovun.s16 d4, q12 -+- vqmovun.s16 d5, q13 -+- vqmovun.s16 d6, q14 -+- vqmovun.s16 d7, q15 -+- -+- vstm r0, {q0-q3} -+- add r0, r2 -+-.endm -++ vadd.s8 q0, q12 //diff0 + diff1 -++ vadd.s8 q1, q13 -+ -+-.macro edge_w32_body -+- vcgt.u8 q12, q4, q0 // c > a -> -1 , otherwise 0 -+- vcgt.u8 q0, q0, q4 // a > c -> -1 , otherwise 0 -+- vcgt.u8 q13, q5, q1 -+- vcgt.u8 q1, q1, q5 -++ vcgt.u8 q14, q6, q2 -++ vcgt.u8 q2, q2, q6 -++ vcgt.u8 q15, q7, q3 -++ vcgt.u8 q3, q3, q7 -+ -+- vsub.s8 q12, q0, q12 // diff0 -+- vcgt.u8 q0, q4, q8 // c > b -+- vsub.s8 q13, q1, q13 // diff0 part 2 -++ vsub.s8 q14, q2, q14 -++ vcgt.u8 q2, q6, q10 -++ vsub.s8 q15, q3, q15 -+ -+- vcgt.u8 q6, q8, q4 // b > c -+- vcgt.u8 q1, q5, q9 -+- vcgt.u8 q7, q9, q5 -++ vcgt.u8 q12, q10, q6 -++ vcgt.u8 q3, q7, q11 -++ vcgt.u8 q13, q11, q7 -++ vsub.s8 q2, q12, q2 -++ vsub.s8 q3, q13, q3 -+ -+- vsub.s8 q0, q6, q0 // diff1 -+- vsub.s8 q1, q7, q1 // diff1 part 2 -+- vadd.s8 q0, q12 //diff0 + diff1 -++ vmov.s8 q13, #2 // 2 to all elements -+ -+- vdup.s8 q7, r6 // 3 to all elements -+- sub r6, #1 -+- vadd.s8 q1, q13 -++ vadd.s8 q2, q14 -++ vadd.s8 q3, q15 -++ -++ vmov.32 d24[0], r4 // load offset table from general registers -++ vmov.32 d24[1], r5 // load rest of offset table -+ -+- vclt.s8 q12, q0, #0 // diff0 + diff1 < 0 -+- vclt.s8 q13, q1, #0 -+- -+- vadd.s8 q6, q0, q7 // diff0 + diff1 + 3 -+- vadd.s8 q10, q1, q7 -+- vdup.s8 q7, r6 // 2 to all elements -+- add r6, #1 -+- vand.8 q12, q6, q12 // if (diff0 + diff1 < 0) then (diff0 + diff1 + 3) else 0 -+- vand.8 q13, q10, q13 -+- -+- -+- vcgt.s8 q10, q0, #0 // diff0 + diff1 > 0 -+- vadd.s8 q6, q0, q7 // diff0 + diff1 + 2 -+- vand.8 q11, q6, q10 // if (diff0 + diff1 > 0) then (diff0 + diff1 + 2) else 0 -+- vcgt.s8 q10, q1, #0 -+- vadd.s8 q0, q11, q12 // offset_idx -+- -+- vadd.s8 q6, q1, q7 // diff0 + diff1 + 2 -+- vmov.32 d14[0], r7 // load offset table from general registers -+- vand.8 q11, q6, q10 // if (diff0 + diff1 > 0) then (diff0 + diff1 + 2) else 0 -+- vmov.32 d14[1], r5 // load rest of offset table -+- vadd.s8 q1, q11, q13 -+- -+- vtbl.8 d0, {d14}, d0 -+- vtbl.8 d1, {d14}, d1 -+- vtbl.8 d2, {d14}, d2 -+- vtbl.8 d3, {d14}, d3 -+- -+- vmovl.u8 q6, d8 -+- vmovl.u8 q7, d9 -+- vmovl.u8 q10, d10 -+- vmovl.u8 q11, d11 -+- -+- vaddw.s8 q6, d0 -+- vaddw.s8 q7, d1 -+- vaddw.s8 q10, d2 -+- vaddw.s8 q11, d3 -+- -+- vqmovun.s16 d0, q6 -+- vqmovun.s16 d1, q7 -+- vqmovun.s16 d2, q10 -+- vqmovun.s16 d3, q11 -+- -+- vstm r0, {q0-q1} -+- add r0, r2 -++ vadd.s8 q0, q13 -++ vadd.s8 q1, q13 -++ vadd.s8 q2, q13 -++ vadd.s8 q3, q13 -++ -++ vmov.u8 q15, #128 // s8 #-128 -++ vtbl.8 d0, {d24}, d0 -++ vtbl.8 d1, {d24}, d1 -++ vtbl.8 d2, {d24}, d2 -++ vtbl.8 d3, {d24}, d3 -++ vtbl.8 d4, {d24}, d4 -++ vtbl.8 d5, {d24}, d5 -++ vtbl.8 d6, {d24}, d6 -++ vtbl.8 d7, {d24}, d7 -++ -++ vadd.s8 q12, q4, q15 -++ vadd.s8 q13, q5, q15 -++ vadd.s8 q14, q6, q15 -++ vadd.s8 q15, q7, q15 -++ vqadd.s8 q12, q0 -++ vqadd.s8 q15, q3 -++ vmov.u8 q3, #128 // s8 #-128 -++ vqadd.s8 q13, q1 -++ vqadd.s8 q14, q2 -++ vsub.s8 q0, q12, q3 -++ vsub.s8 q1, q13, q3 -++ vsub.s8 q2, q14, q3 -++ vsub.s8 q3, q15, q3 -++ vst1.8 {q0-q1}, [r0, :128]! -++ vst1.8 {q2-q3}, [r0, :128], r2 -++ sub r0, #32 -+ .endm -+ -+-function ff_hevc_sao_edge_eo0_w64_neon_8, export=1 -+- push {r4-r8} -+- ldr r4, [sp, #20] // height -+- ldr r5, [sp, #24] // sao_offset_val_table -+- ldr r6, =0x03 -+- ldr r7, [r5] -++.macro init_edge_64 -++ push {r4-r5} -++ ldr r12, [sp, #8] // height -++ ldr r5, [sp, #12] // sao_offset_val_table -++ ldr r4, [r5] -+ add r5, #4 -+ ldr r5, [r5] -++.endm -++ -++function ff_hevc_sao_edge_eo0_w64_neon_8, export=1 -++ init_edge_64 -+ vpush {d8-d15} -+ sub r1, #8 -+-1: subs r4, #1 -+- vld1.64 {q10-q11}, [r1]! -+- vld1.64 {q12-q13}, [r1]! -+- vld1.64 {q14}, [r1], r3 -+- sub r1, #64 -++1: subs r12, #1 -++ vld1.64 {d7}, [r1, :64]! -++ vld1.64 {q4-q5}, [r1, :128]! // load c -++ vld1.64 {q6-q7}, [r1, :128]! -++ vld1.64 {d24}, [r1, :64], r3 -++ sub r1, #72 -+ // load a -+- vext.8 q0, q10, q11, #7 -+- vext.8 q1, q11, q12, #7 -+- vext.8 q2, q12, q13, #7 -+- vext.8 q3, q13, q14, #7 -+- // load c -+- vext.8 q4, q10, q11, #8 -+- vext.8 q5, q11, q12, #8 -+- vext.8 q6, q12, q13, #8 -+- vext.8 q7, q13, q14, #8 -++ vext.8 q0, q3, q4, #15 -++ vext.8 q1, q4, q5, #15 -++ vext.8 q2, q5, q6, #15 -++ vext.8 q3, q6, q7, #15 -+ // load b -+- vext.8 q8, q10, q11, #9 -+- vext.8 q9, q11, q12, #9 -+- vext.8 q10, q12, q13, #9 -+- vext.8 q11, q13, q14, #9 -++ vext.8 q8, q4, q5, #1 -++ vext.8 q9, q5, q6, #1 -++ vext.8 q10, q6, q7, #1 -++ vext.8 q11, q7, q12, #1 -+ edge_w64_body -+ bne 1b -+ vpop {d8-d15} -+- pop {r4-r8} -++ pop {r4-r5} -+ bx lr -+ endfunc -+ -+ function ff_hevc_sao_edge_eo1_w64_neon_8, export=1 -+- push {r4-r8} -+- ldr r4, [sp, #20] // height -+- ldr r5, [sp, #24] // sao_offset_val_table -+- ldr r6, =0x03 -+- ldr r7, [r5] -+- add r5, #4 -+- ldr r5, [r5] -++ init_edge_64 -+ vpush {d8-d15} -+ sub r1, r3 -+ // load a -+- vld1.8 {q0-q1}, [r1]! -+- vld1.8 {q2-q3}, [r1], r3 -++ vld1.8 {q0-q1}, [r1, :128]! -++ vld1.8 {q2-q3}, [r1, :128], r3 -+ sub r1, #32 -+-1: subs r4, #1 -+ // load c -+- vld1.8 {q4-q5}, [r1]! -+- vld1.8 {q6-q7}, [r1], r3 -++ vld1.8 {q4-q5}, [r1, :128]! -++ vld1.8 {q6-q7}, [r1, :128], r3 -+ sub r1, #32 -++1: subs r12, #1 -+ // load b -+- vld1.8 {q8-q9}, [r1]! -+- vld1.8 {q10-q11}, [r1] -++ vld1.8 {q8-q9}, [r1, :128]! -++ vld1.8 {q10-q11}, [r1, :128], r3 -+ sub r1, #32 -+ edge_w64_body -+ // copy c to a -+@@ -356,20 +242,19 @@ function ff_hevc_sao_edge_eo1_w64_neon_8, export=1 -+ vmov.64 q1, q5 -+ vmov.64 q2, q6 -+ vmov.64 q3, q7 -++ // copy b to c -++ vmov.64 q4, q8 -++ vmov.64 q5, q9 -++ vmov.64 q6, q10 -++ vmov.64 q7, q11 -+ bne 1b -+ vpop {d8-d15} -+- pop {r4-r8} -++ pop {r4-r5} -+ bx lr -+ endfunc -+ -+ function ff_hevc_sao_edge_eo2_w64_neon_8, export=1 -+- push {r4-r8} -+- ldr r4, [sp, #20] // height -+- ldr r5, [sp, #24] // sao_offset_val_table -+- ldr r6, =0x03 -+- ldr r7, [r5] -+- add r5, #4 -+- ldr r5, [r5] -++ init_edge_64 -+ vpush {d8-d15} -+ 1: sub r1, r3 -+ // load a -+@@ -379,10 +264,10 @@ function ff_hevc_sao_edge_eo2_w64_neon_8, export=1 -+ vld1.8 {q0-q1}, [r1]! -+ vld1.8 {q2-q3}, [r1], r3 -+ sub r1, #31 -+- subs r4, #1 -++ subs r12, #1 -+ // load c -+- vld1.8 {q4-q5}, [r1]! -+- vld1.8 {q6-q7}, [r1], r3 -++ vld1.8 {q4-q5}, [r1, :128]! -++ vld1.8 {q6-q7}, [r1, :128], r3 -+ sub r1, #32 -+ // load b -+ add r1, #1 -+@@ -390,25 +275,14 @@ function ff_hevc_sao_edge_eo2_w64_neon_8, export=1 -+ vld1.8 {q10-q11}, [r1] -+ sub r1, #33 -+ edge_w64_body -+- // copy c to a -+- vmov.64 q0, q4 -+- vmov.64 q1, q5 -+- vmov.64 q2, q6 -+- vmov.64 q3, q7 -+ bne 1b -+ vpop {d8-d15} -+- pop {r4-r8} -++ pop {r4-r5} -+ bx lr -+ endfunc -+ -+ function ff_hevc_sao_edge_eo3_w64_neon_8, export=1 -+- push {r4-r8} -+- ldr r4, [sp, #20] // height -+- ldr r5, [sp, #24] // sao_offset_val_table -+- ldr r6, =0x03 -+- ldr r7, [r5] -+- add r5, #4 -+- ldr r5, [r5] -++ init_edge_64 -+ vpush {d8-d15} -+ 1: sub r1, r3 -+ // load a -+@@ -418,10 +292,10 @@ function ff_hevc_sao_edge_eo3_w64_neon_8, export=1 -+ vld1.8 {q0-q1}, [r1]! -+ vld1.8 {q2-q3}, [r1], r3 -+ sub r1, #33 -+- subs r4, #1 -++ subs r12, #1 -+ // load c -+- vld1.8 {q4-q5}, [r1]! -+- vld1.8 {q6-q7}, [r1], r3 -++ vld1.8 {q4-q5}, [r1, :128]! -++ vld1.8 {q6-q7}, [r1, :128], r3 -+ sub r1, #32 -+ // load b -+ sub r1, #1 -+@@ -429,178 +303,176 @@ function ff_hevc_sao_edge_eo3_w64_neon_8, export=1 -+ vld1.8 {q10-q11}, [r1] -+ sub r1, #31 -+ edge_w64_body -+- // copy c to a -+- vmov.64 q0, q4 -+- vmov.64 q1, q5 -+- vmov.64 q2, q6 -+- vmov.64 q3, q7 -+ bne 1b -+ vpop {d8-d15} -+- pop {r4-r8} -++ pop {r4-r5} -+ bx lr -+ endfunc -+ -++// inputs: -++// a in q0, q1 -++// c in q2, q3 -++// b in q8, q9 -++// offset table in d31 -++// clobbered registers q0, q1, q10, q11, q12, q13 -++// output q0, q1 -++.macro edge_w32_body -++ vcgt.u8 q12, q2, q0 // c > a -> -1 , otherwise 0 -++ vcgt.u8 q0, q0, q2 // a > c -> -1 , otherwise 0 -++ vcgt.u8 q13, q3, q1 -++ vcgt.u8 q1, q1, q3 -++ -++ vsub.s8 q12, q0, q12 // diff0 -++ vcgt.u8 q0, q2, q8 // c > b -++ vsub.s8 q13, q1, q13 // diff0 part 2 -++ -++ vcgt.u8 q10, q8, q2 // b > c -++ vcgt.u8 q1, q3, q9 -++ vcgt.u8 q11, q9, q3 -++ -++ vsub.s8 q0, q10, q0 // diff1 -++ -++ vmov.s8 q10, #2 // 2 to all elements -++ vsub.s8 q1, q11, q1 // diff1 part 2 -++ vadd.s8 q0, q12 //diff0 + diff1 -++ vadd.s8 q1, q13 -++ -++ vadd.s8 q0, q10 -++ vadd.s8 q1, q10 -++ -++ vmov.u8 q10, #128 -++ vtbl.8 d0, {d31}, d0 -++ vtbl.8 d1, {d31}, d1 -++ vtbl.8 d2, {d31}, d2 -++ vtbl.8 d3, {d31}, d3 -++ -++ vadd.s8 q11, q2, q10 -++ vadd.s8 q12, q3, q10 -++ vqadd.s8 q11, q0 -++ vqadd.s8 q12, q1 -++ vsub.s8 q0, q11, q10 -++ vsub.s8 q1, q12, q10 -++ vst1.8 {q0-q1}, [r0, :128], r2 -++.endm -++ -++.macro init_edge_32 -++ ldr r12, [sp, #4] // sao_offset_val_table -++ vld1.32 {d31}, [r12] -++ ldr r12, [sp] // height -++.endm -++ -+ function ff_hevc_sao_edge_eo0_w32_neon_8, export=1 -+- push {r4-r8} -+- ldr r4, [sp, #20] // height -+- ldr r5, [sp, #24] // sao_offset_val_table -+- ldr r6, =0x03 -+- ldr r7, [r5] -+- add r5, #4 -+- ldr r5, [r5] -+- vpush {d8-d15} -+- sub r1, #8 // load 8 extra bytes -+-1: subs r4, #1 -+- vld1.8 {q10-q11}, [r1] -+- add r1, #32 -+- vld1.8 {q12}, [r1], r3 // only first 9 bytes are used -+- sub r1, #32 -++ init_edge_32 -++ sub r1, #4 // load 4 extra bytes -++1: subs r12, #1 -++ vld1.32 d3[1], [r1]! -++ vld1.8 {q2-q3}, [r1, :128]! // c -++ vld1.32 d20[0], [r1], r3 -++ sub r1, #36 -+ // a -+- vext.8 q0, q10, q11, #7 -+- vext.8 q1, q11, q12, #7 -+- // c -+- vext.8 q4, q10, q11, #8 -+- vext.8 q5, q11, q12, #8 -++ vext.8 q0, q1, q2, #15 -++ vext.8 q1, q2, q3, #15 -+ // b -+- vext.8 q8, q10, q11, #9 -+- vext.8 q9, q11, q12, #9 -++ vext.8 q8, q2, q3, #1 -++ vext.8 q9, q3, q10, #1 -+ edge_w32_body -+- bne 1b -+- vpop {d8-d15} -+- pop {r4-r8} -+- bx lr -++ bne 1b -++ bx lr -+ endfunc -+ -+ function ff_hevc_sao_edge_eo1_w32_neon_8, export=1 -+- push {r4-r8} -+- ldr r4, [sp, #20] // height -+- ldr r5, [sp, #24] // sao_offset_val_table -+- ldr r6, =0x03 -+- ldr r7, [r5] -+- add r5, #4 -+- ldr r5, [r5] -+- vpush {d8-d15} -++ init_edge_32 -+ // load a -+ sub r1, r3 -+- vld1.8 {q0-q1}, [r1], r3 -++ vld1.8 {q0-q1}, [r1, :128], r3 -+ // load c -+- vld1.8 {q4-q5}, [r1], r3 -+-1: subs r4, #1 -++ vld1.8 {q2-q3}, [r1, :128], r3 -++1: subs r12, #1 -+ // load b -+- vld1.8 {q8-q9}, [r1], r3 -++ vld1.8 {q8-q9}, [r1, :128], r3 -+ edge_w32_body -+ // inputs for next loop iteration -+ // a -+- vmov.64 q0, q4 -+- vmov.64 q1, q5 -++ vmov.64 q0, q2 -++ vmov.64 q1, q3 -+ // c -+- vmov.64 q4, q8 -+- vmov.64 q5, q9 -+- bne 1b -+- vpop {d8-d15} -+- pop {r4-r8} -+- bx lr -++ vmov.64 q2, q8 -++ vmov.64 q3, q9 -++ bne 1b -++ bx lr -+ endfunc -+ -+ function ff_hevc_sao_edge_eo2_w32_neon_8, export=1 -+- push {r4-r8} -+- ldr r4, [sp, #20] // height -+- ldr r5, [sp, #24] // sao_offset_val_table -+- ldr r6, =0x03 -+- ldr r7, [r5] -+- add r5, #4 -+- ldr r5, [r5] -+- vpush {d8-d15} -++ init_edge_32 -++ vpush {d8-d15} -+ // load a -+ sub r1, r3 -+- sub r1, #8 -+- vld1.8 {q10-q11}, [r1] -+- add r1, #32 -+- vld1.8 {q12}, [r1], r3 -+- sub r1, #32 -++ sub r1, #8 -++ vld1.8 {q10-q11}, [r1, :64]! -++ vld1.8 {d24}, [r1, :64], r3 -++ sub r1, #32 -+ vext.8 q0, q10, q11, #7 -+ vext.8 q1, q11, q12, #7 -+ // load c -+- vld1.8 {q10-q11}, [r1] -+- add r1, #32 -+- vld1.8 {q12}, [r1], r3 -+- sub r1, #32 -+- vext.8 q4, q10, q11, #8 -+- vext.8 q5, q11, q12, #8 -+- vext.8 q2, q10, q11, #7 -+-1: subs r4, #1 -++ vld1.8 {d9}, [r1, :64]! -++ vld1.8 {q2-q3}, [r1, :64], r3 -++ sub r1, #8 -++ vext.8 q4, q4, q2, #15 -++1: subs r12, #1 -+ // load b -+- vld1.8 {q10-q11}, [r1] -+- add r1, #32 -+- vld1.8 {q12}, [r1], r3 -+- sub r1, #32 -++ vld1.8 {q10-q11}, [r1, :64]! -++ vld1.8 {q12}, [r1, :64], r3 -++ sub r1, #32 -+ vext.8 q8, q10, q11, #9 -+ vext.8 q9, q11, q12, #9 -+- vext.8 q14, q10, q11, #8 -+- vext.8 q15, q11, q12, #8 -+- vext.8 q3, q10, q11, #7 -++ vext.8 q6, q10, q11, #8 -++ vext.8 q7, q11, q12, #8 -++ vext.8 q5, q10, q11, #7 -+ edge_w32_body -+ // inputs for next loop iteration -+ // a -+- vmov.8 q0, q2 -+- vext.8 q1, q4, q5, #15 -++ vmov.8 q0, q4 -++ vext.8 q1, q2, q3, #15 -+ // c -+- vmov.8 q4, q14 -+- vmov.8 q5, q15 -+- vmov.8 q2, q3 -+- bne 1b -+- vpop {d8-d15} -+- pop {r4-r8} -+- bx lr -++ vmov.8 q2, q6 -++ vmov.8 q3, q7 -++ vmov.8 q4, q5 -++ bne 1b -++ vpop {d8-d15} -++ bx lr -+ endfunc -+ -+ function ff_hevc_sao_edge_eo3_w32_neon_8, export=1 -+- push {r4-r8} -+- ldr r4, [sp, #20] // height -+- ldr r5, [sp, #24] // sao_offset_val_table -+- ldr r6, =0x03 -+- ldr r7, [r5] -+- add r5, #4 -+- sub r1, r3 -+- ldr r5, [r5] -+- sub r1, #8 -+- vpush {d8-d15} -++ init_edge_32 -++ sub r1, r3 -+ // load a -+- vld1.8 {q10-q11}, [r1] -+- add r1, #32 -+- vld1.8 {q12}, [r1], r3 -+- sub r1, #32 -+- vext.8 q0, q10, q11, #9 -+- vext.8 q1, q11, q12, #9 -++ vld1.8 {q10-q11}, [r1, :64]! -++ vld1.8 {d24}, [r1, :64], r3 -++ sub r1, #32 -++ vext.8 q0, q10, q11, #1 -++ vext.8 q1, q11, q12, #1 -+ // load c -+- vld1.8 {q10-q11}, [r1] -+- add r1, #32 -+- vld1.8 {q12}, [r1], r3 -+- sub r1, #32 -+- vext.8 q4, q10, q11, #8 -+- vext.8 q5, q11, q12, #8 -+- vext.8 q2, q12, q11, #8 -+-1: subs r4, #1 -++ vld1.8 {q2-q3}, [r1, :64]! -++ vld1.8 {d30}, [r1, :64], r3 -++ sub r1, #40 -++1: subs r12, #1 -+ // load b -+- vld1.8 {q10-q11}, [r1] -+- add r1, #32 -+- vld1.8 {q12}, [r1], r3 -+- sub r1, #32 -++ vld1.8 {q10-q11}, [r1, :64]! -++ vld1.8 {q12}, [r1, :64], r3 -++ sub r1, #32 -+ vext.8 q8, q10, q11, #7 -+ vext.8 q9, q11, q12, #7 -+- vext.8 q3, q12, q10, #7 -++ vext.8 q14, q12, q10, #7 -+ edge_w32_body -+ // inputs for next loop iteration -+ // a -+- vext.8 q0, q4, q5, #1 -+- vext.8 q1, q5, q2, #1 -++ vext.8 q0, q2, q3, #1 -++ vext.8 q1, q3, q15, #1 -+ // c -+- vext.8 q4, q8, q9, #1 -+- vext.8 q5, q9, q3, #1 -+- vext.8 q2, q3, q1, #1 -+- bne 1b -+- vpop {d8-d15} -+- pop {r4-r8} -+- bx lr -++ vext.8 q2, q8, q9, #1 -++ vext.8 q3, q9, q14, #1 -++ vext.8 d30, d28, d2, #1 -++ bne 1b -++ bx lr -+ endfunc -+ -+-- -+2.5.0 -+ -+ -+From 016c39d46b86830204a4519590332d2a38f7ee51 Mon Sep 17 00:00:00 2001 -+From: Seppo Tomperi -+Date: Thu, 8 Jan 2015 09:58:55 +0200 -+Subject: [PATCH 7/9] small optimization to SAO BAND. correct path for -+ bit_depth_template.c -+ -+--- -+ libavcodec/arm/hevcdsp_init_neon.c | 2 +- -+ libavcodec/arm/hevcdsp_sao_neon.S | 2 +- -+ 2 files changed, 2 insertions(+), 2 deletions(-) -+ -+diff --git a/libavcodec/arm/hevcdsp_init_neon.c b/libavcodec/arm/hevcdsp_init_neon.c -+index 8d6e863..385c35d 100644 -+--- a/libavcodec/arm/hevcdsp_init_neon.c -++++ b/libavcodec/arm/hevcdsp_init_neon.c -+@@ -23,7 +23,7 @@ -+ #include "libavcodec/hevcdsp.h" -+ #include "hevcdsp_arm.h" -+ #include "libavcodec/avcodec.h" -+-#include "../bit_depth_template.c" -++#include "libavcodec/bit_depth_template.c" -+ -+ void ff_hevc_v_loop_filter_luma_neon(uint8_t *_pix, ptrdiff_t _stride, int _beta, int *_tc, uint8_t *_no_p, uint8_t *_no_q); -+ void ff_hevc_h_loop_filter_luma_neon(uint8_t *_pix, ptrdiff_t _stride, int _beta, int *_tc, uint8_t *_no_p, uint8_t *_no_q); -+diff --git a/libavcodec/arm/hevcdsp_sao_neon.S b/libavcodec/arm/hevcdsp_sao_neon.S -+index 5fc482b..710b32b 100644 -+--- a/libavcodec/arm/hevcdsp_sao_neon.S -++++ b/libavcodec/arm/hevcdsp_sao_neon.S -+@@ -26,12 +26,12 @@ -+ pld [r1] -+ vld1.8 {q0, q1}, [r12] // offset table -+ ldr r12, [sp, #4] // height -++ vmov.u8 q14, #128 -+ .endm -+ -+ .macro sao_band_32 -+ vshr.u8 q8, q2, #3 -+ vshr.u8 q9, q3, #3 -+- vmov.u8 q14, #128 -+ vtbl.8 d16, {q0, q1}, d16 -+ vtbl.8 d17, {q0, q1}, d17 -+ vtbl.8 d18, {q0, q1}, d18 -+-- -+2.5.0 -+ -+ -+From 579f1584d688e1ac24fb7d22697e2a7b64f62e8e Mon Sep 17 00:00:00 2001 -+From: Seppo Tomperi -+Date: Fri, 9 Jan 2015 10:28:52 +0200 -+Subject: [PATCH 8/9] Added height check for SAO NEON optimizations. Faster SAO -+ band NEON Some reordering to use NEON pipelines more efficiently -+ -+--- -+ libavcodec/arm/hevcdsp_init_neon.c | 12 +++- -+ libavcodec/arm/hevcdsp_sao_neon.S | 142 ++++++++++++++++++++++--------------- -+ 2 files changed, 93 insertions(+), 61 deletions(-) -+ -+diff --git a/libavcodec/arm/hevcdsp_init_neon.c b/libavcodec/arm/hevcdsp_init_neon.c -+index 385c35d..6d0689c 100644 -+--- a/libavcodec/arm/hevcdsp_init_neon.c -++++ b/libavcodec/arm/hevcdsp_init_neon.c -+@@ -176,6 +176,7 @@ static void ff_hevc_sao_band_neon_wrapper(uint8_t *_dst, uint8_t *_src, ptrdiff_ -+ int8_t offset_table[32] = { 0 }; -+ int k, y, x; -+ int shift = 3; // BIT_DEPTH - 5 -++ int cwidth = 0; -+ -+ stride_src /= sizeof(pixel); -+ stride_dst /= sizeof(pixel); -+@@ -183,7 +184,10 @@ static void ff_hevc_sao_band_neon_wrapper(uint8_t *_dst, uint8_t *_src, ptrdiff_ -+ for (k = 0; k < 4; k++) -+ offset_table[(k + sao_left_class) & 31] = sao_offset_val[k + 1]; -+ -+- switch(width){ -++ if (height % 8 == 0) -++ cwidth = width; -++ -++ switch(cwidth){ -+ case 8: -+ ff_hevc_sao_band_w8_neon_8(_dst, _src, stride_dst, stride_src, offset_table, height); -+ break; -+@@ -223,15 +227,19 @@ static void ff_hevc_sao_edge_neon_wrapper(uint8_t *_dst /* align 16 */, uint8_t -+ pixel *src = (pixel *)_src; -+ int a_stride, b_stride; -+ int x, y; -++ int cwidth = 0; -+ -+ for (x = 0; x < 5; x++) { -+ sao_offset_val[x] = _sao_offset_val[edge_idx[x]]; -+ } -+ -++ if (height % 8 == 0) -++ cwidth = width; -++ -+ stride_src /= sizeof(pixel); -+ stride_dst /= sizeof(pixel); -+ -+- switch (width) { -++ switch (cwidth) { -+ case 32: -+ switch(eo) { -+ case 0: -+diff --git a/libavcodec/arm/hevcdsp_sao_neon.S b/libavcodec/arm/hevcdsp_sao_neon.S -+index 710b32b..08f50b8 100644 -+--- a/libavcodec/arm/hevcdsp_sao_neon.S -++++ b/libavcodec/arm/hevcdsp_sao_neon.S -+@@ -26,36 +26,59 @@ -+ pld [r1] -+ vld1.8 {q0, q1}, [r12] // offset table -+ ldr r12, [sp, #4] // height -+- vmov.u8 q14, #128 -++ vmov.u8 q3, #128 -+ .endm -+ -+-.macro sao_band_32 -+- vshr.u8 q8, q2, #3 -+- vshr.u8 q9, q3, #3 -+- vtbl.8 d16, {q0, q1}, d16 -+- vtbl.8 d17, {q0, q1}, d17 -+- vtbl.8 d18, {q0, q1}, d18 -+- vtbl.8 d19, {q0, q1}, d19 -+- vadd.s8 q2, q14 -+- vadd.s8 q3, q14 -+- vqadd.s8 q2, q8 -+- vqadd.s8 q3, q9 -+- vsub.s8 q2, q14 -+- vsub.s8 q3, q14 -++// 128 in q3 -++// input q8 - q11 -++// 32 cycles -++.macro sao_band_64 -++ vshr.u8 q12, q8, #3 -++ vshr.u8 q13, q9, #3 -++ vshr.u8 q14, q10, #3 -++ vshr.u8 q15, q11, #3 -++ vtbl.8 d24, {d0, d1, d2, d3}, d24 -++ vadd.s8 q8, q3 -++ vtbl.8 d25, {d0, d1, d2, d3}, d25 -++ vadd.s8 q9, q3 -++ vtbl.8 d26, {d0, d1, d2, d3}, d26 -++ vadd.s8 q10, q3 -++ vtbl.8 d27, {d0, d1, d2, d3}, d27 -++ vadd.s8 q11, q3 -++ vtbl.8 d28, {d0, d1, d2, d3}, d28 -++ vqadd.s8 q8, q12 -++ vtbl.8 d29, {d0, d1, d2, d3}, d29 -++ vqadd.s8 q9, q13 -++ vtbl.8 d30, {d0, d1, d2, d3}, d30 -++ vqadd.s8 q10, q14 -++ vtbl.8 d31, {d0, d1, d2, d3}, d31 -++ vqadd.s8 q11, q15 -++ vsub.s8 q8, q3 -++ vsub.s8 q9, q3 -++ vsub.s8 q10, q3 -++ vsub.s8 q11, q3 -+ .endm -+ -+ function ff_hevc_sao_band_w8_neon_8, export=1 -+ init_sao_band -+-1: subs r12, #4 -+- vld1.8 {d4}, [r1, :64], r3 -+- vld1.8 {d5}, [r1, :64], r3 -+- vld1.8 {d6}, [r1, :64], r3 -+- vld1.8 {d7}, [r1, :64], r3 -+- sao_band_32 -+- vst1.8 {d4}, [r0, :64], r2 -+- vst1.8 {d5}, [r0, :64], r2 -+- vst1.8 {d6}, [r0, :64], r2 -+- vst1.8 {d7}, [r0, :64], r2 -++1: subs r12, #8 -++ vld1.8 {d16}, [r1, :64], r3 -++ vld1.8 {d17}, [r1, :64], r3 -++ vld1.8 {d18}, [r1, :64], r3 -++ vld1.8 {d19}, [r1, :64], r3 -++ vld1.8 {d20}, [r1, :64], r3 -++ vld1.8 {d21}, [r1, :64], r3 -++ vld1.8 {d22}, [r1, :64], r3 -++ vld1.8 {d23}, [r1, :64], r3 -++ sao_band_64 -++ vst1.8 {d16}, [r0, :64], r2 -++ vst1.8 {d17}, [r0, :64], r2 -++ vst1.8 {d18}, [r0, :64], r2 -++ vst1.8 {d19}, [r0, :64], r2 -++ vst1.8 {d20}, [r0, :64], r2 -++ vst1.8 {d21}, [r0, :64], r2 -++ vst1.8 {d22}, [r0, :64], r2 -++ vst1.8 {d23}, [r0, :64], r2 -+ bne 1b -+ -+ bx lr -+@@ -63,12 +86,16 @@ endfunc -+ -+ function ff_hevc_sao_band_w16_neon_8, export=1 -+ init_sao_band -+-1: subs r12, #2 -+- vld1.8 {q2}, [r1, :128], r3 -+- vld1.8 {q3}, [r1, :128], r3 -+- sao_band_32 -+- vst1.8 {q2}, [r0, :128], r2 -+- vst1.8 {q3}, [r0, :128], r2 -++1: subs r12, #4 -++ vld1.8 {q8}, [r1, :128], r3 -++ vld1.8 {q9}, [r1, :128], r3 -++ vld1.8 {q10}, [r1, :128], r3 -++ vld1.8 {q11}, [r1, :128], r3 -++ sao_band_64 -++ vst1.8 {q8}, [r0, :128], r2 -++ vst1.8 {q9}, [r0, :128], r2 -++ vst1.8 {q10}, [r0, :128], r2 -++ vst1.8 {q11}, [r0, :128], r2 -+ bne 1b -+ -+ bx lr -+@@ -76,10 +103,12 @@ endfunc -+ -+ function ff_hevc_sao_band_w32_neon_8, export=1 -+ init_sao_band -+-1: subs r12, #1 -+- vld1.8 {q2-q3}, [r1, :128], r3 -+- sao_band_32 -+- vst1.8 {q2-q3}, [r0, :128], r2 -++1: subs r12, #2 -++ vld1.8 {q8-q9}, [r1, :128], r3 -++ vld1.8 {q10-q11}, [r1, :128], r3 -++ sao_band_64 -++ vst1.8 {q8-q9}, [r0, :128], r2 -++ vst1.8 {q10-q11}, [r0, :128], r2 -+ bne 1b -+ -+ bx lr -+@@ -89,13 +118,12 @@ function ff_hevc_sao_band_w64_neon_8, export=1 -+ init_sao_band -+ 1: subs r12, #1 -+ pld [r1, r3] -+- vld1.8 {q2-q3}, [r1, :128]! -+- sao_band_32 -+- vst1.8 {q2-q3}, [r0, :128]! -+- vld1.8 {q2-q3}, [r1, :128], r3 -++ vld1.8 {q8-q9}, [r1, :128]! -++ vld1.8 {q10-q11}, [r1, :128], r3 -+ sub r1, #32 -+- sao_band_32 -+- vst1.8 {q2-q3}, [r0, :128], r2 -++ sao_band_64 -++ vst1.8 {q8-q9}, [r0, :128]! -++ vst1.8 {q10-q11}, [r0, :128], r2 -+ sub r0, #32 -+ bne 1b -+ -+@@ -121,7 +149,6 @@ endfunc -+ vcgt.u8 q1, q5, q9 -+ vcgt.u8 q15, q9, q5 -+ vsub.s8 q0, q14, q0 // diff1 -+- -+ vsub.s8 q1, q15, q1 -+ -+ vadd.s8 q0, q12 //diff0 + diff1 -+@@ -157,27 +184,25 @@ endfunc -+ -+ vmov.u8 q15, #128 // s8 #-128 -+ vtbl.8 d0, {d24}, d0 -++ vadd.s8 q13, q4, q15 -+ vtbl.8 d1, {d24}, d1 -++ vadd.s8 q14, q5, q15 -+ vtbl.8 d2, {d24}, d2 -++ vqadd.s8 q0, q13 -+ vtbl.8 d3, {d24}, d3 -++ vqadd.s8 q1, q14 -+ vtbl.8 d4, {d24}, d4 -++ vadd.s8 q13, q6, q15 -+ vtbl.8 d5, {d24}, d5 -++ vadd.s8 q14, q7, q15 -+ vtbl.8 d6, {d24}, d6 -++ vqadd.s8 q2, q13 -+ vtbl.8 d7, {d24}, d7 -+- -+- vadd.s8 q12, q4, q15 -+- vadd.s8 q13, q5, q15 -+- vadd.s8 q14, q6, q15 -+- vadd.s8 q15, q7, q15 -+- vqadd.s8 q12, q0 -+- vqadd.s8 q15, q3 -+- vmov.u8 q3, #128 // s8 #-128 -+- vqadd.s8 q13, q1 -+- vqadd.s8 q14, q2 -+- vsub.s8 q0, q12, q3 -+- vsub.s8 q1, q13, q3 -+- vsub.s8 q2, q14, q3 -+- vsub.s8 q3, q15, q3 -++ vqadd.s8 q3, q14 -++ vsub.s8 q0, q15 -++ vsub.s8 q1, q15 -++ vsub.s8 q2, q15 -++ vsub.s8 q3, q15 -+ vst1.8 {q0-q1}, [r0, :128]! -+ vst1.8 {q2-q3}, [r0, :128], r2 -+ sub r0, #32 -+@@ -342,13 +367,12 @@ endfunc -+ -+ vmov.u8 q10, #128 -+ vtbl.8 d0, {d31}, d0 -++ vadd.s8 q11, q2, q10 -+ vtbl.8 d1, {d31}, d1 -++ vadd.s8 q12, q3, q10 -+ vtbl.8 d2, {d31}, d2 -++ vqadd.s8 q11, q0 -+ vtbl.8 d3, {d31}, d3 -+- -+- vadd.s8 q11, q2, q10 -+- vadd.s8 q12, q3, q10 -+- vqadd.s8 q11, q0 -+ vqadd.s8 q12, q1 -+ vsub.s8 q0, q11, q10 -+ vsub.s8 q1, q12, q10 -+-- -+2.5.0 -+ -+ -+From 026bac1824e4936e948e6b1efec82868c520ea66 Mon Sep 17 00:00:00 2001 -+From: Seppo Tomperi -+Date: Mon, 2 Feb 2015 16:08:27 +0200 -+Subject: [PATCH 9/9] Further SAO NEON optimisations -+ -+--- -+ libavcodec/arm/hevcdsp_init_neon.c | 16 +-- -+ libavcodec/arm/hevcdsp_sao_neon.S | 224 +++++++++++++++++++------------------ -+ 2 files changed, 124 insertions(+), 116 deletions(-) -+ -+diff --git a/libavcodec/arm/hevcdsp_init_neon.c b/libavcodec/arm/hevcdsp_init_neon.c -+index 6d0689c..e5da7e9 100644 -+--- a/libavcodec/arm/hevcdsp_init_neon.c -++++ b/libavcodec/arm/hevcdsp_init_neon.c -+@@ -45,10 +45,10 @@ void ff_hevc_transform_add_16x16_neon_8(uint8_t *_dst, int16_t *coeffs, -+ void ff_hevc_transform_add_32x32_neon_8(uint8_t *_dst, int16_t *coeffs, -+ ptrdiff_t stride); -+ -+-void ff_hevc_sao_band_w8_neon_8(uint8_t *_dst, uint8_t *_src, ptrdiff_t stride_dst, ptrdiff_t stride_src, int8_t * offset_table, int height); -+-void ff_hevc_sao_band_w16_neon_8(uint8_t *_dst, uint8_t *_src, ptrdiff_t stride_dst, ptrdiff_t stride_src, int8_t * offset_table, int height); -+-void ff_hevc_sao_band_w32_neon_8(uint8_t *_dst, uint8_t *_src, ptrdiff_t stride_dst, ptrdiff_t stride_src, int8_t * offset_table, int height); -+-void ff_hevc_sao_band_w64_neon_8(uint8_t *_dst, uint8_t *_src, ptrdiff_t stride_dst, ptrdiff_t stride_src, int8_t * offset_table, int height); -++void ff_hevc_sao_band_w8_neon_8(uint8_t *_dst, uint8_t *_src, int8_t * offset_table, ptrdiff_t stride_src, ptrdiff_t stride_dst, int height); -++void ff_hevc_sao_band_w16_neon_8(uint8_t *_dst, uint8_t *_src, int8_t * offset_table, ptrdiff_t stride_src, ptrdiff_t stride_dst, int height); -++void ff_hevc_sao_band_w32_neon_8(uint8_t *_dst, uint8_t *_src, int8_t * offset_table, ptrdiff_t stride_src, ptrdiff_t stride_dst, int height); -++void ff_hevc_sao_band_w64_neon_8(uint8_t *_dst, uint8_t *_src, int8_t * offset_table, ptrdiff_t stride_src, ptrdiff_t stride_dst, int height); -+ -+ void ff_hevc_sao_edge_eo0_w32_neon_8(uint8_t *_dst, uint8_t *_src, ptrdiff_t stride_dst, ptrdiff_t stride_src, int height, int8_t *sao_offset_table); -+ void ff_hevc_sao_edge_eo1_w32_neon_8(uint8_t *_dst, uint8_t *_src, ptrdiff_t stride_dst, ptrdiff_t stride_src, int height, int8_t *sao_offset_table); -+@@ -189,16 +189,16 @@ static void ff_hevc_sao_band_neon_wrapper(uint8_t *_dst, uint8_t *_src, ptrdiff_ -+ -+ switch(cwidth){ -+ case 8: -+- ff_hevc_sao_band_w8_neon_8(_dst, _src, stride_dst, stride_src, offset_table, height); -++ ff_hevc_sao_band_w8_neon_8(_dst, _src, offset_table, stride_src, stride_dst, height); -+ break; -+ case 16: -+- ff_hevc_sao_band_w16_neon_8(_dst, _src, stride_dst, stride_src, offset_table, height); -++ ff_hevc_sao_band_w16_neon_8(_dst, _src, offset_table, stride_src, stride_dst, height); -+ break; -+ case 32: -+- ff_hevc_sao_band_w32_neon_8(_dst, _src, stride_dst, stride_src, offset_table, height); -++ ff_hevc_sao_band_w32_neon_8(_dst, _src, offset_table, stride_src, stride_dst, height); -+ break; -+ case 64: -+- ff_hevc_sao_band_w64_neon_8(_dst, _src, stride_dst, stride_src, offset_table, height); -++ ff_hevc_sao_band_w64_neon_8(_dst, _src, offset_table, stride_src, stride_dst, height); -+ break; -+ default: -+ for (y = 0; y < height; y++) { -+diff --git a/libavcodec/arm/hevcdsp_sao_neon.S b/libavcodec/arm/hevcdsp_sao_neon.S -+index 08f50b8..9c7808d 100644 -+--- a/libavcodec/arm/hevcdsp_sao_neon.S -++++ b/libavcodec/arm/hevcdsp_sao_neon.S -+@@ -22,21 +22,16 @@ -+ #include "neon.S" -+ -+ .macro init_sao_band -+- ldr r12, [sp, #0] // offset_table address -+ pld [r1] -+- vld1.8 {q0, q1}, [r12] // offset table -+- ldr r12, [sp, #4] // height -++ vld1.8 {q0, q1}, [r2] // offset table -++ ldr r2, [sp, #0] // stride_dst -++ ldr r12, [sp, #4] // height -+ vmov.u8 q3, #128 -+ .endm -+ -+ // 128 in q3 -+ // input q8 - q11 -+-// 32 cycles -+ .macro sao_band_64 -+- vshr.u8 q12, q8, #3 -+- vshr.u8 q13, q9, #3 -+- vshr.u8 q14, q10, #3 -+- vshr.u8 q15, q11, #3 -+ vtbl.8 d24, {d0, d1, d2, d3}, d24 -+ vadd.s8 q8, q3 -+ vtbl.8 d25, {d0, d1, d2, d3}, d25 -+@@ -52,8 +47,8 @@ -+ vtbl.8 d30, {d0, d1, d2, d3}, d30 -+ vqadd.s8 q10, q14 -+ vtbl.8 d31, {d0, d1, d2, d3}, d31 -+- vqadd.s8 q11, q15 -+ vsub.s8 q8, q3 -++ vqadd.s8 q11, q15 -+ vsub.s8 q9, q3 -+ vsub.s8 q10, q3 -+ vsub.s8 q11, q3 -+@@ -64,12 +59,16 @@ function ff_hevc_sao_band_w8_neon_8, export=1 -+ 1: subs r12, #8 -+ vld1.8 {d16}, [r1, :64], r3 -+ vld1.8 {d17}, [r1, :64], r3 -++ vshr.u8 q12, q8, #3 -+ vld1.8 {d18}, [r1, :64], r3 -+ vld1.8 {d19}, [r1, :64], r3 -++ vshr.u8 q13, q9, #3 -+ vld1.8 {d20}, [r1, :64], r3 -+ vld1.8 {d21}, [r1, :64], r3 -++ vshr.u8 q14, q10, #3 -+ vld1.8 {d22}, [r1, :64], r3 -+ vld1.8 {d23}, [r1, :64], r3 -++ vshr.u8 q15, q11, #3 -+ sao_band_64 -+ vst1.8 {d16}, [r0, :64], r2 -+ vst1.8 {d17}, [r0, :64], r2 -+@@ -88,9 +87,13 @@ function ff_hevc_sao_band_w16_neon_8, export=1 -+ init_sao_band -+ 1: subs r12, #4 -+ vld1.8 {q8}, [r1, :128], r3 -++ vshr.u8 q12, q8, #3 -+ vld1.8 {q9}, [r1, :128], r3 -++ vshr.u8 q13, q9, #3 -+ vld1.8 {q10}, [r1, :128], r3 -++ vshr.u8 q14, q10, #3 -+ vld1.8 {q11}, [r1, :128], r3 -++ vshr.u8 q15, q11, #3 -+ sao_band_64 -+ vst1.8 {q8}, [r0, :128], r2 -+ vst1.8 {q9}, [r0, :128], r2 -+@@ -105,7 +108,11 @@ function ff_hevc_sao_band_w32_neon_8, export=1 -+ init_sao_band -+ 1: subs r12, #2 -+ vld1.8 {q8-q9}, [r1, :128], r3 -++ vshr.u8 q12, q8, #3 -++ vshr.u8 q13, q9, #3 -+ vld1.8 {q10-q11}, [r1, :128], r3 -++ vshr.u8 q14, q10, #3 -++ vshr.u8 q15, q11, #3 -+ sao_band_64 -+ vst1.8 {q8-q9}, [r0, :128], r2 -+ vst1.8 {q10-q11}, [r0, :128], r2 -+@@ -119,7 +126,11 @@ function ff_hevc_sao_band_w64_neon_8, export=1 -+ 1: subs r12, #1 -+ pld [r1, r3] -+ vld1.8 {q8-q9}, [r1, :128]! -++ vshr.u8 q12, q8, #3 -++ vshr.u8 q13, q9, #3 -+ vld1.8 {q10-q11}, [r1, :128], r3 -++ vshr.u8 q14, q10, #3 -++ vshr.u8 q15, q11, #3 -+ sub r1, #32 -+ sao_band_64 -+ vst1.8 {q8-q9}, [r0, :128]! -+@@ -129,51 +140,18 @@ function ff_hevc_sao_band_w64_neon_8, export=1 -+ -+ bx lr -+ endfunc -+-// input -+-// a in q0 - q3 -+-// c in q4 - q7 -+-// b in q8 - q11 -+-// offset table in r7 and r5 -+-// output in q0 - q3 -+-// clobbers q12 - q15 -+-.macro edge_w64_body -+- vcgt.u8 q12, q4, q0 // c > a -> -1 , otherwise 0 -+- vcgt.u8 q0, q0, q4 // a > c -> -1 , otherwise 0 -+- vcgt.u8 q13, q5, q1 -+- vcgt.u8 q1, q1, q5 -+- vsub.s8 q12, q0, q12 // diff0 -+- vcgt.u8 q0, q4, q8 // c > b -+- vsub.s8 q13, q1, q13 -+- -+- vcgt.u8 q14, q8, q4 // b > c -+- vcgt.u8 q1, q5, q9 -+- vcgt.u8 q15, q9, q5 -+- vsub.s8 q0, q14, q0 // diff1 -+- vsub.s8 q1, q15, q1 -+ -+- vadd.s8 q0, q12 //diff0 + diff1 -+- vadd.s8 q1, q13 -+- -+- vcgt.u8 q14, q6, q2 -+- vcgt.u8 q2, q2, q6 -+- vcgt.u8 q15, q7, q3 -+- vcgt.u8 q3, q3, q7 -+- -+- vsub.s8 q14, q2, q14 -+- vcgt.u8 q2, q6, q10 -+- vsub.s8 q15, q3, q15 -+- -+- vcgt.u8 q12, q10, q6 -+- vcgt.u8 q3, q7, q11 -+- vcgt.u8 q13, q11, q7 -+- vsub.s8 q2, q12, q2 -+- vsub.s8 q3, q13, q3 -++.macro diff32 out0, out1, tmp0, tmp1, in0, in1, in2, in3 -++ vcgt.u8 \out0, \in2, \in0 // c > a -> -1 , otherwise 0 -++ vcgt.u8 \tmp0, \in0, \in2 // a > c -> -1 , otherwise 0 -++ vcgt.u8 \out1, \in3, \in1 // c > a -> -1 , otherwise 0 part 2 -++ vcgt.u8 \tmp1, \in1, \in3 // a > c -> -1 , otherwise 0 part 2 -++ vsub.s8 \out0, \tmp0, \out0 // diff0 -++ vsub.s8 \out1, \tmp1, \out1 // diff0 part 2 -++.endm -+ -++.macro table64 -+ vmov.s8 q13, #2 // 2 to all elements -+- -+- vadd.s8 q2, q14 -+- vadd.s8 q3, q15 -+- -+ vmov.32 d24[0], r4 // load offset table from general registers -+ vmov.32 d24[1], r5 // load rest of offset table -+ -+@@ -208,6 +186,28 @@ endfunc -+ sub r0, #32 -+ .endm -+ -++// input -++// a in q0 - q3 -++// c in q4 - q7 -++// b in q8 - q11 -++// offset table in r7 and r5 -++// output in q0 - q3 -++// clobbers q12 - q15 -++.macro edge_w64_body -++ diff32 q12, q13, q0, q1, q0, q1, q4, q5 -++ diff32 q0, q1, q14, q15, q8, q9, q4, q5 -++ -++ vadd.s8 q0, q12 //diff0 + diff1 -++ vadd.s8 q1, q13 -++ -++ diff32 q14, q15, q2, q3, q2, q3, q6, q7 -++ diff32 q2, q3, q12, q13, q10, q11, q6, q7 -++ -++ vadd.s8 q2, q14 -++ vadd.s8 q3, q15 -++ table64 -++.endm -++ -+ .macro init_edge_64 -+ push {r4-r5} -+ ldr r12, [sp, #8] // height -+@@ -334,38 +334,23 @@ function ff_hevc_sao_edge_eo3_w64_neon_8, export=1 -+ bx lr -+ endfunc -+ -+-// inputs: -+-// a in q0, q1 -+-// c in q2, q3 -+-// b in q8, q9 -+-// offset table in d31 -+-// clobbered registers q0, q1, q10, q11, q12, q13 -+-// output q0, q1 -+-.macro edge_w32_body -+- vcgt.u8 q12, q2, q0 // c > a -> -1 , otherwise 0 -+- vcgt.u8 q0, q0, q2 // a > c -> -1 , otherwise 0 -+- vcgt.u8 q13, q3, q1 -+- vcgt.u8 q1, q1, q3 -+- -+- vsub.s8 q12, q0, q12 // diff0 -+- vcgt.u8 q0, q2, q8 // c > b -+- vsub.s8 q13, q1, q13 // diff0 part 2 -+- -+- vcgt.u8 q10, q8, q2 // b > c -+- vcgt.u8 q1, q3, q9 -+- vcgt.u8 q11, q9, q3 -+- -+- vsub.s8 q0, q10, q0 // diff1 -+- -+- vmov.s8 q10, #2 // 2 to all elements -+- vsub.s8 q1, q11, q1 // diff1 part 2 -+- vadd.s8 q0, q12 //diff0 + diff1 -+- vadd.s8 q1, q13 -++.macro init_edge_32 -++ ldr r12, [sp, #4] // sao_offset_val_table -++ vld1.32 {d31}, [r12] -++ ldr r12, [sp] // height -++.endm -+ -+- vadd.s8 q0, q10 -+- vadd.s8 q1, q10 -++.macro diff out0, tmp0, in0, in1 -++ vcgt.u8 \out0, \in1, \in0 // c > a -> -1 , otherwise 0 -++ vcgt.u8 \tmp0, \in0, \in1 // a > c -> -1 , otherwise 0 -++ vsub.s8 \out0, \tmp0, \out0 // diff0 -++.endm -+ -+- vmov.u8 q10, #128 -++.macro table32 -++ vmov.s8 q10, #2 -++ vadd.s8 q0, q10 -++ vadd.s8 q1, q10 -++ vmov.s8 q10, #128 -+ vtbl.8 d0, {d31}, d0 -+ vadd.s8 q11, q2, q10 -+ vtbl.8 d1, {d31}, d1 -+@@ -373,56 +358,68 @@ endfunc -+ vtbl.8 d2, {d31}, d2 -+ vqadd.s8 q11, q0 -+ vtbl.8 d3, {d31}, d3 -+- vqadd.s8 q12, q1 -+- vsub.s8 q0, q11, q10 -+- vsub.s8 q1, q12, q10 -++ vqadd.s8 q12, q1 -++ vsub.s8 q0, q11, q10 -++ vsub.s8 q1, q12, q10 -+ vst1.8 {q0-q1}, [r0, :128], r2 -+ .endm -+ -+-.macro init_edge_32 -+- ldr r12, [sp, #4] // sao_offset_val_table -+- vld1.32 {d31}, [r12] -+- ldr r12, [sp] // height -+-.endm -+- -+ function ff_hevc_sao_edge_eo0_w32_neon_8, export=1 -+ init_edge_32 -+- sub r1, #4 // load 4 extra bytes -++ vpush {q4-q7} -++ sub r1, #4 -+ 1: subs r12, #1 -+- vld1.32 d3[1], [r1]! -+- vld1.8 {q2-q3}, [r1, :128]! // c -+- vld1.32 d20[0], [r1], r3 -+- sub r1, #36 -++ vld1.8 {q13-q14}, [r1]! -++ vld1.32 d30, [r1], r3 -++ sub r1, #32 -+ // a -+- vext.8 q0, q1, q2, #15 -+- vext.8 q1, q2, q3, #15 -+- // b -+- vext.8 q8, q2, q3, #1 -+- vext.8 q9, q3, q10, #1 -+- edge_w32_body -++ vext.8 q0, q13, q14, #3 -++ vext.8 q1, q14, q15, #3 -++ vshr.u64 d24, d30, #24 -++ // c -++ vext.8 q2, q13, q14, #4 -++ vext.8 q3, q14, q15, #4 -++ vshr.u64 d16, d30, #32 -++ // diff0 -++ diff32 q13, q14, q4, q5, q0, q1, q2, q3 -++ diff d18, d25, d24, d16 -++ // -diff1 -++ vext.s8 q0, q13, q14, #1 -++ vext.s8 q1, q14, q9, #1 -++ -++ vsub.s8 q0, q13, q0 //diff0 + diff1 -++ vsub.s8 q1, q14, q1 -++ table32 -+ bne 1b -++ vpop {q4-q7} -++ -+ bx lr -+ endfunc -+ -+ function ff_hevc_sao_edge_eo1_w32_neon_8, export=1 -+ init_edge_32 -++ vpush {q4-q7} -+ // load a -+ sub r1, r3 -+ vld1.8 {q0-q1}, [r1, :128], r3 -+ // load c -+ vld1.8 {q2-q3}, [r1, :128], r3 -++ diff32 q12, q13, q0, q1, q0, q1, q2, q3 // CMP ( c, a ) -+ 1: subs r12, #1 -+ // load b -+ vld1.8 {q8-q9}, [r1, :128], r3 -+- edge_w32_body -+- // inputs for next loop iteration -+- // a -+- vmov.64 q0, q2 -+- vmov.64 q1, q3 -++ diff32 q4, q5, q10, q11, q8, q9, q2, q3 // CMP ( c, b ) -++ vadd.s8 q0, q4, q12 //diff0 + diff1 -++ vadd.s8 q1, q5, q13 -++ table32 -++ // CMP ( c, a ) -++ vneg.s8 q12, q4 -++ vneg.s8 q13, q5 -+ // c -+ vmov.64 q2, q8 -+ vmov.64 q3, q9 -+ bne 1b -++ vpop {q4-q7} -+ bx lr -+ endfunc -+ -+@@ -452,7 +449,11 @@ function ff_hevc_sao_edge_eo2_w32_neon_8, export=1 -+ vext.8 q6, q10, q11, #8 -+ vext.8 q7, q11, q12, #8 -+ vext.8 q5, q10, q11, #7 -+- edge_w32_body -++ diff32 q12, q13, q0, q1, q0, q1, q2, q3 -++ diff32 q0, q1, q10, q11, q8, q9, q2, q3 -++ vadd.s8 q0, q12 //diff0 + diff1 -++ vadd.s8 q1, q13 -++ table32 -+ // inputs for next loop iteration -+ // a -+ vmov.8 q0, q4 -+@@ -487,7 +488,14 @@ function ff_hevc_sao_edge_eo3_w32_neon_8, export=1 -+ vext.8 q8, q10, q11, #7 -+ vext.8 q9, q11, q12, #7 -+ vext.8 q14, q12, q10, #7 -+- edge_w32_body -++ -++ diff32 q12, q13, q0, q1, q0, q1, q2, q3 -++ diff32 q0, q1, q10, q11, q8, q9, q2, q3 -++ -++ vadd.s8 q0, q12 //diff0 + diff1 -++ vadd.s8 q1, q13 -++ table32 -++ -+ // inputs for next loop iteration -+ // a -+ vext.8 q0, q2, q3, #1 -+-- -+2.5.0 -+ -diff --git a/tools/depends/target/ffmpeg/autobuild.sh b/tools/depends/target/ffmpeg/autobuild.sh -index 1add222..7ef281d 100755 ---- a/tools/depends/target/ffmpeg/autobuild.sh -+++ b/tools/depends/target/ffmpeg/autobuild.sh -@@ -72,6 +72,7 @@ do - ;; - --arch=*) - FLAGS="$FLAGS --arch=${1#*=}" -+ ARCH=${1#*=} - shift - ;; - --extra-cflags=*) -@@ -100,6 +101,9 @@ do - esac - done - -+[ -n ${ARCH} ] || ARCH=$(dpkg-architecture -qDEB_BUILD_GNU_CPU) -+[ ${ARCH} = $(dpkg-architecture -qDEB_BUILD_GNU_CPU) ] || FLAGS="$FLAGS --enable-cross-compile" -+ - BUILDTHREADS=${BUILDTHREADS:-$(grep -c "^processor" /proc/cpuinfo)} - [ ${BUILDTHREADS} -eq 0 ] && BUILDTHREADS=1 - -@@ -107,9 +111,12 @@ BUILDTHREADS=${BUILDTHREADS:-$(grep -c "^processor" /proc/cpuinfo)} - if [ -f ${FFMPEG_PREFIX}/lib/pkgconfig/libavcodec.pc ] && [ -f .ffmpeg-installed ] - then - CURVER=$(cat .ffmpeg-installed) -- [ "$VERSION" == "$CURVER" ] && exit 0 -+ [ "$VERSION" == "$CURVER" ] && exit 0 || rm -fr .ffmpeg-installed - fi - -+CFLAG="$CFLAGS" CPPFLAGS="$CFLAGS" ARCH=$ARCH CXXFLAGS="$CXXFLAGS" LDFLAGS="$LDFLAGS" PLATFORM=ffmpeg-${VERSION} CONFFLAGS=${FLAGS} PREFIX=${FFMPEG_PREFIX} make -j ${BUILDTHREADS} -+exit $? -+ - [ -f ${ARCHIVE} ] || - curl -Ls --create-dirs -f -o ${ARCHIVE} ${BASE_URL}/${VERSION}.tar.gz || - { echo "error fetching ${BASE_URL}/${VERSION}.tar.gz" ; exit 3; } -diff --git a/tools/depends/target/ffmpeg/h264_parser_fix_parsing_of_mvc_slices_in_some_corner_cases.patch b/tools/depends/target/ffmpeg/h264_parser_fix_parsing_of_mvc_slices_in_some_corner_cases.patch -new file mode 100644 -index 0000000..648f64f ---- /dev/null -+++ b/tools/depends/target/ffmpeg/h264_parser_fix_parsing_of_mvc_slices_in_some_corner_cases.patch -@@ -0,0 +1,66 @@ -+From fd627f6435db524f3e1fd8df6f64a17dcda5c8b9 Mon Sep 17 00:00:00 2001 -+From: Hendrik Leppkes -+Date: Fri, 26 Feb 2016 00:23:53 +0100 -+Subject: [PATCH] h264_parser: fix parsing of mvc slices in some corner cases -+ -+--- -+ libavcodec/h264.h | 2 +- -+ libavcodec/h264_parser.c | 10 +++++----- -+ 2 files changed, 6 insertions(+), 6 deletions(-) -+ -+diff --git a/libavcodec/h264.h b/libavcodec/h264.h -+index 9e1d377..846e4dc 100644 -+--- a/libavcodec/h264.h -++++ b/libavcodec/h264.h -+@@ -828,7 +828,7 @@ typedef struct H264Context { -+ int cur_bit_depth_luma; -+ int16_t slice_row[MAX_SLICES]; ///< to detect when MAX_SLICES is too low -+ -+- uint8_t parse_history[6]; -++ uint8_t parse_history[9]; -+ int parse_history_count; -+ int parse_last_mb; -+ -+diff --git a/libavcodec/h264_parser.c b/libavcodec/h264_parser.c -+index 4337c8c..2fd3f2b 100644 -+--- a/libavcodec/h264_parser.c -++++ b/libavcodec/h264_parser.c -+@@ -39,6 +39,7 @@ typedef struct H264ParseContext { -+ ParseContext pc; -+ int got_first; -+ int is_mvc; -++ int slice_ext; -+ } H264ParseContext; -+ -+ -+@@ -97,18 +98,17 @@ static int h264_find_frame_end(H264ParseContext *p, const uint8_t *buf, -+ nalu_type == NAL_IDR_SLICE || (p->is_mvc && nalu_type == NAL_SLICE_EXT)) { -+ state += 8; -+ -+- if (nalu_type == NAL_SLICE_EXT) -+- i += 3; // skip mvc extension -++ p->slice_ext = (nalu_type == NAL_SLICE_EXT); -+ continue; -+ } -+ state = 7; -+ } else { -+ h->parse_history[h->parse_history_count++]= buf[i]; -+- if (h->parse_history_count>5) { -++ if (h->parse_history_count>8) { -+ unsigned int mb, last_mb= h->parse_last_mb; -+ GetBitContext gb; -+ -+- init_get_bits(&gb, h->parse_history, 8*h->parse_history_count); -++ init_get_bits8(&gb, h->parse_history + 3*p->slice_ext, h->parse_history_count - 3*p->slice_ext); -+ h->parse_history_count=0; -+ mb= get_ue_golomb_long(&gb); -+ h->parse_last_mb= mb; -+@@ -131,7 +131,7 @@ static int h264_find_frame_end(H264ParseContext *p, const uint8_t *buf, -+ pc->frame_start_found = 0; -+ if (h->is_avc) -+ return next_avc; -+- return i - (state & 5) - 5 * (state > 7); -++ return i - (state & 5) - 8 * (state > 7); -+ } -+ -+ static int scan_mmco_reset(AVCodecParserContext *s) -diff --git a/tools/depends/target/ffmpeg/hevcdsp_ARM_NEON_optimized_epel_functions.patch b/tools/depends/target/ffmpeg/hevcdsp_ARM_NEON_optimized_epel_functions.patch -new file mode 100644 -index 0000000..5e8e07d ---- /dev/null -+++ b/tools/depends/target/ffmpeg/hevcdsp_ARM_NEON_optimized_epel_functions.patch -@@ -0,0 +1,409 @@ -+From 29c3327a0d72a7e872ff170363cfe5ed13bca5d0 Mon Sep 17 00:00:00 2001 -+From: Seppo Tomperi -+Date: Tue, 22 Dec 2015 18:10:24 +0000 -+Subject: [PATCH] hevcdsp: ARM NEON optimized epel functions -+ -+--- -+ libavcodec/arm/Makefile | 1 + -+ libavcodec/arm/hevcdsp_epel_neon.S | 334 +++++++++++++++++++++++++++++++++++++ -+ libavcodec/arm/hevcdsp_init_neon.c | 23 +++ -+ 3 files changed, 358 insertions(+) -+ create mode 100644 libavcodec/arm/hevcdsp_epel_neon.S -+ -+diff --git a/libavcodec/arm/Makefile b/libavcodec/arm/Makefile -+index cdd35b0..6051ec8 100644 -+--- a/libavcodec/arm/Makefile -++++ b/libavcodec/arm/Makefile -+@@ -131,6 +131,7 @@ NEON-OBJS-$(CONFIG_DCA_DECODER) += arm/dcadsp_neon.o \ -+ arm/synth_filter_neon.o -+ NEON-OBJS-$(CONFIG_HEVC_DECODER) += arm/hevcdsp_init_neon.o \ -+ arm/hevcdsp_deblock_neon.o \ -++ arm/hevcdsp_epel_neon.o \ -+ arm/hevcdsp_idct_neon.o \ -+ arm/hevcdsp_qpel_neon.o -+ NEON-OBJS-$(CONFIG_RV30_DECODER) += arm/rv34dsp_neon.o -+diff --git a/libavcodec/arm/hevcdsp_epel_neon.S b/libavcodec/arm/hevcdsp_epel_neon.S -+new file mode 100644 -+index 0000000..516ae5b -+--- /dev/null -++++ b/libavcodec/arm/hevcdsp_epel_neon.S -+@@ -0,0 +1,334 @@ -++/* -++ * Copyright (c) 2014 - 2015 Seppo Tomperi -++ * -++ * This file is part of FFmpeg. -++ * -++ * FFmpeg is free software; you can redistribute it and/or -++ * modify it under the terms of the GNU Lesser General Public -++ * License as published by the Free Software Foundation; either -++ * version 2.1 of the License, or (at your option) any later version. -++ * -++ * FFmpeg is distributed in the hope that it will be useful, -++ * but WITHOUT ANY WARRANTY; without even the implied warranty of -++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -++ * Lesser General Public License for more details. -++ * -++ * You should have received a copy of the GNU Lesser General Public -++ * License along with FFmpeg; if not, write to the Free Software -++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -++ */ -++ -++#include "libavutil/arm/asm.S" -++#include "neon.S" -++ -++#define MAX_PB_SIZE #64 -++ -++.macro vextin_d4 -++ vld1.8 {q10}, [r1], r2 -++ vmov d16, d20 -++ vext.8 d17, d20, d21, #1 -++ vext.8 d18, d20, d21, #2 -++ vext.8 d19, d20, d21, #3 -++.endm -++ -++.macro vextin_d4_8 -++ vld1.8 d16, [r1], r2 -++ vext.8 d17, d16, d16, #1 -++ vext.8 d18, d16, d16, #2 -++ vext.8 d19, d16, d16, #3 -++.endm -++ -++.macro load_coeffs_16b coeffs -++ ldr \coeffs, [\coeffs] -++ vdup.i8 d0, \coeffs -++ lsr \coeffs, #8 -++ vdup.i8 d1, \coeffs -++ lsr \coeffs, #8 -++ vdup.i8 d2, \coeffs -++ lsr \coeffs, #8 -++ vdup.i8 d3, \coeffs -++.endm -++ -++.macro epel_filter_16b out=q12 -++ vmull.u8 q3, d16, d0 -++ vmull.u8 q11, d19, d3 -++ vmull.u8 \out, d17, d1 -++ vmull.u8 q10, d18, d2 -++ vadd.s16 q3, q11 -++ vadd.s16 \out, q10 -++ vsub.s16 \out, q3 -++.endm -++ -++.macro load_coeffs_32b coeffs -++ ldr \coeffs, [\coeffs] -++ vmov.i64 d4, #0 -++ vmov.8 d4[0], \coeffs -++ lsr \coeffs, #8 -++ vmov.8 d4[2], \coeffs -++ lsr \coeffs, #8 -++ vmov.8 d4[4], \coeffs -++ lsr \coeffs, #8 -++ vmov.8 d4[6], \coeffs -++.endm -++ -++.macro epel_filter_32b -++ vmull.s16 q3, d24, d4[0] //q12 -++ vmull.s16 q4, d25, d4[0] -++ vmull.s16 q5, d30, d4[3] //q15 -++ vmull.s16 q6, d31, d4[3] -++ -++ vmull.s16 q7, d26, d4[1] // q13 -++ vmull.s16 q8, d27, d4[1] -++ vmull.s16 q9, d28, d4[2] // q14 -++ vmull.s16 q10, d29, d4[2] -++ vadd.s32 q3, q5 -++ vadd.s32 q4, q6 -++ vadd.s32 q7, q9 -++ vadd.s32 q8, q10 -++ vsub.s32 q7, q3 -++ vsub.s32 q8, q4 -++ vqshrn.s32 d6, q7, #6 -++ vqshrn.s32 d7, q8, #6 -++.endm -++ -++.macro epel_filter_32b_4 -++ vmull.s16 q3, d24, d4[0] //q12 -++ vmull.s16 q5, d30, d4[3] //q15 -++ vmull.s16 q7, d26, d4[1] // q13 -++ vmull.s16 q9, d28, d4[2] // q14 -++ vadd.s32 q3, q5 -++ vadd.s32 q7, q9 -++ vsub.s32 q7, q3 -++ vqshrn.s32 d6, q7, #6 -++.endm -++ -++function ff_hevc_put_epel_h_neon_8, export=1 -++ push {r4-r7} -++ mov r4, MAX_PB_SIZE -++ ldr r7, [sp, #16] // mx -++ ldr r5, [sp, #24] // width -++ sub r7, #1 -++ lsl r7, #2 -++ vpush {d8-d15} -++ adrl r12, epel_coeffs -++ add r7, r12 -++ sub r1, #1 -++ lsl r4, #1 -++ load_coeffs_16b r7 -++ mov r12, r3 -++ mov r6, r0 -++ mov r7, r1 -++ cmp r5, #6 -++ bgt 8f -++ cmp r5, #4 -++ blt 2f -++ b 4f -++8: subs r3, #1 -++ pld [r1] -++ vextin_d4 -++ epel_filter_16b -++ vst1.16 {q12}, [r0], r4 -++ bne 8b -++ subs r5, #8 -++ beq 99f -++ mov r3, r12 -++ add r6, #16 -++ mov r0, r6 -++ add r7, #8 -++ mov r1, r7 -++ cmp r5, #4 -++ bgt 8b -++4: subs r3, #1 -++ pld [r1] -++ vextin_d4_8 -++ epel_filter_16b -++ vst1.16 d24, [r0], r4 -++ bne 4b -++ subs r5, #4 -++ beq 99f -++ mov r3, r12 -++ add r6, #8 -++ mov r0, r6 -++ add r7, #4 -++ mov r1, r7 -++2: subs r3, #1 -++ pld [r1] -++ vextin_d4_8 -++ epel_filter_16b -++ vst1.32 d24[0], [r0], r4 -++ bne 2b -++99: vpop {d8-d15} -++ pop {r4-r7} -++ bx lr -++endfunc -++ -++function ff_hevc_put_epel_v_neon_8, export=1 -++ push {r4-r7} -++ mov r4, MAX_PB_SIZE -++ ldr r7, [sp, #20] // my -++ ldr r5, [sp, #24] // width -++ sub r7, #1 -++ lsl r7, #2 -++ vpush {d8-d15} -++ adrl r12, epel_coeffs -++ add r7, r12 -++ load_coeffs_16b r7 -++ sub r1, r2 -++ lsl r4, #1 -++ mov r12, r3 -++ mov r6, r0 -++ mov r7, r1 -++0: pld [r1] -++ vld1.8 {d16}, [r1], r2 -++ pld [r1] -++ vld1.8 {d17}, [r1], r2 -++ pld [r1] -++ vld1.8 {d18}, [r1], r2 -++ cmp r5, #6 -++ bgt 8f -++ cmp r5, #4 -++ blt 2f -++ b 4f -++8: pld [r1] -++ vld1.8 {d19}, [r1], r2 -++ subs r3, #1 -++ epel_filter_16b -++ vst1.16 {q12}, [r0], r4 -++ vmov d16, d17 -++ vmov d17, d18 -++ vmov d18, d19 -++ bne 8b -++ subs r5, #8 -++ beq 99f -++ mov r3, r12 -++ add r6, #16 -++ mov r0, r6 -++ add r7, #8 -++ mov r1, r7 -++ b 0b -++4: pld [r1] -++ vld1.8 {d19}, [r1], r2 -++ subs r3, #1 -++ epel_filter_16b -++ vst1.16 d24, [r0], r4 -++ vmov d16, d17 -++ vmov d17, d18 -++ vmov d18, d19 -++ bne 4b -++ subs r5, #4 -++ beq 99f -++ mov r3, r12 -++ add r6, #8 -++ mov r0, r6 -++ add r7, #4 -++ mov r1, r7 -++ b 0b -++2: pld [r1] -++ vld1.8 {d19}, [r1], r2 -++ subs r3, #1 -++ epel_filter_16b -++ vst1.32 d24[0], [r0], r4 -++ vmov d16, d17 -++ vmov d17, d18 -++ vmov d18, d19 -++ bne 2b -++99: vpop {d8-d15} -++ pop {r4-r7} -++ bx lr -++endfunc -++ -++function ff_hevc_put_epel_hv_neon_8, export=1 -++ push {r4-r7} -++ mov r4, MAX_PB_SIZE -++ ldr r6, [sp, #16] // mx -++ ldr r7, [sp, #20] // my -++ ldr r5, [sp, #24] // width -++ sub r7, #1 -++ lsl r7, #2 -++ vpush {d8-d15} -++ adrl r12, epel_coeffs -++ sub r6, #1 -++ lsl r6, #2 -++ add r6, r12 // mx epel coeff offset -++ add r7, r12 -++ sub r1, #1 -++ sub r1, r2 -++ lsl r4, #1 -++ load_coeffs_16b r6 -++ load_coeffs_32b r7 -++ mov r12, r3 -++ mov r6, r0 -++ mov r7, r1 -++0: pld [r1] -++ vextin_d4 -++ epel_filter_16b q12 -++ pld [r1] -++ vextin_d4 -++ epel_filter_16b q13 -++ pld [r1] -++ vextin_d4 -++ epel_filter_16b q14 -++ cmp r5, #6 -++ bgt 8f -++ cmp r5, #4 -++ blt 2f -++ b 4f -++8: pld [r1] -++ vextin_d4 -++ epel_filter_16b q15 -++ subs r3, #1 -++ epel_filter_32b -++ vst1.16 {q3}, [r0], r4 -++ vmov q12, q13 -++ vmov q13, q14 -++ vmov q14, q15 -++ bne 8b -++ subs r5, #8 -++ beq 99f -++ mov r3, r12 -++ add r6, #16 -++ mov r0, r6 -++ add r7, #8 -++ mov r1, r7 -++ b 0b -++4: pld [r1] -++ vextin_d4_8 -++ epel_filter_16b q15 -++ subs r3, #1 -++ epel_filter_32b_4 -++ vst1.16 d6, [r0], r4 -++ vmov q12, q13 -++ vmov q13, q14 -++ vmov q14, q15 -++ bne 4b -++ subs r5, #4 -++ beq 99f -++ mov r3, r12 -++ add r6, #8 -++ mov r0, r6 -++ add r7, #4 -++ mov r1, r7 -++ b 0b -++2: pld [r1] -++ vextin_d4_8 -++ epel_filter_16b q15 -++ subs r3, #1 -++ epel_filter_32b_4 -++ vst1.32 d6[0], [r0], r4 -++ vmov q12, q13 -++ vmov q13, q14 -++ vmov q14, q15 -++ bne 2b -++99: vpop {d8-d15} -++ pop {r4-r7} -++ bx lr -++endfunc -++ -++epel_coeffs: -++ .byte 2, 58, 10, 2 -++ .byte 4, 54, 16, 2 -++ .byte 6, 46, 28, 4 -++ .byte 4, 36, 36, 4 -++ .byte 4, 28, 46, 6 -++ .byte 2, 16, 54, 4 -++ .byte 2, 10, 58, 2 -+diff --git a/libavcodec/arm/hevcdsp_init_neon.c b/libavcodec/arm/hevcdsp_init_neon.c -+index 5591807..733ff08 100644 -+--- a/libavcodec/arm/hevcdsp_init_neon.c -++++ b/libavcodec/arm/hevcdsp_init_neon.c -+@@ -58,6 +58,15 @@ PUT_PIXELS(ff_hevc_put_pixels_w32_neon_8); -+ PUT_PIXELS(ff_hevc_put_pixels_w48_neon_8); -+ PUT_PIXELS(ff_hevc_put_pixels_w64_neon_8); -+ #undef PUT_PIXELS -++void ff_hevc_put_epel_h_neon_8(int16_t *dst, uint8_t *src, -++ ptrdiff_t srcstride, int height, -++ intptr_t mx, intptr_t my, int width); -++void ff_hevc_put_epel_v_neon_8(int16_t *dst, uint8_t *src, -++ ptrdiff_t srcstride, int height, -++ intptr_t mx, intptr_t my, int width); -++void ff_hevc_put_epel_hv_neon_8(int16_t *dst, uint8_t *src, -++ ptrdiff_t srcstride, int height, -++ intptr_t mx, intptr_t my, int width); -+ -+ static void (*put_hevc_qpel_neon[4][4])(int16_t *dst, ptrdiff_t dststride, uint8_t *src, ptrdiff_t srcstride, -+ int height, int width); -+@@ -201,7 +210,21 @@ av_cold void ff_hevcdsp_init_neon(HEVCDSPContext *c, const int bit_depth) -+ c->put_hevc_qpel_bi[x][1][0] = ff_hevc_put_qpel_bi_neon_wrapper; -+ c->put_hevc_qpel_bi[x][0][1] = ff_hevc_put_qpel_bi_neon_wrapper; -+ c->put_hevc_qpel_bi[x][1][1] = ff_hevc_put_qpel_bi_neon_wrapper; -++ c->put_hevc_epel[x][1][0] = ff_hevc_put_epel_v_neon_8; -++ c->put_hevc_epel[x][0][1] = ff_hevc_put_epel_h_neon_8; -++ c->put_hevc_epel[x][1][1] = ff_hevc_put_epel_hv_neon_8; -+ } -++ c->put_hevc_epel[0][0][0] = ff_hevc_put_pixels_w2_neon_8; -++ c->put_hevc_epel[1][0][0] = ff_hevc_put_pixels_w4_neon_8; -++ c->put_hevc_epel[2][0][0] = ff_hevc_put_pixels_w6_neon_8; -++ c->put_hevc_epel[3][0][0] = ff_hevc_put_pixels_w8_neon_8; -++ c->put_hevc_epel[4][0][0] = ff_hevc_put_pixels_w12_neon_8; -++ c->put_hevc_epel[5][0][0] = ff_hevc_put_pixels_w16_neon_8; -++ c->put_hevc_epel[6][0][0] = ff_hevc_put_pixels_w24_neon_8; -++ c->put_hevc_epel[7][0][0] = ff_hevc_put_pixels_w32_neon_8; -++ c->put_hevc_epel[8][0][0] = ff_hevc_put_pixels_w48_neon_8; -++ c->put_hevc_epel[9][0][0] = ff_hevc_put_pixels_w64_neon_8; -++ -+ c->put_hevc_qpel[0][0][0] = ff_hevc_put_pixels_w2_neon_8; -+ c->put_hevc_qpel[1][0][0] = ff_hevc_put_pixels_w4_neon_8; -+ c->put_hevc_qpel[2][0][0] = ff_hevc_put_pixels_w6_neon_8; -+-- -+2.5.0 -+ -diff --git a/xbmc/Application.cpp b/xbmc/Application.cpp -index b44e467..39eb53c 100644 ---- a/xbmc/Application.cpp -+++ b/xbmc/Application.cpp -@@ -29,6 +29,8 @@ - #include "utils/Splash.h" - #include "LangInfo.h" - #include "utils/Screenshot.h" -+#include -+#include - #include "Util.h" - #include "URL.h" - #include "guilib/TextureManager.h" -@@ -92,6 +94,7 @@ - #include "utils/CPUInfo.h" - #include "utils/SeekHandler.h" - -+#include "video/VideoReferenceClock.h" - #include "input/KeyboardLayoutManager.h" - - #if HAVE_SDL_VERSION == 1 -@@ -110,6 +113,9 @@ - #ifdef HAS_FILESYSTEM_NFS - #include "filesystem/NFSFile.h" - #endif -+#ifdef HAS_FILESYSTEM_AFP -+#include "filesystem/AFPFile.h" -+#endif - #ifdef HAS_FILESYSTEM_SFTP - #include "filesystem/SFTPFile.h" - #endif -@@ -215,10 +221,16 @@ - #include "utils/AMLUtils.h" - #endif - -+#ifdef HAS_IMXVPU -+#include "cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecIMX.h" -+#include "peripherals/bus/linux/PeripheralBusPLATFORMLibUdev.h" -+#endif -+ - #include "cores/FFmpeg.h" - #include "utils/CharsetConverter.h" - #include "pictures/GUIWindowSlideShow.h" - #include "windows/GUIWindowLoginScreen.h" -+#include "utils/Screen.h" - - using namespace ADDON; - using namespace XFILE; -@@ -279,6 +291,7 @@ CApplication::CApplication(void) - m_bPlaybackStarting = false; - m_ePlayState = PLAY_STATE_NONE; - m_skinReverting = false; -+ m_ourVT = -1; - - #ifdef HAS_GLX - XInitThreads(); -@@ -331,7 +344,10 @@ bool CApplication::OnEvent(XBMC_Event& newEvent) - { - case XBMC_QUIT: - if (!g_application.m_bStop) -+ { - CApplicationMessenger::GetInstance().PostMsg(TMSG_QUIT); -+ g_screen.SetOn(); -+ } - break; - case XBMC_VIDEORESIZE: - if (g_windowManager.Initialized() && -@@ -444,6 +460,7 @@ bool CApplication::Create() - CApplicationMessenger::GetInstance().RegisterReceiver(this); - CApplicationMessenger::GetInstance().RegisterReceiver(&g_playlistPlayer); - CApplicationMessenger::GetInstance().RegisterReceiver(&g_infoManager); -+ g_screen.RegisterToAnnouncer(); - - for (int i = RES_HDTV_1080i; i <= RES_PAL60_16x9; i++) - { -@@ -689,7 +706,7 @@ bool CApplication::Create() - return true; - } - --bool CApplication::CreateGUI() -+bool CApplication::CreateGUI(bool showXBMCSplash) - { - m_frameMoveGuard.lock(); - -@@ -733,6 +750,8 @@ bool CApplication::CreateGUI() - // Initialize core peripheral port support. Note: If these parameters - // are 0 and NULL, respectively, then the default number and types of - // controllers will be initialized. -+ RESOLUTION r = (RESOLUTION)CSettings::GetInstance().GetInt("videoscreen.resolution"); -+ CDisplaySettings::GetInstance().SetCurrentResolution(r ? r : RES_DESKTOP); - if (!g_Windowing.InitWindowSystem()) - { - CLog::Log(LOGFATAL, "CApplication::Create: Unable to init windowing system"); -@@ -776,7 +795,7 @@ bool CApplication::CreateGUI() - if (sav_res) - CDisplaySettings::GetInstance().SetCurrentResolution(RES_DESKTOP, true); - -- if (g_advancedSettings.m_splashImage) -+ if (g_advancedSettings.m_splashImage && showXBMCSplash) - CSplash::GetInstance().Show(); - - // The key mappings may already have been loaded by a peripheral -@@ -1085,6 +1104,9 @@ bool CApplication::Initialize() - #if !defined(TARGET_DARWIN_IOS) - g_peripherals.Initialise(); - #endif -+#if defined(HAS_IMXVPU) -+ g_peripherals.CreatePeripheralBus(std::make_shared(&g_peripherals)); -+#endif - - // Load curl so curl_global_init gets called before any service threads - // are started. Unloading will have no effect as curl is never fully unloaded. -@@ -1185,6 +1207,7 @@ bool CApplication::Initialize() - } - - m_slowTimer.StartZero(); -+ m_slowTimerVT.StartZero(); - - CAddonMgr::GetInstance().StartServices(true); - -@@ -2382,6 +2405,10 @@ void CApplication::OnApplicationMessage(ThreadMessage* pMsg) - #endif - break; - -+ case TMSG_CHANGEVT: -+ g_application.ChangeVT((int)pMsg->param1); -+ break; -+ - case TMSG_INHIBITIDLESHUTDOWN: - InhibitIdleShutdown(pMsg->param1 != 0); - break; -@@ -2410,6 +2437,11 @@ void CApplication::OnApplicationMessage(ThreadMessage* pMsg) - break; - #endif - -+ case TMSG_DISPLAY_RECONFIGURE: -+ g_Windowing.UpdateResolutions(); -+ g_graphicsContext.SetFullScreenVideo(g_graphicsContext.IsFullScreenVideo()); -+ break; -+ - case TMSG_SETAUDIODSPSTATE: - if(pMsg->param1 == ACTIVE_AE_DSP_STATE_ON) - CServiceBroker::GetADSP().Activate(); -@@ -2695,13 +2727,19 @@ void CApplication::FrameMove(bool processEvents, bool processGUI) - if (processGUI && m_renderGUI) - { - m_skipGuiRender = false; -+ int idleSeconds = 15 * (m_pPlayer->IsPlayingAudio() && !m_pPlayer->IsPausedPlayback() ? 4*3/*3 min total*/ : 1); - int fps = 0; - - #if defined(TARGET_RASPBERRY_PI) || defined(HAS_IMXVPU) - // This code reduces rendering fps of the GUI layer when playing videos in fullscreen mode - // it makes only sense on architectures with multiple layers -- if (g_graphicsContext.IsFullScreenVideo() && !m_pPlayer->IsPausedPlayback() && m_pPlayer->IsRenderingVideoLayer()) -+ idleSeconds *= !(g_graphicsContext.IsFullScreenVideo() && !m_pPlayer->IsPausedPlayback() && m_pPlayer->IsRenderingVideoLayer()); -+#endif -+ if ((idleSeconds && m_screenSaverTimer.GetElapsedSeconds() > idleSeconds) || !idleSeconds) -+#if defined(TARGET_RASPBERRY_PI) || defined(HAS_IMXVPU) - fps = CSettings::GetInstance().GetInt(CSettings::SETTING_VIDEOPLAYER_LIMITGUIUPDATE); -+#else -+ fps = 5; - #endif - - unsigned int now = XbmcThreads::SystemClockMillis(); -@@ -3882,6 +3920,9 @@ bool CApplication::WakeUpScreenSaverAndDPMS(bool bPowerOffKeyPressed /* = false - CVariant data(CVariant::VariantTypeObject); - data["shuttingdown"] = bPowerOffKeyPressed; - CAnnouncementManager::GetInstance().Announce(GUI, "xbmc", "OnScreensaverDeactivated", data); -+ -+ if (m_screenSaver->ID() == "screensaver.xbmc.builtin.black") -+ g_screen.SetOn(); - #ifdef TARGET_ANDROID - // Screensaver deactivated -> acquire wake lock - CXBMCApp::EnableWakeLock(true); -@@ -4377,6 +4418,62 @@ void CApplication::ShowAppMigrationMessage() - } - } - -+void CApplication::ChangeVT(int newVT) -+{ -+ std::string cmd = StringUtils::Format("sudo /sbin/start xbian-chvt TTYNR=%d", newVT); -+ CLog::Log(LOGINFO,"%s : activating tty%d", __FUNCTION__, newVT); -+ system(cmd.c_str()); -+} -+ -+void CApplication::checkVTchange() -+{ -+ struct vt_stat vts; -+ static int last_active; -+ -+ int cur_tty = open("/dev/tty0", O_RDONLY | O_NONBLOCK | O_NOCTTY); -+ if(cur_tty < 0 || ioctl(cur_tty, VT_GETSTATE, &vts) < 0) -+ goto out; -+ -+ if (last_active != vts.v_active && m_ourVT >= 0) -+ { -+ // We are back home -+ if (m_ourVT == vts.v_active) -+ { -+ CLog::Log(LOGDEBUG,"%s : our VT active again", __func__); -+ CWinEvents::Stop(false); -+#ifdef HAS_IMXVPU -+ g_IMXContext.Unblank(); -+#endif -+ SetRenderGUI(true); -+ g_graphicsContext.SetFullScreenVideo(g_graphicsContext.IsFullScreenVideo()); -+ //g_VideoReferenceClock.Start(); -+ } -+ else -+ { -+ CLog::Log(LOGDEBUG,"%s : our VT being deactivated", __func__); -+ SetRenderGUI(false); -+ //g_VideoReferenceClock.Stop(); -+#ifdef HAS_IMXVPU -+ g_IMXContext.Blank(); -+#endif -+ { -+ CSingleLock lock(g_graphicsContext); -+ g_graphicsContext.Clear(0); -+ g_windowManager.Render(); -+ } -+ CWinEvents::Stop(true); -+ } -+ } -+ else if (m_ourVT < 0) -+ m_ourVT = vts.v_active; -+ -+ last_active = vts.v_active; -+ -+out: -+ if (cur_tty > -1) -+ close(cur_tty); -+} -+ - void CApplication::Process() - { - MEASURE_FUNCTION; -@@ -4422,6 +4519,12 @@ void CApplication::Process() - // update sound - m_pPlayer->DoAudioWork(); - -+ if( m_slowTimerVT.GetElapsedMilliseconds() > 100) -+ { -+ m_slowTimerVT.Reset(); -+ checkVTchange(); -+ } -+ - // do any processing that isn't needed on each run - if( m_slowTimer.GetElapsedMilliseconds() > 500 ) - { -@@ -4510,6 +4613,10 @@ void CApplication::ProcessSlow() - gNfsConnection.CheckIfIdle(); - #endif - -+#ifdef HAS_FILESYSTEM_AFP -+ gAfpConnection.CheckIfIdle(); -+#endif -+ - #ifdef HAS_FILESYSTEM_SFTP - CSFTPSessionManager::ClearOutIdleSessions(); - #endif -@@ -5158,7 +5265,11 @@ void CApplication::CloseNetworkShares() - #ifdef HAS_FILESYSTEM_NFS - gNfsConnection.Deinit(); - #endif -- -+ -+#ifdef HAS_FILESYSTEM_AFP -+ gAfpConnection.Deinit(); -+#endif -+ - #ifdef HAS_FILESYSTEM_SFTP - CSFTPSessionManager::DisconnectAllSessions(); - #endif -diff --git a/xbmc/Application.h b/xbmc/Application.h -index fc4f69c..e38712f 100644 ---- a/xbmc/Application.h -+++ b/xbmc/Application.h -@@ -74,6 +74,8 @@ namespace MEDIA_DETECT - #include "ApplicationPlayer.h" - #include "interfaces/IActionListener.h" - -+#include "guilib/Resolution.h" -+ - class CSeekHandler; - class CInertialScrollingHandler; - class DPMSSupport; -@@ -143,7 +145,7 @@ public: - virtual bool Create() override; - virtual bool Cleanup() override; - -- bool CreateGUI(); -+ bool CreateGUI(bool showXBMCSplash); - bool InitWindow(RESOLUTION res = RES_INVALID); - bool DestroyWindow(); - void StartServices(); -@@ -401,6 +403,9 @@ public: - */ - void UnlockFrameMoveGuard(); - -+ bool ScreenSaverDisablesAutoScrolling(); -+ void ChangeVT(int newVT); -+ - protected: - virtual bool OnSettingsSaving() const override; - -@@ -427,6 +432,9 @@ protected: - bool m_saveSkinOnUnloading; - bool m_autoExecScriptExecuted; - -+ int m_ourVT; -+ void checkVTchange(); -+ - #if defined(TARGET_DARWIN_IOS) - friend class CWinEventsIOS; - #endif -@@ -449,6 +457,7 @@ protected: - CStopWatch m_frameTime; - CStopWatch m_navigationTimer; - CStopWatch m_slowTimer; -+ CStopWatch m_slowTimerVT; - CStopWatch m_shutdownTimer; - - bool m_bInhibitIdleShutdown; -diff --git a/xbmc/PlayListPlayer.cpp b/xbmc/PlayListPlayer.cpp -index d65087b..3e5e4c2 100644 ---- a/xbmc/PlayListPlayer.cpp -+++ b/xbmc/PlayListPlayer.cpp -@@ -904,7 +904,6 @@ void PLAYLIST::CPlayListPlayer::OnApplicationMessage(KODI::MESSAGING::ThreadMess - g_windowManager.PreviousWindow(); - - g_application.ResetScreenSaver(); -- g_application.WakeUpScreenSaverAndDPMS(); - - // stop playing file - if (g_application.m_pPlayer->IsPlaying()) g_application.StopPlaying(); -@@ -915,7 +914,6 @@ void PLAYLIST::CPlayListPlayer::OnApplicationMessage(KODI::MESSAGING::ThreadMess - if (g_application.m_pPlayer->HasPlayer()) - { - g_application.ResetScreenSaver(); -- g_application.WakeUpScreenSaverAndDPMS(); - g_application.m_pPlayer->Pause(); - } - break; -@@ -933,7 +931,6 @@ void PLAYLIST::CPlayListPlayer::OnApplicationMessage(KODI::MESSAGING::ThreadMess - if (g_application.m_pPlayer->IsPlaying() && !g_application.m_pPlayer->IsPaused()) - { - g_application.ResetScreenSaver(); -- g_application.WakeUpScreenSaverAndDPMS(); - g_application.m_pPlayer->Pause(); - } - break; -diff --git a/xbmc/URL.cpp b/xbmc/URL.cpp -index 2349a80..a53b035 100644 ---- a/xbmc/URL.cpp -+++ b/xbmc/URL.cpp -@@ -292,6 +292,8 @@ void CURL::Parse(const std::string& strURL1) - if (m_strHostName.empty()) - m_strHostName = strHostNameAndPort; - -+ m_strHostName = URIUtils::CanonizeIPv6(m_strHostName); -+ - if (iSlash != std::string::npos) - { - iPos = iSlash + 1; -diff --git a/xbmc/Util.cpp b/xbmc/Util.cpp -index 148bc09..9996881 100644 ---- a/xbmc/Util.cpp -+++ b/xbmc/Util.cpp -@@ -793,8 +793,8 @@ bool CUtil::CreateDirectoryEx(const std::string& strPath) - // return true if directory already exist - if (CDirectory::Exists(strPath)) return true; - -- // we currently only allow HD and smb and nfs paths -- if (!URIUtils::IsHD(strPath) && !URIUtils::IsSmb(strPath) && !URIUtils::IsNfs(strPath)) -+ // we currently only allow HD and smb, nfs and afp paths -+ if (!URIUtils::IsHD(strPath) && !URIUtils::IsSmb(strPath) && !URIUtils::IsNfs(strPath) && !URIUtils::IsAfp(strPath)) - { - CLog::Log(LOGERROR,"%s called with an unsupported path: %s", __FUNCTION__, strPath.c_str()); - return false; -@@ -846,8 +846,8 @@ std::string CUtil::MakeLegalPath(const std::string &strPathAndFile, int LegalTyp - return MakeLegalPath(CStackDirectory::GetFirstStackedFile(strPathAndFile)); - if (URIUtils::IsMultiPath(strPathAndFile)) - return MakeLegalPath(CMultiPathDirectory::GetFirstPath(strPathAndFile)); -- if (!URIUtils::IsHD(strPathAndFile) && !URIUtils::IsSmb(strPathAndFile) && !URIUtils::IsNfs(strPathAndFile)) -- return strPathAndFile; // we don't support writing anywhere except HD, SMB and NFS - no need to legalize path -+ if (!URIUtils::IsHD(strPathAndFile) && !URIUtils::IsSmb(strPathAndFile) && !URIUtils::IsNfs(strPathAndFile) && !URIUtils::IsAfp(strPathAndFile)) -+ return strPathAndFile; // we don't support writing anywhere except HD, SMB, NFS and AFP - no need to legalize path - - bool trailingSlash = URIUtils::HasSlashAtEnd(strPathAndFile); - std::vector dirs = URIUtils::SplitPath(strPathAndFile); -@@ -1378,7 +1378,7 @@ bool CUtil::MakeShortenPath(std::string StrInput, std::string& StrOutput, size_t - - bool CUtil::SupportsWriteFileOperations(const std::string& strPath) - { -- // currently only hd, smb, nfs and dav support delete and rename -+ // currently only hd, smb, nfs, afp and dav support delete and rename - if (URIUtils::IsHD(strPath)) - return true; - if (URIUtils::IsSmb(strPath)) -@@ -1387,6 +1387,8 @@ bool CUtil::SupportsWriteFileOperations(const std::string& strPath) - return CPVRDirectory::SupportsWriteFileOperations(strPath); - if (URIUtils::IsNfs(strPath)) - return true; -+ if (URIUtils::IsAfp(strPath)) -+ return true; - if (URIUtils::IsDAV(strPath)) - return true; - if (URIUtils::IsStack(strPath)) -@@ -1886,7 +1888,7 @@ void CUtil::ScanForExternalSubtitles(const std::string& strMovie, std::vector threshold && stream->m_syncState == CAESyncInfo::AESyncState::SYNC_INSYNC) - { - stream->m_syncState = CAESyncInfo::AESyncState::SYNC_ADJUST; -- stream->m_processingBuffers->SetRR(1.0); -- stream->m_resampleIntegral = 0; -+ stream->m_processingBuffers->SetRR(stream->GetResampleRatio()); - stream->m_lastSyncError = error; - CLog::Log(LOGDEBUG,"ActiveAE::SyncStream - average error %f above threshold of %f", error, threshold); - } -@@ -2444,6 +2443,7 @@ CSampleBuffer* CActiveAE::SyncStream(CActiveAEStream *stream) - } - } - -+ static double lerr; - if (fabs(error) < 30) - { - if (stream->m_lastSyncError > threshold * 2) -@@ -2455,13 +2455,18 @@ CSampleBuffer* CActiveAE::SyncStream(CActiveAEStream *stream) - } - else - { -+ lerr = threshold; - stream->m_syncState = CAESyncInfo::AESyncState::SYNC_INSYNC; - stream->m_syncError.Flush(1000); -- stream->m_resampleIntegral = 0; -- stream->m_processingBuffers->SetRR(1.0); - CLog::Log(LOGDEBUG,"ActiveAE::SyncStream - average error %f below threshold of %f", error, 30.0); - } - } -+ else -+ { -+ if (lerr && fabs(error) < lerr) -+ stream->m_processingBuffers->SetRR((1.0 / stream->m_pClock->GetClockSpeed() + stream->GetResampleRatio()) / 2); -+ lerr = fabs(error); -+ } - - return ret; - } -@@ -2474,6 +2479,7 @@ CSampleBuffer* CActiveAE::SyncStream(CActiveAEStream *stream) - if (stream->m_processingBuffers) - { - stream->m_processingBuffers->SetRR(stream->CalcResampleRatio(error)); -+ stream->SetResampleRatio(stream->m_processingBuffers->GetRR()); - } - } - else if (stream->m_resampleBuffers) -diff --git a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAESink.cpp b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAESink.cpp -index 1598900..fde70b1 100644 ---- a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAESink.cpp -+++ b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAESink.cpp -@@ -1005,28 +1005,15 @@ unsigned int CActiveAESink::OutputSamples(CSampleBuffer* samples) - { - maxFrames = std::min(frames, m_sinkFormat.m_frames); - written = m_sink->AddPackets(buffer, maxFrames, totalFrames - frames); -- if (written == 0) -+ if (written == 0 && retry++ < 4) - { - Sleep(500*m_sinkFormat.m_frames/m_sinkFormat.m_sampleRate); -- retry++; -- if (retry > 4) -- { -- m_extError = true; -- CLog::Log(LOGERROR, "CActiveAESink::OutputSamples - failed"); -- status.SetDelay(0); -- framesOrPackets = frames; -- if (m_requestedFormat.m_dataFormat == AE_FMT_RAW) -- framesOrPackets = 1; -- m_stats->UpdateSinkDelay(status, samples->pool ? framesOrPackets : 0); -- return 0; -- } -- else -- continue; -+ continue; - } -- else if (written > maxFrames) -+ else if (!written || written > maxFrames) - { - m_extError = true; -- CLog::Log(LOGERROR, "CActiveAESink::OutputSamples - sink returned error"); -+ CLog::Log(LOGERROR, "CActiveAESink::OutputSamples - %s", written ? "sink returned error" : "failed"); - status.SetDelay(0); - framesOrPackets = frames; - if (m_requestedFormat.m_dataFormat == AE_FMT_RAW) -diff --git a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEStream.cpp b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEStream.cpp -index 1d58691..f95e54a 100644 ---- a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEStream.cpp -+++ b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEStream.cpp -@@ -200,11 +200,14 @@ void CActiveAEStream::RemapBuffer() - - double CActiveAEStream::CalcResampleRatio(double error) - { -+ const double maxDiff = 0.02; -+ static double retLast; -+ - //reset the integral on big errors, failsafe - if (fabs(error) > 1000) - m_resampleIntegral = 0; - else if (fabs(error) > 5) -- m_resampleIntegral += error / 1000 / 50; -+ m_resampleIntegral += error / 1000 / 100; - - double proportional = 0.0; - -@@ -215,7 +218,15 @@ double CActiveAEStream::CalcResampleRatio(double error) - if (m_pClock) - clockspeed = m_pClock->GetClockSpeed(); - -- double ret = 1.0 / clockspeed + proportional + m_resampleIntegral; -+ double ret = proportional + m_resampleIntegral; -+ -+ if (ret - retLast > maxDiff) -+ ret = retLast + maxDiff; -+ else if (retLast - ret > maxDiff) -+ ret = retLast - maxDiff; -+ -+ retLast = ret; -+ ret += 1.0 / clockspeed; - //CLog::Log(LOGNOTICE,"----- error: %f, rr: %f, prop: %f, int: %f", - // error, ret, proportional, m_resampleIntegral); - return ret; -diff --git a/xbmc/cores/AudioEngine/Sinks/AESinkALSA.cpp b/xbmc/cores/AudioEngine/Sinks/AESinkALSA.cpp -index 95db8cf..d77707f 100644 ---- a/xbmc/cores/AudioEngine/Sinks/AESinkALSA.cpp -+++ b/xbmc/cores/AudioEngine/Sinks/AESinkALSA.cpp -@@ -926,50 +926,43 @@ unsigned int CAESinkALSA::AddPackets(uint8_t **data, unsigned int frames, unsign - unsigned int amount = 0; - int64_t data_left = (int64_t) frames; - int frames_written = 0; -+ int ret = 0; - -- while (data_left > 0) -+ snd_pcm_nonblock(m_pcm, 0); -+ while (data_left > 0 && HandleError(__func__, ret)) - { - if (m_fragmented) - amount = std::min((unsigned int) data_left, m_originalPeriodSize); - else // take care as we can come here a second time if the sink does not eat all data - amount = (unsigned int) data_left; - -- int ret = snd_pcm_writei(m_pcm, buffer, amount); -- if (ret < 0) -- { -- CLog::Log(LOGERROR, "CAESinkALSA - snd_pcm_writei(%d) %s - trying to recover", ret, snd_strerror(ret)); -- ret = snd_pcm_recover(m_pcm, ret, 1); -- if(ret < 0) -- { -- HandleError("snd_pcm_writei(1)", ret); -- ret = snd_pcm_writei(m_pcm, buffer, amount); -- if (ret < 0) -- { -- HandleError("snd_pcm_writei(2)", ret); -- ret = 0; -- } -- } -- } -+ ret = snd_pcm_writei(m_pcm, buffer, amount); - -- if ( ret > 0 && snd_pcm_state(m_pcm) == SND_PCM_STATE_PREPARED) -+ if (ret < 0) -+ continue; -+ else if (ret > 0 && snd_pcm_state(m_pcm) == SND_PCM_STATE_PREPARED) - snd_pcm_start(m_pcm); - -- if (ret <= 0) -- break; -- - frames_written += ret; - data_left -= ret; - buffer = data[0]+offset*m_format.m_frameSize + frames_written*m_format.m_frameSize; - } -+ - return frames_written; - } - --void CAESinkALSA::HandleError(const char* name, int err) -+inline -+int CAESinkALSA::HandleError(const char* name, int err) - { -+ static int recoveries; -+ -+ if (err >= 0) -+ recoveries = -2; -+ - switch(err) - { - case -EPIPE: -- CLog::Log(LOGERROR, "CAESinkALSA::HandleError(%s) - underrun", name); -+ CLog::Log(LOGDEBUG, "CAESinkALSA::HandleError(%s) - underrun", name); - if ((err = snd_pcm_prepare(m_pcm)) < 0) - CLog::Log(LOGERROR, "CAESinkALSA::HandleError(%s) - snd_pcm_prepare returned %d (%s)", name, err, snd_strerror(err)); - break; -@@ -988,9 +981,11 @@ void CAESinkALSA::HandleError(const char* name, int err) - break; - - default: -- CLog::Log(LOGERROR, "CAESinkALSA::HandleError(%s) - snd_pcm_writei returned %d (%s)", name, err, snd_strerror(err)); - break; - } -+ -+ snd_pcm_avail_update(m_pcm); -+ return recoveries++; - } - - void CAESinkALSA::Drain() -@@ -1027,7 +1022,7 @@ bool CAESinkALSA::TryDevice(const std::string &name, snd_pcm_t **pcmp, snd_confi - int err = snd_pcm_open_lconf(pcmp, name.c_str(), SND_PCM_STREAM_PLAYBACK, ALSA_OPTIONS, lconf); - if (err < 0) - { -- CLog::Log(LOGINFO, "CAESinkALSA - Unable to open device \"%s\" for playback", name.c_str()); -+ CLog::Log(LOGINFO, "CAESinkALSA - Unable to open device \"%s\" for playback (error: %s)", name.c_str(), snd_strerror(err)); - } - - return err == 0; -diff --git a/xbmc/cores/AudioEngine/Sinks/AESinkALSA.h b/xbmc/cores/AudioEngine/Sinks/AESinkALSA.h -index 4ca5941..8de0318 100644 ---- a/xbmc/cores/AudioEngine/Sinks/AESinkALSA.h -+++ b/xbmc/cores/AudioEngine/Sinks/AESinkALSA.h -@@ -73,7 +73,7 @@ private: - #endif - - void GetAESParams(const AEAudioFormat& format, std::string& params); -- void HandleError(const char* name, int err); -+ int HandleError(const char* name, int err); - - std::string m_initDevice; - AEAudioFormat m_initFormat; -diff --git a/xbmc/cores/IPlayer.h b/xbmc/cores/IPlayer.h -index 484dcde..4b07b4e 100644 ---- a/xbmc/cores/IPlayer.h -+++ b/xbmc/cores/IPlayer.h -@@ -173,6 +173,10 @@ enum EINTERLACEMETHOD - - VS_INTERLACEMETHOD_IMX_FASTMOTION = 29, - VS_INTERLACEMETHOD_IMX_FASTMOTION_DOUBLE = 30, -+ VS_INTERLACEMETHOD_IMX_FASTMOTION_DOUBLE_INVERTED = 31, -+ VS_INTERLACEMETHOD_IMX_ADVMOTION = 32, -+ VS_INTERLACEMETHOD_IMX_ADVMOTION_DOUBLE = 33, -+ VS_INTERLACEMETHOD_IMX_WEAVE = 34, - - VS_INTERLACEMETHOD_MAX // do not use and keep as last enum value. - }; -diff --git a/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodec.h b/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodec.h -index a2da9de..99d2bb3 100644 ---- a/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodec.h -+++ b/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodec.h -@@ -311,6 +311,8 @@ public: - */ - virtual void Reopen() {}; - -+ virtual bool GetInterlaced() { return false; } -+ - protected: - CProcessInfo &m_processInfo; - }; -diff --git a/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp b/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp -index e6f46c5..711b071 100644 ---- a/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp -+++ b/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp -@@ -22,11 +22,16 @@ - - #include "settings/AdvancedSettings.h" - #include "threads/SingleLock.h" --#include "threads/Atomics.h" - #include "utils/log.h" --#include "DVDClock.h" - #include "windowing/WindowingFactory.h" - #include "cores/VideoPlayer/VideoRenderers/RenderFlags.h" -+#include "guilib/GraphicContext.h" -+#include "utils/StringUtils.h" -+#include "settings/MediaSettings.h" -+#include "cores/VideoPlayer/VideoRenderers/BaseRenderer.h" -+ -+#include "linux/imx/IMX.h" -+#include "libavcodec/avcodec.h" - - #include - #include -@@ -36,33 +41,76 @@ - #include - #include - #include -+#include -+#include -+ -+#define FRAME_ALIGN 16 -+#define MEDIAINFO 1 -+#define RENDER_QUEUE_SIZE NUM_BUFFERS -+#define DECODE_OUTPUT_SIZE 15 -+#define IN_DECODER_SET -1 - --#define IMX_VDI_MAX_WIDTH 968 --#define FRAME_ALIGN 16 --#define MEDIAINFO 1 --#define RENDER_QUEUE_SIZE 3 - #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)) - #define Align2(ptr,align) (((unsigned int)ptr)/(align)*(align)) -+#define ALIGN Align -+ -+#define BIT(nr) (1UL << (nr)) -+#define SZ_4K 4*1024 -+ -+#ifdef TRACE_FRAMES -+unsigned char CDVDVideoCodecIMXBuffer::i = 0; -+#endif - -+CIMXContext g_IMXContext; -+std::shared_ptr g_IMXCodec; - --// Global instance --CIMXContext g_IMXContext; -+std::list m_recycleBuffers; - - // Number of fb pages used for paning --const int CIMXContext::m_fbPages = 2; -+const int CIMXContext::m_fbPages = 3; - - // Experiments show that we need at least one more (+1) VPU buffer than the min value returned by the VPU --const int CDVDVideoCodecIMX::m_extraVpuBuffers = 1+RENDER_QUEUE_SIZE+2; --const int CDVDVideoCodecIMX::m_maxVpuDecodeLoops = 5; --CCriticalSection CDVDVideoCodecIMX::m_codecBufferLock; -+const unsigned int CIMXCodec::m_extraVpuBuffers = 2 + RENDER_QUEUE_SIZE; -+ -+CDVDVideoCodecIMX::~CDVDVideoCodecIMX() -+{ -+ m_IMXCodec.reset(); -+ if (g_IMXCodec.use_count() == 1) -+ g_IMXCodec.reset(); -+} -+ -+bool CDVDVideoCodecIMX::Open(CDVDStreamInfo &hints, CDVDCodecOptions &options) -+{ -+ if (!g_IMXCodec) -+ { -+ m_IMXCodec.reset(new CIMXCodec); -+ g_IMXCodec = m_IMXCodec; -+ } -+ else -+ m_IMXCodec = g_IMXCodec; - --bool CDVDVideoCodecIMX::VpuAllocBuffers(VpuMemInfo *pMemBlock) -+ return g_IMXCodec->Open(hints, options, m_pFormatName); -+} -+ -+unsigned CDVDVideoCodecIMX::GetAllowedReferences() -+{ -+ return RENDER_QUEUE_SIZE; -+} -+ -+bool CDVDVideoCodecIMX::ClearPicture(DVDVideoPicture* pDvdVideoPicture) -+{ -+ if (pDvdVideoPicture) -+ SAFE_RELEASE(pDvdVideoPicture->IMXBuffer); -+ -+ return true; -+} -+ -+bool CIMXCodec::VpuAllocBuffers(VpuMemInfo *pMemBlock) - { - int i, size; - void* ptr; - VpuMemDesc vpuMem; -- VpuDecRetCode ret; - - for(i=0; inSubBlockNum; i++) - { -@@ -72,9 +120,10 @@ bool CDVDVideoCodecIMX::VpuAllocBuffers(VpuMemInfo *pMemBlock) - ptr = malloc(size); - if(ptr == NULL) - { -- CLog::Log(LOGERROR, "%s - Unable to malloc %d bytes.\n", __FUNCTION__, size); -- goto AllocFailure; -+ ExitError("%s - Unable to malloc %d bytes.\n", size); -+ return false; - } -+ - pMemBlock->MemSubBlock[i].pVirtAddr = (unsigned char*)Align(ptr, pMemBlock->MemSubBlock[i].nAlignment); - - m_decMemInfo.nVirtNum++; -@@ -84,48 +133,27 @@ bool CDVDVideoCodecIMX::VpuAllocBuffers(VpuMemInfo *pMemBlock) - 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; -- } -+ if(!VpuAlloc(&vpuMem)) -+ return false; -+ - 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; i=m_decMemInfo.nPhyNum - freePhyNum; i--) - { - vpuMem.nPhyAddr = m_decMemInfo.phyMem[i].nPhyAddr; - vpuMem.nVirtAddr = m_decMemInfo.phyMem[i].nVirtAddr; -@@ -152,24 +181,31 @@ bool CDVDVideoCodecIMX::VpuFreeBuffers() - { - CLog::Log(LOGERROR, "%s - Error while trying to free physical memory (%d).\n", __FUNCTION__, ret); - ret = false; -+ break; - } -+ else -+ released++; -+ } -+ -+ m_decMemInfo.nPhyNum -= released; -+ if (!m_decMemInfo.nPhyNum) -+ { -+ free(m_decMemInfo.phyMem); -+ m_decMemInfo.phyMem = NULL; - } -- free(m_decMemInfo.phyMem); -- m_decMemInfo.phyMem = NULL; -- m_decMemInfo.nPhyNum = 0; - } - -+ m_vpuFrameBuffers.clear(); - return ret; - } - - --bool CDVDVideoCodecIMX::VpuOpen() -+bool CIMXCodec::VpuOpen() - { - VpuDecRetCode ret; - VpuVersionInfo vpuVersion; - VpuMemInfo memInfo; -- VpuDecConfig config; -- int param; -+ int param; - - memset(&memInfo, 0, sizeof(VpuMemInfo)); - ret = VPU_DecLoad(); -@@ -207,7 +243,6 @@ bool CDVDVideoCodecIMX::VpuOpen() - #else - m_decOpenParam.nChromaInterleave = 1; - #endif -- m_decOpenParam.nMapType = 0; - m_decOpenParam.nTiled2LinearEnable = 0; - m_decOpenParam.nEnableFileMode = 0; - -@@ -218,44 +253,8 @@ bool CDVDVideoCodecIMX::VpuOpen() - goto VpuOpenError; - } - -- config = VPU_DEC_CONF_SKIPMODE; -- param = VPU_DEC_SKIPNONE; -- ret = VPU_DecConfig(m_vpuHandle, config, ¶m); -- if (ret != VPU_DEC_RET_SUCCESS) -- { -- CLog::Log(LOGERROR, "%s - iMX VPU set skip mode failed (%d).\n", __FUNCTION__, ret); -- goto VpuOpenError; -- } -- -- config = VPU_DEC_CONF_BUFDELAY; - param = 0; -- ret = VPU_DecConfig(m_vpuHandle, config, ¶m); -- if (ret != VPU_DEC_RET_SUCCESS) -- { -- CLog::Log(LOGERROR, "%s - iMX VPU set buffer delay failed (%d).\n", __FUNCTION__, ret); -- goto VpuOpenError; -- } -- -- config = VPU_DEC_CONF_INPUTTYPE; -- param = VPU_DEC_IN_NORMAL; -- ret = VPU_DecConfig(m_vpuHandle, config, ¶m); -- if (ret != VPU_DEC_RET_SUCCESS) -- { -- CLog::Log(LOGERROR, "%s - iMX VPU configure input type failed (%d).\n", __FUNCTION__, ret); -- goto VpuOpenError; -- } -- -- // Note that libvpufsl (file vpu_wrapper.c) associates VPU_DEC_CAP_FRAMESIZE -- // capability to the value of nDecFrameRptEnabled which is in fact directly -- // related to the ability to generate VPU_DEC_ONE_FRM_CONSUMED even if the -- // naming is misleading... -- ret = VPU_DecGetCapability(m_vpuHandle, VPU_DEC_CAP_FRAMESIZE, ¶m); -- m_frameReported = (param != 0); -- if (ret != VPU_DEC_RET_SUCCESS) -- { -- CLog::Log(LOGERROR, "%s - iMX VPU get framesize capability failed (%d).\n", __FUNCTION__, ret); -- m_frameReported = false; -- } -+ SetVPUParams(VPU_DEC_CONF_BUFDELAY, ¶m); - - return true; - -@@ -264,7 +263,26 @@ VpuOpenError: - return false; - } - --bool CDVDVideoCodecIMX::VpuAllocFrameBuffers() -+bool CIMXCodec::VpuAlloc(VpuMemDesc *vpuMem) -+{ -+ VpuDecRetCode ret = VPU_DecGetMem(vpuMem); -+ if (ret) -+ { -+ CLog::Log(LOGERROR, "%s: vpu malloc frame buf of size %d failure: ret=%d \r\n",__FUNCTION__, vpuMem->nSize, ret); -+ return false; -+ } -+ -+ 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; -+ -+ return true; -+} -+ -+bool CIMXCodec::VpuAllocFrameBuffers() - { - int totalSize = 0; - int ySize = 0; -@@ -274,14 +292,12 @@ bool CDVDVideoCodecIMX::VpuAllocFrameBuffers() - int yStride = 0; - int uvStride = 0; - -- VpuDecRetCode ret; - VpuMemDesc vpuMem; - unsigned char* ptr; - unsigned char* ptrVirt; - int nAlign; - -- m_vpuFrameBufferNum = m_initInfo.nMinFrameBufferCount + m_extraVpuBuffers; -- m_vpuFrameBuffers = new VpuFrameBuffer[m_vpuFrameBufferNum]; -+ int nrBuf = std::min(m_initInfo.nMinFrameBufferCount + m_extraVpuBuffers + DECODE_OUTPUT_SIZE, (unsigned int)30); - - yStride = Align(m_initInfo.nPicWidth,FRAME_ALIGN); - if(m_initInfo.nInterlace) -@@ -309,7 +325,7 @@ bool CDVDVideoCodecIMX::VpuAllocFrameBuffers() - uSize = vSize = mvSize = ySize; - break; - default: -- CLog::Log(LOGERROR, "%s: invalid source format in init info\n",__FUNCTION__,ret); -+ CLog::Log(LOGERROR, "%s: invalid source format in init info\n",__FUNCTION__); - return false; - } - -@@ -329,27 +345,18 @@ bool CDVDVideoCodecIMX::VpuAllocFrameBuffers() - mvSize = Align(mvSize, nAlign); - } - -- m_outputBuffers = new CDVDVideoCodecIMXBuffer*[m_vpuFrameBufferNum]; -- -- for (int i=0 ; i < m_vpuFrameBufferNum; i++) -+ totalSize = ySize + uSize + vSize + mvSize + nAlign; -+ for (int i=0 ; i < nrBuf; i++) - { -- totalSize = ySize + uSize + vSize + mvSize + nAlign; -- - vpuMem.nSize = totalSize; -- ret = VPU_DecGetMem(&vpuMem); -- if(ret != VPU_DEC_RET_SUCCESS) -+ if(!VpuAlloc(&vpuMem)) - { -- CLog::Log(LOGERROR, "%s: vpu malloc frame buf failure: ret=%d \r\n",__FUNCTION__,ret); -- return false; -- } -+ if (m_vpuFrameBuffers.size() < m_initInfo.nMinFrameBufferCount + m_extraVpuBuffers) -+ 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; -+ CLog::Log(LOGWARNING, "%s: vpu can't allocate sufficient extra buffers. specify bigger CMA e.g. cma=320M.\r\n",__FUNCTION__); -+ break; -+ } - - //fill frameBuf - ptr = (unsigned char*)vpuMem.nPhyAddr; -@@ -362,6 +369,9 @@ bool CDVDVideoCodecIMX::VpuAllocFrameBuffers() - ptrVirt = (unsigned char*)Align(ptrVirt,nAlign); - } - -+ VpuFrameBuffer vpuFrameBuffer; -+ m_vpuFrameBuffers.push_back(vpuFrameBuffer); -+ - // fill stride info - m_vpuFrameBuffers[i].nStrideY = yStride; - m_vpuFrameBuffers[i].nStrideC = uvStride; -@@ -390,53 +400,66 @@ bool CDVDVideoCodecIMX::VpuAllocFrameBuffers() - 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 -- // Those buffers are ours so lock them to prevent destruction -- m_outputBuffers[i]->Lock(); - } - -+ if (VPU_DEC_RET_SUCCESS != VPU_DecRegisterFrameBuffer(m_vpuHandle, &m_vpuFrameBuffers[0], m_vpuFrameBuffers.size())) -+ return false; -+ -+ m_decOutput.setquotasize(m_vpuFrameBuffers.size() - m_initInfo.nMinFrameBufferCount - m_extraVpuBuffers); - return true; - } - --CDVDVideoCodecIMX::CDVDVideoCodecIMX(CProcessInfo &processInfo) : CDVDVideoCodec(processInfo) -+CIMXCodec::CIMXCodec() -+ : CThread("iMX VPU") -+ , m_dropped(0) -+ , m_lastPTS(DVD_NOPTS_VALUE) -+ , m_codecControlFlags(0) -+ , m_decSignal(0) -+ , m_threadID(0) -+ , m_decRet(VPU_DEC_INPUT_NOT_USED) -+ , m_fps(-1) - { -- m_pFormatName = "iMX-xxx"; - m_vpuHandle = 0; -- m_vpuFrameBuffers = NULL; -- m_outputBuffers = NULL; -- m_lastBuffer = NULL; -- m_currentBuffer = NULL; -- m_extraMem = NULL; -- m_vpuFrameBufferNum = 0; -- m_dropState = false; -- m_convert_bitstream = false; -- m_frameCounter = 0; -- m_usePTS = true; -- if (getenv("IMX_NOPTS") != NULL) -- { -- m_usePTS = false; -- } - m_converter = NULL; -- m_convert_bitstream = false; -- m_bytesToBeConsumed = 0; -- m_previousPts = DVD_NOPTS_VALUE; - #ifdef DUMP_STREAM - m_dump = NULL; - #endif -+ m_drainMode = VPU_DEC_IN_NORMAL; -+ m_skipMode = VPU_DEC_SKIPNONE; -+ -+ m_decOutput.setquotasize(1); -+ m_decInput.setquotasize(20); -+ m_loaded.Reset(); - } - --CDVDVideoCodecIMX::~CDVDVideoCodecIMX() -+CIMXCodec::~CIMXCodec() - { -- Dispose(); -+ StopThread(false); -+ ProcessSignals(SIGNAL_SIGNAL); -+ SetDrainMode(VPU_DEC_IN_DRAIN); -+ StopThread(); - } - --bool CDVDVideoCodecIMX::Open(CDVDStreamInfo &hints, CDVDCodecOptions &options) -+void CIMXCodec::DisposeDecQueues() -+{ -+ m_decInput.signal(); -+ m_decInput.for_each(Release); -+ m_decOutput.signal(); -+ m_decOutput.for_each(Release); -+} -+ -+void CIMXCodec::Reset() -+{ -+ m_queuesLock.lock(); -+ DisposeDecQueues(); -+ ProcessSignals(SIGNAL_FLUSH); -+ CLog::Log(LOGVIDEO, "iMX VPU : queues cleared ===== in/out %d/%d =====\n", m_decInput.size(), m_decOutput.size()); -+} -+ -+bool CIMXCodec::Open(CDVDStreamInfo &hints, CDVDCodecOptions &options, std::string &m_pFormatName) - { -+ CSingleLock lk(m_openLock); -+ - if (hints.software) - { - CLog::Log(LOGNOTICE, "iMX VPU : software decoding requested.\n"); -@@ -447,7 +470,7 @@ bool CDVDVideoCodecIMX::Open(CDVDStreamInfo &hints, CDVDCodecOptions &options) - CLog::Log(LOGNOTICE, "iMX VPU : software decoding forced - video dimensions out of spec: %d %d.", hints.width, hints.height); - return false; - } -- else if (hints.stills) -+ else if (hints.stills && hints.dvd) - return false; - - #ifdef DUMP_STREAM -@@ -468,24 +491,25 @@ bool CDVDVideoCodecIMX::Open(CDVDStreamInfo &hints, CDVDCodecOptions &options) - #endif - - m_hints = hints; -- if (g_advancedSettings.CanLogComponent(LOGVIDEO)) -- CLog::Log(LOGDEBUG, "Let's decode with iMX VPU\n"); -+ CLog::Log(LOGVIDEO, "Let's decode with iMX VPU\n"); -+ -+ int param = 0; -+ SetVPUParams(VPU_DEC_CONF_INPUTTYPE, ¶m); -+ SetVPUParams(VPU_DEC_CONF_SKIPMODE, ¶m); - - #ifdef MEDIAINFO -- if (g_advancedSettings.CanLogComponent(LOGVIDEO)) - { -- CLog::Log(LOGDEBUG, "Decode: MEDIAINFO: fpsrate %d / fpsscale %d\n", m_hints.fpsrate, m_hints.fpsscale); -- CLog::Log(LOGDEBUG, "Decode: MEDIAINFO: CodecID %d \n", m_hints.codec); -- CLog::Log(LOGDEBUG, "Decode: MEDIAINFO: StreamType %d \n", m_hints.type); -- CLog::Log(LOGDEBUG, "Decode: MEDIAINFO: Level %d \n", m_hints.level); -- CLog::Log(LOGDEBUG, "Decode: MEDIAINFO: Profile %d \n", m_hints.profile); -- CLog::Log(LOGDEBUG, "Decode: MEDIAINFO: PTS_invalid %d \n", m_hints.ptsinvalid); -- CLog::Log(LOGDEBUG, "Decode: MEDIAINFO: Tag %d \n", m_hints.codec_tag); -- CLog::Log(LOGDEBUG, "Decode: MEDIAINFO: %dx%d \n", m_hints.width, m_hints.height); -+ CLog::Log(LOGVIDEO, "Decode: MEDIAINFO: fpsrate %d / fpsscale %d\n", m_hints.fpsrate, m_hints.fpsscale); -+ CLog::Log(LOGVIDEO, "Decode: MEDIAINFO: CodecID %d \n", m_hints.codec); -+ CLog::Log(LOGVIDEO, "Decode: MEDIAINFO: StreamType %d \n", m_hints.type); -+ CLog::Log(LOGVIDEO, "Decode: MEDIAINFO: Level %d \n", m_hints.level); -+ CLog::Log(LOGVIDEO, "Decode: MEDIAINFO: Profile %d \n", m_hints.profile); -+ CLog::Log(LOGVIDEO, "Decode: MEDIAINFO: PTS_invalid %d \n", m_hints.ptsinvalid); -+ CLog::Log(LOGVIDEO, "Decode: MEDIAINFO: Tag %d \n", m_hints.codec_tag); -+ CLog::Log(LOGVIDEO, "Decode: MEDIAINFO: %dx%d \n", m_hints.width, m_hints.height); - } -- { uint8_t *pb = (uint8_t*)&m_hints.codec_tag; -- if ((isalnum(pb[0]) && isalnum(pb[1]) && isalnum(pb[2]) && isalnum(pb[3])) && g_advancedSettings.CanLogComponent(LOGVIDEO)) -- CLog::Log(LOGDEBUG, "Decode: MEDIAINFO: Tag fourcc %c%c%c%c\n", pb[0], pb[1], pb[2], pb[3]); -+ { char str_tag[128]; av_get_codec_tag_string(str_tag, sizeof(str_tag), m_hints.codec_tag); -+ CLog::Log(LOGVIDEO, "Decode: MEDIAINFO: Tag fourcc %s\n", str_tag); - } - if (m_hints.extrasize) - { -@@ -494,18 +518,13 @@ bool CDVDVideoCodecIMX::Open(CDVDStreamInfo &hints, CDVDCodecOptions &options) - for (unsigned int i=0; i < m_hints.extrasize; i++) - sprintf(buf+i*2, "%02x", ((uint8_t*)m_hints.extradata)[i]); - -- if (g_advancedSettings.CanLogComponent(LOGVIDEO)) -- CLog::Log(LOGDEBUG, "Decode: MEDIAINFO: extradata %d %s\n", m_hints.extrasize, buf); -- } -- if (g_advancedSettings.CanLogComponent(LOGVIDEO)) -- { -- CLog::Log(LOGDEBUG, "Decode: MEDIAINFO: %d / %d \n", m_hints.width, m_hints.height); -- CLog::Log(LOGDEBUG, "Decode: aspect %f - forced aspect %d\n", m_hints.aspect, m_hints.forced_aspect); -+ CLog::Log(LOGVIDEO, "Decode: MEDIAINFO: extradata %d %s\n", m_hints.extrasize, buf); - } -+ CLog::Log(LOGVIDEO, "Decode: MEDIAINFO: %d / %d \n", m_hints.width, m_hints.height); -+ CLog::Log(LOGVIDEO, "Decode: aspect %f - forced aspect %d\n", m_hints.aspect, m_hints.forced_aspect); - #endif - - m_warnOnce = true; -- m_convert_bitstream = false; - switch(m_hints.codec) - { - case AV_CODEC_ID_MPEG1VIDEO: -@@ -524,8 +543,7 @@ bool CDVDVideoCodecIMX::Open(CDVDStreamInfo &hints, CDVDCodecOptions &options) - case AV_CODEC_ID_H264: - { - // Test for VPU unsupported profiles to revert to sw decoding -- if ((m_hints.profile == 110) || //hi10p -- (m_hints.profile == 578 && m_hints.level == 30)) //quite uncommon h264 profile with Main 3.0 -+ if (m_hints.profile == 110) - { - CLog::Log(LOGNOTICE, "i.MX6 VPU is not able to decode AVC profile %d level %d", m_hints.profile, m_hints.level); - return false; -@@ -536,8 +554,16 @@ bool CDVDVideoCodecIMX::Open(CDVDStreamInfo &hints, CDVDCodecOptions &options) - { - if ( *(char*)hints.extradata == 1 ) - { -- m_converter = new CBitstreamConverter(); -- m_convert_bitstream = m_converter->Open(hints.codec, (uint8_t *)hints.extradata, hints.extrasize, true); -+ m_converter = new CBitstreamConverter(); -+ if (!m_converter->Open(hints.codec, (uint8_t *)m_hints.extradata, m_hints.extrasize, true)) -+ { -+ SAFE_DELETE(m_converter); -+ break; -+ } -+ std::free(m_hints.extradata); -+ m_hints.extrasize = m_converter->GetExtraSize(); -+ m_hints.extradata = std::malloc(m_hints.extrasize); -+ std::memcpy(m_hints.extradata, m_converter->GetExtraData(), m_hints.extrasize); - } - } - break; -@@ -570,6 +596,12 @@ bool CDVDVideoCodecIMX::Open(CDVDStreamInfo &hints, CDVDCodecOptions &options) - switch(m_hints.codec_tag) - { - case _4CC('D','I','V','X'): -+ // Test for VPU unsupported profiles to revert to sw decoding -+ if (m_hints.profile == -99 && m_hints.level == -99) -+ { -+ CLog::Log(LOGNOTICE, "i.MX6 iMX-divx4 profile %d level %d - sw decoding", m_hints.profile, m_hints.level); -+ return false; -+ } - m_decOpenParam.CodecFormat = VPU_V_XVID; // VPU_V_DIVX4 - m_pFormatName = "iMX-divx4"; - break; -@@ -598,7 +630,7 @@ bool CDVDVideoCodecIMX::Open(CDVDStreamInfo &hints, CDVDCodecOptions &options) - return true; - } - --void CDVDVideoCodecIMX::Dispose() -+void CIMXCodec::Dispose() - { - #ifdef DUMP_STREAM - if (m_dump) -@@ -608,66 +640,29 @@ void CDVDVideoCodecIMX::Dispose() - } - #endif - -- g_IMXContext.Clear(); -- - VpuDecRetCode ret; - bool VPU_loaded = m_vpuHandle; - -- // Release last buffer -- SAFE_RELEASE(m_lastBuffer); -- SAFE_RELEASE(m_currentBuffer); -- -- Enter(); -- -- // Invalidate output buffers to prevent the renderer from mapping this memory -- for (int i=0; iReleaseFramebuffer(&m_vpuHandle); -- SAFE_RELEASE(m_outputBuffers[i]); -- } -- -- Leave(); -+ RecycleFrameBuffers(); - - 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; -+ else -+ CLog::Log(LOGVIDEO, "%s - VPU closed.", __FUNCTION__); - -- // Release memory -- if (m_outputBuffers != NULL) -- { -- delete m_outputBuffers; -- m_outputBuffers = NULL; -+ m_vpuHandle = 0; - } - - 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) -@@ -675,620 +670,539 @@ void CDVDVideoCodecIMX::Dispose() - m_converter->Close(); - SAFE_DELETE(m_converter); - } -+} - -- return; -+void CIMXCodec::SetVPUParams(VpuDecConfig InDecConf, void* pInParam) -+{ -+ if (m_vpuHandle) -+ if (VPU_DEC_RET_SUCCESS != VPU_DecConfig(m_vpuHandle, InDecConf, pInParam)) -+ CLog::Log(LOGERROR, "%s - iMX VPU set dec param failed (%d).\n", __FUNCTION__, (int)InDecConf); - } - --int CDVDVideoCodecIMX::Decode(BYTE *pData, int iSize, double dts, double pts) -+void CIMXCodec::SetDrainMode(VpuDecInputType drain) - { -- 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; -+ if (m_drainMode == drain) -+ return; - --#ifdef IMX_PROFILE -- static unsigned long long previous, current; --#endif --#if defined(IMX_PROFILE) || defined(IMX_PROFILE_BUFFERS) -- unsigned long long before_dec; --#endif -+ m_drainMode = drain; -+ VpuDecInputType config = drain == IN_DECODER_SET ? VPU_DEC_IN_DRAIN : drain; -+ SetVPUParams(VPU_DEC_CONF_INPUTTYPE, &config); -+ if (drain == VPU_DEC_IN_DRAIN && !EOS()) -+ ProcessSignals(SIGNAL_SIGNAL); -+} - --#ifdef DUMP_STREAM -- if (m_dump != NULL) -+void CIMXCodec::SetSkipMode(VpuDecSkipMode skip) -+{ -+ if (m_skipMode == skip) -+ return; -+ -+ m_skipMode = skip; -+ VpuDecSkipMode config = skip == IN_DECODER_SET ? VPU_DEC_SKIPB : skip; -+ SetVPUParams(VPU_DEC_CONF_SKIPMODE, &config); -+} -+ -+bool CIMXCodec::GetCodecStats(double &pts, int &droppedFrames, int &skippedPics) -+{ -+ droppedFrames = m_dropped; -+ skippedPics = -1; -+ m_dropped = 0; -+ pts = m_lastPTS; -+ return true; -+} -+ -+void CIMXCodec::SetCodecControl(int flags) -+{ -+ if (!FBRegistered()) -+ return; -+ -+ m_codecControlFlags = flags; -+ -+ //SetSkipMode(m_codecControlFlags & DVD_CODEC_CTRL_DROP ? VPU_DEC_ISEARCH : VPU_DEC_SKIPNONE); -+ SetDrainMode(m_codecControlFlags & DVD_CODEC_CTRL_DRAIN && !m_decInput.size() ? VPU_DEC_IN_DRAIN : VPU_DEC_IN_NORMAL); -+} -+ -+bool CIMXCodec::getOutputFrame(VpuDecOutFrameInfo *frm) -+{ -+ VpuDecRetCode ret = VPU_DecGetOutputFrame(m_vpuHandle, frm); -+ if(VPU_DEC_RET_SUCCESS != ret) -+ CLog::Log(LOGERROR, "%s - VPU Cannot get output frame(%d).\n", __FUNCTION__, ret); -+ return ret == VPU_DEC_RET_SUCCESS; -+} -+ -+int CIMXCodec::Decode(BYTE *pData, int iSize, double dts, double pts) -+{ -+ if (EOS() && m_drainMode && !m_decOutput.size()) -+ return VC_BUFFER; -+ -+ int ret = 0; -+ if (!g_IMXCodec->IsRunning()) - { -- if (pData) -+ static double pattern; -+ if (!m_decInput.full()) -+ { -+ ret |= VC_BUFFER; -+ if (dts != DVD_NOPTS_VALUE) -+ { -+ static double last; -+ if (last != 0.0) -+ pattern = (pattern + dts - last) / 2; -+ last = dts; -+ } -+ } -+ else - { -- fwrite(&dts, sizeof(double), 1, m_dump); -- fwrite(&pts, sizeof(double), 1, m_dump); -- fwrite(&iSize, sizeof(int), 1, m_dump); -- fwrite(pData, 1, iSize, m_dump); -+ if (pattern > 0.01) -+ m_fps = (double)DVD_TIME_BASE/pattern; -+ else -+ m_fps = m_hints.fpsscale ? (double)m_hints.fpsrate / m_hints.fpsscale : 60; -+ m_decOpenParam.nMapType = 1; -+ -+ g_IMXCodec->Create(); -+ g_IMXCodec->WaitStartup(); - } - } --#endif - -- SAFE_RELEASE(m_currentBuffer); -+ if (pData) -+ m_decInput.push(new VPUTask({ pData, iSize, 0, 0, 0, pts, dts, 0, 0 }, m_converter)); - -- if (!m_vpuHandle) -+ if (!IsDraining() && -+ (m_decInput.size() < m_decInput.getquotasize() -1)) - { -- VpuOpen(); -- if (!m_vpuHandle) -- return VC_ERROR; -+ ret |= VC_BUFFER; -+ if (!(m_codecControlFlags & DVD_CODEC_CTRL_HURRY) && (m_decInput.size() < m_decInput.getquotasize() /2)) -+ return ret; - } - -- for (int i=0; i < m_vpuFrameBufferNum; i++) -+ if ((m_decOutput.size() >= m_decOutput.getquotasize() /2 || -+ m_drainMode || (m_codecControlFlags & DVD_CODEC_CTRL_HURRY)) && m_decOutput.size()) -+ ret |= VC_PICTURE; -+ -+#ifdef IMX_PROFILE -+ CLog::Log(LOGVIDEO, "%s - demux size: %d dts : %f - pts : %f - addr : 0x%x, return %d ===== in/out %d/%d =====\n", -+ __FUNCTION__, iSize, recalcPts(dts), recalcPts(pts), (uint)pData, ret, m_decInput.size(), m_decOutput.size()); -+#endif -+ -+ if (!ret || m_drainMode) -+ Sleep(5); -+ -+ return ret; -+} -+ -+void CIMXCodec::ReleaseFramebuffer(VpuFrameBuffer* fb) -+{ -+ m_recycleBuffers.push_back(fb); -+} -+ -+void CIMXCodec::RecycleFrameBuffers() -+{ -+ while(!m_recycleBuffers.empty()) - { -- 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); -- } -- } -+ m_pts[m_recycleBuffers.front()] = DVD_NOPTS_VALUE; -+ VPU_DecOutFrameDisplayed(m_vpuHandle, m_recycleBuffers.front()); -+ m_recycleBuffers.pop_front(); - } -+} -+ -+inline -+void CIMXCodec::AddExtraData(VpuBufferNode *bn, bool force) -+{ -+ if ((m_decOpenParam.CodecFormat == VPU_V_MPEG2) || -+ (m_decOpenParam.CodecFormat == VPU_V_VC1_AP)|| -+ (m_decOpenParam.CodecFormat == VPU_V_XVID) || -+ (force)) -+ bn->sCodecData = { (unsigned char *)m_hints.extradata, m_hints.extrasize }; -+ else -+ bn->sCodecData = { nullptr, 0 }; -+} - -+void CIMXCodec::Process() -+{ -+ VpuDecFrameLengthInfo frameLengthInfo; -+ VpuBufferNode inData; -+ VpuBufferNode dummy; -+ VpuDecRetCode ret; -+ int retStatus; -+ VPUTask *task = nullptr; - #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; -+ static unsigned long long previous, current; -+ int freeInfo; - #endif - -- if ((pData && iSize) || -- (m_bytesToBeConsumed)) -+ m_threadID = GetCurrentThreadId(); -+ -+ m_recycleBuffers.clear(); -+ m_pts.clear(); -+ m_loaded.Set(); -+ -+ memset(&dummy, 0, sizeof(dummy)); -+ AddExtraData(&dummy); -+ inData = dummy; -+ -+ VpuOpen(); -+ -+ while (!m_bStop && m_vpuHandle) - { -- //printf("D %f %d\n", pts, iSize); -- 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__); -- } -+ RecycleFrameBuffers(); -+ SAFE_DELETE(task); -+ if (!(task = m_decInput.pop())) -+ task = new VPUTask(); -+ -+#if defined(IMX_PROFILE) || defined(IMX_PROFILE_BUFFERS) -+ unsigned long long before_dec; -+#ifdef IMX_PROFILE -+ current = XbmcThreads::SystemClockMillis(); -+ CLog::Log(LOGVIDEO, "%s - delta time decode : %llu - demux size : %d dts : %f - pts : %f - addr : 0x%x\n", -+ __FUNCTION__, current - previous, task->demux.iSize, recalcPts(task->demux.dts), recalcPts(task->demux.pts), (uint)task->demux.pData); -+ previous = current; -+#endif -+#endif - -- inData.nSize = demuxer_bytes; -+ inData.nSize = task->demux.iSize; - inData.pPhyAddr = NULL; -- inData.pVirAddr = demuxer_content; -- 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; -- } -+ inData.pVirAddr = task->demux.pData; -+ -+ // some streams have problem with getting intial info after seek into (during playback start). -+ // feeding VPU with extra data helps -+ if (!m_vpuFrameBuffers.size() && m_converter && !task->IsEmpty() && m_decRet & VPU_DEC_NO_ENOUGH_INBUF) -+ AddExtraData(&inData, true); - - #ifdef IMX_PROFILE_BUFFERS - static unsigned long long dec_time = 0; - #endif - -- while (true) // Decode as long as the VPU consumes data -+ while (!m_bStop) // Decode as long as the VPU consumes data - { -+ RecycleFrameBuffers(); -+ ProcessSignals(); -+ -+ retStatus = m_decRet & VPU_DEC_SKIP ? VC_USERDATA : 0; -+ - #if defined(IMX_PROFILE) || defined(IMX_PROFILE_BUFFERS) - before_dec = XbmcThreads::SystemClockMillis(); - #endif -- if (m_frameReported) -- m_bytesToBeConsumed += inData.nSize; -- -- ret = VPU_DecDecodeBuf(m_vpuHandle, &inData, &decRet); -+ ret = VPU_DecDecodeBuf(m_vpuHandle, &inData, &m_decRet); - #ifdef IMX_PROFILE_BUFFERS - unsigned long long dec_single_call = XbmcThreads::SystemClockMillis()-before_dec; - dec_time += dec_single_call; - #endif - #ifdef IMX_PROFILE -- CLog::Log(LOGDEBUG, "%s - VPU dec 0x%x decode takes : %lld\n\n", __FUNCTION__, decRet, XbmcThreads::SystemClockMillis() - before_dec); -+ VPU_DecGetNumAvailableFrameBuffers(m_vpuHandle, &freeInfo); -+ CLog::Log(LOGVIDEO, "%s - VPU ret %d dec 0x%x decode takes : %lld free: %d\n\n", __FUNCTION__, ret, m_decRet, XbmcThreads::SystemClockMillis() - before_dec, freeInfo); - #endif - -- if (ret == VPU_DEC_RET_WRONG_CALL_SEQUENCE && -- decRet & VPU_DEC_RESOLUTION_CHANGED) -- { -- VpuFreeBuffers(); -- } -- else if (ret != VPU_DEC_RET_SUCCESS) -+ if (m_drainMode == IN_DECODER_SET) - { -- CLog::Log(LOGERROR, "%s - VPU decode failed with error code %d (0x%x).\n", __FUNCTION__, ret, decRet); -- goto out_error; -+ AddExtraData(&inData); -+ SetDrainMode(VPU_DEC_IN_NORMAL); - } - -- if (decRet & VPU_DEC_INIT_OK || decRet & VPU_DEC_RESOLUTION_CHANGED) -- // VPU decoding init OK : We can retrieve stream info -- { -- ret = VPU_DecGetInitialInfo(m_vpuHandle, &m_initInfo); -- if (ret == VPU_DEC_RET_SUCCESS) -- { -- if (g_advancedSettings.CanLogComponent(LOGVIDEO)) -- { -- 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; -- } -+ if (m_decRet & VPU_DEC_OUTPUT_EOS) -+ break; - -- } -- else -- { -- CLog::Log(LOGERROR, "%s - VPU get initial info failed (%d).\n", __FUNCTION__, ret); -- goto out_error; -- } -- } //VPU_DEC_INIT_OK -+ if (ret != VPU_DEC_RET_SUCCESS && ret != VPU_DEC_RET_FAILURE_TIMEOUT) -+ ExitError("VPU decode failed with error code %d (0x%x).\n", ret, m_decRet); - -- if (decRet & VPU_DEC_ONE_FRM_CONSUMED) -+ if (m_decRet & VPU_DEC_INIT_OK || m_decRet & VPU_DEC_RESOLUTION_CHANGED) -+ // VPU decoding init OK : We can retrieve stream info - { -- ret = VPU_DecGetConsumedFrameInfo(m_vpuHandle, &frameLengthInfo); -- if (ret != VPU_DEC_RET_SUCCESS) -+ m_decOutput.setquotasize(1); -+ if (m_decRet & VPU_DEC_RESOLUTION_CHANGED && m_decOutput.size()) - { -- CLog::Log(LOGERROR, "%s - VPU error retireving info about consummed frame (%d).\n", __FUNCTION__, ret); -+ int returning = m_decOutput.size() + RENDER_QUEUE_SIZE; -+ while (m_recycleBuffers.size() < returning) -+ std::this_thread::yield(); - } -- m_bytesToBeConsumed -= (frameLengthInfo.nFrameLength + frameLengthInfo.nStuffLength); -- if (frameLengthInfo.pFrame) -+ -+ if (VPU_DecGetInitialInfo(m_vpuHandle, &m_initInfo) != VPU_DEC_RET_SUCCESS) -+ ExitError("VPU get initial info failed"); -+ -+ 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 (!VpuFreeBuffers(false) || !VpuAllocFrameBuffers()) -+ ExitError("VPU error while registering frame buffers"); -+ -+ if (m_initInfo.nInterlace && m_fps >= 50 && !m_converter && m_decOpenParam.nMapType == 1) - { -- 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__); -+ m_decOpenParam.nMapType = 0; -+ Dispose(); -+ VpuOpen(); -+ continue; - } -- } //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__); -+ m_decInput.setquotasize(m_initInfo.nMinFrameBufferCount*7); - -- ret = VPU_DecGetOutputFrame(m_vpuHandle, &m_frameInfo); -- if(ret != VPU_DEC_RET_SUCCESS) -+ if (m_decOpenParam.CodecFormat != VPU_V_MPEG2) - { -- CLog::Log(LOGERROR, "%s - VPU Cannot get output frame(%d).\n", __FUNCTION__, ret); -- goto out_error; -+ SetDrainMode((VpuDecInputType)IN_DECODER_SET); -+ inData = dummy; -+ continue; - } -+ } -+ -+ if (m_decRet & VPU_DEC_ONE_FRM_CONSUMED) -+ if (!VPU_DecGetConsumedFrameInfo(m_vpuHandle, &frameLengthInfo) && frameLengthInfo.pFrame) -+ m_pts[frameLengthInfo.pFrame] = task->demux.pts; - -+ if (m_decRet & CLASS_PICTURE && getOutputFrame(&m_frameInfo)) -+ { - // 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); - -- idx = VpuFindBuffer(m_frameInfo.pDisplayFrameBuf->pbufY); -- if (idx != -1) -- { -- CDVDVideoCodecIMXBuffer *buffer = m_outputBuffers[idx]; -+ CDVDVideoCodecIMXBuffer *buffer = new CDVDVideoCodecIMXBuffer(&m_frameInfo, m_fps, m_decOpenParam.nMapType); - -- /* quick & dirty fix to get proper timestamping for VP8 codec */ -- if (m_decOpenParam.CodecFormat == VPU_V_VP8) -- buffer->SetPts(pts); -+ /* quick & dirty fix to get proper timestamping for VP8 codec */ -+ if (m_decOpenParam.CodecFormat == VPU_V_VP8) -+ buffer->SetPts(task->demux.pts); -+ else -+ buffer->SetPts(m_pts[m_frameInfo.pDisplayFrameBuf]); - -- buffer->Lock(); -- buffer->SetDts(dts); -- buffer->Queue(&m_frameInfo, m_lastBuffer); -+ buffer->SetDts(task->demux.dts); - - #ifdef IMX_PROFILE_BUFFERS -- CLog::Log(LOGNOTICE, "+D %f %lld\n", buffer->GetPts(), dec_time); -- dec_time = 0; -+ CLog::Log(LOGVIDEO, "+D %f %lld\n", recalcPts(buffer->GetPts()), dec_time); -+ dec_time = 0; - #endif -- - #ifdef TRACE_FRAMES -- CLog::Log(LOGDEBUG, "+ %02d dts %f pts %f (VPU)\n", idx, dts, pts); -- CLog::Log(LOGDEBUG, "+ %02d dts %f pts %f (VPU)\n", idx, buffer->GetDts(), buffer->GetPts()); -+ CLog::Log(LOGVIDEO, "+ 0x%x dts %f pts %f (VPU)\n", buffer->GetIdx(), recalcPts(task->demux.dts), recalcPts(buffer->GetPts())); - #endif - -- if (!m_usePTS) -- { -- buffer->SetPts(DVD_NOPTS_VALUE); -- buffer->SetDts(DVD_NOPTS_VALUE); -- } -- -- // Save last buffer -- SAFE_RELEASE(m_lastBuffer); -- m_lastBuffer = buffer; -- m_lastBuffer->Lock(); -- - #ifdef IMX_PROFILE_BUFFERS -- static unsigned long long lastD = 0; -- unsigned long long current = XbmcThreads::SystemClockMillis(), tmp; -- CLog::Log(LOGNOTICE, "+V %f %lld\n", buffer->GetPts(), current-lastD); -- lastD = current; -+ static unsigned long long lastD = 0; -+ unsigned long long current = XbmcThreads::SystemClockMillis(); -+ CLog::Log(LOGVIDEO, "+V %f %lld\n", recalcPts(buffer->GetPts()), current-lastD); -+ lastD = current; - #endif - -- m_currentBuffer = buffer; -+ if (m_decRet & VPU_DEC_OUTPUT_DIS) -+ buffer->SetFlags(DVP_FLAG_ALLOCATED); - -- if (m_currentBuffer) -- { -- retStatus |= VC_PICTURE; -- } -- } -- } //VPU_DEC_OUTPUT_DIS -+ if (!m_decOutput.push(buffer)) -+ SAFE_RELEASE(buffer); -+ else -+ m_lastPTS = buffer->GetPts(); - -- // 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. -- else 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; -- } -+ } -+ else if (m_decRet & CLASS_DROP) -+ m_dropped++; - -- // 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 (m_decRet & VPU_DEC_SKIP) -+ m_dropped++; - -- else if (decRet & VPU_DEC_OUTPUT_REPEAT) -- { -- if (g_advancedSettings.CanLogComponent(LOGVIDEO)) -- CLog::Log(LOGDEBUG, "%s - Frame repeat.\n", __FUNCTION__); -- m_dropState = true; -- } -- else if (decRet & VPU_DEC_NO_ENOUGH_BUF) -+ if (m_decRet & VPU_DEC_NO_ENOUGH_BUF && m_decOutput.size()) - { -- CLog::Log(LOGERROR, "%s - No frame buffer available.\n", __FUNCTION__); -- } -- else if (decRet & VPU_DEC_SKIP) -- { -- if (g_advancedSettings.CanLogComponent(LOGVIDEO)) -- CLog::Log(LOGDEBUG, "%s - Frame skipped.\n", __FUNCTION__); -- } -- else if (decRet & VPU_DEC_FLUSH) -- { -- CLog::Log(LOGNOTICE, "%s - VPU requires a flush.\n", __FUNCTION__); -- Reset(); -- retStatus = VC_FLUSHED; -- } -- else if (decRet & VPU_DEC_OUTPUT_EOS) -- { -- CLog::Log(LOGNOTICE, "%s - EOS encountered.\n", __FUNCTION__); -+ m_decOutput.pop()->Release(); -+ FlushVPU(); -+ continue; - } - -- if (decRet & (VPU_DEC_NO_ENOUGH_INBUF | -- VPU_DEC_OUTPUT_REPEAT | VPU_DEC_OUTPUT_DIS)) -- { -- // We are done with VPU decoder that time -- break; -- } -+ ProcessSignals(); - -- retries++; -- if (retries >= m_maxVpuDecodeLoops) -- { -- CLog::Log(LOGERROR, "%s - Leaving VPU decoding loop after %d iterations\n", __FUNCTION__, m_maxVpuDecodeLoops); -+ if (retStatus & VC_USERDATA) -+ continue; -+ -+ if (m_decRet & CLASS_FORCEBUF) - break; -- } - -- if (!(decRet & VPU_DEC_INPUT_USED)) -- { -- CLog::Log(LOGERROR, "%s - input not used : addr %p size :%d!\n", __FUNCTION__, inData.pVirAddr, inData.nSize); -- } -+ if (!(m_drainMode || -+ m_decRet & (CLASS_NOBUF | CLASS_DROP))) -+ break; - -- // 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; -+ inData = dummy; - } // Decode loop -- } //(pData && iSize) - -- if (!retStatus) -- 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; -- } -- --#ifdef IMX_PROFILE -- CLog::Log(LOGDEBUG, "%s - returns %x - duration %lld\n", __FUNCTION__, retStatus, XbmcThreads::SystemClockMillis() - previous); --#endif -- return retStatus; -+ task->Release(); -+ } // Process() main loop - --out_error: -- return VC_ERROR; -+ ProcessSignals(SIGNAL_RESET | SIGNAL_DISPOSE); - } - --void CDVDVideoCodecIMX::Reset() -+void CIMXCodec::ProcessSignals(int signal) - { -- int ret; -- -- if (g_advancedSettings.CanLogComponent(LOGVIDEO)) -- CLog::Log(LOGDEBUG, "%s - called\n", __FUNCTION__); -+ if (signal & SIGNAL_SIGNAL) -+ { -+ m_decInput.signal(); -+ m_decOutput.signal(); -+ } -+ if (!(m_decSignal | signal)) -+ return; - -- // Release last buffer -- SAFE_RELEASE(m_lastBuffer); -- SAFE_RELEASE(m_currentBuffer); -+ CSingleLock lk(m_signalLock); -+ m_decSignal |= signal & ~SIGNAL_SIGNAL; - -- // Invalidate all buffers -- for(int i=0; i < m_vpuFrameBufferNum; i++) -- m_outputBuffers[i]->ReleaseFramebuffer(&m_vpuHandle); -+ if (!IsCurrentThread()) -+ return; - -- m_frameCounter = 0; -- m_bytesToBeConsumed = 0; -- m_previousPts = DVD_NOPTS_VALUE; -+ int process = m_decSignal; -+ m_decSignal = 0; - -- // Flush VPU -- ret = VPU_DecFlushAll(m_vpuHandle); -- if (ret != VPU_DEC_RET_SUCCESS) -+ if (process & SIGNAL_FLUSH) - { -- CLog::Log(LOGERROR, "%s - VPU flush failed with error code %d.\n", __FUNCTION__, ret); -+ FlushVPU(); -+ m_queuesLock.unlock(); - } -+ if (process & SIGNAL_RESET) -+ DisposeDecQueues(); -+ if (process & SIGNAL_DISPOSE) -+ Dispose(); - } - --unsigned CDVDVideoCodecIMX::GetAllowedReferences() -+void CIMXCodec::FlushVPU() - { -- return RENDER_QUEUE_SIZE; -+ int ret = VPU_DecFlushAll(m_vpuHandle); -+ if (ret != VPU_DEC_RET_SUCCESS && ret != VPU_DEC_RET_INVALID_HANDLE) -+ CLog::Log(LOGERROR, "%s: VPU flush failed with error code %d.\n", __FUNCTION__, ret); - } - --bool CDVDVideoCodecIMX::ClearPicture(DVDVideoPicture* pDvdVideoPicture) -+inline -+void CIMXCodec::ExitError(const char *msg, ...) - { -- if (pDvdVideoPicture) -- { -- SAFE_RELEASE(pDvdVideoPicture->IMXBuffer); -- } -+ va_list va; -+ va_start(va, msg); -+ CLog::Log(LOGERROR, "%s: %s", __FUNCTION__, StringUtils::FormatV(msg, va).c_str()); -+ va_end(va); - -- return true; -+ StopThread(false); - } - --bool CDVDVideoCodecIMX::GetPicture(DVDVideoPicture* pDvdVideoPicture) -+bool CIMXCodec::GetPicture(DVDVideoPicture* pDvdVideoPicture) - { -+ pDvdVideoPicture->IMXBuffer = m_decOutput.pop(); -+ assert(pDvdVideoPicture->IMXBuffer); -+ - #ifdef IMX_PROFILE - static unsigned int previous = 0; - unsigned int current; - - current = XbmcThreads::SystemClockMillis(); -- CLog::Log(LOGDEBUG, "%s tm:%03d\n", __FUNCTION__, current - previous); -+ CLog::Log(LOGDEBUG | LOGVIDEO, "+G 0x%x %f/%f tm:%03d : Interlaced 0x%x\n", pDvdVideoPicture->IMXBuffer->GetIdx(), -+ recalcPts(pDvdVideoPicture->IMXBuffer->GetDts()), recalcPts(pDvdVideoPicture->IMXBuffer->GetPts()), current - previous, -+ m_initInfo.nInterlace ? pDvdVideoPicture->IMXBuffer->GetFieldType() : 0); - previous = current; - #endif - -- if (m_dropState) -- { -- pDvdVideoPicture->iFlags = DVP_FLAG_DROPPED; -- m_dropState = false; -- } -- -- if (m_frameCounter++ && pDvdVideoPicture->iFlags == DVP_FLAG_DROPPED) -- { -- SAFE_RELEASE(m_currentBuffer); -- return true; -- } -- -- pDvdVideoPicture->iFlags = DVP_FLAG_ALLOCATED; -+ pDvdVideoPicture->iFlags = pDvdVideoPicture->IMXBuffer->GetFlags(); - - if (m_initInfo.nInterlace) - { -- if (m_currentBuffer->GetFieldType() == VPU_FIELD_NONE && m_warnOnce) -+ if (pDvdVideoPicture->IMXBuffer->GetFieldType() == VPU_FIELD_NONE && m_warnOnce) - { - m_warnOnce = false; - CLog::Log(LOGWARNING, "Interlaced content reported by VPU, but full frames detected - Please turn off deinterlacing manually."); - } -- else if (m_currentBuffer->GetFieldType() == VPU_FIELD_TB || m_currentBuffer->GetFieldType() == VPU_FIELD_TOP) -+ else if (pDvdVideoPicture->IMXBuffer->GetFieldType() == VPU_FIELD_TB || pDvdVideoPicture->IMXBuffer->GetFieldType() == VPU_FIELD_TOP) - pDvdVideoPicture->iFlags |= DVP_FLAG_TOP_FIELD_FIRST; - - pDvdVideoPicture->iFlags |= DVP_FLAG_INTERLACED; - } - - pDvdVideoPicture->format = RENDER_FMT_IMXMAP; -- 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->iWidth = pDvdVideoPicture->IMXBuffer->m_pctWidth; -+ pDvdVideoPicture->iHeight = pDvdVideoPicture->IMXBuffer->m_pctHeight; - - pDvdVideoPicture->iDisplayWidth = ((pDvdVideoPicture->iWidth * m_frameInfo.pExtInfo->nQ16ShiftWidthDivHeightRatio) + 32767) >> 16; - pDvdVideoPicture->iDisplayHeight = pDvdVideoPicture->iHeight; - -- // Current buffer is locked already -> hot potato -- pDvdVideoPicture->pts = m_currentBuffer->GetPts(); -- pDvdVideoPicture->dts = m_currentBuffer->GetDts(); -+ pDvdVideoPicture->pts = pDvdVideoPicture->IMXBuffer->GetPts(); -+ pDvdVideoPicture->dts = pDvdVideoPicture->IMXBuffer->GetDts(); - -- pDvdVideoPicture->IMXBuffer = m_currentBuffer; -- m_currentBuffer = NULL; -+ if (pDvdVideoPicture->iFlags & DVP_FLAG_DROPPED) -+ SAFE_RELEASE(pDvdVideoPicture->IMXBuffer); - - return true; - } - --void CDVDVideoCodecIMX::SetDropState(bool bDrop) -+void CIMXCodec::SetDropState(bool bDrop) - { - return; -- // 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 (bDrop) - { --#ifdef TRACE_FRAMES -- CLog::Log(LOGDEBUG, "%s : %d\n", __FUNCTION__, bDrop); --#endif -+ if (m_decOutput.size() && !m_bStop) -+ { -+ m_decOutput.pop()->Release(); -+ ++m_dropped; -+ } -+ else if (m_skipMode < 1 && m_speed != DVD_PLAYSPEED_PAUSE) -+ SetSkipMode((VpuDecSkipMode)IN_DECODER_SET); - } - } - --void CDVDVideoCodecIMX::Enter() -+bool CIMXCodec::IsCurrentThread() const - { -- m_codecBufferLock.lock(); -+ return CThread::IsCurrentThread(m_threadID); - } - --void CDVDVideoCodecIMX::Leave() -+std::string CIMXCodec::GetPlayerInfo() - { -- m_codecBufferLock.unlock(); -+ std::ostringstream s; -+ s << "buf In/Out: " << m_decInput.size() << "/" << m_decOutput.size(); -+ return s.str(); - } - - /*******************************************/ --#ifdef TRACE_FRAMES --CDVDVideoCodecIMXBuffer::CDVDVideoCodecIMXBuffer(int idx) -- : m_idx(idx) -- , --#else --CDVDVideoCodecIMXBuffer::CDVDVideoCodecIMXBuffer() -- : --#endif -- m_pts(DVD_NOPTS_VALUE) -- , m_dts(DVD_NOPTS_VALUE) -- , m_frameBuffer(NULL) -- , m_rendered(false) -- , m_previousBuffer(NULL) -+CDVDVideoCodecIMXBuffer::CDVDVideoCodecIMXBuffer(VpuDecOutFrameInfo *frameInfo, double fps, int map) -+ : m_dts(DVD_NOPTS_VALUE) -+ , m_fieldType(frameInfo->eFieldType) -+ , m_frameBuffer(frameInfo->pDisplayFrameBuf) -+ , m_iFlags(DVP_FLAG_DROPPED) -+ , m_convBuffer(nullptr) - { --} - --void CDVDVideoCodecIMXBuffer::SetPts(double pts) --{ -- m_pts = pts; --} -+ m_pctWidth = frameInfo->pExtInfo->FrmCropRect.nRight - frameInfo->pExtInfo->FrmCropRect.nLeft; -+ m_pctHeight = frameInfo->pExtInfo->FrmCropRect.nBottom - frameInfo->pExtInfo->FrmCropRect.nTop; -+ iWidth = frameInfo->pExtInfo->nFrmWidth; -+ iHeight = frameInfo->pExtInfo->nFrmHeight; -+ pVirtAddr = m_frameBuffer->pbufVirtY; -+ pPhysAddr = (int)m_frameBuffer->pbufY; - --void CDVDVideoCodecIMXBuffer::SetDts(double dts) --{ -- m_dts = dts; -+#ifdef IMX_INPUT_FORMAT_I420 -+ iFormat = _4CC('I', '4', '2', '0'); -+#else -+ iFormat = map == 1 ? _4CC('T', 'N', 'V', 'P'): -+ map == 0 ? _4CC('N', 'V', '1', '2'): -+ _4CC('T', 'N', 'V', 'F'); -+#endif -+ m_fps = fps; -+#ifdef TRACE_FRAMES -+ m_idx = i++; -+#endif -+ Lock(); - } - - void CDVDVideoCodecIMXBuffer::Lock() - { -+ long count = ++m_iRefs; - #ifdef TRACE_FRAMES -- long count = AtomicIncrement(&m_iRefs); -- CLog::Log(LOGDEBUG, "R+ %02d - ref : %d (VPU)\n", m_idx, count); --#else -- AtomicIncrement(&m_iRefs); -+ CLog::Log(LOGVIDEO, "R+ 0x%x - ref : %ld (VPU)\n", m_idx, count); - #endif - } - - long CDVDVideoCodecIMXBuffer::Release() - { -- long count = AtomicDecrement(&m_iRefs); -+ long count = --m_iRefs; - #ifdef TRACE_FRAMES -- CLog::Log(LOGDEBUG, "R- %02d - ref : %d (VPU)\n", m_idx, count); -+ CLog::Log(LOGVIDEO, "R- 0x%x - ref : %ld (VPU)\n", m_idx, count); - #endif -- if (count == 2) -- { -- // Only referenced by the codec and its next frame, release the previous -- SAFE_RELEASE(m_previousBuffer); -- } -- else 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; --} -- --void CDVDVideoCodecIMXBuffer::BeginRender() --{ -- CDVDVideoCodecIMX::Enter(); --} -+ if (count) -+ return count; - --void CDVDVideoCodecIMXBuffer::EndRender() --{ -- CDVDVideoCodecIMX::Leave(); --} -+ CIMXCodec::ReleaseFramebuffer(m_frameBuffer); -+ if (m_convBuffer) -+ g2d_free(m_convBuffer); - --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(); -- --#ifdef IMX_INPUT_FORMAT_I420 -- iFormat = _4CC('I', '4', '2', '0'); --#else -- iFormat = _4CC('N', 'V', '1', '2'); --#endif -- iWidth = frameInfo->pExtInfo->nFrmWidth; -- iHeight = frameInfo->pExtInfo->nFrmHeight; -- pVirtAddr = m_frameBuffer->pbufVirtY; -- pPhysAddr = (int)m_frameBuffer->pbufY; -- m_fieldType = 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; -- SetPts(DVD_NOPTS_VALUE); -- SAFE_RELEASE(m_previousBuffer); -- -- return ret; -+ delete this; -+ return 0; - } - - CDVDVideoCodecIMXBuffer::~CDVDVideoCodecIMXBuffer() - { -- assert(m_iRefs == 0); - #ifdef TRACE_FRAMES -- CLog::Log(LOGDEBUG, "~ %02d (VPU)\n", m_idx); -+ CLog::Log(LOGVIDEO, "~ 0x%x (VPU)\n", m_idx); - #endif - } - -@@ -1304,39 +1218,77 @@ CIMXContext::CIMXContext() - , m_bFbIsConfigured(false) - , m_g2dHandle(NULL) - , m_bufferCapture(NULL) -+ , m_CaptureDone(true) - , m_deviceName("/dev/fb1") - { -- // Limit queue to 2 -- m_input.resize(2); -- m_beginInput = m_endInput = m_bufferedInput = 0; -+ m_input.clear(); -+ m_input.setquotasize(m_fbPages); - m_pageCrops = new CRectInt[m_fbPages]; -- CLog::Log(LOGDEBUG, "iMX : Allocated %d render buffers\n", m_fbPages); -+ CLog::Log(LOGVIDEO, "iMX : Allocated %d render buffers\n", m_fbPages); - - SetBlitRects(CRectInt(), CRectInt()); - -- // Start the ipu thread -+ g2dOpenDevices(); - Create(); - } - - CIMXContext::~CIMXContext() - { -- StopThread(false); -+ Stop(false); - Dispose(); - CloseDevices(); -+ g2dCloseDevices(); -+} -+ -+bool CIMXContext::GetFBInfo(const std::string &fbdev, struct fb_var_screeninfo *fbVar) -+{ -+ int fb = open(fbdev.c_str(), O_RDONLY, 0); -+ if (fb < 0) -+ { -+ CLog::Log(LOGWARNING, "iMX : Failed to open /dev/fb0\n"); -+ return false; -+ } -+ -+ int err = ioctl(fb, FBIOGET_VSCREENINFO, fbVar); -+ if (err < 0) -+ CLog::Log(LOGWARNING, "iMX : Failed to query variable screen info at %s\n", fbdev.c_str()); -+ -+ close(fb); -+ return err >= 0; - } - -+void CIMXContext::MemMap(struct fb_fix_screeninfo *fb_fix) -+{ -+ if (m_fbVirtAddr && m_fbPhysSize) -+ { -+ munmap(m_fbVirtAddr, m_fbPhysSize); -+ m_fbVirtAddr = NULL; -+ m_fbPhysAddr = 0; -+ } -+ else if (fb_fix) -+ { -+ m_fbLineLength = fb_fix->line_length; -+ m_fbPhysSize = fb_fix->smem_len; -+ m_fbPageSize = m_fbLineLength * m_fbVar.yres_virtual / m_fbPages; -+ m_fbPhysAddr = fb_fix->smem_start; -+ m_fbVirtAddr = (uint8_t*)mmap(0, m_fbPhysSize, PROT_READ | PROT_WRITE, MAP_SHARED, m_fbHandle, 0); -+ m_fbCurrentPage = 0; -+ Clear(); -+ } -+} - --bool CIMXContext::Configure() -+bool CIMXContext::AdaptScreen(bool allocate) - { - -- if(m_ipuHandle) { -+ if(m_ipuHandle) -+ { - close(m_ipuHandle); - m_ipuHandle = 0; - } - - MemMap(); - -- if(!m_fbHandle) -+ if(!m_fbHandle && !OpenDevices()) - goto Err; - - struct fb_var_screeninfo fbVar; -@@ -1345,8 +1297,10 @@ bool CIMXContext::Configure() - - CLog::Log(LOGNOTICE, "iMX : Changing framebuffer parameters\n"); - -- m_fbWidth = fbVar.xres; -- m_fbHeight = fbVar.yres; -+ m_fbWidth = allocate ? 1920 : fbVar.xres; -+ m_fbHeight = allocate ? 1080 : fbVar.yres; -+ -+ m_fbInterlaced = g_graphicsContext.GetResInfo().dwFlags & D3DPRESENTFLAG_INTERLACED; - - if (!GetFBInfo(m_deviceName, &m_fbVar)) - goto Err; -@@ -1354,9 +1308,9 @@ bool CIMXContext::Configure() - m_fbVar.xoffset = 0; - m_fbVar.yoffset = 0; - -- if (m_currentFieldFmt) -+ if (!allocate && (fbVar.bits_per_pixel == 16 || m_currentFieldFmt || m_fbHeight >= 1080 && m_fps >= 49)) - { -- m_fbVar.nonstd = _4CC('U', 'Y', 'V', 'Y'); -+ m_fbVar.nonstd = _4CC('Y', 'U', 'Y', 'V'); - m_fbVar.bits_per_pixel = 16; - } - else -@@ -1367,29 +1321,37 @@ bool CIMXContext::Configure() - m_fbVar.activate = FB_ACTIVATE_NOW; - m_fbVar.xres = m_fbWidth; - m_fbVar.yres = m_fbHeight; -- // One additional line that is required for deinterlacing -- m_fbVar.yres_virtual = (m_fbVar.yres+1) * m_fbPages; -+ -+ if (m_fbInterlaced) -+ m_fbVar.vmode |= FB_VMODE_INTERLACED; -+ else -+ m_fbVar.vmode &= ~FB_VMODE_INTERLACED; -+ -+ m_fbVar.yres_virtual = (m_fbVar.yres + 1) * m_fbPages; - m_fbVar.xres_virtual = m_fbVar.xres; - - Blank(); - - struct fb_fix_screeninfo fb_fix; -- bool bErr; -- -- if ((bErr = ioctl(m_fbHandle, FBIOPUT_VSCREENINFO, &m_fbVar) < 0)) -- CLog::Log(LOGWARNING, "iMX : Failed to setup %s\n", m_deviceName.c_str()); -- else if ((bErr = ioctl(m_fbHandle, FBIOGET_FSCREENINFO, &fb_fix) < 0)) -- CLog::Log(LOGWARNING, "iMX : Failed to query fixed screen info at %s\n", m_deviceName.c_str()); - -- if (bErr) -+ if (ioctl(m_fbHandle, FBIOPUT_VSCREENINFO, &m_fbVar) == -1) -+ { -+ CLog::Log(LOGWARNING, "iMX : Failed to setup %s (%s)\n", m_deviceName.c_str(), strerror(errno)); -+ goto Err; -+ } -+ else if (ioctl(m_fbHandle, FBIOGET_FSCREENINFO, &fb_fix) == -1) -+ { -+ CLog::Log(LOGWARNING, "iMX : Failed to query fixed screen info at %s (%s)\n", m_deviceName.c_str(), strerror(errno)); - goto Err; -+ } - - MemMap(&fb_fix); - -- if (m_currentFieldFmt) -+ if (m_fbVar.bits_per_pixel == 16 || !RENDER_USE_G2D) - m_ipuHandle = open("/dev/mxc_ipu", O_RDWR, 0); - - Unblank(); -+ - return true; - - Err: -@@ -1397,59 +1359,23 @@ Err: - return false; - } - --bool CIMXContext::GetFBInfo(const std::string &fbdev, struct fb_var_screeninfo *fbVar) --{ -- int fb = open(fbdev.c_str(), O_RDONLY, 0); -- if (fb < 0) -- { -- CLog::Log(LOGWARNING, "iMX : Failed to open /dev/fb0\n"); -- return false; -- } -- -- int err = ioctl(fb, FBIOGET_VSCREENINFO, fbVar); -- if (err < 0) -- CLog::Log(LOGWARNING, "iMX : Failed to query variable screen info at %s\n", fbdev.c_str()); -- -- close(fb); -- return err >= 0; --} -- --void CIMXContext::MemMap(struct fb_fix_screeninfo *fb_fix) --{ -- if (m_fbVirtAddr && m_fbPhysSize) -- { -- munmap(m_fbVirtAddr, m_fbPhysSize); -- m_fbVirtAddr = NULL; -- m_fbPhysAddr = 0; -- } -- else if (fb_fix) -- { -- m_fbLineLength = fb_fix->line_length; -- m_fbPhysSize = fb_fix->smem_len; -- m_fbPageSize = m_fbLineLength * m_fbVar.yres_virtual / m_fbPages; -- m_fbPhysAddr = fb_fix->smem_start; -- m_fbVirtAddr = (uint8_t*)mmap(0, m_fbPhysSize, PROT_READ | PROT_WRITE, MAP_SHARED, m_fbHandle, 0); -- m_fbCurrentPage = 0; -- Clear(); -- } --} -- - void CIMXContext::OnResetDisplay() - { - CSingleLock lk(m_pageSwapLock); -+ -+ CLog::Log(LOGDEBUG, "iMX : %s - going to change screen parameters\n", __FUNCTION__); - m_bFbIsConfigured = false; -- Configure(); -+ AdaptScreen(); - } - - bool CIMXContext::TaskRestart() - { - CLog::Log(LOGINFO, "iMX : %s - restarting IMX rendererer\n", __FUNCTION__); - // Stop the ipu thread -- StopThread(); -+ Stop(); - MemMap(); - CloseDevices(); - -- // Start the ipu thread - Create(); - return true; - } -@@ -1475,7 +1401,27 @@ bool CIMXContext::OpenDevices() - return m_fbHandle > 0; - } - --bool CIMXContext::CloseDevices() -+void CIMXContext::g2dOpenDevices() -+{ -+ // open g2d here to ensure all g2d fucntions are called from the same thread -+ if (!g2d_open(&m_g2dHandle)) -+ return; -+ -+ m_g2dHandle = NULL; -+ CLog::Log(LOGERROR, "%s - Error while trying open G2D\n", __FUNCTION__); -+} -+ -+void CIMXContext::g2dCloseDevices() -+{ -+ // close g2d here to ensure all g2d fucntions are called from the same thread -+ if (m_bufferCapture && !g2d_free(m_bufferCapture)) -+ m_bufferCapture = NULL; -+ -+ if (m_g2dHandle && !g2d_close(m_g2dHandle)) -+ m_g2dHandle = NULL; -+} -+ -+void CIMXContext::CloseDevices() - { - CLog::Log(LOGINFO, "iMX : Closing devices\n"); - -@@ -1490,40 +1436,23 @@ bool CIMXContext::CloseDevices() - close(m_ipuHandle); - m_ipuHandle = 0; - } -- -- return true; --} -- --bool CIMXContext::GetPageInfo(CIMXBuffer *info, int page) --{ -- if (page < 0 || page >= m_fbPages) -- return false; -- -- info->iWidth = m_fbWidth; -- info->iHeight = m_fbHeight; -- info->iFormat = m_fbVar.nonstd; -- info->pPhysAddr = m_fbPhysAddr + page*m_fbPageSize; -- info->pVirtAddr = m_fbVirtAddr + page*m_fbPageSize; -- -- return true; - } - - bool CIMXContext::Blank() - { - if (!m_fbHandle) return false; - -- CSingleLock lk(m_pageSwapLock); - m_bFbIsConfigured = false; -- return ioctl(m_fbHandle, FBIOBLANK, 1) == 0; -+ return ioctl(m_fbHandle, FBIOBLANK, FB_BLANK_NORMAL) == 0; - } - - bool CIMXContext::Unblank() - { - if (!m_fbHandle) return false; - -- CSingleLock lk(m_pageSwapLock); -+ int ret = ioctl(m_fbHandle, FBIOBLANK, FB_BLANK_UNBLANK); - m_bFbIsConfigured = true; -- return ioctl(m_fbHandle, FBIOBLANK, FB_BLANK_UNBLANK) == 0; -+ return ret == 0; - } - - bool CIMXContext::SetVSync(bool enable) -@@ -1539,83 +1468,140 @@ void CIMXContext::SetBlitRects(const CRect &srcRect, const CRect &dstRect) - } - - inline --void CIMXContext::SetFieldData(uint8_t fieldFmt) -+void CIMXContext::SetFieldData(uint8_t fieldFmt, double fps) - { - if (m_bStop || !IsRunning()) - return; - -+ fieldFmt &= -!m_fbInterlaced; -+ -+ bool dr = IsDoubleRate(); - bool deint = !!m_currentFieldFmt; - m_currentFieldFmt = fieldFmt; -- if (!!fieldFmt == deint) -+ -+ if (!!fieldFmt != deint || -+ dr != IsDoubleRate()|| -+ fps != m_fps) -+ m_bFbIsConfigured = false; -+ -+ if (m_bFbIsConfigured) - return; - -- CLog::Log(LOGDEBUG, "iMX : Deinterlacing parameters changed (%s) %s\n", !!fieldFmt ? "active" : "not active", IsDoubleRate() ? "DR" : ""); -+ m_fps = fps; -+ CLog::Log(LOGDEBUG, "iMX : Output parameters changed - deinterlace %s%s, fps: %.3f\n", !!fieldFmt ? "active" : "not active", IsDoubleRate() ? " DR" : "", m_fps); - - CSingleLock lk(m_pageSwapLock); -- m_bFbIsConfigured = false; -- Configure(); -+ AdaptScreen(); - } - --bool CIMXContext::Blit(int page, CIMXBuffer *source_p, CIMXBuffer *source, uint8_t fieldFmt) -+#define MASK1 (IPU_DEINTERLACE_RATE_FRAME1 | RENDER_FLAG_TOP) -+#define MASK2 (IPU_DEINTERLACE_RATE_FRAME1 | RENDER_FLAG_BOT) -+#define VAL1 MASK1 -+#define VAL2 RENDER_FLAG_BOT -+ -+inline -+bool checkIPUStrideOffset(struct ipu_deinterlace *d) - { -- if (page < 0 || page >= m_fbPages) -- return false; -+ switch (d->motion) -+ { -+ case HIGH_MOTION: -+ return ((d->field_fmt & MASK1) == VAL1) || ((d->field_fmt & MASK2) == VAL2); -+ case MED_MOTION: -+ return ((d->field_fmt & MASK2) == VAL1); -+ default: -+ return true; -+ } -+} - -- IPUTask ipu; -+inline -+int setIPUMotion(bool hasPrev, EINTERLACEMETHOD imethod) -+{ -+ if (hasPrev && imethod == VS_INTERLACEMETHOD_IMX_WEAVE) -+ return LOW_MOTION; -+ else if (hasPrev && imethod >= VS_INTERLACEMETHOD_IMX_ADVMOTION) -+ return MED_MOTION; - -- SetFieldData(fieldFmt); -- PrepareTask(ipu, source_p, source); -- return DoTask(ipu, page); -+ return HIGH_MOTION; - } - --bool CIMXContext::BlitAsync(CIMXBuffer *source_p, CIMXBuffer *source, uint8_t fieldFmt, CRect *dest) -+void CIMXContext::Blit(CIMXBuffer *source_p, CIMXBuffer *source, uint8_t fieldFmt, int page, CRect *dest) - { -- IPUTask ipu; -+ static int pg; -+ -+ if (likely(page == RENDER_TASK_AUTOPAGE)) -+ page = pg; -+ else if (page == RENDER_TASK_CAPTURE) -+ m_CaptureDone = false; -+ else if (page < 0 && page >= m_fbPages) -+ return; - -- SetFieldData(fieldFmt); -+ pg = ++pg % m_fbPages; -+ -+ IPUTask *ipu = new IPUTask; -+ -+ SetFieldData(fieldFmt, source->m_fps); - PrepareTask(ipu, source_p, source, dest); -- return PushTask(ipu); -+ -+ ipu->page = page; -+#ifdef IMX_PROFILE_BUFFERS -+ unsigned long long before = XbmcThreads::SystemClockMillis(); -+#endif -+ if (!DoTask(ipu)) -+ { -+ delete ipu; -+ return; -+ } -+#ifdef IMX_PROFILE_BUFFERS -+ unsigned long long after = XbmcThreads::SystemClockMillis(); -+ CLog::Log(LOGVIDEO, "+P 0x%x@%d %d\n", ((CDVDVideoCodecIMXBuffer*)ipu->current)->GetIdx(), ipu->page, (int)(after-before)); -+#endif -+ -+ CSingleLock lk(m_pageSwapLock); -+ if (ipu->task.output.width) -+ m_input.push(ipu); -+ else -+ delete ipu; - } - - bool CIMXContext::PushCaptureTask(CIMXBuffer *source, CRect *dest) - { -- IPUTask ipu; -- m_CaptureDone = false; -- PrepareTask(ipu, NULL, source, dest); -- return PushTask(ipu); -+ Blit(NULL, source, RENDER_TASK_CAPTURE, 0, dest); -+ return true; - } - - bool CIMXContext::ShowPage(int page, bool shift) - { -- if (!m_fbHandle) return false; -- if (page < 0 || page >= m_fbPages) return false; -- if (!m_bFbIsConfigured) return false; -+#if defined(TRACE_FRAMES) && defined(IMX_PROFILE_BUFFERS) -+ unsigned long long pgstart = XbmcThreads::SystemClockMillis(); -+#endif -+ if (!m_fbHandle || !m_bFbIsConfigured) return false; - - // Protect page swapping from screen capturing that does read the current - // front buffer. This is actually not done very frequently so the lock - // does not hurt. -+ - CSingleLock lk(m_pageSwapLock); - -+ m_fbCurrentPage = page; - m_fbVar.activate = FB_ACTIVATE_VBL; -- - m_fbVar.yoffset = (m_fbVar.yres + 1) * page + !shift; - if (ioctl(m_fbHandle, FBIOPAN_DISPLAY, &m_fbVar) < 0) - { - CLog::Log(LOGWARNING, "Panning failed: %s\n", strerror(errno)); - return false; - } -- m_fbCurrentPage = page; - -- // Wait for sync -- if (m_vsync) -+ // Wait for flip -+ if (m_vsync && ioctl(m_fbHandle, FBIO_WAITFORVSYNC, 0) < 0) - { -- if (ioctl(m_fbHandle, FBIO_WAITFORVSYNC, 0) < 0) -- { -- CLog::Log(LOGWARNING, "Vsync failed: %s\n", strerror(errno)); -- return false; -- } -+ CLog::Log(LOGWARNING, "Vsync failed: %s\n", strerror(errno)); -+ return false; - } - -+#if defined(TRACE_FRAMES) && defined(IMX_PROFILE_BUFFERS) -+ unsigned long long pgend = XbmcThreads::SystemClockMillis(); -+ CLog::Log(LOGVIDEO, "NP(@%d) - pgswap: %d\n", m_fbCurrentPage, (int)(pgend - pgstart)); -+#endif - return true; - } - -@@ -1643,21 +1629,17 @@ void CIMXContext::Clear(int page) - - if (m_fbVar.nonstd == _4CC('R', 'G', 'B', '4')) - memset(tmp_buf, 0, bytes); -- else if (m_fbVar.nonstd == _4CC('U', 'Y', 'V', 'Y')) -+ else if (m_fbVar.nonstd == _4CC('Y', 'U', 'Y', 'V')) - { -+ uint16_t clr = 128 << 8 | 16; - int pixels = bytes / 2; - for (int i = 0; i < pixels; ++i, tmp_buf += 2) -- { -- tmp_buf[0] = 128; -- tmp_buf[1] = 16; -- } -+ memcpy(tmp_buf, &clr, 2); - } - else - CLog::Log(LOGERROR, "iMX Clear fb error : Unexpected format"); - } - --#define clamp_byte(x) (x<0?0:(x>255?255:x)) -- - void CIMXContext::CaptureDisplay(unsigned char *buffer, int iWidth, int iHeight) - { - if ((m_fbVar.nonstd != _4CC('R', 'G', 'B', '4')) && -@@ -1688,7 +1670,7 @@ void CIMXContext::CaptureDisplay(unsigned char *buffer, int iWidth, int iHeight) - } - else //_4CC('U', 'Y', 'V', 'Y'))) - { -- int r,g,b,a; -+ uint8_t r,g,b,a; - int u, y0, v, y1; - int iStride = m_fbWidth*2; - int oStride = iWidth*4; -@@ -1706,8 +1688,8 @@ void CIMXContext::CaptureDisplay(unsigned char *buffer, int iWidth, int iHeight) - - for (int y = 0; y < iHeight; ++y, display += iStride, buffer += oStride) - { -- unsigned char *iLine = display; -- unsigned char *oLine = buffer; -+ uint8_t *iLine = display; -+ uint8_t *oLine = buffer; - - for (int x = 0; x < iWidth; ++x, iLine += 4, oLine += 8 ) - { -@@ -1721,9 +1703,9 @@ void CIMXContext::CaptureDisplay(unsigned char *buffer, int iWidth, int iHeight) - g = (cy*y0 + cb2*u + cr2*v) >> 16; - b = (cy*y0 + cb3*u + cr3*v) >> 16; - -- oLine[0] = (clamp_byte(b)*a + oLine[0]*oLine[3])/255; -- oLine[1] = (clamp_byte(g)*a + oLine[1]*oLine[3])/255; -- oLine[2] = (clamp_byte(r)*a + oLine[2]*oLine[3])/255; -+ oLine[0] = (b*a + oLine[0]*oLine[3])/255; -+ oLine[1] = (g*a + oLine[1]*oLine[3])/255; -+ oLine[2] = (r*a + oLine[2]*oLine[3])/255; - oLine[3] = 255; - - a = 255-oLine[7]; -@@ -1731,64 +1713,26 @@ void CIMXContext::CaptureDisplay(unsigned char *buffer, int iWidth, int iHeight) - g = (cy*y0 + cb2*u + cr2*v) >> 16; - b = (cy*y0 + cb3*u + cr3*v) >> 16; - -- oLine[4] = (clamp_byte(b)*a + oLine[4]*oLine[7])/255; -- oLine[5] = (clamp_byte(g)*a + oLine[5]*oLine[7])/255; -- oLine[6] = (clamp_byte(r)*a + oLine[6]*oLine[7])/255; -+ oLine[4] = (b*a + oLine[4]*oLine[7])/255; -+ oLine[5] = (g*a + oLine[5]*oLine[7])/255; -+ oLine[6] = (r*a + oLine[6]*oLine[7])/255; - oLine[7] = 255; - } - } - } - } - --bool CIMXContext::PushTask(const IPUTask &task) --{ -- if (!task.current) -- return false; -- -- CSingleLock lk(m_monitor); -- -- if (m_bStop) -- { -- m_inputNotEmpty.notifyAll(); -- return false; -- } -- -- // If the input queue is full, wait for a free slot -- while ((m_bufferedInput == m_input.size()) && !m_bStop) -- m_inputNotFull.wait(lk); -- -- if (m_bStop) -- { -- m_inputNotEmpty.notifyAll(); -- return false; -- } -- -- // Store the value -- if (task.previous) task.previous->Lock(); -- task.current->Lock(); -- -- memcpy(&m_input[m_endInput], &task, sizeof(IPUTask)); -- m_endInput = (m_endInput+1) % m_input.size(); -- ++m_bufferedInput; -- m_inputNotEmpty.notifyAll(); -- -- return true; --} -- - void CIMXContext::WaitCapture() - { -- CSingleLock lk(m_monitor); -- while (!m_CaptureDone) -- m_inputNotFull.wait(lk); - } - --void CIMXContext::PrepareTask(IPUTask &ipu, CIMXBuffer *source_p, CIMXBuffer *source, -+void CIMXContext::PrepareTask(IPUTask *ipu, CIMXBuffer *source_p, CIMXBuffer *source, - CRect *dest) - { - // Fill with zeros -- ipu.Zero(); -- ipu.previous = source_p; -- ipu.current = source; -+ ipu->Zero(); -+ ipu->previous = source_p; -+ ipu->current = source; - - CRect srcRect = m_srcRect; - CRect dstRect; -@@ -1840,76 +1784,144 @@ void CIMXContext::PrepareTask(IPUTask &ipu, CIMXBuffer *source_p, CIMXBuffer *so - iDstRect.x2 = Align2((int)dstRect.x2,8); - iDstRect.y2 = Align2((int)dstRect.y2,8); - -- ipu.task.input.crop.pos.x = iSrcRect.x1; -- ipu.task.input.crop.pos.y = iSrcRect.y1; -- ipu.task.input.crop.w = iSrcRect.Width(); -- ipu.task.input.crop.h = iSrcRect.Height(); -+ ipu->task.input.crop.pos.x = iSrcRect.x1; -+ ipu->task.input.crop.pos.y = iSrcRect.y1; -+ ipu->task.input.crop.w = iSrcRect.Width(); -+ ipu->task.input.crop.h = iSrcRect.Height(); - -- ipu.task.output.crop.pos.x = iDstRect.x1; -- ipu.task.output.crop.pos.y = iDstRect.y1; -- ipu.task.output.crop.w = iDstRect.Width(); -- ipu.task.output.crop.h = iDstRect.Height(); -+ ipu->task.output.crop.pos.x = iDstRect.x1; -+ ipu->task.output.crop.pos.y = iDstRect.y1; -+ ipu->task.output.crop.w = iDstRect.Width(); -+ ipu->task.output.crop.h = iDstRect.Height(); - - // If dest is set it means we do not want to blit to frame buffer - // but to a capture buffer and we state this capture buffer dimensions - if (dest) - { - // Populate partly output block -- ipu.task.output.crop.pos.x = 0; -- ipu.task.output.crop.pos.y = 0; -- ipu.task.output.crop.w = iDstRect.Width(); -- ipu.task.output.crop.h = iDstRect.Height(); -- ipu.task.output.width = iDstRect.Width(); -- ipu.task.output.height = iDstRect.Height(); -+ ipu->task.output.crop.pos.x = 0; -+ ipu->task.output.crop.pos.y = 0; -+ ipu->task.output.crop.w = iDstRect.Width(); -+ ipu->task.output.crop.h = iDstRect.Height(); -+ ipu->task.output.width = iDstRect.Width(); -+ ipu->task.output.height = iDstRect.Height(); - } - else - { - // Setup deinterlacing if enabled - if (m_currentFieldFmt) - { -- ipu.task.input.deinterlace.enable = 1; -- /* -- if (source_p) -+ ipu->task.input.deinterlace.enable = 1; -+ ipu->task.input.deinterlace.motion = setIPUMotion(ipu->previous, CMediaSettings::GetInstance().GetCurrentVideoSettings().m_InterlaceMethod); -+ ipu->task.input.deinterlace.field_fmt = m_currentFieldFmt; -+ } -+ } -+} -+ -+bool CIMXContext::TileTask(IPUTask *ipu) -+{ -+ int pad = ipu->task.input.height == 1080 && ipu->current->iHeight>ipu->task.input.height ? 8*ipu->current->iWidth : 0; -+ -+ if (ipu->current->iFormat != _4CC('T', 'N', 'V', 'F') && ipu->current->iFormat != _4CC('T', 'N', 'V', 'P')) -+ { -+ if (ipu->task.input.deinterlace.enable && ipu->task.input.deinterlace.motion != HIGH_MOTION) - { -- task.input.deinterlace.motion = MED_MOTION; -- task.input.paddr = source_p->pPhysAddr; -- task.input.paddr_n = source->pPhysAddr; -+ ipu->task.input.paddr_n = ipu->task.input.paddr; -+ ipu->task.input.paddr = ipu->previous->pPhysAddr + pad; - } - else -- */ -- ipu.task.input.deinterlace.motion = HIGH_MOTION; -- ipu.task.input.deinterlace.field_fmt = m_currentFieldFmt; -+ ipu->task.input.paddr += pad; -+ return true; -+ } -+ -+ // Use band mode directly to FB, as no transformations needed (eg cropping) -+ if (m_fps >= 49 && m_fbWidth == 1920 && ipu->task.input.width == 1920 && !ipu->task.input.deinterlace.enable && m_CaptureDone) -+ { -+ ipu->task.output.crop.pos.x = ipu->task.input.crop.pos.x = 0; -+ ipu->task.output.crop.pos.y = ipu->task.input.crop.pos.y = 0; -+ ipu->task.output.crop.h = ipu->task.input.height = ipu->task.input.crop.h = ipu->current->iHeight; -+ ipu->task.output.paddr += m_fbLineLength * (m_fbHeight - ipu->task.input.crop.h)/2; -+ -+ return true; -+ } -+ -+ // rasterize from tile (frame) -+ struct ipu_task vdoa; -+ -+ memset(&vdoa, 0, sizeof(ipu->task)); -+ vdoa.input.width = vdoa.output.width = ipu->current->iWidth; -+ vdoa.input.height = vdoa.output.height = ipu->current->iHeight; -+ vdoa.input.format = ipu->current->iFormat; -+ -+ // check for 3-field deinterlace (no HIGH_MOTION allowed) from tile field format -+ if (ipu->previous && ipu->current->iFormat == _4CC('T', 'N', 'V', 'F')) -+ { -+ memcpy(&vdoa.input.deinterlace, &ipu->task.input.deinterlace, sizeof(ipu->task.input.deinterlace)); -+ memset(&ipu->task.input.deinterlace, 0, sizeof(ipu->task.input.deinterlace)); -+ vdoa.input.paddr_n = ipu->current->pPhysAddr; -+ } -+ -+ struct g2d_buf *conv = g2d_alloc(ipu->current->iWidth *ipu->current->iHeight * 2, 0); -+ if (!conv) -+ { -+ CLog::Log(LOGERROR, "iMX: can't allocate crop buffer"); -+ return false; -+ } -+ -+ ((CDVDVideoCodecIMXBuffer*)ipu->current)->m_convBuffer = conv; -+ -+ vdoa.input.paddr = vdoa.input.paddr_n ? ipu->previous->pPhysAddr : ipu->current->pPhysAddr; -+ vdoa.output.format = m_fbVar.bits_per_pixel == 16 && m_CaptureDone ? _4CC('Y', 'U', 'Y', 'V') : _4CC('N', 'V', '1', '2'); -+ vdoa.output.paddr = conv->buf_paddr; -+ -+ if (int ret = ioctl(m_ipuHandle, IPU_CHECK_TASK, &vdoa)) -+ { -+ CLog::Log(LOGERROR, "IPU conversion from tiled failed %d at #%d", ret, __LINE__); -+ return false; - } -+ if (ioctl(m_ipuHandle, IPU_QUEUE_TASK, &vdoa) < 0) -+ return false; -+ -+ ipu->task.input.paddr = vdoa.output.paddr + pad; -+ ipu->task.input.format = vdoa.output.format; -+ if (ipu->task.input.deinterlace.enable && ipu->task.input.deinterlace.motion != HIGH_MOTION && ipu->previous) -+ { -+ ipu->task.input.paddr_n = ipu->task.input.paddr; -+ ipu->task.input.paddr = ipu->previous->pPhysAddr; - } -+ ipu->current->iFormat = vdoa.output.format; -+ ipu->current->pPhysAddr = vdoa.output.paddr; -+ -+ return true; - } - --bool CIMXContext::DoTask(IPUTask &ipu, int targetPage) -+bool CIMXContext::DoTask(IPUTask *ipu) - { - bool swapColors = false; - - // Clear page if cropping changes -- CRectInt dstRect(ipu.task.output.crop.pos.x, ipu.task.output.crop.pos.y, -- ipu.task.output.crop.pos.x + ipu.task.output.crop.w, -- ipu.task.output.crop.pos.y + ipu.task.output.crop.h); -+ CRectInt dstRect(ipu->task.output.crop.pos.x, ipu->task.output.crop.pos.y, -+ ipu->task.output.crop.pos.x + ipu->task.output.crop.w, -+ ipu->task.output.crop.pos.y + ipu->task.output.crop.h); - - // Populate input block -- ipu.task.input.width = ipu.current->iWidth; -- ipu.task.input.height = ipu.current->iHeight; -- ipu.task.input.format = ipu.current->iFormat; -- ipu.task.input.paddr = ipu.current->pPhysAddr; -+ ipu->task.input.width = ipu->current->iWidth; -+ ipu->task.input.height = std::min(ipu->current->iHeight, (unsigned int)1080); -+ ipu->task.input.format = ipu->current->iFormat; -+ ipu->task.input.paddr = ipu->current->pPhysAddr; - - // Populate output block if it has not already been filled -- if (ipu.task.output.width == 0) -+ if (ipu->task.output.width == 0) - { -- ipu.task.output.width = m_fbWidth; -- ipu.task.output.height = m_fbHeight; -- ipu.task.output.format = m_fbVar.nonstd; -- ipu.task.output.paddr = m_fbPhysAddr + targetPage*m_fbPageSize; -+ ipu->task.output.width = m_fbWidth; -+ ipu->task.output.height = m_fbHeight; -+ ipu->task.output.format = m_fbVar.nonstd; -+ ipu->task.output.paddr = m_fbPhysAddr + ipu->page*m_fbPageSize; - -- if (m_pageCrops[targetPage] != dstRect) -+ if (m_pageCrops[ipu->page] != dstRect) - { -- m_pageCrops[targetPage] = dstRect; -- Clear(targetPage); -+ m_pageCrops[ipu->page] = dstRect; -+ Clear(ipu->page); - } - } - else -@@ -1917,7 +1929,7 @@ bool CIMXContext::DoTask(IPUTask &ipu, int targetPage) - // If we have already set dest dimensions we want to use capture buffer - // Note we allocate this capture buffer as late as this function because - // all g2d functions have to be called from the same thread -- int size = ipu.task.output.width * ipu.task.output.height * 4; -+ int size = ipu->task.output.width * ipu->task.output.height * 4; - if ((m_bufferCapture) && (size != m_bufferCapture->buf_size)) - { - if (g2d_free(m_bufferCapture)) -@@ -1931,72 +1943,55 @@ bool CIMXContext::DoTask(IPUTask &ipu, int targetPage) - if (m_bufferCapture == NULL) - CLog::Log(LOGERROR, "iMX : Error allocating capture buffer\n"); - } -- ipu.task.output.paddr = m_bufferCapture->buf_paddr; -+ ipu->task.output.paddr = m_bufferCapture->buf_paddr; - swapColors = true; - } - -- if ((ipu.task.input.crop.w <= 0) || (ipu.task.input.crop.h <= 0) -- || (ipu.task.output.crop.w <= 0) || (ipu.task.output.crop.h <= 0)) -+ if ((ipu->task.input.crop.w <= 0) || (ipu->task.input.crop.h <= 0) -+ || (ipu->task.output.crop.w <= 0) || (ipu->task.output.crop.h <= 0)) - return false; - --#ifdef IMX_PROFILE_BUFFERS -- unsigned long long before = XbmcThreads::SystemClockMillis(); --#endif -+ if (!TileTask(ipu)) -+ return false; - -- if (ipu.task.input.deinterlace.enable) -+ if (m_CaptureDone && (m_fbVar.bits_per_pixel == 16 || !RENDER_USE_G2D)) - { - //We really use IPU only if we have to deinterlace (using VDIC) - int ret = IPU_CHECK_ERR_INPUT_CROP; - while (ret > IPU_CHECK_ERR_MIN) - { -- ret = ioctl(m_ipuHandle, IPU_CHECK_TASK, &ipu.task); -+ ret = ioctl(m_ipuHandle, IPU_CHECK_TASK, &ipu->task); - switch (ret) - { - case IPU_CHECK_OK: - break; - case IPU_CHECK_ERR_SPLIT_INPUTW_OVER: -- ipu.task.input.crop.w -= 8; -+ ipu->task.input.crop.w -= 8; - break; - case IPU_CHECK_ERR_SPLIT_INPUTH_OVER: -- ipu.task.input.crop.h -= 8; -+ ipu->task.input.crop.h -= 8; - break; - case IPU_CHECK_ERR_SPLIT_OUTPUTW_OVER: -- ipu.task.output.crop.w -= 8; -+ ipu->task.output.crop.w -= 8; - break; - case IPU_CHECK_ERR_SPLIT_OUTPUTH_OVER: -- ipu.task.output.crop.h -= 8; -+ ipu->task.output.crop.h -= 8; - break; - // deinterlacing setup changing, m_ipuHandle is closed - case -1: - return true; - default: -- CLog::Log(LOGWARNING, "iMX : unhandled IPU check error: %d\n", ret); -+ CLog::Log(LOGWARNING, "iMX : unhandled IPU check error: %d", ret); - return false; - } - } - -- // Need to find another interface to protect ipu.current from disposing -- // in CDVDVideoCodecIMX::Dispose. CIMXContext must not have knowledge -- // about CDVDVideoCodecIMX. -- ipu.current->BeginRender(); -- if (ipu.current->IsValid()) -- ret = ioctl(m_ipuHandle, IPU_QUEUE_TASK, &ipu.task); -- else -- ret = 0; -- ipu.current->EndRender(); -- -+ ret = ioctl(m_ipuHandle, IPU_QUEUE_TASK, &ipu->task); - if (ret < 0) - { -- CLog::Log(LOGERROR, "IPU task failed: %s\n", strerror(errno)); -+ CLog::Log(LOGERROR, "IPU task failed: %s at #%d\n", strerror(errno), __LINE__); - return false; - } -- -- // Duplicate 2nd scandline if double rate is active -- if (IsDoubleRate()) -- { -- uint8_t *pageAddr = m_fbVirtAddr + targetPage*m_fbPageSize; -- memcpy(pageAddr, pageAddr+m_fbLineLength, m_fbLineLength); -- } - } - else - { -@@ -2006,64 +2001,50 @@ bool CIMXContext::DoTask(IPUTask &ipu, int targetPage) - memset(&src, 0, sizeof(src)); - memset(&dst, 0, sizeof(dst)); - -- ipu.current->BeginRender(); -- if (ipu.current->IsValid()) - { -- if (ipu.current->iFormat == _4CC('I', '4', '2', '0')) -+ if (ipu->current->iFormat == _4CC('I', '4', '2', '0')) - { - src.format = G2D_I420; -- src.planes[0] = ipu.current->pPhysAddr; -- src.planes[1] = src.planes[0] + Align(ipu.current->iWidth * ipu.current->iHeight, 64); -- src.planes[2] = src.planes[1] + Align((ipu.current->iWidth * ipu.current->iHeight) / 2, 64); -+ src.planes[0] = ipu->current->pPhysAddr; -+ src.planes[1] = src.planes[0] + Align(ipu->current->iWidth * ipu->current->iHeight, 64); -+ src.planes[2] = src.planes[1] + Align((ipu->current->iWidth * ipu->current->iHeight) / 2, 64); - } - else //_4CC('N', 'V', '1', '2'); - { - src.format = G2D_NV12; -- src.planes[0] = ipu.current->pPhysAddr; -- src.planes[1] = src.planes[0] + Align(ipu.current->iWidth * ipu.current->iHeight, 64); -+ src.planes[0] = ipu->current->pPhysAddr; -+ src.planes[1] = src.planes[0] + Align(ipu->current->iWidth * ipu->current->iHeight, 64); - } - -- src.left = ipu.task.input.crop.pos.x; -- src.right = ipu.task.input.crop.w + src.left ; -- src.top = ipu.task.input.crop.pos.y; -- src.bottom = ipu.task.input.crop.h + src.top; -- src.stride = ipu.current->iWidth; -- src.width = ipu.current->iWidth; -- src.height = ipu.current->iHeight; -+ src.left = ipu->task.input.crop.pos.x; -+ src.right = ipu->task.input.crop.w + src.left ; -+ src.top = ipu->task.input.crop.pos.y; -+ src.bottom = ipu->task.input.crop.h + src.top; -+ src.stride = ipu->current->iWidth; -+ src.width = ipu->current->iWidth; -+ src.height = ipu->current->iHeight; - src.rot = G2D_ROTATION_0; -- /*printf("src planes :%x -%x -%x \n",src.planes[0], src.planes[1], src.planes[2] ); -- printf("src left %d right %d top %d bottom %d stride %d w : %d h %d rot : %d\n", -- src.left, src.right, src.top, src.bottom, src.stride, src.width, src.height, src.rot);*/ -- -- dst.planes[0] = ipu.task.output.paddr; -- dst.left = ipu.task.output.crop.pos.x; -- dst.top = ipu.task.output.crop.pos.y; -- dst.right = ipu.task.output.crop.w + dst.left; -- dst.bottom = ipu.task.output.crop.h + dst.top; -- -- dst.stride = ipu.task.output.width; -- dst.width = ipu.task.output.width; -- dst.height = ipu.task.output.height; -+ -+ dst.planes[0] = ipu->task.output.paddr; -+ dst.left = ipu->task.output.crop.pos.x; -+ dst.top = ipu->task.output.crop.pos.y; -+ dst.right = ipu->task.output.crop.w + dst.left; -+ dst.bottom = ipu->task.output.crop.h + dst.top; -+ -+ dst.stride = ipu->task.output.width; -+ dst.width = ipu->task.output.width; -+ dst.height = ipu->task.output.height; - dst.rot = G2D_ROTATION_0; - dst.format = swapColors ? G2D_BGRA8888 : G2D_RGBA8888; -- /*printf("dst planes :%x -%x -%x \n",dst.planes[0], dst.planes[1], dst.planes[2] ); -- printf("dst left %d right %d top %d bottom %d stride %d w : %d h %d rot : %d format %d\n", -- dst.left, dst.right, dst.top, dst.bottom, dst.stride, dst.width, dst.height, dst.rot, dst.format);*/ - - // Launch synchronous blit - g2d_blit(m_g2dHandle, &src, &dst); - g2d_finish(m_g2dHandle); -- if ((m_bufferCapture) && (ipu.task.output.paddr == m_bufferCapture->buf_paddr)) -+ if ((m_bufferCapture) && (ipu->task.output.paddr == m_bufferCapture->buf_paddr)) - m_CaptureDone = true; - } -- ipu.current->EndRender(); - } - --#ifdef IMX_PROFILE_BUFFERS -- unsigned long long after = XbmcThreads::SystemClockMillis(); -- CLog::Log(LOGNOTICE, "+P %f %d\n", ((CDVDVideoCodecIMXBuffer*)ipu.current)->GetPts(), (int)(after-before)); --#endif -- - return true; - } - -@@ -2071,7 +2052,9 @@ void CIMXContext::OnStartup() - { - OpenDevices(); - -- Configure(); -+ AdaptScreen(true); -+ AdaptScreen(); -+ - g_Windowing.Register(this); - CLog::Log(LOGNOTICE, "iMX : IPU thread started"); - } -@@ -2082,98 +2065,32 @@ void CIMXContext::OnExit() - CLog::Log(LOGNOTICE, "iMX : IPU thread terminated"); - } - --void CIMXContext::StopThread(bool bWait /*= true*/) -+void CIMXContext::Stop(bool bWait /*= true*/) - { - if (!IsRunning()) - return; - -- Blank(); - CThread::StopThread(false); -- m_inputNotFull.notifyAll(); -- m_inputNotEmpty.notifyAll(); -+ m_input.signal(); -+ Blank(); - if (bWait && IsRunning()) - CThread::StopThread(true); - } - --#define MASK1 (IPU_DEINTERLACE_RATE_FRAME1 | RENDER_FLAG_TOP) --#define MASK2 (IPU_DEINTERLACE_RATE_FRAME1 | RENDER_FLAG_BOT) --#define VAL1 MASK1 --#define VAL2 RENDER_FLAG_BOT -- --inline --bool checkIPUStrideOffset(struct ipu_deinterlace *d) --{ -- return ((d->field_fmt & MASK1) == VAL1) || -- ((d->field_fmt & MASK2) == VAL2); --} -- - void CIMXContext::Process() - { -- bool ret; -- -- // open g2d here to ensure all g2d fucntions are called from the same thread -- if (m_g2dHandle == NULL) -- { -- if (g2d_open(&m_g2dHandle) != 0) -- { -- m_g2dHandle = NULL; -- CLog::Log(LOGERROR, "%s - Error while trying open G2D\n", __FUNCTION__); -- } -- } -- - while (!m_bStop) - { -- IPUTask *task; -- { -- CSingleLock lk(m_monitor); -- while (!m_bufferedInput && !m_bStop) -- m_inputNotEmpty.wait(lk); -+ IPUTask *ipu = m_input.pop(); - -- task = &m_input[m_beginInput]; -- } -- if (m_bStop) -- break; -- -- ret = DoTask(*task, (1-m_fbCurrentPage) & m_vsync); -- bool shift = checkIPUStrideOffset(&task->task.input.deinterlace); -+ if (!ipu) -+ continue; - -- // Free resources -- task->Done(); -- -- { -- CSingleLock lk(m_monitor); -- m_beginInput = (m_beginInput+1) % m_input.size(); -- --m_bufferedInput; -- m_inputNotFull.notifyAll(); -- } -+ ipu->shift = checkIPUStrideOffset(&ipu->task.input.deinterlace); - - // Show back buffer -- if (task->task.output.width && ret) -- ShowPage(1-m_fbCurrentPage, shift); -- } -- -- // Mark all pending jobs as done -- CSingleLock lk(m_monitor); -- while (m_bufferedInput > 0) -- { -- m_input[m_beginInput].Done(); -- m_beginInput = (m_beginInput+1) % m_input.size(); -- --m_bufferedInput; -- } -+ ShowPage(ipu->page, ipu->shift); - -- // close g2d here to ensure all g2d fucntions are called from the same thread -- if (m_bufferCapture) -- { -- if (g2d_free(m_bufferCapture)) -- CLog::Log(LOGERROR, "iMX : Failed to free capture buffers\n"); -- m_bufferCapture = NULL; -- } -- if (m_g2dHandle) -- { -- if (g2d_close(m_g2dHandle)) -- CLog::Log(LOGERROR, "iMX : Error while closing G2D\n"); -- m_g2dHandle = NULL; -+ delete ipu; - } -- -- return; - } -diff --git a/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecIMX.h b/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecIMX.h -index b0286e2..5b64310 100644 ---- a/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecIMX.h -+++ b/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecIMX.h -@@ -19,6 +19,8 @@ - * - */ - -+#include "linux/imx/IMX.h" -+ - #include "threads/CriticalSection.h" - #include "threads/Condition.h" - #include "threads/Thread.h" -@@ -27,13 +29,17 @@ - #include "DVDVideoCodec.h" - #include "DVDStreamInfo.h" - #include "guilib/DispResource.h" -+#include "DVDClock.h" -+#include "cores/VideoPlayer/DVDDemuxers/DVDDemuxPacket.h" - --#include - #include - #include - #include - #include - -+#include -+#include -+#include - - // The decoding format of the VPU buffer. Comment this to decode - // as NV12. The VPU works faster with NV12 in combination with -@@ -49,43 +55,42 @@ - // priorities to those subsystems can result in a very different user - // experience. With that setting enabled we can build some statistics, - // as numbers are always better than "feelings" --//#define IMX_PROFILE_BUFFERS -+#define IMX_PROFILE_BUFFERS -+ -+#define IMX_PROFILE -+#define TRACE_FRAMES - --//#define IMX_PROFILE --//#define TRACE_FRAMES -+#define RENDER_USE_G2D 0 - - // If uncommented a file "stream.dump" will be created in the current - // directory whenever a new stream is started. This is only for debugging - // and performance tests. This define must never be active in distributions. - //#define DUMP_STREAM - -+inline -+double recalcPts(double pts) -+{ -+ return (double)(pts == DVD_NOPTS_VALUE ? 0.0 : pts*1e-6); -+} - --/*>> TO BE MOVED TO A MORE CENTRAL PLACE IN THE SOURCE DIR >>>>>>>>>>>>>>>>>>>*/ --// Generell description of a buffer used by --// the IMX context, e.g. for blitting --class CIMXBuffer { --public: -- CIMXBuffer() : m_iRefs(0) {} -- -- // Shared pointer interface -- virtual void Lock() = 0; -- virtual long Release() = 0; -- virtual bool IsValid() = 0; -- -- virtual void BeginRender() = 0; -- virtual void EndRender() = 0; -- --public: -- uint32_t iWidth; -- uint32_t iHeight; -- int pPhysAddr; -- uint8_t *pVirtAddr; -- int iFormat; -+enum SIGNALS -+{ -+ SIGNAL_RESET = (1 << 0), -+ SIGNAL_DISPOSE = (1 << 1), -+ SIGNAL_SIGNAL = (1 << 2), -+ SIGNAL_FLUSH = (1 << 3), -+}; - --protected: -- long m_iRefs; -+enum RENDER_TASK -+{ -+ RENDER_TASK_AUTOPAGE = -1, -+ RENDER_TASK_CAPTURE = -2, - }; - -+#define CLASS_PICTURE (VPU_DEC_OUTPUT_DIS | VPU_DEC_OUTPUT_MOSAIC_DIS) -+#define CLASS_NOBUF (VPU_DEC_OUTPUT_NODIS | VPU_DEC_NO_ENOUGH_BUF | VPU_DEC_OUTPUT_REPEAT) -+#define CLASS_FORCEBUF (VPU_DEC_OUTPUT_EOS | VPU_DEC_NO_ENOUGH_INBUF) -+#define CLASS_DROP (VPU_DEC_OUTPUT_DROPPED | VPU_DEC_SKIP) - - // iMX context class that handles all iMX hardware - // related stuff -@@ -95,46 +100,34 @@ public: - CIMXContext(); - ~CIMXContext(); - -- bool Configure(); -+ bool AdaptScreen(bool allocate = false); - bool TaskRestart(); -- bool CloseDevices(); -+ void CloseDevices(); -+ void g2dCloseDevices(); -+ void g2dOpenDevices(); - bool OpenDevices(); - - bool Blank(); - bool Unblank(); - bool SetVSync(bool enable); - -- bool IsValid() const { return IsRunning() && m_bFbIsConfigured; } -- -- // Populates a CIMXBuffer with attributes of a page -- bool GetPageInfo(CIMXBuffer *info, int page); -- - // Blitter configuration - bool IsDoubleRate() const { return m_currentFieldFmt & IPU_DEINTERLACE_RATE_EN; } - - void SetBlitRects(const CRect &srcRect, const CRect &dstRect); - -- // Blits a buffer to a particular page. -+ // Blits a buffer to a particular page (-1 for auto page) - // source_p (previous buffer) is required for de-interlacing - // modes LOW_MOTION and MED_MOTION. -- bool Blit(int targetPage, CIMXBuffer *source_p, -- CIMXBuffer *source, -- uint8_t fieldFmt = 0); -- -- // Same as blit but runs in another thread and returns after the task has -- // been queued. BlitAsync renders always to the current backbuffer and -- // swaps the pages. -- bool BlitAsync(CIMXBuffer *source_p, CIMXBuffer *source, -- uint8_t fieldFmt = 0, CRect *dest = NULL); -+ void Blit(CIMXBuffer *source_p, CIMXBuffer *source, -+ uint8_t fieldFmt = 0, int targetPage = RENDER_TASK_AUTOPAGE, -+ CRect *dest = NULL); - - // Shows a page vsynced - bool ShowPage(int page, bool shift = false); - -- // Returns the visible page -- int GetCurrentPage() const { return m_fbCurrentPage; } -- - // Clears the pages or a single page with 'black' -- void Clear(int page = -1); -+ void Clear(int page = RENDER_TASK_AUTOPAGE); - - // Captures the current visible frame buffer page and blends it into - // the passed overlay. The buffer format is BGRA (4 byte) -@@ -143,8 +136,11 @@ public: - void *GetCaptureBuffer() const { if (m_bufferCapture) return m_bufferCapture->buf_vaddr; else return NULL; } - void WaitCapture(); - -+ void RendererAllowed(bool yes); - void OnResetDisplay(); - -+ static const int m_fbPages; -+ - private: - struct IPUTask - { -@@ -154,44 +150,42 @@ private: - memset(&task, 0, sizeof(task)); - } - -- void Done() -- { -- SAFE_RELEASE(previous); -- SAFE_RELEASE(current); -- } -- - // Kept for reference - CIMXBuffer *previous; - CIMXBuffer *current; - - // The actual task - struct ipu_task task; -- }; -+ -+ int page; -+ int shift; -+ } IPUTask_t; - - bool GetFBInfo(const std::string &fbdev, struct fb_var_screeninfo *fbVar); - -- bool PushTask(const IPUTask &); -- void PrepareTask(IPUTask &ipu, CIMXBuffer *source_p, CIMXBuffer *source, -+ void PrepareTask(IPUTask *ipu, CIMXBuffer *source_p, CIMXBuffer *source, - CRect *dest = NULL); -- bool DoTask(IPUTask &ipu, int targetPage); -+ bool DoTask(IPUTask *ipu); -+ bool TileTask(IPUTask *ipu); - -- void SetFieldData(uint8_t fieldFmt); -+ void SetFieldData(uint8_t fieldFmt, double fps); - -- void MemMap(struct fb_fix_screeninfo *fb_fix = NULL); - void Dispose(); -+ void MemMap(struct fb_fix_screeninfo *fb_fix = NULL); -+ void Stop(bool bWait = true); - - virtual void OnStartup(); - virtual void OnExit(); -- virtual void StopThread(bool bWait = true); - virtual void Process(); - - private: -- typedef std::vector TaskQueue; -+ lkFIFO m_input; - - int m_fbHandle; - int m_fbCurrentPage; - int m_fbWidth; - int m_fbHeight; -+ bool m_fbInterlaced; - int m_fbLineLength; - int m_fbPageSize; - int m_fbPhysSize; -@@ -203,31 +197,28 @@ private: - bool m_vsync; - CRect m_srcRect; - CRect m_dstRect; -- CRectInt m_inputRect; -- CRectInt m_outputRect; - CRectInt *m_pageCrops; - bool m_bFbIsConfigured; - - CCriticalSection m_pageSwapLock; -- TaskQueue m_input; -- volatile int m_beginInput, m_endInput; -- volatile size_t m_bufferedInput; -- XbmcThreads::ConditionVariable m_inputNotEmpty; -- XbmcThreads::ConditionVariable m_inputNotFull; -- mutable CCriticalSection m_monitor; -- -- void *m_g2dHandle; -- struct g2d_buf *m_bufferCapture; -+public: -+ void *m_g2dHandle; -+ struct g2d_buf *m_bufferCapture; - bool m_CaptureDone; -- static const int m_fbPages; - - std::string m_deviceName; -+ int m_speed; -+ -+ double m_fps; - }; - - - extern CIMXContext g_IMXContext; -+ - /*<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/ - -+class CDVDVideoCodecIMX; -+class CIMXCodec; - - class CDecMemInfo - { -@@ -248,111 +239,216 @@ public: - VpuMemDesc *phyMem; - }; - -- - // Base class of IMXVPU and IMXIPU buffer --class CDVDVideoCodecIMXBuffer : public CIMXBuffer { -+class CDVDVideoCodecIMXBuffer : public CIMXBuffer -+{ -+friend class CIMXCodec; -+friend class CIMXContext; - public: --#ifdef TRACE_FRAMES -- CDVDVideoCodecIMXBuffer(int idx); --#else -- CDVDVideoCodecIMXBuffer(); --#endif -+ CDVDVideoCodecIMXBuffer(VpuDecOutFrameInfo *frameInfo, double fps, int map); -+ virtual ~CDVDVideoCodecIMXBuffer(); - - // reference counting - virtual void Lock(); - virtual long Release(); -- virtual bool IsValid(); - -- virtual void BeginRender(); -- virtual void EndRender(); -+ void SetPts(double pts) { m_pts = pts; } -+ double GetPts() const { return m_pts; } - -- void SetPts(double pts); -- double GetPts() const { return m_pts; } -+ void SetDts(double dts) { m_dts = dts; } -+ double GetDts() const { return m_dts; } - -- void SetDts(double dts); -- double GetDts() const { return m_dts; } -+ void SetFlags(int flags) { m_iFlags = flags; } -+ int GetFlags() const { return m_iFlags; } - -- bool Rendered() const; -- void Queue(VpuDecOutFrameInfo *frameInfo, -- CDVDVideoCodecIMXBuffer *previous); -- VpuDecRetCode ReleaseFramebuffer(VpuDecHandle *handle); -- CDVDVideoCodecIMXBuffer *GetPreviousBuffer() const { return m_previousBuffer; } -- VpuFieldType GetFieldType() const { return m_fieldType; } -- --private: -- // private because we are reference counted -- virtual ~CDVDVideoCodecIMXBuffer(); -+#if defined(IMX_PROFILE) || defined(IMX_PROFILE_BUFFERS) -+ int GetIdx() { return m_idx; } -+#endif -+ VpuFieldType GetFieldType() const { return m_fieldType; } - - protected: --#ifdef TRACE_FRAMES -- int m_idx; --#endif -+ unsigned int m_pctWidth; -+ unsigned int m_pctHeight; - - private: - double m_pts; - double m_dts; - VpuFieldType m_fieldType; - VpuFrameBuffer *m_frameBuffer; -- bool m_rendered; -- CDVDVideoCodecIMXBuffer *m_previousBuffer; // Holds the reference counted previous buffer --}; -+ int m_iFlags; -+#if defined(IMX_PROFILE) || defined(IMX_PROFILE_BUFFERS) -+ unsigned char m_idx; -+ static unsigned char i; -+#endif - -+public: -+ struct g2d_buf *m_convBuffer; -+}; - --class CDVDVideoCodecIMX : public CDVDVideoCodec -+class CIMXCodec : public CThread - { - public: -- CDVDVideoCodecIMX(CProcessInfo &processInfo); -- virtual ~CDVDVideoCodecIMX(); -+ CIMXCodec(); -+ ~CIMXCodec(); - -- // Methods from CDVDVideoCodec which require overrides -- virtual bool Open(CDVDStreamInfo &hints, CDVDCodecOptions &options); -- virtual int Decode(BYTE *pData, int iSize, double dts, double pts); -- virtual void Reset(); -- virtual bool ClearPicture(DVDVideoPicture *pDvdVideoPicture); -- virtual bool GetPicture(DVDVideoPicture *pDvdVideoPicture); -- virtual void SetDropState(bool bDrop); -- virtual const char* GetName() { return (const char*)m_pFormatName; } -- virtual unsigned GetAllowedReferences(); -- -- static void Enter(); -- static void Leave(); -+ bool Open(CDVDStreamInfo &hints, CDVDCodecOptions &options, std::string &m_pFormatName); -+ int Decode(BYTE *pData, int iSize, double dts, double pts); -+ -+ void SetDropState(bool bDrop); -+ -+ void Reset(); -+ -+ void SetSpeed(int iSpeed) { m_speed = iSpeed; } -+ void WaitStartup() { m_loaded.Wait(); } -+ -+ bool GetPicture(DVDVideoPicture *pDvdVideoPicture); -+ -+ bool GetCodecStats(double &pts, int &droppedFrames, int &skippedPics); -+ void SetCodecControl(int flags); -+ -+ virtual void Process() override; -+ -+ static void ReleaseFramebuffer(VpuFrameBuffer* fb); -+ -+ virtual bool GetInterlaced() { return m_initInfo.nInterlace; } -+ std::string GetPlayerInfo(); - - protected: -+ class VPUTask -+ { -+ public: -+ VPUTask(DemuxPacket pkg = { nullptr, 0, 0, 0, 0, DVD_NOPTS_VALUE, DVD_NOPTS_VALUE, 0, 0 }, -+ CBitstreamConverter *cnv = nullptr) : demux(pkg) -+ { -+ if (IsEmpty()) -+ return; -+ -+ bool cok = false; -+ if (cnv && (cok = cnv->Convert(pkg.pData, pkg.iSize))) -+ demux.iSize = cnv->GetConvertSize(); -+ -+ posix_memalign((void**)&demux.pData, 1024, demux.iSize); -+ std::memcpy(demux.pData, cok ? cnv->GetConvertBuffer() : pkg.pData, demux.iSize); -+ } -+ -+ void Release() -+ { -+ if (!IsEmpty()) -+ free(demux.pData); -+ demux.pData = nullptr; -+ } -+ -+ bool IsEmpty() { return !demux.pData; } -+ -+ DemuxPacket demux; -+ }; -+ - bool VpuOpen(); - bool VpuAllocBuffers(VpuMemInfo *); -- bool VpuFreeBuffers(); -+ bool VpuFreeBuffers(bool dispose = true); - bool VpuAllocFrameBuffers(); -- int VpuFindBuffer(void *frameAddr); -- void Dispose(); - -- static const int m_extraVpuBuffers; // Number of additional buffers for VPU -- static const int m_maxVpuDecodeLoops; // Maximum iterations in VPU decoding loop -+ void SetVPUParams(VpuDecConfig InDecConf, void* pInParam); -+ void SetDrainMode(VpuDecInputType drop); -+ void SetSkipMode(VpuDecSkipMode skip); -+ -+ void RecycleFrameBuffers(); -+ -+ static void Release(VPUTask *&t) { SAFE_RELEASE(t); } -+ static void Release(CDVDVideoCodecIMXBuffer *&t) { SAFE_RELEASE(t); } -+ static bool noDTS(VPUTask *&t) { return t->demux.dts == 0.0; } -+ -+ lkFIFO m_decInput; -+ lkFIFO -+ m_decOutput; -+ -+ static const unsigned int m_extraVpuBuffers; // Number of additional buffers for VPU - // by both decoding and rendering threads -- static CCriticalSection m_codecBufferLock; // Lock to protect buffers handled - 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_dropRequest; // Current drop request -- bool m_dropState; // Actual drop result -- int m_vpuFrameBufferNum; // Total number of allocated frame buffers -- VpuFrameBuffer *m_vpuFrameBuffers; // Table of VPU frame buffers description -- CDVDVideoCodecIMXBuffer **m_outputBuffers; // Table of VPU output buffers -- CDVDVideoCodecIMXBuffer *m_lastBuffer; // Keep track of previous VPU output buffer (needed by deinterlacing motion engin) -- CDVDVideoCodecIMXBuffer *m_currentBuffer; -- 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 -+ VpuDecSkipMode m_skipMode; // Current drop state -+ VpuDecInputType m_drainMode; -+ int m_dropped; -+ -+ std::vector m_vpuFrameBuffers; // Table of VPU frame buffers description -+ std::unordered_map -+ m_pts; -+ double m_lastPTS; - VpuDecOutFrameInfo m_frameInfo; // Store last VPU output frame info - CBitstreamConverter *m_converter; // H264 annex B converter -- bool m_convert_bitstream; // State whether bitstream conversion is required -- 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 - bool m_warnOnce; // Track warning messages to only warn once -+ int m_codecControlFlags; -+ int m_speed; -+ CCriticalSection m_signalLock; -+ CCriticalSection m_queuesLock; - #ifdef DUMP_STREAM - FILE *m_dump; - #endif -+ -+private: -+ bool IsDraining() { return m_drainMode || m_codecControlFlags & DVD_CODEC_CTRL_DRAIN; } -+ bool EOS() { return m_decRet & VPU_DEC_OUTPUT_EOS; } -+ bool FBRegistered() { return m_vpuFrameBuffers.size(); } -+ -+ bool getOutputFrame(VpuDecOutFrameInfo *frm); -+ void ProcessSignals(int signal = 0); -+ void AddExtraData(VpuBufferNode *bn, bool force = false); -+ -+ bool VpuAlloc(VpuMemDesc *vpuMem); -+ -+ void DisposeDecQueues(); -+ void FlushVPU(); -+ -+ void Dispose(); -+ -+ unsigned int m_decSignal; -+ ThreadIdentifier m_threadID; -+ CEvent m_loaded; -+ int m_decRet; -+ double m_fps; -+ -+private: -+ void ExitError(const char *msg, ...); -+ bool IsCurrentThread() const; -+ -+ CCriticalSection m_openLock; -+}; -+ -+class CDVDVideoCodecIMX : public CDVDVideoCodec -+{ -+public: -+ CDVDVideoCodecIMX(CProcessInfo &processInfo) : CDVDVideoCodec(processInfo), m_pFormatName("iMX-xxx") {} -+ virtual ~CDVDVideoCodecIMX(); -+ -+ // Methods from CDVDVideoCodec which require overrides -+ virtual bool Open(CDVDStreamInfo &hints, CDVDCodecOptions &options); -+ virtual bool ClearPicture(DVDVideoPicture *pDvdVideoPicture); -+ -+ virtual int Decode(BYTE *pData, int iSize, double dts, double pts) { return m_IMXCodec->Decode(pData, iSize, dts, pts); } -+ -+ virtual void Reset() { m_IMXCodec->Reset(); } -+ virtual const char* GetName() { return (const char*)m_pFormatName.c_str(); } -+ -+ virtual bool GetPicture(DVDVideoPicture *pDvdVideoPicture) { return m_IMXCodec->GetPicture(pDvdVideoPicture); } -+ virtual void SetDropState(bool bDrop) { m_IMXCodec->SetDropState(bDrop); } -+ virtual unsigned GetAllowedReferences(); -+ -+ virtual bool GetCodecStats(double &pts, int &droppedFrames, int &skippedPics) override -+ { return m_IMXCodec->GetCodecStats(pts, droppedFrames, skippedPics); } -+ virtual void SetCodecControl(int flags) override { m_IMXCodec->SetCodecControl(flags); } -+ virtual void SetSpeed(int iSpeed) { m_IMXCodec->SetSpeed(iSpeed); } -+ -+ virtual bool GetInterlaced() { return m_IMXCodec->GetInterlaced(); } -+ -+ std::string GetPlayerInfo() { return m_IMXCodec ? m_IMXCodec->GetPlayerInfo() : ""; } -+ -+private: -+ std::shared_ptr m_IMXCodec; -+ -+ std::string m_pFormatName; // Current decoder format name - }; -+ -diff --git a/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxFFmpeg.cpp b/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxFFmpeg.cpp -index f37a2ea..fd041c1 100644 ---- a/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxFFmpeg.cpp -+++ b/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxFFmpeg.cpp -@@ -419,7 +419,7 @@ bool CDVDDemuxFFmpeg::Open(CDVDInputStream* pInput, bool streaminfo, bool filein - bool isBluray = pInput->IsStreamType(DVDSTREAM_TYPE_BLURAY); - if (iformat && (strcmp(iformat->name, "mpegts") == 0) && !fileinfo && !isBluray) - { -- av_opt_set_int(m_pFormatContext, "analyzeduration", 500000, 0); -+ av_opt_set_int(m_pFormatContext, "analyzeduration", 1000000, 0); - m_checkvideo = true; - skipCreateStreams = true; - } -diff --git a/xbmc/cores/VideoPlayer/VideoPlayerAudio.cpp b/xbmc/cores/VideoPlayer/VideoPlayerAudio.cpp -index e8f073f..39c23ca 100644 ---- a/xbmc/cores/VideoPlayer/VideoPlayerAudio.cpp -+++ b/xbmc/cores/VideoPlayer/VideoPlayerAudio.cpp -@@ -485,6 +485,8 @@ void CVideoPlayerAudio::Process() - } - } - } -+ -+ UpdatePlayerInfo(); - } - - // guess next pts -diff --git a/xbmc/cores/VideoPlayer/VideoPlayerVideo.cpp b/xbmc/cores/VideoPlayer/VideoPlayerVideo.cpp -index cdd1938..7ee8702 100644 ---- a/xbmc/cores/VideoPlayer/VideoPlayerVideo.cpp -+++ b/xbmc/cores/VideoPlayer/VideoPlayerVideo.cpp -@@ -38,6 +38,9 @@ - #include - #include - #include "utils/log.h" -+#ifdef HAS_IMXVPU -+#include "DVDCodecs/Video/DVDVideoCodecIMX.h" -+#endif - - using namespace RenderManager; - -@@ -769,6 +772,7 @@ int CVideoPlayerVideo::OutputPicture(const DVDVideoPicture* src, double pts) - } - - flags |= stereo_flags; -+ flags |= GetInterlacedModeFlag(m_pVideoCodec->GetInterlaced()); - - if(!m_renderManager.Configure(picture, - config_framerate, -@@ -907,6 +911,9 @@ std::string CVideoPlayerVideo::GetPlayerInfo() - s << ", pc:" << pc; - else - s << ", pc:none"; -+#ifdef HAS_IMXVPU -+ s << ", " << ((CDVDVideoCodecIMX*)m_pVideoCodec)->GetPlayerInfo(); -+#endif - - return s.str(); - } -diff --git a/xbmc/cores/VideoPlayer/VideoRenderers/BaseRenderer.cpp b/xbmc/cores/VideoPlayer/VideoRenderers/BaseRenderer.cpp -index f18c671..60224b6 100644 ---- a/xbmc/cores/VideoPlayer/VideoRenderers/BaseRenderer.cpp -+++ b/xbmc/cores/VideoPlayer/VideoRenderers/BaseRenderer.cpp -@@ -22,6 +22,7 @@ - - #include // std::abs(int) prototype - #include -+#include - #include "BaseRenderer.h" - #include "settings/DisplaySettings.h" - #include "settings/MediaSettings.h" -@@ -34,6 +35,7 @@ - #include "utils/SystemInfo.h" - #include "settings/AdvancedSettings.h" - #include "cores/VideoPlayer/VideoRenderers/RenderFlags.h" -+#include "cores/VideoPlayer/VideoRenderers/RenderManager.h" - - - CBaseRenderer::CBaseRenderer() -@@ -220,6 +222,14 @@ void CBaseRenderer::CalcNormalRenderRect(float offsetX, float offsetY, float wid - return; - } - -+#if defined(HAS_IMXVPU) -+ if (g_graphicsContext.GetResInfo().dwFlags & D3DPRESENTFLAG_INTERLACED) -+ { -+ inputFrameRatio = (float) width / height; -+ zoomAmount = 1.0f; -+ } -+#endif -+ - // scale up image as much as possible - // and keep the aspect ratio (introduces with black bars) - // calculate the correct output frame ratio (using the users pixel ratio setting -diff --git a/xbmc/cores/VideoPlayer/VideoRenderers/HwDecRender/RendererIMX.cpp b/xbmc/cores/VideoPlayer/VideoRenderers/HwDecRender/RendererIMX.cpp -index ed5b643..ffd807d 100644 ---- a/xbmc/cores/VideoPlayer/VideoRenderers/HwDecRender/RendererIMX.cpp -+++ b/xbmc/cores/VideoPlayer/VideoRenderers/HwDecRender/RendererIMX.cpp -@@ -30,10 +30,12 @@ - #include "windowing/WindowingFactory.h" - #include "cores/VideoPlayer/VideoRenderers/RenderCapture.h" - #include "cores/VideoPlayer/VideoRenderers/RenderFlags.h" -+#include "linux/imx/IMX.h" - - #define RENDER_FLAG_FIELDS (RENDER_FLAG_FIELD0 | RENDER_FLAG_FIELD1) - - CRendererIMX::CRendererIMX() -+ : buffer_p(nullptr) - { - - } -@@ -41,6 +43,9 @@ CRendererIMX::CRendererIMX() - CRendererIMX::~CRendererIMX() - { - UnInit(); -+ SAFE_RELEASE(buffer_p); -+ g_IMXContext.Clear(); -+ g_IMX.Deinitialize(); - } - - bool CRendererIMX::RenderCapture(CRenderCapture* capture) -@@ -86,8 +91,12 @@ bool CRendererIMX::Supports(EINTERLACEMETHOD method) - if(method == VS_INTERLACEMETHOD_AUTO) - return true; - -- if(method == VS_INTERLACEMETHOD_IMX_FASTMOTION -- || method == VS_INTERLACEMETHOD_IMX_FASTMOTION_DOUBLE) -+ if(method == VS_INTERLACEMETHOD_IMX_ADVMOTION -+ || method == VS_INTERLACEMETHOD_IMX_WEAVE -+ || method == VS_INTERLACEMETHOD_IMX_FASTMOTION -+ || method == VS_INTERLACEMETHOD_IMX_ADVMOTION_DOUBLE -+ || method == VS_INTERLACEMETHOD_IMX_FASTMOTION_DOUBLE -+ || method == VS_INTERLACEMETHOD_IMX_FASTMOTION_DOUBLE_INVERTED) - return true; - else - return false; -@@ -105,12 +114,12 @@ bool CRendererIMX::Supports(EDEINTERLACEMODE mode) - - bool CRendererIMX::Supports(ESCALINGMETHOD method) - { -- return false; -+ return method == VS_SCALINGMETHOD_AUTO; - } - - EINTERLACEMETHOD CRendererIMX::AutoInterlaceMethod() - { -- return VS_INTERLACEMETHOD_IMX_FASTMOTION; -+ return VS_INTERLACEMETHOD_IMX_ADVMOTION_DOUBLE; - } - - CRenderInfo CRendererIMX::GetRenderInfo() -@@ -138,6 +147,9 @@ bool CRendererIMX::RenderHook(int index) - - bool CRendererIMX::RenderUpdateVideoHook(bool clear, DWORD flags, DWORD alpha) - { -+ static int bufPrev; -+ static DWORD flagsPrev; -+ - #if 0 - static unsigned long long previous = 0; - unsigned long long current = XbmcThreads::SystemClockMillis(); -@@ -145,8 +157,17 @@ bool CRendererIMX::RenderUpdateVideoHook(bool clear, DWORD flags, DWORD alpha) - previous = current; - #endif - CDVDVideoCodecIMXBuffer *buffer = static_cast(m_buffers[m_iYV12RenderBuffer].hwDec); -- if (buffer != NULL && buffer->IsValid()) -+ if (buffer) - { -+ if (!(bufPrev ^ m_iYV12RenderBuffer | flagsPrev ^ flags)) -+ { -+ g_IMX.WaitVsync(); -+ return true; -+ } -+ -+ bufPrev = m_iYV12RenderBuffer; -+ flagsPrev = flags; -+ - // this hack is needed to get the 2D mode of a 3D movie going - RENDER_STEREO_MODE stereo_mode = g_graphicsContext.GetStereoMode(); - if (stereo_mode) -@@ -178,25 +199,29 @@ bool CRendererIMX::RenderUpdateVideoHook(bool clear, DWORD flags, DWORD alpha) - //CLog::Log(LOGDEBUG, "BLIT RECTS: source x1 %f x2 %f y1 %f y2 %f dest x1 %f x2 %f y1 %f y2 %f", srcRect.x1, srcRect.x2, srcRect.y1, srcRect.y2, dstRect.x1, dstRect.x2, dstRect.y1, dstRect.y2); - g_IMXContext.SetBlitRects(srcRect, dstRect); - -- uint8_t fieldFmt = 0; -- if (g_graphicsContext.IsFullScreenVideo()) -+ uint8_t fieldFmt = flags & RENDER_FLAG_FIELDMASK; -+ if (flags & RENDER_FLAG_FIELDS && g_graphicsContext.IsFullScreenVideo()) - { -- fieldFmt |= flags & RENDER_FLAG_FIELDMASK; -- if (flags & RENDER_FLAG_FIELDS) -+ fieldFmt |= IPU_DEINTERLACE_RATE_EN; -+ if (flags & RENDER_FLAG_FIELD1) - { -- fieldFmt |= IPU_DEINTERLACE_RATE_EN; -- if (flags & RENDER_FLAG_FIELD1) -- { -- fieldFmt |= IPU_DEINTERLACE_RATE_FRAME1; -- // CXBMCRenderManager::PresentFields() is swapping field flag for frame1 -- // this makes IPU render same picture as before, just shifted one line. -- // let's correct this -- fieldFmt ^= RENDER_FLAG_FIELDMASK; -- } -+ fieldFmt |= IPU_DEINTERLACE_RATE_FRAME1; -+ // CXBMCRenderManager::PresentFields() is swapping field flag for frame1 -+ // this makes IPU render same picture as before, just shifted one line. -+ // let's correct this -+ fieldFmt ^= RENDER_FLAG_FIELDMASK; - } - } - -- g_IMXContext.BlitAsync(NULL, buffer, fieldFmt); -+ g_IMXContext.Blit(buffer_p, buffer, fieldFmt); -+ -+ if (flags & RENDER_FLAG_FIELDMASK && !(flags & RENDER_FLAG_FIELD0)) -+ { -+ SAFE_RELEASE(buffer_p); -+ -+ buffer_p = buffer; -+ buffer_p->Lock(); -+ } - } - - #if 0 -diff --git a/xbmc/cores/VideoPlayer/VideoRenderers/HwDecRender/RendererIMX.h b/xbmc/cores/VideoPlayer/VideoRenderers/HwDecRender/RendererIMX.h -index 22b1ed0..74f6888 100644 ---- a/xbmc/cores/VideoPlayer/VideoRenderers/HwDecRender/RendererIMX.h -+++ b/xbmc/cores/VideoPlayer/VideoRenderers/HwDecRender/RendererIMX.h -@@ -60,6 +60,8 @@ protected: - virtual bool RenderHook(int index); - virtual int GetImageHook(YV12Image *image, int source = AUTOSOURCE, bool readonly = false); - virtual bool RenderUpdateVideoHook(bool clear, DWORD flags = 0, DWORD alpha = 255); -+ -+ CDVDVideoCodecIMXBuffer *buffer_p; - }; - - #endif -diff --git a/xbmc/cores/VideoPlayer/VideoRenderers/RenderFlags.cpp b/xbmc/cores/VideoPlayer/VideoRenderers/RenderFlags.cpp -index 809766a..b4c6586 100644 ---- a/xbmc/cores/VideoPlayer/VideoRenderers/RenderFlags.cpp -+++ b/xbmc/cores/VideoPlayer/VideoRenderers/RenderFlags.cpp -@@ -108,6 +108,11 @@ namespace RenderManager { - return convert[mode]; - } - -+ unsigned int GetInterlacedModeFlag(bool interlaced) -+ { -+ return interlaced ? CONF_FLAGS_INTERLACED : 0; -+ } -+ - std::string GetStereoModeInvert(const std::string& mode) - { - static std::map convert; -diff --git a/xbmc/cores/VideoPlayer/VideoRenderers/RenderFlags.h b/xbmc/cores/VideoPlayer/VideoRenderers/RenderFlags.h -index f65d4b2..39e4743 100644 ---- a/xbmc/cores/VideoPlayer/VideoRenderers/RenderFlags.h -+++ b/xbmc/cores/VideoPlayer/VideoRenderers/RenderFlags.h -@@ -79,7 +79,9 @@ - #define CONF_FLAGS_STEREO_CADANCE_LEFT_RIGHT 0x000000 - #define CONF_FLAGS_STEREO_CADANCE_RIGHT_LEFT 0x008000 - -- -+/* defines interlaced modes */ -+#define CONF_FLAGS_INTERLACED 0x010000 -+#define CONF_FLAGS_INTERLACED_MODE_MASK(a) ((a) & CONF_FLAGS_INTERLACED) - - namespace RenderManager { - -@@ -88,6 +90,7 @@ namespace RenderManager { - unsigned int GetFlagsColorPrimaries(unsigned int color_primaries); - unsigned int GetFlagsColorTransfer(unsigned int color_transfer); - unsigned int GetStereoModeFlags(const std::string& mode); -+ unsigned int GetInterlacedModeFlag(bool interlaced); - std::string GetStereoModeInvert(const std::string& mode); - - } -diff --git a/xbmc/cores/VideoPlayer/VideoRenderers/RenderManager.cpp b/xbmc/cores/VideoPlayer/VideoRenderers/RenderManager.cpp -index aaf5359..9e0b81d 100644 ---- a/xbmc/cores/VideoPlayer/VideoRenderers/RenderManager.cpp -+++ b/xbmc/cores/VideoPlayer/VideoRenderers/RenderManager.cpp -@@ -808,26 +808,16 @@ void CRenderManager::FlipPage(volatile s - { - { - bool invert = false; -- if (interlacemethod == VS_INTERLACEMETHOD_RENDER_BLEND) -- presentmethod = PRESENT_METHOD_BLEND; -- else if (interlacemethod == VS_INTERLACEMETHOD_RENDER_WEAVE) -- presentmethod = PRESENT_METHOD_WEAVE; -- else if (interlacemethod == VS_INTERLACEMETHOD_RENDER_WEAVE_INVERTED) -- { -- presentmethod = PRESENT_METHOD_WEAVE; -- invert = true; -- } -- else if (interlacemethod == VS_INTERLACEMETHOD_RENDER_BOB) -- presentmethod = PRESENT_METHOD_BOB; -- else if (interlacemethod == VS_INTERLACEMETHOD_RENDER_BOB_INVERTED) -- { -- presentmethod = PRESENT_METHOD_BOB; -- invert = true; -- } -- else if (interlacemethod == VS_INTERLACEMETHOD_IMX_FASTMOTION_DOUBLE) -- presentmethod = PRESENT_METHOD_BOB; -- else -- presentmethod = PRESENT_METHOD_SINGLE; -+ if (interlacemethod == VS_INTERLACEMETHOD_RENDER_BLEND) presentmethod = PRESENT_METHOD_BLEND; -+ else if (interlacemethod == VS_INTERLACEMETHOD_RENDER_WEAVE) presentmethod = PRESENT_METHOD_WEAVE; -+ else if (interlacemethod == VS_INTERLACEMETHOD_RENDER_WEAVE_INVERTED) { presentmethod = PRESENT_METHOD_WEAVE ; invert = true; } -+ else if (interlacemethod == VS_INTERLACEMETHOD_RENDER_BOB) presentmethod = PRESENT_METHOD_BOB; -+ else if (interlacemethod == VS_INTERLACEMETHOD_RENDER_BOB_INVERTED) { presentmethod = PRESENT_METHOD_BOB; invert = true; } -+ else if (interlacemethod == VS_INTERLACEMETHOD_IMX_ADVMOTION_DOUBLE) presentmethod = PRESENT_METHOD_BOB; -+ else if (interlacemethod == VS_INTERLACEMETHOD_IMX_FASTMOTION_DOUBLE) presentmethod = PRESENT_METHOD_BOB; -+ else if (interlacemethod == VS_INTERLACEMETHOD_IMX_FASTMOTION_DOUBLE_INVERTED) -+ { presentmethod = PRESENT_METHOD_BOB; invert = true; } -+ else presentmethod = PRESENT_METHOD_SINGLE; - - if (presentmethod != PRESENT_METHOD_SINGLE) - { - -@@ -884,7 +874,7 @@ RESOLUTION CRenderManager::GetResolution() - return res; - - if (CSettings::GetInstance().GetInt(CSettings::SETTING_VIDEOPLAYER_ADJUSTREFRESHRATE) != ADJUST_REFRESHRATE_OFF) -- res = CResolutionUtils::ChooseBestResolution(m_fps, m_width, CONF_FLAGS_STEREO_MODE_MASK(m_flags)); -+ res = CResolutionUtils::ChooseBestResolution(m_fps, m_width, m_height, CONF_FLAGS_STEREO_MODE_MASK(m_flags), CONF_FLAGS_INTERLACED_MODE_MASK(m_flags)); - - return res; - } -@@ -1090,7 +1080,7 @@ void CRenderManager::UpdateResolution() - { - if (CSettings::GetInstance().GetInt(CSettings::SETTING_VIDEOPLAYER_ADJUSTREFRESHRATE) != ADJUST_REFRESHRATE_OFF && m_fps > 0.0f) - { -- RESOLUTION res = CResolutionUtils::ChooseBestResolution(m_fps, m_width, CONF_FLAGS_STEREO_MODE_MASK(m_flags)); -+ RESOLUTION res = CResolutionUtils::ChooseBestResolution(m_fps, m_width, m_height, CONF_FLAGS_STEREO_MODE_MASK(m_flags), CONF_FLAGS_INTERLACED_MODE_MASK(m_flags)); - g_graphicsContext.SetVideoResolution(res); - UpdateDisplayLatency(); - -@@ -1413,6 +1403,12 @@ bool CRenderManager::GetStats(int &lateframes, double &pts, int &queued, int &di - - void CRenderManager::CheckEnableClockSync() - { -+ if (CSettings::GetInstance().GetBool(CSettings::SETTING_VIDEOPLAYER_USEDISPLAYASCLOCK)) -+ { -+ m_clockSync.m_enabled = true; -+ return; -+ } -+ - // refresh rate can be a multiple of video fps - double diff = 1.0; - -diff --git a/xbmc/dbwrappers/Database.cpp b/xbmc/dbwrappers/Database.cpp -index 4dc71c5..a590487 100644 ---- a/xbmc/dbwrappers/Database.cpp -+++ b/xbmc/dbwrappers/Database.cpp -@@ -532,6 +532,9 @@ bool CDatabase::UpdateVersion(const std::string &dbName) - } - else if (version < GetSchemaVersion()) - { -+ CLog::Log(LOGNOTICE, "XBian: notifying Upstart (doing DB upgrades)"); -+ system("sudo /sbin/start -n -q xbmc-loaded"); -+ - CLog::Log(LOGNOTICE, "Attempting to update the database %s from version %i to %i", dbName.c_str(), version, GetSchemaVersion()); - bool success = true; - BeginTransaction(); -diff --git a/xbmc/filesystem/CurlFile.cpp b/xbmc/filesystem/CurlFile.cpp -index d3ab8b1..ee1ad20 100644 ---- a/xbmc/filesystem/CurlFile.cpp -+++ b/xbmc/filesystem/CurlFile.cpp -@@ -18,6 +18,8 @@ - * - */ - -+#include "network/Network.h" -+#include "Application.h" - #include "CurlFile.h" - #include "utils/URIUtils.h" - #include "Util.h" -@@ -917,13 +919,13 @@ bool CCurlFile::Download(const std::string& strURL, const std::string& strFileNa - // Detect whether we are "online" or not! Very simple and dirty! - bool CCurlFile::IsInternet() - { -- CURL url("http://www.msftncsi.com/ncsi.txt"); -+ CURL url(StringUtils::Format("http://%s.msftncsi.com/ncsi.txt", g_application.getNetwork().GetFirstConnectedFamily() == AF_INET6 ? "ipv6" : "www")); - bool found = Exists(url); - if (!found) - { - // fallback - Close(); -- url.Parse("http://www.w3.org/"); -+ url.Parse(StringUtils::Format("http://%s.w3.org/", g_application.getNetwork().GetFirstConnectedFamily() == AF_INET6 ? "ipv6" : "www")); - found = Exists(url); - } - Close(); -diff --git a/xbmc/filesystem/DirectoryFactory.cpp b/xbmc/filesystem/DirectoryFactory.cpp -index c66e1d8..c87cb63 100644 ---- a/xbmc/filesystem/DirectoryFactory.cpp -+++ b/xbmc/filesystem/DirectoryFactory.cpp -@@ -91,6 +91,9 @@ - #ifdef HAS_FILESYSTEM_NFS - #include "NFSDirectory.h" - #endif -+#ifdef HAS_FILESYSTEM_AFP -+#include "AFPDirectory.h" -+#endif - #ifdef HAVE_LIBBLURAY - #include "BlurayDirectory.h" - #endif -@@ -171,7 +174,7 @@ IDirectory* CDirectoryFactory::Create(const CURL& url) - if (url.IsProtocol("resource")) return new CResourceDirectory(); - if (url.IsProtocol("events")) return new CEventsDirectory(); - -- bool networkAvailable = g_application.getNetwork().IsAvailable(); -+ bool networkAvailable = g_application.getNetwork().IsConnected(); - if (networkAvailable) - { - if (url.IsProtocol("ftp") || url.IsProtocol("ftps")) return new CFTPDirectory(); -@@ -202,6 +205,9 @@ IDirectory* CDirectoryFactory::Create(const CURL& url) - #ifdef HAS_FILESYSTEM_NFS - if (url.IsProtocol("nfs")) return new CNFSDirectory(); - #endif -+#ifdef HAS_FILESYSTEM_AFP -+ if (url.IsProtocol("afp")) return new CAFPDirectory(); -+#endif - } - - CLog::Log(LOGWARNING, "%s - %sunsupported protocol(%s) in %s", __FUNCTION__, networkAvailable ? "" : "Network down or ", url.GetProtocol().c_str(), url.GetRedacted().c_str() ); -diff --git a/xbmc/filesystem/FileFactory.cpp b/xbmc/filesystem/FileFactory.cpp -index 66e2c4b..dc1044e 100644 ---- a/xbmc/filesystem/FileFactory.cpp -+++ b/xbmc/filesystem/FileFactory.cpp -@@ -60,6 +60,9 @@ - #ifdef HAS_FILESYSTEM_NFS - #include "NFSFile.h" - #endif -+#ifdef HAS_FILESYSTEM_AFP -+#include "AFPFile.h" -+#endif - #if defined(TARGET_ANDROID) - #include "AndroidAppFile.h" - #endif -@@ -142,7 +145,7 @@ IFile* CFileFactory::CreateLoader(const CURL& url) - #endif - else if (url.IsProtocol("resource")) return new CResourceFile(); - -- bool networkAvailable = g_application.getNetwork().IsAvailable(); -+ bool networkAvailable = g_application.getNetwork().IsConnected(); - if (networkAvailable) - { - if (url.IsProtocol("ftp") -@@ -165,6 +168,9 @@ IFile* CFileFactory::CreateLoader(const CURL& url) - #ifdef HAS_FILESYSTEM_NFS - else if (url.IsProtocol("nfs")) return new CNFSFile(); - #endif -+#ifdef HAS_FILESYSTEM_AFP -+ else if (url.IsProtocol("afp")) return new CAFPFile(); -+#endif - #ifdef HAS_UPNP - else if (url.IsProtocol("upnp")) return new CUPnPFile(); - #endif -diff --git a/xbmc/guilib/Resolution.cpp b/xbmc/guilib/Resolution.cpp -index b307524..64c7eda 100644 ---- a/xbmc/guilib/Resolution.cpp -+++ b/xbmc/guilib/Resolution.cpp -@@ -24,7 +24,13 @@ - #include "utils/MathUtils.h" - #include "settings/AdvancedSettings.h" - #include "settings/DisplaySettings.h" -+#include "settings/Settings.h" - #include -+#include -+ -+#include "Application.h" -+ -+#include "windowing/egl/vc_hdmi.h" - - RESOLUTION_INFO::RESOLUTION_INFO(int width, int height, float aspect, const std::string &mode) : - strMode(mode) -@@ -51,7 +57,7 @@ RESOLUTION_INFO::RESOLUTION_INFO(const RESOLUTION_INFO& res) : - iScreenWidth = res.iScreenWidth; iScreenHeight = res.iScreenHeight; - iSubtitles = res.iSubtitles; dwFlags = res.dwFlags; - fPixelRatio = res.fPixelRatio; fRefreshRate = res.fRefreshRate; -- iBlanking = res.iBlanking; -+ refresh_rate = res.refresh_rate; iBlanking = res.iBlanking; - } - - float RESOLUTION_INFO::DisplayRatio() const -@@ -59,21 +65,21 @@ float RESOLUTION_INFO::DisplayRatio() const - return iWidth * fPixelRatio / iHeight; - } - --RESOLUTION CResolutionUtils::ChooseBestResolution(float fps, int width, bool is3D) -+RESOLUTION CResolutionUtils::ChooseBestResolution(float fps, int width, int height, bool is3D, bool isI) - { - RESOLUTION res = g_graphicsContext.GetVideoResolution(); - float weight; -- if (!FindResolutionFromOverride(fps, width, is3D, res, weight, false)) //find a refreshrate from overrides -+ if (!FindResolutionFromOverride(fps, width, height, is3D, isI, res, weight, false)) //find a refreshrate from overrides - { -- if (!FindResolutionFromOverride(fps, width, is3D, res, weight, true))//if that fails find it from a fallback -- FindResolutionFromFpsMatch(fps, width, is3D, res, weight);//if that fails use automatic refreshrate selection -+ if (!FindResolutionFromOverride(fps, width, height, is3D, isI, res, weight, true))//if that fails find it from a fallback -+ FindResolutionFromFpsMatch(fps, width, height, is3D, isI, res, weight);//if that fails use automatic refreshrate selection - } - CLog::Log(LOGNOTICE, "Display resolution ADJUST : %s (%d) (weight: %.3f)", - g_graphicsContext.GetResInfo(res).strMode.c_str(), res, weight); - return res; - } - --bool CResolutionUtils::FindResolutionFromOverride(float fps, int width, bool is3D, RESOLUTION &resolution, float& weight, bool fallback) -+bool CResolutionUtils::FindResolutionFromOverride(float fps, int width, int height, bool is3D, bool isI, RESOLUTION &resolution, float& weight, bool fallback) - { - RESOLUTION_INFO curr = g_graphicsContext.GetResInfo(resolution); - -@@ -127,12 +133,12 @@ bool CResolutionUtils::FindResolutionFromOverride(float fps, int width, bool is3 - return false; //no override found - } - --void CResolutionUtils::FindResolutionFromFpsMatch(float fps, int width, bool is3D, RESOLUTION &resolution, float& weight) -+void CResolutionUtils::FindResolutionFromFpsMatch(float fps, int width, int height, bool is3D, bool isI, RESOLUTION &resolution, float& weight) - { - const float maxWeight = 0.0021f; - RESOLUTION_INFO curr; - -- resolution = FindClosestResolution(fps, width, is3D, 1.0, resolution, weight); -+ resolution = FindClosestResolution(fps, width, height, is3D, isI, 1.0, resolution, weight); - curr = g_graphicsContext.GetResInfo(resolution); - - if (weight >= maxWeight) //not a very good match, try a 2:3 cadence instead -@@ -140,7 +146,7 @@ void CResolutionUtils::FindResolutionFromFpsMatch(float fps, int width, bool is3 - CLog::Log(LOGDEBUG, "Resolution %s (%d) not a very good match for fps %.3f (weight: %.3f), trying 2:3 cadence", - curr.strMode.c_str(), resolution, fps, weight); - -- resolution = FindClosestResolution(fps, width, is3D, 2.5, resolution, weight); -+ resolution = FindClosestResolution(fps, width, height, is3D, isI, 2.5, resolution, weight); - curr = g_graphicsContext.GetResInfo(resolution); - - if (weight >= maxWeight) //2:3 cadence not a good match -@@ -191,8 +197,11 @@ void CResolutionUtils::FindResolutionFromFpsMatch(float fps, int width, bool is3 - } - } - --RESOLUTION CResolutionUtils::FindClosestResolution(float fps, int width, bool is3D, float multiplier, RESOLUTION current, float& weight) -+RESOLUTION CResolutionUtils::FindClosestResolution(float fps, int width, int height, bool is3D, bool isI, float multiplier, RESOLUTION current, float& weight) - { -+ if (CDisplaySettings::GetInstance().ResolutionInfoSize() < 2) -+ return current; -+ - RESOLUTION_INFO curr = g_graphicsContext.GetResInfo(current); - RESOLUTION orig_res = CDisplaySettings::GetInstance().GetCurrentResolution(); - -@@ -203,11 +212,80 @@ RESOLUTION CResolutionUtils::FindClosestResolution(float fps, int width, bool is - - float fRefreshRate = fps; - -- float last_diff = fRefreshRate; -+ float last_diff = FLT_MAX; - - int curr_diff = std::abs(width - curr.iScreenWidth); - int loop_diff = 0; - -+ // CHANGERESOLUTION -+ if (CSettings::GetInstance().GetBool(CSettings::SETTING_VIDEOPLAYER_ADJUSTRESOLUTION) && !is3D) -+ { -+ bool i_found = false; -+ -+ // if interlaced mode -+ if (isI && CSettings::GetInstance().GetBool(CSettings::SETTING_VIDEOPLAYER_ADJUSTRESOLUTIONINTERLACED)) -+ for (size_t i = (int)RES_DESKTOP; i < CDisplaySettings::GetInstance().ResolutionInfoSize(); i++) -+ { -+ const RESOLUTION_INFO info = g_graphicsContext.GetResInfo((RESOLUTION)i); -+ if (!(info.dwFlags & D3DPRESENTFLAG_INTERLACED) -+ || CSettings::GetInstance().GetInt(CSettings::SETTING_VIDEOPLAYER_MINIMUMVERTICAL) > info.iScreenHeight -+ || ((int)CSettings::GetInstance().GetBool(CSettings::SETTING_VIDEOPLAYER_ADJUSTALLOWNONCEA) < GETFLAGS_GROUP(info.dwFlags)-1) -+ || info.iScreenHeight != height -+ || IS_3D(info.dwFlags)) -+ continue; -+ -+ current = (RESOLUTION)i; -+ curr = info; -+ i_found = true; -+ } -+ -+ if (!i_found) -+ for (size_t i = (int)RES_DESKTOP; i < CDisplaySettings::GetInstance().ResolutionInfoSize(); i++) -+ { -+ const RESOLUTION_INFO info = g_graphicsContext.GetResInfo((RESOLUTION)i); -+ if ((fabs(info.fRefreshRate - fRefreshRate) > 0.001 && fabs(info.fRefreshRate - 2*fRefreshRate) > 0.001) -+ || IS_3D(info.dwFlags) -+ || CSettings::GetInstance().GetInt(CSettings::SETTING_VIDEOPLAYER_MINIMUMVERTICAL) > info.iScreenHeight -+ || (info.dwFlags & D3DPRESENTFLAG_INTERLACED && !isI) -+ || (!CSettings::GetInstance().GetBool(CSettings::SETTING_VIDEOPLAYER_ADJUSTRESOLUTIONINTERLACED) && (info.dwFlags & D3DPRESENTFLAG_INTERLACED)) -+ || ((int)CSettings::GetInstance().GetBool(CSettings::SETTING_VIDEOPLAYER_ADJUSTALLOWNONCEA) < GETFLAGS_GROUP(info.dwFlags)-1) -+ || width > info.iScreenWidth || height > info.iScreenHeight -+ || pow(info.iScreenWidth*info.iScreenHeight - width*height, 2) > last_diff) -+ continue; -+ -+ current = (RESOLUTION)i; -+ curr = info; -+ i_found = true; -+ last_diff = pow(curr.iScreenWidth*curr.iScreenHeight - width*height, 2); -+ -+ if (info.iScreenWidth == width && info.iScreenHeight == height) -+ break; -+ } -+ -+ last_diff = FLT_MAX; -+ for (size_t i = (int)RES_DESKTOP; !i_found && i < CDisplaySettings::GetInstance().ResolutionInfoSize(); i++) -+ { -+ const RESOLUTION_INFO info = g_graphicsContext.GetResInfo((RESOLUTION)i); -+ -+ if (width > info.iScreenWidth || height > info.iScreenHeight -+ || CSettings::GetInstance().GetInt(CSettings::SETTING_VIDEOPLAYER_MINIMUMVERTICAL) > info.iScreenHeight -+ || pow(info.iScreenWidth*info.iScreenHeight - width*height, 2) > last_diff -+ || info.iScreen != curr.iScreen -+ || ((int)CSettings::GetInstance().GetBool(CSettings::SETTING_VIDEOPLAYER_ADJUSTALLOWNONCEA) < GETFLAGS_GROUP(info.dwFlags)-1) -+ || (info.dwFlags & D3DPRESENTFLAG_MODEMASK) != (curr.dwFlags & D3DPRESENTFLAG_MODEMASK)) -+ { -+ /* CLog::Log(LOGDEBUG, "curr %.2f, trying %.2f, mode nr. %d, %dx%d msk %d, m_msk %d", info.fPixelRatio, curr.fPixelRatio, i, -+ info.iScreenWidth, info.iScreenHeight, info.dwFlags & D3DPRESENTFLAG_MODEMASK, -+ m_iFlags & D3DPRESENTFLAG_MODEMASK); */ -+ continue; -+ } -+ -+ current = (RESOLUTION)i; -+ curr = info; -+ last_diff = pow(curr.iScreenWidth*curr.iScreenHeight - width*height, 2); -+ } -+ } -+ - // Find closest refresh rate - for (size_t i = (int)RES_DESKTOP; i < CDisplaySettings::GetInstance().ResolutionInfoSize(); i++) - { -@@ -215,9 +293,15 @@ RESOLUTION CResolutionUtils::FindClosestResolution(float fps, int width, bool is - - //discard resolutions that are not the same width and height (and interlaced/3D flags) - //or have a too low refreshrate -- if (info.iScreenWidth != curr.iScreenWidth || -- info.iScreenHeight != curr.iScreenHeight || -- info.iScreen != curr.iScreen || -+ if ((!CSettings::GetInstance().GetBool(CSettings::SETTING_VIDEOPLAYER_ADJUSTRESOLUTION) && -+ (info.iScreenWidth != curr.iScreenWidth || -+ info.iScreenHeight != curr.iScreenHeight)) || -+ (CSettings::GetInstance().GetBool(CSettings::SETTING_VIDEOPLAYER_ADJUSTRESOLUTION) && -+ CSettings::GetInstance().GetInt(CSettings::SETTING_VIDEOPLAYER_MINIMUMVERTICAL) > info.iScreenHeight)) -+ continue; -+ -+ if (info.iScreen != curr.iScreen || -+ ((int)CSettings::GetInstance().GetBool(CSettings::SETTING_VIDEOPLAYER_ADJUSTALLOWNONCEA) < GETFLAGS_GROUP(info.dwFlags)-1) || - (info.dwFlags & D3DPRESENTFLAG_MODEMASK) != (curr.dwFlags & D3DPRESENTFLAG_MODEMASK) || - info.fRefreshRate < (fRefreshRate * multiplier / 1.001) - 0.001) - { -@@ -227,6 +311,7 @@ RESOLUTION CResolutionUtils::FindClosestResolution(float fps, int width, bool is - if ((width < orig.iScreenWidth) || // orig res large enough - (info.iScreenWidth < orig.iScreenWidth) || // new res is smaller - (info.iScreenHeight < orig.iScreenHeight) || // new height would be smaller -+ ((int)CSettings::GetInstance().GetBool(CSettings::SETTING_VIDEOPLAYER_ADJUSTALLOWNONCEA) < GETFLAGS_GROUP(info.dwFlags)-1) || - (info.dwFlags & D3DPRESENTFLAG_MODEMASK) != (curr.dwFlags & D3DPRESENTFLAG_MODEMASK) || // don't switch to interlaced modes - (info.iScreen != curr.iScreen)) // skip not current displays - { -diff --git a/xbmc/guilib/Resolution.h b/xbmc/guilib/Resolution.h -index f571528..9c69aee 100644 ---- a/xbmc/guilib/Resolution.h -+++ b/xbmc/guilib/Resolution.h -@@ -88,6 +88,7 @@ struct RESOLUTION_INFO - uint32_t dwFlags; - float fPixelRatio; - float fRefreshRate; -+ float refresh_rate; - std::string strMode; - std::string strOutput; - std::string strId; -@@ -100,10 +101,10 @@ public: - class CResolutionUtils - { - public: -- static RESOLUTION ChooseBestResolution(float fps, int width, bool is3D); -+ static RESOLUTION ChooseBestResolution(float fps, int width, int height, bool is3D, bool isI); -+ static RESOLUTION FindClosestResolution(float fps, int width, int height, bool is3D, bool isI, float multiplier, RESOLUTION current, float& weight); - protected: -- static bool FindResolutionFromOverride(float fps, int width, bool is3D, RESOLUTION &resolution, float& weight, bool fallback); -- static void FindResolutionFromFpsMatch(float fps, int width, bool is3D, RESOLUTION &resolution, float& weight); -- static RESOLUTION FindClosestResolution(float fps, int width, bool is3D, float multiplier, RESOLUTION current, float& weight); -+ static bool FindResolutionFromOverride(float fps, int width, int height, bool is3D, bool isI, RESOLUTION &resolution, float& weight, bool fallback); -+ static void FindResolutionFromFpsMatch(float fps, int width, int height, bool is3D, bool isI, RESOLUTION &resolution, float& weight); - static float RefreshWeight(float refresh, float fps); - }; -diff --git a/xbmc/input/linux/LinuxInputDevices.cpp b/xbmc/input/linux/LinuxInputDevices.cpp -index 5486e28..1da2986 100644 ---- a/xbmc/input/linux/LinuxInputDevices.cpp -+++ b/xbmc/input/linux/LinuxInputDevices.cpp -@@ -1245,6 +1245,17 @@ void CLinuxInputDevices::InitAvailable() - } - } - -+void CLinuxInputDevices::Close() -+{ -+ CSingleLock lock(m_devicesListLock); -+ -+ for (size_t i = 0; i < m_devices.size(); i++) -+ { -+ delete m_devices[i]; -+ } -+ m_devices.clear(); -+} -+ - /* - * Check for hot plugged devices. - */ -diff --git a/xbmc/input/linux/LinuxInputDevices.h b/xbmc/input/linux/LinuxInputDevices.h -index 44a05fe..409bc2e 100644 ---- a/xbmc/input/linux/LinuxInputDevices.h -+++ b/xbmc/input/linux/LinuxInputDevices.h -@@ -96,6 +96,7 @@ class CLinuxInputDevices - { - public: - void InitAvailable(); -+ void Close(); - void CheckHotplugged(); - XBMC_Event ReadEvent(); - bool IsRemoteLowBattery(); -diff --git a/xbmc/interfaces/IAnnouncer.h b/xbmc/interfaces/IAnnouncer.h -index e3dfdd1..3284590 100644 ---- a/xbmc/interfaces/IAnnouncer.h -+++ b/xbmc/interfaces/IAnnouncer.h -@@ -33,10 +33,11 @@ namespace ANNOUNCEMENT - Application = 0x040, - Input = 0x080, - PVR = 0x100, -- Other = 0x200 -+ Other = 0x200, -+ Network = 0x400 - }; - -- #define ANNOUNCE_ALL (Player | Playlist | GUI | System | VideoLibrary | AudioLibrary | Application | Input | ANNOUNCEMENT::PVR | Other) -+ #define ANNOUNCE_ALL (Player | Playlist | GUI | System | VideoLibrary | AudioLibrary | Application | Input | ANNOUNCEMENT::PVR | Other | Network) - - /*! - \brief Returns a string representation for the -@@ -68,6 +69,8 @@ namespace ANNOUNCEMENT - return "PVR"; - case Other: - return "Other"; -+ case Network: -+ return "Network"; - default: - return "Unknown"; - } -diff --git a/xbmc/interfaces/builtins/SystemBuiltins.cpp b/xbmc/interfaces/builtins/SystemBuiltins.cpp -index a3b568e..e6976be 100644 ---- a/xbmc/interfaces/builtins/SystemBuiltins.cpp -+++ b/xbmc/interfaces/builtins/SystemBuiltins.cpp -@@ -142,6 +142,12 @@ static int Suspend(const std::vector& params) - return 0; - } - -+static int ChangeVT(const std::vector& params) -+{ -+ CApplicationMessenger::GetInstance().PostMsg(TMSG_CHANGEVT, atoi(params[0].c_str())); -+ -+ return 0; -+} - - // Note: For new Texts with comma add a "\" before!!! Is used for table text. - // -@@ -246,6 +252,7 @@ CBuiltins::CommandMap CSystemBuiltins::GetOperations() const - {"shutdown", {"Shutdown the system", 0, Shutdown}}, - {"suspend", {"Suspends the system", 0, Suspend}}, - {"system.exec", {"Execute shell commands", 1, Exec<0>}}, -- {"system.execwait", {"Execute shell commands and freezes Kodi until shell is closed", 1, Exec<1>}} -+ {"system.execwait", {"Execute shell commands and freezes Kodi until shell is closed", 1, Exec<1>}}, -+ {"changevt", {"Change active VT", 1, ChangeVT}} - }; - } -diff --git a/xbmc/linux/RBP.cpp b/xbmc/linux/RBP.cpp -index 080f176..494865d 100644 ---- a/xbmc/linux/RBP.cpp -+++ b/xbmc/linux/RBP.cpp -@@ -264,6 +264,20 @@ void CRBP::Deinitialize() - vcsm_exit(); - } - -+void CRBP::SuspendVideoOutput() -+{ -+ CLog::Log(LOGDEBUG, "Raspberry PI suspending video output\n"); -+ char response[80]; -+ m_DllBcmHost->vc_gencmd(response, sizeof response, "display_power 0"); -+} -+ -+void CRBP::ResumeVideoOutput() -+{ -+ char response[80]; -+ m_DllBcmHost->vc_gencmd(response, sizeof response, "display_power 1"); -+ CLog::Log(LOGDEBUG, "Raspberry PI resuming video output\n"); -+} -+ - static int mbox_property(int file_desc, void *buf) - { - int ret_val = ioctl(file_desc, IOCTL_MBOX_PROPERTY, buf); -diff --git a/xbmc/linux/RBP.h b/xbmc/linux/RBP.h -index a35a509..78e4487 100644 ---- a/xbmc/linux/RBP.h -+++ b/xbmc/linux/RBP.h -@@ -82,6 +82,9 @@ public: - void VSyncCallback(); - int GetMBox() { return m_mb; } - -+ void SuspendVideoOutput(); -+ void ResumeVideoOutput(); -+ - private: - DllBcmHost *m_DllBcmHost; - bool m_initialized; -diff --git a/xbmc/linux/imx/IMX.h b/xbmc/linux/imx/IMX.h -index 75378ff..1d3d937 100644 ---- a/xbmc/linux/imx/IMX.h -+++ b/xbmc/linux/imx/IMX.h -@@ -23,6 +23,20 @@ - #include "threads/Event.h" - #include "threads/Thread.h" - #include "guilib/DispResource.h" -+#include "utils/log.h" -+ -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#define likely(x) __builtin_expect(!!(x),1) -+#define unlikely(x) __builtin_expect(!!(x),0) -+ -+class CIMX; -+extern CIMX g_IMX; - - class CIMX : public CThread, IDispResource - { -@@ -52,4 +66,123 @@ private: - uint32_t m_lastSyncFlag; - }; - --extern CIMX g_IMX; -+// A blocking FIFO buffer -+template -+class lkFIFO -+{ -+public: -+ lkFIFO() { m_size = queue.max_size(); queue.clear(); m_abort = false; } -+ -+public: -+ T pop() -+ { -+ std::unique_lock m_lock(lkqueue); -+ m_abort = false; -+ while (!queue.size() && !m_abort) -+ read.wait(m_lock); -+ -+ T val; -+ if (!queue.empty()) -+ { -+ val = queue.front(); -+ queue.pop_front(); -+ } -+ -+ m_lock.unlock(); -+ write.notify_one(); -+ return val; -+ } -+ -+ bool push(const T& item) -+ { -+ std::unique_lock m_lock(lkqueue); -+ m_abort = false; -+ while (queue.size() >= m_size && !m_abort) -+ write.wait(m_lock); -+ -+ if (m_abort) -+ return false; -+ -+ queue.push_back(item); -+ m_lock.unlock(); -+ read.notify_one(); -+ return true; -+ } -+ -+ void signal() -+ { -+ m_abort = true; -+ read.notify_one(); -+ write.notify_one(); -+ } -+ -+ void setquotasize(size_t newsize) -+ { -+ m_size = newsize; -+ write.notify_one(); -+ } -+ -+ size_t getquotasize() -+ { -+ return m_size; -+ } -+ -+ void for_each(void (*fn)(T &t), bool clear = true) -+ { -+ std::unique_lock m_lock(lkqueue); -+ std::for_each(queue.begin(), queue.end(), fn); -+ -+ if (clear) -+ queue.clear(); -+ -+ write.notify_one(); -+ } -+ -+ size_t size() -+ { -+ return queue.size(); -+ } -+ -+ void clear() -+ { -+ std::unique_lock m_lock(lkqueue); -+ queue.clear(); -+ write.notify_one(); -+ } -+ -+ bool full() { return m_size == queue.size(); } -+ -+private: -+ std::deque queue; -+ std::mutex lkqueue; -+ std::condition_variable write; -+ std::condition_variable read; -+ -+ size_t m_size; -+ volatile bool m_abort; -+}; -+ -+// Generell description of a buffer used by -+// the IMX context, e.g. for blitting -+class CIMXBuffer { -+public: -+ CIMXBuffer() : m_iRefs(0) {} -+ -+ // Shared pointer interface -+ virtual void Lock() = 0; -+ virtual long Release() = 0; -+ -+ int GetFormat() { return iFormat; } -+ -+public: -+ uint32_t iWidth; -+ uint32_t iHeight; -+ int pPhysAddr; -+ uint8_t *pVirtAddr; -+ int iFormat; -+ double m_fps; -+ -+protected: -+ std::atomic m_iRefs; -+}; -+ -diff --git a/xbmc/messaging/ApplicationMessenger.h b/xbmc/messaging/ApplicationMessenger.h -index b54b1c8..67cda36 100644 ---- a/xbmc/messaging/ApplicationMessenger.h -+++ b/xbmc/messaging/ApplicationMessenger.h -@@ -90,6 +90,9 @@ - #define TMSG_LOADPROFILE TMSG_MASK_APPLICATION + 27 - #define TMSG_VIDEORESIZE TMSG_MASK_APPLICATION + 28 - #define TMSG_SETAUDIODSPSTATE TMSG_MASK_APPLICATION + 29 -+#define TMSG_CHANGEVT TMSG_MASK_APPLICATION + 30 -+#define TMSG_DISPLAY_RECONFIGURE TMSG_MASK_APPLICATION + 31 -+ - - #define TMSG_GUI_INFOLABEL TMSG_MASK_GUIINFOMANAGER + 0 - #define TMSG_GUI_INFOBOOL TMSG_MASK_GUIINFOMANAGER + 1 -diff --git a/xbmc/music/MusicDatabase.cpp b/xbmc/music/MusicDatabase.cpp -index 87494f2..4673b75 100644 ---- a/xbmc/music/MusicDatabase.cpp -+++ b/xbmc/music/MusicDatabase.cpp -@@ -3225,7 +3225,7 @@ bool CMusicDatabase::LookupCDDBInfo(bool bRequery/*=false*/) - return false; - - // check network connectivity -- if (!g_application.getNetwork().IsAvailable()) -+ if (!g_application.getNetwork().IsConnected()) - return false; - - // Get information for the inserted disc -diff --git a/xbmc/network/DNSNameCache.cpp b/xbmc/network/DNSNameCache.cpp -index f12c782..e1a8ec4 100644 ---- a/xbmc/network/DNSNameCache.cpp -+++ b/xbmc/network/DNSNameCache.cpp -@@ -22,6 +22,8 @@ - #include "threads/SingleLock.h" - #include "utils/log.h" - #include "utils/StringUtils.h" -+#include "network/Network.h" -+#include "Application.h" - - #include - #include -@@ -32,25 +34,37 @@ CDNSNameCache g_DNSCache; - CCriticalSection CDNSNameCache::m_critical; - - CDNSNameCache::CDNSNameCache(void) --{} -+{ -+} - - CDNSNameCache::~CDNSNameCache(void) --{} -+{ -+} -+ -+void CDNSNameCache::Flush() -+{ -+ CSingleLock lock(m_critical); -+ CLog::Log(LOGINFO, "%s - DNS cache flushed (%u records)", __FUNCTION__, g_DNSCache.m_vecDNSNames.size()); -+ g_DNSCache.m_vecDNSNames.clear(); -+} - - bool CDNSNameCache::Lookup(const std::string& strHostName, std::string& strIpAddress) - { - if (strHostName.empty() && strIpAddress.empty()) - return false; - -- // first see if this is already an ip address -- unsigned long address = inet_addr(strHostName.c_str()); - strIpAddress.clear(); -- -- if (address != INADDR_NONE) -+ // first see if this is already an ip address - { -- strIpAddress = StringUtils::Format("%lu.%lu.%lu.%lu", (address & 0xFF), (address & 0xFF00) >> 8, (address & 0xFF0000) >> 16, (address & 0xFF000000) >> 24 ); -- return true; -+ struct sockaddr_in sa; -+ -+ if (CNetwork::ConvIPv6(strHostName)) -+ strIpAddress = CNetwork::CanonizeIPv6(strHostName); -+ else if (CNetwork::ConvIPv4(strHostName, &sa)) -+ strIpAddress = inet_ntoa(sa.sin_addr); - } -+ if (!strIpAddress.empty()) -+ return true; - - // check if there's a custom entry or if it's already cached - if(g_DNSCache.GetCached(strHostName, strIpAddress)) -@@ -84,20 +98,56 @@ bool CDNSNameCache::Lookup(const std::string& strHostName, std::string& strIpAdd - #endif - - // perform dns lookup -- struct hostent *host = gethostbyname(strHostName.c_str()); -- if (host && host->h_addr_list[0]) -+ struct addrinfo hints; -+ struct addrinfo *result = NULL; -+ -+ memset(&hints, 0, sizeof(struct addrinfo)); -+ int err; -+ -+ // prefer DNS record type (A vs AAAA) be the same as active interface(address). -+ // otherwise (by default) system prefers A(IPv4) records. this can make -+ // troubles on dual stack configured hosts or even make network access completely -+ // unusable in case of pure IPv6 configuration because returning IPv4 record as first. -+ -+ // (NOTE/TODO: we might consider for future iterating via all returned results, -+ // while checking accessibiity and use record which we can access. For now we just grab -+ // first record from returned list). -+ do - { -- strIpAddress = StringUtils::Format("%d.%d.%d.%d", -- (unsigned char)host->h_addr_list[0][0], -- (unsigned char)host->h_addr_list[0][1], -- (unsigned char)host->h_addr_list[0][2], -- (unsigned char)host->h_addr_list[0][3]); -+ if (result) -+ freeaddrinfo(result); -+ hints.ai_family = hints.ai_family == 0 ? g_application.getNetwork().GetFirstConnectedFamily() : AF_UNSPEC; -+ err = getaddrinfo(strHostName.c_str(), NULL, &hints, &result); -+ } while ((err || !result) && hints.ai_family != AF_UNSPEC); -+ -+ std::string str_err; -+ if (err) -+ str_err = gai_strerror(err); -+ -+ bool bReturn; -+ if (result) -+ { -+ strIpAddress = CNetwork::GetIpStr(result->ai_addr); -+ freeaddrinfo(result); -+ CLog::Log(LOGDEBUG, "%s - %s", __FUNCTION__, strIpAddress.c_str()); - g_DNSCache.Add(strHostName, strIpAddress); -- return true; -+ bReturn = true; -+ } -+ else -+ { -+ CLog::Log(LOGERROR, "Unable to lookup host: '%s' (err detail: %s)", strHostName.c_str(), str_err.c_str()); -+ bReturn = false; - } - -- CLog::Log(LOGERROR, "Unable to lookup host: '%s'", strHostName.c_str()); -- return false; -+ return bReturn; -+} -+ -+std::string CDNSNameCache::Lookup(const std::string& strHostName) -+{ -+ std::string ip; -+ -+ Lookup(strHostName, ip); -+ return ip; - } - - bool CDNSNameCache::GetCached(const std::string& strHostName, std::string& strIpAddress) -diff --git a/xbmc/network/DNSNameCache.h b/xbmc/network/DNSNameCache.h -index 97bb20b..126a980 100644 ---- a/xbmc/network/DNSNameCache.h -+++ b/xbmc/network/DNSNameCache.h -@@ -27,6 +27,8 @@ class CCriticalSection; - - class CDNSNameCache - { -+friend class CNetwork; -+ - public: - class CDNSName - { -@@ -37,9 +39,13 @@ public: - CDNSNameCache(void); - virtual ~CDNSNameCache(void); - static bool Lookup(const std::string& strHostName, std::string& strIpAddress); -+ static std::string Lookup(const std::string& strHostName); - static void Add(const std::string& strHostName, const std::string& strIpAddress); - - protected: -+ static void Flush(); -+ -+private: - static bool GetCached(const std::string& strHostName, std::string& strIpAddress); - static CCriticalSection m_critical; - std::vector m_vecDNSNames; -diff --git a/xbmc/network/Makefile.in b/xbmc/network/Makefile.in -index c80651c..4baa1ce 100644 ---- a/xbmc/network/Makefile.in -+++ b/xbmc/network/Makefile.in -@@ -27,3 +27,4 @@ LIB = network.a - - include @abs_top_srcdir@/Makefile.include - -include $(patsubst %.cpp,%.P,$(patsubst %.c,%.P,$(SRCS))) -+CXXFLAGS += --std=c++11 -DHAVE_CHAR32_T -DHAVE_CHAR16_T -diff --git a/xbmc/network/Network.cpp b/xbmc/network/Network.cpp -index 5247036..065afc8 100644 ---- a/xbmc/network/Network.cpp -+++ b/xbmc/network/Network.cpp -@@ -18,11 +18,16 @@ - * - */ - -+#include -+#include -+ - #include - #include - #include - -+#include "settings/Settings.h" - #include "Network.h" -+#include "DNSNameCache.h" - #include "messaging/ApplicationMessenger.h" - #include "network/NetworkServices.h" - #include "utils/log.h" -@@ -32,8 +37,32 @@ - #include "utils/CharsetConverter.h" - #endif - #include "utils/StringUtils.h" -+#include "xbmc/interfaces/AnnouncementManager.h" - - using namespace KODI::MESSAGING; -+using namespace ANNOUNCEMENT; -+ -+/* -+ * in all the geniality of new AF/AF6 compatible system functions & structs, -+ * most of *UNIX socket interface calls vitally depends on (struct)addr size to be specified. -+ * -+ * TODO for v18: as was initially discussed in PR#7030 let's define common 'ADT' to represent -+ * network entity (physical as well as logical ones (connectors/listeners/servers(services), -+ * but also interfaces, hosts). -+ * -+ * ((someone nicely started back in 2008 - xbmc/network/Socket.{cpp,h})) -+ */ -+socklen_t sa_len(struct sockaddr *addr) -+{ -+ switch(((struct sockaddr_storage*)addr)->ss_family) -+ { -+ case AF_INET: -+ return sizeof(struct sockaddr_in); -+ case AF_INET6: -+ return sizeof(struct sockaddr_in6); -+ } -+ return 0; -+} - - /* slightly modified in_ether taken from the etherboot project (http://sourceforge.net/projects/etherboot) */ - bool in_ether (const char *bufp, unsigned char *addr) -@@ -132,14 +161,61 @@ int NetworkAccessPoint::FreqToChannel(float frequency) - } - - --CNetwork::CNetwork() -+CNetwork::CNetwork() : -+ m_bStop(false) - { -- CApplicationMessenger::GetInstance().PostMsg(TMSG_NETWORKMESSAGE, SERVICES_UP, 0); -+ m_signalNetworkChange.Reset(); - } - - CNetwork::~CNetwork() - { -+ m_bStop = true; -+ m_updThread->StopThread(false); -+ m_signalNetworkChange.Set(); - CApplicationMessenger::GetInstance().PostMsg(TMSG_NETWORKMESSAGE, SERVICES_DOWN, 0); -+ m_updThread->StopThread(true); -+} -+ -+std::string CNetwork::GetIpStr(const struct sockaddr *sa) -+{ -+ std::string result; -+ if (!sa) -+ return result; -+ -+ char s[INET6_ADDRSTRLEN] = {0}; -+ switch(sa->sa_family) -+ { -+ case AF_INET: -+ inet_ntop(AF_INET, &(((struct sockaddr_in *)sa)->sin_addr), s, INET6_ADDRSTRLEN); -+ break; -+ case AF_INET6: -+ inet_ntop(AF_INET6, &(((struct sockaddr_in6 *)sa)->sin6_addr), s, INET6_ADDRSTRLEN); -+ break; -+ default: -+ return result; -+ } -+ -+ result = s; -+ return result; -+} -+ -+std::string CNetwork::GetIpStr(unsigned long address) -+{ -+ struct in_addr in = { htonl(address) }; -+ std::string addr = inet_ntoa(in); -+ -+ return addr; -+} -+ -+bool CNetworkInterface::GetHostMacAddress(const std::string &host, std::string &mac) -+{ -+ struct sockaddr_in in; -+ -+ if (!CNetwork::ConvIPv4(host, &in)) -+ return false; -+ -+ unsigned long ip = in.sin_addr.s_addr; -+ return GetHostMacAddress(ip, mac); - } - - int CNetwork::ParseHex(char *str, unsigned char *addr) -@@ -161,6 +237,58 @@ int CNetwork::ParseHex(char *str, unsigned char *addr) - return len; - } - -+bool CNetwork::ConvIPv4(const std::string &address, struct sockaddr_in *sa, unsigned short port) -+{ -+ if (address.empty()) -+ return false; -+ -+ struct in_addr sin_addr; -+ int ret = inet_pton(AF_INET, address.c_str(), &sin_addr); -+ -+ if (ret > 0 && sa) -+ { -+ sa->sin_family = AF_INET; -+ sa->sin_port = htons(port); -+ memcpy(&(sa->sin_addr), &sin_addr, sizeof(struct in_addr)); -+ } -+ -+ return (ret > 0); -+} -+ -+bool CNetwork::ConvIPv6(const std::string &address, struct sockaddr_in6 *sa, unsigned short port) -+{ -+ if (address.empty()) -+ return false; -+ -+ struct in6_addr sin6_addr; -+ int ret = inet_pton(AF_INET6, address.c_str(), &sin6_addr); -+ -+ if (ret > 0 && sa) -+ { -+ sa->sin6_family = AF_INET6; -+ sa->sin6_port = htons((u_int16_t)port); -+ memcpy(&(sa->sin6_addr), &sin6_addr, sizeof(struct in6_addr)); -+ } -+ -+ return (ret > 0); -+} -+ -+struct sockaddr_storage *CNetwork::ConvIP(const std::string &address, unsigned short port) -+{ -+ struct sockaddr_storage *sa = NULL; -+ -+ if (!address.empty()) -+ if (sa = (struct sockaddr_storage *) malloc(sizeof(struct sockaddr_storage))) -+ if (ConvIPv4(address, (struct sockaddr_in *) sa, port) -+ || ConvIPv6(address, (struct sockaddr_in6 *) sa, port)) -+ return sa; -+ -+ if (sa) -+ free(sa); -+ -+ return NULL; -+} -+ - bool CNetwork::GetHostName(std::string& hostname) - { - char hostName[128]; -@@ -192,15 +320,12 @@ bool CNetwork::IsLocalHost(const std::string& hostname) - && StringUtils::EqualsNoCase(hostname, myhostname)) - return true; - -- std::vector& ifaces = GetInterfaceList(); -- std::vector::const_iterator iter = ifaces.begin(); -- while (iter != ifaces.end()) -+ myhostname = CanonizeIPv6(hostname); -+ if (ConvIPv4(myhostname) || ConvIPv6(myhostname)) - { -- CNetworkInterface* iface = *iter; -- if (iface && iface->GetCurrentIPAddress() == hostname) -- return true; -- -- ++iter; -+ for (auto &&iface: GetInterfaceList()) -+ if (iface && iface->GetCurrentIPAddress() == myhostname) -+ return true; - } - - return false; -@@ -208,45 +333,87 @@ bool CNetwork::IsLocalHost(const std::string& hostname) - - CNetworkInterface* CNetwork::GetFirstConnectedInterface() - { -- std::vector& ifaces = GetInterfaceList(); -- std::vector::const_iterator iter = ifaces.begin(); -- while (iter != ifaces.end()) -- { -- CNetworkInterface* iface = *iter; -- if (iface && iface->IsConnected()) -- return iface; -- ++iter; -- } -+ for (auto &&iface: GetInterfaceList()) -+ if (iface && iface->IsConnected()) -+ return iface; - - return NULL; - } - --bool CNetwork::HasInterfaceForIP(unsigned long address) -+bool CNetwork::AddrMatch(const std::string &addr, const std::string &match_ip, const std::string &match_mask) - { -- unsigned long subnet; -- unsigned long local; -- std::vector& ifaces = GetInterfaceList(); -- std::vector::const_iterator iter = ifaces.begin(); -- while (iter != ifaces.end()) -- { -- CNetworkInterface* iface = *iter; -- if (iface && iface->IsConnected()) -+ if (ConvIPv4(addr) && ConvIPv4(match_ip) && ConvIPv4(match_mask)) -+ { -+ unsigned long address = ntohl(inet_addr(addr.c_str())); -+ unsigned long subnet = ntohl(inet_addr(match_mask.c_str())); -+ unsigned long local = ntohl(inet_addr(match_ip.c_str())); -+ return ((address & subnet) == (local & subnet)); -+ } -+ else if (!g_application.getNetwork().SupportsIPv6()) -+ { -+ return false; -+ } -+ else -+ { -+ struct sockaddr_in6 address; -+ struct sockaddr_in6 local; -+ struct sockaddr_in6 subnet; -+ if (!ConvIPv6(addr, &address) || !ConvIPv6(match_ip, &local) -+ || !ConvIPv6(match_mask, &subnet)) -+ return false; -+ -+ // mask matching of IPv6 follows same rule as for IPv4, only -+ // difference is the storage object of IPv6 address what -+ // is 16 segments of 8bit information (16bytes => 128bits) -+ // lets assume we match fd::2 against fd::1/16. this means -+ // for illustration: -+ // 00fd:0000:0000:0000:0000:0000:0000:0002 -+ // to -+ // 00fd:0000:0000:0000:0000:0000:0000:0001 with mask -+ // ffff:0000:0000:0000:0000:0000:0000:0000 -+ // as with IPv4, addr1 & mask == addr2 & mask - for each segment -+ -+ // despite the comment explaining uint_8[16] structure -+ // (what at the time of writing this text was valid for OSX/Linux/BSD) -+ // rather let's use type independent construction. this is because (OSX????) -+ // .h files commented the internal s6_addr structure type inside -+ // sockaddr_in6 as not being mandatory specified by RFC - devil never sleeps. -+ unsigned int m; -+ for (m = 0; m < sizeof(address.sin6_addr.s6_addr); m++) -+ if ((address.sin6_addr.s6_addr[m] & subnet.sin6_addr.s6_addr[m]) != -+ ( local.sin6_addr.s6_addr[m] & subnet.sin6_addr.s6_addr[m])) - { -- subnet = ntohl(inet_addr(iface->GetCurrentNetmask().c_str())); -- local = ntohl(inet_addr(iface->GetCurrentIPAddress().c_str())); -- if( (address & subnet) == (local & subnet) ) -- return true; -+ m = -1; - } -- ++iter; -- } - -- return false; -+ // in case of matching addresses, we loop through each segment, -+ // leaving m with final value of 16. -+ // if we don't match, m is set to .max() and for() is ended. -+ // RESULT: any value of m smaller than .max() indicates success. -+ if (m < (unsigned int)~0) -+ return true; -+ } -+ -+ return false; -+} -+ -+bool CNetwork::HasInterfaceForIP(const std::string &address) -+{ -+ if (address.empty()) -+ return false; -+ -+ for (auto &&iface: GetInterfaceList()) -+ if (iface && iface->IsConnected() && -+ AddrMatch(address, iface->GetCurrentIPAddress(), iface->GetCurrentNetmask())) -+ return true; -+ -+ return false; - } - --bool CNetwork::IsAvailable(void) -+bool CNetwork::HasInterfaceForIP(unsigned long address) - { -- std::vector& ifaces = GetInterfaceList(); -- return (ifaces.size() != 0); -+ std::string addr = GetIpStr(address); -+ return HasInterfaceForIP(addr); - } - - bool CNetwork::IsConnected() -@@ -256,15 +423,9 @@ bool CNetwork::IsConnected() - - CNetworkInterface* CNetwork::GetInterfaceByName(const std::string& name) - { -- std::vector& ifaces = GetInterfaceList(); -- std::vector::const_iterator iter = ifaces.begin(); -- while (iter != ifaces.end()) -- { -- CNetworkInterface* iface = *iter; -- if (iface && iface->GetName() == name) -- return iface; -- ++iter; -- } -+ for (auto &&iface: GetInterfaceList()) -+ if (iface && iface->GetName() == name) -+ return iface; - - return NULL; - } -@@ -274,7 +435,14 @@ void CNetwork::NetworkMessage(EMESSAGE message, int param) - switch( message ) - { - case SERVICES_UP: -+ if (GetInterfaceList().empty()) -+ { -+ CLog::Log(LOGDEBUG, "%s - There is no configured network interface. Not starting network services",__FUNCTION__); -+ break; -+ } -+ - CLog::Log(LOGDEBUG, "%s - Starting network services",__FUNCTION__); -+ CDNSNameCache::Flush(); - CNetworkServices::GetInstance().Start(); - break; - -@@ -284,6 +452,17 @@ void CNetwork::NetworkMessage(EMESSAGE message, int param) - CLog::Log(LOGDEBUG, "%s - Waiting for network services to stop",__FUNCTION__); - CNetworkServices::GetInstance().Stop(true); // wait for network services to stop - break; -+ -+ case NETWORK_CHANGED: -+ m_signalNetworkChange.Set(); -+ ANNOUNCEMENT::CAnnouncementManager::GetInstance().Announce(ANNOUNCEMENT::Network, "network", "OnInterfacesChange"); -+ if (CSettings::GetInstance().GetBool(CSettings::SETTING_NETWORK_RESTARTSERVICES)) -+ { -+ CLog::Log(LOGDEBUG, "%s - Network setup changed. Will restart network services",__FUNCTION__); -+ NetworkMessage(SERVICES_DOWN, 0); -+ NetworkMessage(SERVICES_UP, 0); -+ } -+ break; - } - } - -@@ -294,6 +473,9 @@ bool CNetwork::WakeOnLan(const char* mac) - unsigned char buf [128]; - unsigned char *ptr; - -+ if (GetFirstConnectedFamily() == AF_INET6) -+ return false; -+ - // Fetch the hardware address - if (!in_ether(mac, ethaddr)) - { -@@ -345,7 +527,7 @@ bool CNetwork::WakeOnLan(const char* mac) - } - - // ping helper --static const char* ConnectHostPort(SOCKET soc, const struct sockaddr_in& addr, struct timeval& timeOut, bool tryRead) -+static const char* ConnectHostPort(SOCKET soc, struct sockaddr *addr, struct timeval& timeOut, bool tryRead) - { - // set non-blocking - #ifdef TARGET_WINDOWS -@@ -358,7 +540,7 @@ static const char* ConnectHostPort(SOCKET soc, const struct sockaddr_in& addr, s - if (result != 0) - return "set non-blocking option failed"; - -- result = connect(soc, (struct sockaddr *)&addr, sizeof(addr)); // non-blocking connect, will fail .. -+ result = connect(soc, addr, sa_len(addr)); // non-blocking connect, will fail .. - - if (result < 0) - { -@@ -422,17 +604,17 @@ static const char* ConnectHostPort(SOCKET soc, const struct sockaddr_in& addr, s - return 0; // success - } - --bool CNetwork::PingHost(unsigned long ipaddr, unsigned short port, unsigned int timeOutMs, bool readability_check) -+bool CNetwork::PingHost(const std::string &ipaddr, unsigned short port, unsigned int timeOutMs, bool readability_check) - { - if (port == 0) // use icmp ping -- return PingHost (ipaddr, timeOutMs); -+ return PingHostImpl (ipaddr, timeOutMs); - -- struct sockaddr_in addr; -- addr.sin_family = AF_INET; -- addr.sin_port = htons(port); -- addr.sin_addr.s_addr = ipaddr; -+ struct sockaddr_storage *addr = ConvIP(ipaddr, port); - -- SOCKET soc = socket(AF_INET, SOCK_STREAM, 0); -+ if (!addr) -+ return false; -+ -+ SOCKET soc = socket(addr->ss_family, SOCK_STREAM, 0); - - const char* err_msg = "invalid socket"; - -@@ -442,7 +624,7 @@ bool CNetwork::PingHost(unsigned long ipaddr, unsigned short port, unsigned int - tmout.tv_sec = timeOutMs / 1000; - tmout.tv_usec = (timeOutMs % 1000) * 1000; - -- err_msg = ConnectHostPort (soc, addr, tmout, readability_check); -+ err_msg = ConnectHostPort (soc, (struct sockaddr *)addr, tmout, readability_check); - - (void) closesocket (soc); - } -@@ -455,12 +637,72 @@ bool CNetwork::PingHost(unsigned long ipaddr, unsigned short port, unsigned int - std::string sock_err = strerror(errno); - #endif - -- CLog::Log(LOGERROR, "%s(%s:%d) - %s (%s)", __FUNCTION__, inet_ntoa(addr.sin_addr), port, err_msg, sock_err.c_str()); -+ CLog::Log(LOGERROR, "%s(%s:%d) - %s (%s)", __FUNCTION__, ipaddr.c_str(), port, err_msg, sock_err.c_str()); - } - -+ free(addr); - return err_msg == 0; - } - -+std::string CNetwork::CanonizeIPv6(const std::string &address) -+{ -+ std::string result = address; -+ -+ struct sockaddr_in6 addr; -+ if (!ConvIPv6(address, &addr)) -+ return result; -+ -+ result = GetIpStr((const sockaddr*)&addr); -+ return result; -+} -+ -+uint8_t CNetwork::PrefixLength(const struct sockaddr *netmask) -+{ -+ uint8_t prefixLength = 0; -+ switch (netmask->sa_family) -+ { -+ case AF_INET: -+ prefixLength = std::bitsetsin_addr.s_addr)>(((struct sockaddr_in *) netmask)->sin_addr.s_addr).count(); -+ break; -+ case AF_INET6: -+ for (unsigned int i = 0; i < sizeof(((struct sockaddr_in6 *) netmask)->sin6_addr.s6_addr); ++i) -+ prefixLength += std::bitsetsin6_addr.s6_addr)>(((struct sockaddr_in6 *) netmask)->sin6_addr.s6_addr[i]).count(); -+ break; -+ } -+ return prefixLength; -+} -+ -+bool CNetwork::CompareAddresses(const struct sockaddr * sa, const struct sockaddr * sb) -+{ -+ if (sa->sa_family != sb->sa_family) -+ return false; -+ else if (sa->sa_family == AF_INET) -+ return ((struct sockaddr_in *)(sa))->sin_addr.s_addr == ((struct sockaddr_in *)(sb))->sin_addr.s_addr; -+ else if (sa->sa_family == AF_INET6) -+ return (memcmp((char *) &(((struct sockaddr_in6 *)(sa))->sin6_addr), (char *) &(((struct sockaddr_in6 *)(sb))->sin6_addr), sizeof(((struct sockaddr_in6 *)(sa))->sin6_addr))) == 0; -+ return false; -+} -+ -+CNetwork::CNetworkUpdater::CNetworkUpdater(void (*watcher)(void *caller)) -+ : CThread("NetConfUpdater") -+ , m_watcher(watcher) -+{ -+ CAnnouncementManager::GetInstance().AddAnnouncer(this); -+} -+ -+CNetwork::CNetworkUpdater::~CNetworkUpdater() -+{ -+ CAnnouncementManager::GetInstance().RemoveAnnouncer(this); -+} -+ -+void CNetwork::CNetworkUpdater::Announce(AnnouncementFlag flag, const char *sender, const char *message, const CVariant &data) -+{ -+ if (flag == System && !strcmp(sender, "xbmc") && !strcmp(message, "OnSleep")) -+ StopThread(false); -+ else if (flag == System && !strcmp(sender, "xbmc") && !strcmp(message, "OnWake")) -+ Create(false); -+} -+ - //creates, binds and listens a tcp socket on the desired port. Set bindLocal to - //true to bind to localhost only. The socket will listen over ipv6 if possible - //and fall back to ipv4 if ipv6 is not available on the platform. -@@ -507,7 +749,8 @@ int CreateTCPServerSocket(const int port, const bool bindLocal, const int backlo - { - closesocket(sock); - sock = -1; -- CLog::Log(LOGDEBUG, "%s Server: Failed to bind ipv6 serversocket, trying ipv4", callerName); -+ CLog::Log(LOGDEBUG, "%s Server: Failed to bind ipv6 serversocket on port %d, trying ipv4 (error was %s (%d))", -+ callerName, port, strerror(errno), errno); - } - } - -@@ -529,7 +772,8 @@ int CreateTCPServerSocket(const int port, const bool bindLocal, const int backlo - if (bind( sock, (struct sockaddr *) &addr, sizeof(struct sockaddr_in)) < 0) - { - closesocket(sock); -- CLog::Log(LOGERROR, "%s Server: Failed to bind ipv4 serversocket", callerName); -+ CLog::Log(LOGERROR, "%s Server: Failed to bind ipv4 serversocket on port %d, trying ipv4 (error was %s (%d))", -+ callerName, port, strerror(errno), errno); - return INVALID_SOCKET; - } - } -@@ -548,4 +792,3 @@ int CreateTCPServerSocket(const int port, const bool bindLocal, const int backlo - - return sock; - } -- -diff --git a/xbmc/network/Network.h b/xbmc/network/Network.h -index 0df104f..496b047 100644 ---- a/xbmc/network/Network.h -+++ b/xbmc/network/Network.h -@@ -21,10 +21,17 @@ - - #include - #include -+#include - - #include "system.h" -+#include "threads/Event.h" -+#include "threads/CriticalSection.h" -+#include "threads/Thread.h" -+#include "Application.h" -+#include "interfaces/AnnouncementManager.h" - - #include "settings/lib/ISettingCallback.h" -+#include - - enum EncMode { ENC_NONE = 0, ENC_WEP = 1, ENC_WPA = 2, ENC_WPA2 = 3 }; - enum NetworkAssignment { NETWORK_DASH = 0, NETWORK_DHCP = 1, NETWORK_STATIC = 2, NETWORK_DISABLED = 3 }; -@@ -84,6 +91,7 @@ public: - virtual void GetMacAddressRaw(char rawMac[6]) = 0; - - virtual bool GetHostMacAddress(unsigned long host, std::string& mac) = 0; -+ bool GetHostMacAddress(const std::string &host, std::string& mac); - - virtual std::string GetCurrentIPAddress() = 0; - virtual std::string GetCurrentNetmask() = 0; -@@ -95,45 +103,128 @@ public: - - virtual void GetSettings(NetworkAssignment& assignment, std::string& ipAddress, std::string& networkMask, std::string& defaultGateway, std::string& essId, std::string& key, EncMode& encryptionMode) = 0; - virtual void SetSettings(NetworkAssignment& assignment, std::string& ipAddress, std::string& networkMask, std::string& defaultGateway, std::string& essId, std::string& key, EncMode& encryptionMode) = 0; -+ -+ // tells if interface itself is configured with IPv6 or IPv4 address -+ virtual bool isIPv6() { return false; } -+ virtual bool isIPv4() { return true; } - }; - - class CNetwork - { - public: -+ class CNetworkUpdater : public CThread, public ANNOUNCEMENT::IAnnouncer -+ { -+ public: -+ CNetworkUpdater(void (*watcher)(void *caller)); -+ virtual ~CNetworkUpdater(void); -+ -+ volatile std::atomic *Stopping() { return &m_bStop; } -+ void Announce(ANNOUNCEMENT::AnnouncementFlag flag, const char *sender, const char *message, const CVariant &data); -+ -+ protected: -+ void Process() { m_watcher(this); } -+ -+ private: -+ void (*m_watcher)(void *caller); -+ }; -+ -+public: - enum EMESSAGE - { - SERVICES_UP, -- SERVICES_DOWN -+ SERVICES_DOWN, -+ NETWORK_CHANGED - }; - - CNetwork(); - virtual ~CNetwork(); - -- // Return our hostname -+ /*! -+ \brief Returns local hostname -+ */ - virtual bool GetHostName(std::string& hostname); - -- // Return the list of interfaces -- virtual std::vector& GetInterfaceList(void) = 0; -+ /*! -+ \brief Return the list of interfaces -+ */ -+ virtual std::forward_list& GetInterfaceList(void) = 0; -+ -+ /*! -+ \brief Returns interface with specific name -+ - in the current implementation, interface as the basic configutation item -+ represents specific IP configuration -+ - this means InterfaceName is not unique key. IP address is -+ -+ \return With respect above comment, it returns first valid configuration on interface -+ holding searched interface name. -+ */ - CNetworkInterface* GetInterfaceByName(const std::string& name); - -- // Return the first interface which is active -+ /*! -+ \brief Return the first interface which is active -+ - list of available interfaces is always sorted: by AF_FAMILY, dependence of their type -+ on other types and alphabetically at last. AF_PACKET comes first, then AF_INET, AF_INET6. -+ physical interfaces (eg network cards) come first. Bridges later before virtual -+ itnerfaces, then tunnels... -+ - This assures that ppp0 won't be picked up (presented as -+ GetFirstConnectedInterface()) at the expense of eth0 for instance / thus providing -+ non-sense info to services expecting interface with MAC address. -+ */ - virtual CNetworkInterface* GetFirstConnectedInterface(void); - -- // Return true if there is a interface for the same network as address -- bool HasInterfaceForIP(unsigned long address); -+ /*! -+ \brief Address family of GetFirstConnectedInterface() interface -+ \sa GetFirstConnectedInterface() -+ \return with respect to comment in GetFirstConnectedInterface() -+ - in case of returned AF_INET6 - host is configured with IPv6 stack only (we don't need -+ iterate over interfaces list further, or trying socket() results to confirm this) -+ - AF_INET - host is configured with IPv4 stack. IPv6 availability unknown, we would need -+ to loop over the list. -+ */ -+ int GetFirstConnectedFamily() { return (GetFirstConnectedInterface() && GetFirstConnectedInterface()->isIPv6() ? AF_INET6 : AF_INET); } -+ -+ /*! -+ \brief Return true if there is a interface for the same network as address -+ */ -+ bool HasInterfaceForIP(const std::string &address); - -- // Return true if there's at least one defined network interface -- bool IsAvailable(void); -+ /*! -+ \brief Compat wrapper to -+ \sa HasInterfaceForIP(const std::string &address) -+ */ -+ bool HasInterfaceForIP(unsigned long address); - - // Return true if there's at least one interface which is connected - bool IsConnected(void); - -- // Return true if the magic packet was send -+ /*! -+ \return Return true if the magic packet was send -+ -+ TODO: current implementation uses ARP for MAC resolution. -+ as IPv6 has no ARP, it will provide expected result -+ only if target host is accessible via IPv4. -+ (anyhow it's use is safe regardless actual. -+ configuration, returns false for IPv6 only stack) -+ */ - bool WakeOnLan(const char *mac); - -- // Return true if host replies to ping -- bool PingHost(unsigned long host, unsigned short port, unsigned int timeout_ms = 2000, bool readability_check = false); -- virtual bool PingHost(unsigned long host, unsigned int timeout_ms = 2000) = 0; -+ /*! -+ \brief Ping remote host -+ \param IP host address, port (optional) -+ \return Return true if host replies to ping, false otherwise -+ Function is IPv6/v4 compatible -+ - If port is not specified, system cmd ping/ping6 is called -+ - If port is specified, host is contacted via sock connect() -+ */ -+ bool PingHost(const std::string &ipaddr, unsigned short port, unsigned int timeout_ms = 2000, bool readability_check = false); -+ -+ /*! -+ \brief Ping remote host (compatibility wrapper, see PingHost(std::string&...)) -+ */ -+ bool PingHost(unsigned long ipaddr, unsigned short port, unsigned int timeout_ms = 2000, bool readability_check = false) -+ { return PingHost(GetIpStr(ipaddr), port, timeout_ms, readability_check); } -+ -+ virtual bool PingHostImpl(const std::string &target, unsigned int timeout_ms = 2000) = 0; - - // Get/set the nameserver(s) - virtual std::vector GetNameServers(void) = 0; -@@ -145,12 +236,164 @@ public: - void StartServices(); - void StopServices(bool bWait); - -+ /*! -+ \brief Tests if parameter specifies valid IPv6 address (as specified by RFCs) -+ \param ipaddress to convert/test -+ \param *sockaddr non mandatory destination for conversion -+ \param port non mandatory port specification to connect to -+ \return Function is dual purpose. With just one parameter (IP), -+ it return true if that IP represents IPv6 address. -+ If case of second / third supplied argument, it directly -+ converts parameters into binary struct pointed by 2nd param. -+ (structure needs to be pre-allocated) -+ -+ \sa ConvIP -+ For direct conversion into (sockaddr*) see ConvIP() variants. -+ (it is universal wrapper to ConvIPv6/v4()) -+ */ -+ static bool ConvIPv6(const std::string &address, struct sockaddr_in6 *sa = NULL, unsigned short port = 0); -+ -+ /*! -+ \brief Tests if parameter specifies valid IPv4 address (as specified by RFCs) -+ \param ipaddress stored as std::string -+ \param sockaddr* non mandatory -+ \param port non mandatory -+ \return Function is dual purpose. With just one parameter (IP), -+ it return true if that IP represents IPv4 address. -+ If case of second / third supplied argument, it directly -+ converts parameters into binary struct pointed by 2nd param. -+ (structure needs to be pre-allocated) -+ -+ \sa ConvIP -+ For direct conversion into (sockaddr*) see ConvIP() variants. -+ (it is universal wrapper to ConvIPv6/v4()) -+ */ -+ static bool ConvIPv4(const std::string &address, struct sockaddr_in *sa = NULL, unsigned short port = 0); -+ -+ /*! -+ \brief Converts host IP address into binary sockaddr -+ (wrapper to ConvIP(std::string&, ushort)) -+ */ -+ static struct sockaddr_storage *ConvIP(unsigned long address, unsigned short port = 0) { return ConvIP(GetIpStr(address), port); } -+ -+ /*! -+ \brief Converts host IP address into binary sockaddr -+ \param IP address as std::string, port specification (optional) -+ \return Function converts host IP to structure directly used -+ in network API functions. It allocates sockaddr_storage -+ (via malloc) and returns pointer to it (on error NULL -+ is returned). af_family, s_addr, port are filled in. -+ Struct sockaddr_storage can be cast to needed structure -+ (sockaddr_in, sockaddr_in6, sockaddr, ...) -+ You have to relese memory with free(p) after use. -+ */ -+ static struct sockaddr_storage *ConvIP(const std::string &address, unsigned short port = 0); -+ - static int ParseHex(char *str, unsigned char *addr); - -- // Return true if given name or ip address corresponds to localhost -+ /*! -+ \brief IPv6/IPv4 compatible conversion of host IP address -+ \param struct sockaddr -+ \return Function converts binary structure sockaddr to std::string. -+ It can read sockaddr_in and sockaddr_in6, cast as (sockaddr*). -+ IPv4 address is returned in the format x.x.x.x (where x is 0-255), -+ IPv6 address is returned in it's canonised form. -+ On error (or no IPv6/v4 valid input) empty string is returned. -+ */ -+ static std::string GetIpStr(const struct sockaddr *sa); -+ -+ /*! -+ \brief Converts IPv4 address stored in unsigned long to std::string -+ Function converts from host byte order to network -+ byte order first -+ \param IPaddress unsigned long -+ \return Result is returned as std::string -+ */ -+ static std::string GetIpStr(unsigned long address); -+ -+ /*! -+ \brief Canonisation of IPv6 address -+ \param Any valid IPv6 address representation (std::string) -+ \return In respect to RFC 2373, provided string in any legal -+ representations will be canonised to it's shortest -+ possible form e.g. -+ 12AB:0000:0000:CD30:0000:0000:0000:0000 -> 12AB:0:0:CD30:: -+ */ -+ static std::string CanonizeIPv6(const std::string &address); -+ -+ /*! -+ \brief computes the prefix length for a (IPv4/IPv6) netmask -+ \param struct sockaddr -+ \return The prefix length of the netmask -+ For IPv4 it can be between 0 and 32 -+ For IPv6 it can be between 0 and 128 -+ */ -+ static uint8_t PrefixLength(const struct sockaddr *netmask); -+ -+ /*! -+ \brief compares two ip addresses (IPv4/IPv6) -+ \param ip address 1 -+ \param ip address 2 -+ \return if the two addresses are the same -+ */ -+ static bool CompareAddresses(const struct sockaddr *sa, const struct sockaddr *sb); -+ -+ /*! -+ \brief fully IPv4/IPv6 compatible -+ - IPv6 part is limited to addr/mask match only (IPv4 way) -+ -+ \param ipaddr1 to match -+ \param ipaddr2 to match agains -+ \param mask2 to match agains -+ -+ \return TRUE if: ipaddr1 & mask2 == ipaddr2 & mask2 , FALSE otherwise -+ -+ TODO: beside addr/match matching IPv6 introduced NetworkDiscoveryProtocol(NDP) -+ currently not implemented. -+ */ -+ static bool AddrMatch(const std::string &addr, const std::string &match_ip, const std::string &match_mask); -+ -+ /*! -+ \brief Per platform implementation. -+ - CNetwork class has both IPv6/IPv4 support, but doesn't require each derived -+ class to support IPv6 as well -+ - By default we assume IPv6 support not existend (or IPv6 stack unconfigured) -+ - CNetwork class functions check IPv6 support automatically based on this call -+ and avoid IPv6 depending code automatically. -+ This makes the calls safe for the caller without prior checks or deep knowledge -+ of CNetwork internals -+ -+ - for calls dealing with IPv6 stack - and no IPv6 available - calls return safely -+ returning string.empty() / FALSE / -1 or NULL -+ -+ \return Static functions providing only type<>type conversions or formal valididy checking -+ are independent on actual IPv6 stack availability -+ */ -+ virtual bool SupportsIPv6(void) { return false; } -+ -+ /*! -+ \brief Return true if given name or ip address corresponds to localhost -+ */ - bool IsLocalHost(const std::string& hostname); -+ -+ /*! -+ \brief Registers function as platform. network settings change watcher. Changes on net ifaces -+ should be reported by sending message TMSG_NETWORKMESSAGE (CNetwork::NETWORK_CHANGED). -+ */ -+ void RegisterWatcher(void (*watcher)(void *caller)) { m_updThread = new CNetworkUpdater(watcher); m_updThread->Create(false); } -+ CNetworkUpdater *m_updThread; -+ -+ virtual bool ForceRereadInterfaces() = 0; -+ -+protected: -+ CCriticalSection m_lockInterfaces; -+ -+private: -+ CEvent m_signalNetworkChange; -+ bool m_bStop; - }; - -+ - #ifdef HAS_LINUX_NETWORK - #include "linux/NetworkLinux.h" - #else -diff --git a/xbmc/network/NetworkServices.cpp b/xbmc/network/NetworkServices.cpp -index 1aa03f8..46a677b 100644 ---- a/xbmc/network/NetworkServices.cpp -+++ b/xbmc/network/NetworkServices.cpp -@@ -512,9 +512,6 @@ void CNetworkServices::Stop(bool bWait) - bool CNetworkServices::StartWebserver() - { - #ifdef HAS_WEB_SERVER -- if (!g_application.getNetwork().IsAvailable()) -- return false; -- - if (!CSettings::GetInstance().GetBool(CSettings::SETTING_SERVICES_WEBSERVER)) - return false; - -@@ -587,7 +584,7 @@ bool CNetworkServices::StartAirPlayServer() - return true; - - #ifdef HAS_AIRPLAY -- if (!g_application.getNetwork().IsAvailable() || !CSettings::GetInstance().GetBool(CSettings::SETTING_SERVICES_AIRPLAY)) -+ if (!g_application.getNetwork().IsConnected() || !CSettings::GetInstance().GetBool(CSettings::SETTING_SERVICES_AIRPLAY)) - return false; - - if (IsAirPlayServerRunning()) -@@ -649,7 +646,7 @@ bool CNetworkServices::StopAirPlayServer(bool bWait) - bool CNetworkServices::StartAirTunesServer() - { - #ifdef HAS_AIRTUNES -- if (!g_application.getNetwork().IsAvailable() || !CSettings::GetInstance().GetBool(CSettings::SETTING_SERVICES_AIRPLAY)) -+ if (!g_application.getNetwork().IsConnected() || !CSettings::GetInstance().GetBool(CSettings::SETTING_SERVICES_AIRPLAY)) - return false; - - if (IsAirTunesServerRunning()) -diff --git a/xbmc/network/TCPServer.cpp b/xbmc/network/TCPServer.cpp -index 51f6b93..1009de5 100644 ---- a/xbmc/network/TCPServer.cpp -+++ b/xbmc/network/TCPServer.cpp -@@ -467,8 +467,11 @@ void CTCPServer::Deinitialize() - - m_connections.clear(); - -- for (unsigned int i = 0; i < m_servers.size(); i++) -- closesocket(m_servers[i]); -+ for (unsigned int i = m_servers.size(); i > 0; i--) -+ { -+ shutdown(m_servers[i-1], SHUT_RDWR); -+ closesocket(m_servers[i-1]); -+ } - - m_servers.clear(); - -diff --git a/xbmc/network/WakeOnAccess.cpp b/xbmc/network/WakeOnAccess.cpp -index 2112798..27a1d12 100644 ---- a/xbmc/network/WakeOnAccess.cpp -+++ b/xbmc/network/WakeOnAccess.cpp -@@ -62,13 +62,6 @@ static int GetTotalSeconds(const CDateTimeSpan& ts) - return ts.GetSeconds() + minutes * 60; - } - --static unsigned long HostToIP(const std::string& host) --{ -- std::string ip; -- CDNSNameCache::Lookup(host, ip); -- return inet_addr(ip.c_str()); --} -- - CWakeOnAccess::WakeUpEntry::WakeUpEntry (bool isAwake) - : timeout (0, 0, 0, DEFAULT_TIMEOUT_SEC) - , wait_online1_sec(DEFAULT_WAIT_FOR_ONLINE_SEC_1) -@@ -101,20 +94,14 @@ private: - - bool CMACDiscoveryJob::DoWork() - { -- unsigned long ipAddress = HostToIP(m_host); -+ std::string ipAddress = CDNSNameCache::Lookup(m_host); - -- if (ipAddress == INADDR_NONE) -- { -- CLog::Log(LOGERROR, "%s - can't determine ip of '%s'", __FUNCTION__, m_host.c_str()); -+ if (ipAddress.empty()) - return false; -- } - -- std::vector& ifaces = g_application.getNetwork().GetInterfaceList(); -- for (std::vector::const_iterator it = ifaces.begin(); it != ifaces.end(); ++it) -- { -- if ((*it)->GetHostMacAddress(ipAddress, m_macAddres)) -+ for (auto &&iface : g_application.getNetwork().GetInterfaceList()) -+ if (iface->GetHostMacAddress(ipAddress, m_macAddres)) - return true; -- } - - return false; - } -@@ -237,8 +224,7 @@ public: - } - virtual bool SuccessWaiting () const - { -- unsigned long address = ntohl(HostToIP(m_host)); -- bool online = g_application.getNetwork().HasInterfaceForIP(address); -+ bool online = g_application.getNetwork().HasInterfaceForIP(CDNSNameCache::Lookup(m_host)); - - if (!online) // setup endtime so we dont return true until network is consistently connected - m_end.Set (m_settle_time_ms); -@@ -279,9 +265,7 @@ public: - - static bool Ping (const CWakeOnAccess::WakeUpEntry& server) - { -- ULONG dst_ip = HostToIP(server.host); -- -- return g_application.getNetwork().PingHost(dst_ip, server.ping_port, 2000, server.ping_mode & 1); -+ return g_application.getNetwork().PingHost(CDNSNameCache::Lookup(server.host), server.ping_port, 2000, server.ping_mode & 1); - } - - private: -@@ -374,7 +358,7 @@ bool CWakeOnAccess::WakeUpHost(const WakeUpEntry& server) - - if (dlg.ShowAndWait (waitObj, m_netinit_sec, LOCALIZED(13028)) != ProgressDialogHelper::Success) - { -- if (g_application.getNetwork().IsConnected() && HostToIP(server.host) == INADDR_NONE) -+ if (g_application.getNetwork().IsConnected() && CDNSNameCache::Lookup(server.host).empty()) - { - // network connected (at least one interface) but dns-lookup failed (host by name, not ip-address), so dont abort yet - CLog::Log(LOGWARNING, "WakeOnAccess timeout/cancel while waiting for network (proceeding anyway)"); -@@ -388,9 +372,7 @@ bool CWakeOnAccess::WakeUpHost(const WakeUpEntry& server) - } - - { -- ULONG dst_ip = HostToIP(server.host); -- -- if (g_application.getNetwork().PingHost(dst_ip, server.ping_port, 500)) // quick ping with short timeout to not block too long -+ if (g_application.getNetwork().PingHost(CDNSNameCache::Lookup(server.host), server.ping_port, 500)) // quick ping with short timeout to not block too long - { - CLog::Log(LOGNOTICE,"WakeOnAccess success exit, server already running"); - return true; -diff --git a/xbmc/network/linux/Makefile b/xbmc/network/linux/Makefile -index 207ecda..557c587 100644 ---- a/xbmc/network/linux/Makefile -+++ b/xbmc/network/linux/Makefile -@@ -6,3 +6,4 @@ LIB=network_linux.a - - include ../../../Makefile.include - -include $(patsubst %.cpp,%.P,$(patsubst %.c,%.P,$(SRCS))) -+CXXFLAGS += --std=c++11 -DHAVE_CHAR32_T -DHAVE_CHAR16_T -diff --git a/xbmc/network/linux/NetworkLinux.cpp b/xbmc/network/linux/NetworkLinux.cpp -index 5868845..1a6e684 100644 ---- a/xbmc/network/linux/NetworkLinux.cpp -+++ b/xbmc/network/linux/NetworkLinux.cpp -@@ -19,15 +19,29 @@ - */ - - #include -+#include - -+#include "xbmc/messaging/ApplicationMessenger.h" -+#include - #include -+#include - #include - #include - #include -+#ifdef TARGET_ANDROID -+ #include "network/linux/android-ifaddrs/ifaddrs.h" -+#endif - #if defined(TARGET_LINUX) - #include - #include - #include -+ #include -+ #include -+#ifndef _IFADDRS_H_ -+ #include -+#endif -+#else -+ #include "network/osx/priv_netlink.h" - #endif - #ifdef TARGET_ANDROID - #include "platform/android/bionic_supplement/bionic_supplement.h" -@@ -67,7 +81,13 @@ - #include "utils/log.h" - #include "utils/StringUtils.h" - --CNetworkInterfaceLinux::CNetworkInterfaceLinux(CNetworkLinux* network, std::string interfaceName, char interfaceMacAddrRaw[6]): -+using namespace KODI::MESSAGING; -+ -+CNetworkInterfaceLinux::CNetworkInterfaceLinux(CNetworkLinux* network, unsigned int ifa_flags, -+ struct sockaddr *address, struct sockaddr *netmask, -+ std::string interfaceName, char interfaceMacAddrRaw[6]) : -+ m_interfaceFlags(ifa_flags), -+ m_removed(false), - m_interfaceName(interfaceName), - m_interfaceMacAdr(StringUtils::Format("%02X:%02X:%02X:%02X:%02X:%02X", - (uint8_t)interfaceMacAddrRaw[0], -@@ -78,11 +98,17 @@ CNetworkInterfaceLinux::CNetworkInterfaceLinux(CNetworkLinux* network, std::stri - (uint8_t)interfaceMacAddrRaw[5])) - { - m_network = network; -+ m_address = (struct sockaddr *) malloc(sizeof(struct sockaddr_storage)); -+ m_netmask = (struct sockaddr *) malloc(sizeof(struct sockaddr_storage)); -+ memcpy(m_address, address, sizeof(struct sockaddr_storage)); -+ memcpy(m_netmask, netmask, sizeof(struct sockaddr_storage)); - memcpy(m_interfaceMacAddrRaw, interfaceMacAddrRaw, sizeof(m_interfaceMacAddrRaw)); - } - - CNetworkInterfaceLinux::~CNetworkInterfaceLinux(void) - { -+ free(m_address); -+ free(m_netmask); - } - - std::string& CNetworkInterfaceLinux::GetName(void) -@@ -106,31 +132,21 @@ bool CNetworkInterfaceLinux::IsWireless() - - bool CNetworkInterfaceLinux::IsEnabled() - { -- struct ifreq ifr; -- strcpy(ifr.ifr_name, m_interfaceName.c_str()); -- if (ioctl(m_network->GetSocket(), SIOCGIFFLAGS, &ifr) < 0) -- return false; -- -- return ((ifr.ifr_flags & IFF_UP) == IFF_UP); -+ return true; - } - - bool CNetworkInterfaceLinux::IsConnected() - { -- struct ifreq ifr; -- int zero = 0; -- memset(&ifr,0,sizeof(struct ifreq)); -- strcpy(ifr.ifr_name, m_interfaceName.c_str()); -- if (ioctl(m_network->GetSocket(), SIOCGIFFLAGS, &ifr) < 0) -- return false; -- - // ignore loopback -- int iRunning = ( (ifr.ifr_flags & IFF_RUNNING) && (!(ifr.ifr_flags & IFF_LOOPBACK))); -+ if (IsRemoved() || m_interfaceFlags & IFF_LOOPBACK) -+ return false; - -- if (ioctl(m_network->GetSocket(), SIOCGIFADDR, &ifr) < 0) -- return false; -+ // Don't add IFF_LOWER_UP - looks it is driver dependent on Linux -+ // and missing on running interfaces on OSX (Maverick tested) -+ unsigned int needFlags = IFF_RUNNING; //IFF_LOWER_UP -+ bool iRunning = (m_interfaceFlags & needFlags) == needFlags; - -- // return only interfaces which has ip address -- return iRunning && (0 != memcmp(ifr.ifr_addr.sa_data+sizeof(short), &zero, sizeof(int))); -+ return iRunning; - } - - std::string CNetworkInterfaceLinux::GetMacAddress() -@@ -145,31 +161,17 @@ void CNetworkInterfaceLinux::GetMacAddressRaw(char rawMac[6]) - - std::string CNetworkInterfaceLinux::GetCurrentIPAddress(void) - { -- std::string result; -- -- struct ifreq ifr; -- strcpy(ifr.ifr_name, m_interfaceName.c_str()); -- ifr.ifr_addr.sa_family = AF_INET; -- if (ioctl(m_network->GetSocket(), SIOCGIFADDR, &ifr) >= 0) -- { -- result = inet_ntoa((*((struct sockaddr_in *)&ifr.ifr_addr)).sin_addr); -- } -- -- return result; -+ return CNetwork::GetIpStr(m_address); - } - - std::string CNetworkInterfaceLinux::GetCurrentNetmask(void) - { - std::string result; - -- struct ifreq ifr; -- strcpy(ifr.ifr_name, m_interfaceName.c_str()); -- ifr.ifr_addr.sa_family = AF_INET; -- if (ioctl(m_network->GetSocket(), SIOCGIFNETMASK, &ifr) >= 0) -- { -- result = inet_ntoa((*((struct sockaddr_in*)&ifr.ifr_addr)).sin_addr); -- } -- -+ if (isIPv4()) -+ result = CNetwork::GetIpStr(m_netmask); -+ else -+ result = StringUtils::Format("%u", CNetwork::PrefixLength(m_netmask)); - return result; - } - -@@ -258,7 +260,7 @@ std::string CNetworkInterfaceLinux::GetCurrentDefaultGateway(void) - } - free(buf); - #else -- FILE* fp = fopen("/proc/net/route", "r"); -+ FILE* fp = isIPv4() ? fopen("/proc/net/route", "r") : fopen("/proc/net/ipv6_route", "r"); - if (!fp) - { - // TBD: Error -@@ -269,35 +271,45 @@ std::string CNetworkInterfaceLinux::GetCurrentDefaultGateway(void) - char iface[16]; - char dst[128]; - char gateway[128]; -+ unsigned int metric; -+ unsigned int metric_prev = -1; - size_t linel = 0; - int n; - int linenum = 0; - while (getdelim(&line, &linel, '\n', fp) > 0) - { - // skip first two lines -- if (linenum++ < 1) -+ if (isIPv4() && linenum++ < 1) - continue; - - // search where the word begins -- n = sscanf(line, "%15s %127s %127s", -- iface, dst, gateway); -+ if (isIPv4()) -+ n = sscanf(line, "%15s %127s %127s", -+ iface, dst, gateway); -+ else -+ n = sscanf(line, "%*32s %*2s %32s %*2s %32s %8x %*8s %*8s %*8s %8s", -+ dst, gateway, &metric, iface); - - if (n < 3) - continue; - - if (strcmp(iface, m_interfaceName.c_str()) == 0 && -- strcmp(dst, "00000000") == 0 && -- strcmp(gateway, "00000000") != 0) -+ (strcmp(dst, "00000000") == 0 || strcmp(dst, "00000000000000000000000000000000") == 0) && -+ strcmp(gateway, "00000000") != 0 && strcmp(gateway, "00000000000000000000000000000000") != 0) - { -- unsigned char gatewayAddr[4]; -- int len = CNetwork::ParseHex(gateway, gatewayAddr); -- if (len == 4) -+ if (isIPv4()) - { -- struct in_addr in; -- in.s_addr = (gatewayAddr[0] << 24) | (gatewayAddr[1] << 16) | -- (gatewayAddr[2] << 8) | (gatewayAddr[3]); -- result = inet_ntoa(in); -- break; -+ struct in_addr in; -+ sscanf(gateway, "%8x", &in.s_addr); -+ result = inet_ntoa(in); -+ } -+ else if (metric < metric_prev) -+ { -+ metric_prev = metric; -+ std::string tstr = gateway; -+ for(int i = 7; i > 0; i--) -+ tstr.insert(tstr.begin() + i*4, ':'); -+ result = CNetwork::CanonizeIPv6(tstr); - } - } - } -@@ -312,6 +324,8 @@ CNetworkLinux::CNetworkLinux(void) - { - m_sock = socket(AF_INET, SOCK_DGRAM, 0); - queryInterfaceList(); -+ RegisterWatcher(WatcherProcess); -+ CApplicationMessenger::GetInstance().PostMsg(TMSG_NETWORKMESSAGE, CNetwork::SERVICES_UP, 0); - } - - CNetworkLinux::~CNetworkLinux(void) -@@ -319,18 +333,26 @@ CNetworkLinux::~CNetworkLinux(void) - if (m_sock != -1) - close(CNetworkLinux::m_sock); - -- std::vector::iterator it = m_interfaces.begin(); -- while(it != m_interfaces.end()) -- { -- CNetworkInterface* nInt = *it; -- delete nInt; -- it = m_interfaces.erase(it); -- } -+ CSingleLock lock(m_lockInterfaces); -+ InterfacesClear(); -+ DeleteRemoved(); - } - --std::vector& CNetworkLinux::GetInterfaceList(void) -+void CNetworkLinux::DeleteRemoved(void) - { -- return m_interfaces; -+ m_interfaces.remove_if(IsRemoved); -+} -+ -+void CNetworkLinux::InterfacesClear(void) -+{ -+ for (auto &&iface: m_interfaces) -+ ((CNetworkInterfaceLinux*)iface)->SetRemoved(); -+} -+ -+std::forward_list& CNetworkLinux::GetInterfaceList(void) -+{ -+ CSingleLock lock(m_lockInterfaces); -+ return m_interfaces; - } - - // Overwrite the GetFirstConnectedInterface and requery -@@ -353,147 +375,128 @@ CNetworkInterface* CNetworkLinux::GetFirstConnectedInterface(void) - return pNetIf; - } - -- --void CNetworkLinux::GetMacAddress(const std::string& interfaceName, char rawMac[6]) -+void CNetworkLinux::GetMacAddress(struct ifaddrs *tif, char *mac) - { -- memset(rawMac, 0, 6); --#if defined(TARGET_DARWIN) || defined(TARGET_FREEBSD) -- -+#if !defined(TARGET_LINUX) - #if !defined(IFT_ETHER) - #define IFT_ETHER 0x6/* Ethernet CSMACD */ - #endif -- const struct sockaddr_dl* dlAddr = NULL; -- const uint8_t * base = NULL; -- // Query the list of interfaces. -- struct ifaddrs *list; -- struct ifaddrs *interface; -- -- if( getifaddrs(&list) < 0 ) -- { -- return; -- } -- -- for(interface = list; interface != NULL; interface = interface->ifa_next) -+ if (((const struct sockaddr_dl*) tif->ifa_addr)->sdl_type == IFT_ETHER) - { -- if(interfaceName == interface->ifa_name) -- { -- if ( (interface->ifa_addr->sa_family == AF_LINK) && (((const struct sockaddr_dl *) interface->ifa_addr)->sdl_type == IFT_ETHER) ) -- { -- dlAddr = (const struct sockaddr_dl *) interface->ifa_addr; -- base = (const uint8_t *) &dlAddr->sdl_data[dlAddr->sdl_nlen]; -+ const struct sockaddr_dl *dlAddr = (const struct sockaddr_dl *) tif->ifa_addr; -+ const uint8_t *base = (const uint8_t*) &dlAddr->sdl_data[dlAddr->sdl_nlen]; - -- if( dlAddr->sdl_alen > 5 ) -- { -- memcpy(rawMac, base, 6); -- } -- } -- break; -- } -+ if( dlAddr->sdl_alen > 5 ) -+ memcpy(mac, base, 6); - } -- -- freeifaddrs(list); -- - #else -- -- struct ifreq ifr; -- strcpy(ifr.ifr_name, interfaceName.c_str()); -- if (ioctl(GetSocket(), SIOCGIFHWADDR, &ifr) >= 0) -- { -- memcpy(rawMac, ifr.ifr_hwaddr.sa_data, 6); -- } -+ struct ifreq ifr; -+ strcpy(ifr.ifr_name, tif->ifa_name); -+ if (ioctl(GetSocket(), SIOCGIFHWADDR, &ifr) >= 0) -+ memcpy(mac, ifr.ifr_hwaddr.sa_data, 6); - #endif - } - --void CNetworkLinux::queryInterfaceList() -+CNetworkInterfaceLinux *CNetworkLinux::Exists(const struct sockaddr *addr, const struct sockaddr *mask, const std::string &name) - { -- char macAddrRaw[6]; -- m_interfaces.clear(); -+ for (auto &&iface: m_interfaces) -+ if (((CNetworkInterfaceLinux*)iface)->Exists(addr, mask, name)) -+ return (CNetworkInterfaceLinux*)iface; - --#if defined(TARGET_DARWIN) || defined(TARGET_FREEBSD) -+ return NULL; -+} - -- // Query the list of interfaces. -- struct ifaddrs *list; -- if (getifaddrs(&list) < 0) -- return; -+bool CNetworkLinux::queryInterfaceList() -+{ -+ bool change = false; -+ -+ CSingleLock lock(m_lockInterfaces); -+ -+ // Query the list of interfaces. -+ struct ifaddrs *list; -+ if (getifaddrs(&list) < 0) -+ return false; -+ -+#if !defined(TARGET_LINUX) -+ std::map t_hwaddrs; -+#endif -+ -+ InterfacesClear(); -+ -+ // find last IPv4 record, we will add new interfaces -+ // right after this one (to keep IPv4 in front). -+ auto pos = m_interfaces.before_begin(); -+ for (auto &&iface : m_interfaces) -+ { -+ if (iface && iface->isIPv6()) -+ break; -+ ++pos; -+ } - - struct ifaddrs *cur; - for(cur = list; cur != NULL; cur = cur->ifa_next) - { -- if(cur->ifa_addr->sa_family != AF_INET) -+ std::string name = cur->ifa_name; -+#if !defined(TARGET_LINUX) -+ if(cur->ifa_addr->sa_family == AF_LINK) -+ { -+ struct ifaddrs &t = *cur; -+ t_hwaddrs[name] = t; -+ } -+#endif -+ -+ if(!cur->ifa_addr || -+ (cur->ifa_addr->sa_family != AF_INET && -+ cur->ifa_addr->sa_family != AF_INET6)) -+ continue; -+ -+ if(!(cur->ifa_flags & IFF_UP)) - continue; - -- GetMacAddress(cur->ifa_name, macAddrRaw); - // Add the interface. -- m_interfaces.push_back(new CNetworkInterfaceLinux(this, cur->ifa_name, macAddrRaw)); -- } -+ std::string addr = CNetwork::GetIpStr(cur->ifa_addr); -+ std::string mask = CNetwork::GetIpStr(cur->ifa_netmask); - -- freeifaddrs(list); -+ if(addr.empty() || mask.empty()) -+ continue; - -+ CNetworkInterfaceLinux *iface = Exists(cur->ifa_addr, cur->ifa_netmask, name); -+ if (iface) -+ { -+ iface->SetRemoved(false); -+ iface->m_interfaceFlags = cur->ifa_flags; -+ continue; -+ } -+ -+ char macAddrRaw[6] = {0}; -+#if !defined(TARGET_LINUX) -+ GetMacAddress(&t_hwaddrs[name], macAddrRaw); - #else -- FILE* fp = fopen("/proc/net/dev", "r"); -- if (!fp) -- { -- // TBD: Error -- return; -- } -+ GetMacAddress(cur, macAddrRaw); -+#endif - -- char* line = NULL; -- size_t linel = 0; -- int n; -- char* p; -- int linenum = 0; -- while (getdelim(&line, &linel, '\n', fp) > 0) -- { -- // skip first two lines -- if (linenum++ < 2) -- continue; -+ CNetworkInterfaceLinux *i = new CNetworkInterfaceLinux(this, cur->ifa_flags, cur->ifa_addr, -+ cur->ifa_netmask, name, macAddrRaw); -+ -+ m_interfaces.insert_after(pos, i); -+ if (i->isIPv4()) -+ pos++; -+ change = true; -+ } - -- // search where the word begins -- p = line; -- while (isspace(*p)) -- ++p; -+ freeifaddrs(list); - -- // read word until : -- n = strcspn(p, ": \t"); -- p[n] = 0; -+ change |= std::count_if(m_interfaces.begin(), m_interfaces.end(), IsRemoved); -+ DeleteRemoved(); - -- // save the result -- std::string interfaceName = p; -- GetMacAddress(interfaceName, macAddrRaw); -- m_interfaces.push_back(new CNetworkInterfaceLinux(this, interfaceName, macAddrRaw)); -- } -- free(line); -- fclose(fp); --#endif -+ return change; - } - - std::vector CNetworkLinux::GetNameServers(void) - { - std::vector result; - --#if defined(TARGET_DARWIN) -- FILE* pipe = popen("scutil --dns | grep \"nameserver\" | tail -n2", "r"); -- usleep(100000); -- if (pipe) -- { -- std::vector tmpStr; -- char buffer[256] = {'\0'}; -- if (fread(buffer, sizeof(char), sizeof(buffer), pipe) > 0 && !ferror(pipe)) -- { -- tmpStr = StringUtils::Split(buffer, "\n"); -- for (unsigned int i = 0; i < tmpStr.size(); i ++) -- { -- // result looks like this - > ' nameserver[0] : 192.168.1.1' -- // 2 blank spaces + 13 in 'nameserver[0]' + blank + ':' + blank == 18 :) -- if (tmpStr[i].length() >= 18) -- result.push_back(tmpStr[i].substr(18)); -- } -- } -- pclose(pipe); -- } -- if (result.empty()) -- CLog::Log(LOGWARNING, "Unable to determine nameserver"); --#elif defined(TARGET_ANDROID) -+#if defined(TARGET_ANDROID) - char nameserver[PROP_VALUE_MAX]; - - if (__system_property_get("net.dns1",nameserver)) -@@ -502,19 +505,34 @@ std::vector CNetworkLinux::GetNameServers(void) - result.push_back(nameserver); - if (__system_property_get("net.dns3",nameserver)) - result.push_back(nameserver); -- -- if (!result.size()) -- CLog::Log(LOGWARNING, "Unable to determine nameserver"); - #else -- res_init(); -+ int res = res_init(); - -- for (int i = 0; i < _res.nscount; i ++) -+ for (int i = 0; i < MAXNS && !res; i++) - { -- std::string ns = inet_ntoa(((struct sockaddr_in *)&_res.nsaddr_list[i])->sin_addr); -- result.push_back(ns); -+ std::string strIp = CNetwork::GetIpStr((struct sockaddr *)&_res.nsaddr_list[i]); -+ if (!strIp.empty()) -+ result.push_back(strIp); -+ -+#if !defined(TARGET_DARWIN) -+ strIp = CNetwork::GetIpStr((struct sockaddr *)_res._u._ext.nsaddrs[i]); -+ if (!strIp.empty()) -+ result.push_back(strIp); -+#endif -+ -+ if (_res.nscount -+#if !defined(TARGET_DARWIN) -+ + _res._u._ext.nscount6 -+#endif -+ == result.size()) -+ break; - } -+ - #endif -- return result; -+ if (result.empty()) -+ CLog::Log(LOGWARNING, "Unable to determine nameserver"); -+ -+ return result; - } - - void CNetworkLinux::SetNameServers(const std::vector& nameServers) -@@ -536,19 +554,23 @@ void CNetworkLinux::SetNameServers(const std::vector& nameServers) - #endif - } - --bool CNetworkLinux::PingHost(unsigned long remote_ip, unsigned int timeout_ms) -+bool CNetworkLinux::PingHostImpl(const std::string &target, unsigned int timeout_ms) - { -- char cmd_line [64]; -+ bool isIPv6 = CNetwork::ConvIPv6(target); -+ if (isIPv6 && !SupportsIPv6()) -+ return false; - -- struct in_addr host_ip; -- host_ip.s_addr = remote_ip; -+ char cmd_line [64]; -+ std::string ping = isIPv6 ? "ping6" : "ping"; - - #if defined (TARGET_DARWIN_IOS) // no timeout option available -- sprintf(cmd_line, "ping -c 1 %s", inet_ntoa(host_ip)); -+ sprintf(cmd_line, "%s -c 1 %s", ping.c_str(), target.c_str()); - #elif defined (TARGET_DARWIN) || defined (TARGET_FREEBSD) -- sprintf(cmd_line, "ping -c 1 -t %d %s", timeout_ms / 1000 + (timeout_ms % 1000) != 0, inet_ntoa(host_ip)); -+ sprintf(cmd_line, "%s -c 1 -%s %d %s >/dev/null 2>&1", -+ ping.c_str(), isIPv6 ? "i" : "t", timeout_ms / 1000 + (timeout_ms % 1000) != 0, target.c_str()); - #else -- sprintf(cmd_line, "ping -c 1 -w %d %s", timeout_ms / 1000 + (timeout_ms % 1000) != 0, inet_ntoa(host_ip)); -+ sprintf(cmd_line, "%s -c 1 -w %d %s >/dev/null 2>&1", -+ ping.c_str(), timeout_ms / 1000 + (timeout_ms % 1000) != 0, target.c_str()); - #endif - - int status = system (cmd_line); -@@ -566,9 +588,12 @@ bool CNetworkLinux::PingHost(unsigned long remote_ip, unsigned int timeout_ms) - return result == 0; - } - --#if defined(TARGET_DARWIN) || defined(TARGET_FREEBSD) - bool CNetworkInterfaceLinux::GetHostMacAddress(unsigned long host_ip, std::string& mac) - { -+ if (m_network->GetFirstConnectedFamily() == AF_INET6 || isIPv6()) -+ return false; -+ -+#if defined(TARGET_DARWIN) || defined(TARGET_FREEBSD) - bool ret = false; - size_t needed; - char *buf, *next; -@@ -615,10 +640,7 @@ bool CNetworkInterfaceLinux::GetHostMacAddress(unsigned long host_ip, std::strin - } - } - return ret; --} - #else --bool CNetworkInterfaceLinux::GetHostMacAddress(unsigned long host_ip, std::string& mac) --{ - struct arpreq areq; - struct sockaddr_in* sin; - -@@ -652,8 +674,8 @@ bool CNetworkInterfaceLinux::GetHostMacAddress(unsigned long host_ip, std::strin - return true; - - return false; --} - #endif -+} - - std::vector CNetworkInterfaceLinux::GetAccessPoints(void) - { -@@ -1117,4 +1139,53 @@ void CNetworkInterfaceLinux::WriteSettings(FILE* fw, NetworkAssignment assignmen - fprintf(fw, "auto %s\n\n", GetName().c_str()); - } - -+void WatcherProcess(void *caller) -+{ -+ struct sockaddr_nl addr; -+ int fds = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE); -+ struct pollfd m_fds = { fds, POLLIN, 0 }; -+ char msg[4096]; -+ volatile std::atomic *stopping = ((CNetwork::CNetworkUpdater*)caller)->Stopping(); -+ -+ memset (&addr, 0, sizeof(struct sockaddr_nl)); -+ addr.nl_family = AF_NETLINK; -+ addr.nl_pid = getpid (); -+#if defined(TARGET_LINUX) -+ addr.nl_groups = RTMGRP_LINK | RTMGRP_IPV4_IFADDR | RTMGRP_IPV6_IFADDR; -+ /* RTMGRP_IPV4_IFADDR | RTMGRP_TC | RTMGRP_IPV4_MROUTE | -+ RTMGRP_IPV4_ROUTE | RTMGRP_IPV4_RULE | -+ RTMGRP_IPV6_IFADDR | RTMGRP_IPV6_MROUTE | -+ RTMGRP_IPV6_ROUTE | RTMGRP_IPV6_IFINFO | -+ RTMGRP_IPV6_PREFIX */ -+#else -+ addr.nl_groups = RTMGRP_LINK; -+#endif -+ -+ if (-1 == bind(fds, (const struct sockaddr *) &addr, sizeof(struct sockaddr))) -+ { -+ close(fds); -+ fds = 0; -+ } -+ else -+ fcntl(fds, F_SETFL, O_NONBLOCK); -+ -+ while(!*stopping) -+ if (poll(&m_fds, 1, 1000) > 0) -+ { -+ while (!*stopping && fds && recv(fds, &msg, sizeof(msg), 0) > 0); -+ if (*stopping) -+ continue; -+ -+ if (!fds) -+ ((CNetwork::CNetworkUpdater*)caller)->Sleep(5000); -+ else -+ ((CNetwork::CNetworkUpdater*)caller)->Sleep(1000); -+ -+ if (stopping || !g_application.getNetwork().ForceRereadInterfaces()) -+ continue; -+ -+ CLog::Log(LOGINFO, "Interfaces change %s", __FUNCTION__); -+ CApplicationMessenger::GetInstance().SendMsg(TMSG_NETWORKMESSAGE, CNetwork::NETWORK_CHANGED, 0); -+ } -+} - -diff --git a/xbmc/network/linux/NetworkLinux.h b/xbmc/network/linux/NetworkLinux.h -index d8b65bc..8d316cd 100644 ---- a/xbmc/network/linux/NetworkLinux.h -+++ b/xbmc/network/linux/NetworkLinux.h -@@ -23,15 +23,20 @@ - - #include - #include -+#include - #include - #include "network/Network.h" - - class CNetworkLinux; -+class CNetworkLinuxUpdateThread; - - class CNetworkInterfaceLinux : public CNetworkInterface - { -+ friend class CNetworkLinux; -+ - public: -- CNetworkInterfaceLinux(CNetworkLinux* network, std::string interfaceName, char interfaceMacAddrRaw[6]); -+ CNetworkInterfaceLinux(CNetworkLinux* network, unsigned int ifa_flags, struct sockaddr *address, -+ struct sockaddr *netmask, std::string interfaceName, char interfaceMacAddrRaw[6]); - ~CNetworkInterfaceLinux(void); - - virtual std::string& GetName(void); -@@ -53,11 +58,27 @@ public: - virtual void GetSettings(NetworkAssignment& assignment, std::string& ipAddress, std::string& networkMask, std::string& defaultGateway, std::string& essId, std::string& key, EncMode& encryptionMode); - virtual void SetSettings(NetworkAssignment& assignment, std::string& ipAddress, std::string& networkMask, std::string& defaultGateway, std::string& essId, std::string& key, EncMode& encryptionMode); - -+ bool isIPv6() { return m_address->sa_family == AF_INET6; } -+ bool isIPv4() { return m_address->sa_family == AF_INET; } -+ - // Returns the list of access points in the area - virtual std::vector GetAccessPoints(void); -- -+ -+ bool Exists(const struct sockaddr *address, const struct sockaddr *netmask, const std::string &name) -+ { -+ return CNetwork::CompareAddresses(m_address, address) && CNetwork::CompareAddresses(m_netmask, netmask) && name == m_interfaceName; -+ } -+ -+protected: -+ void SetRemoved(bool removed = true) { m_removed = removed; } -+ bool IsRemoved(void) { return m_removed; } -+ - private: - void WriteSettings(FILE* fw, NetworkAssignment assignment, std::string& ipAddress, std::string& networkMask, std::string& defaultGateway, std::string& essId, std::string& key, EncMode& encryptionMode); -+ unsigned int m_interfaceFlags; /* Flags from SIOCGIFFLAGS */ -+ struct sockaddr* m_address; -+ struct sockaddr* m_netmask; -+ bool m_removed; - std::string m_interfaceName; - std::string m_interfaceMacAdr; - char m_interfaceMacAddrRaw[6]; -@@ -66,30 +87,42 @@ private: - - class CNetworkLinux : public CNetwork - { -+ friend class CNetworkInterfaceLinux; -+ - public: - CNetworkLinux(void); - virtual ~CNetworkLinux(void); - -- // Return the list of interfaces -- virtual std::vector& GetInterfaceList(void); -- virtual CNetworkInterface* GetFirstConnectedInterface(void); -- -- // Ping remote host -- virtual bool PingHost(unsigned long host, unsigned int timeout_ms = 2000); -+ virtual std::forward_list& GetInterfaceList(void); -+ virtual CNetworkInterface* GetFirstConnectedInterface(void); -+ -+ virtual bool SupportsIPv6() { return true; } -+ -+ virtual bool PingHostImpl(const std::string &target, unsigned int timeout_ms = 2000); - - // Get/set the nameserver(s) -+ // Current code is safe for any stack configuration, but APi -+ // used provides IPv4 nameservers only (those specified in system -+ // via IPv4 address). empty otherwise. -+ // TODO: find a method to get list of all defined nameservers - virtual std::vector GetNameServers(void); - virtual void SetNameServers(const std::vector& nameServers); - -- friend class CNetworkInterfaceLinux; -- -+ bool ForceRereadInterfaces() { return queryInterfaceList(); } - private: -+ CNetworkInterfaceLinux *Exists(const struct sockaddr *addr, const struct sockaddr *mask, const std::string &name); -+ void InterfacesClear(void); -+ void DeleteRemoved(void); -+ - int GetSocket() { return m_sock; } -- void GetMacAddress(const std::string& interfaceName, char macAddrRaw[6]); -- void queryInterfaceList(); -- std::vector m_interfaces; -+ void GetMacAddress(struct ifaddrs *tif, char *mac); -+ bool queryInterfaceList(); -+ std::forward_list m_interfaces; - int m_sock; -+ -+ static bool IsRemoved(const CNetworkInterface *i) { return ((CNetworkInterfaceLinux*)i)->IsRemoved(); } - }; - - #endif - -+void WatcherProcess(void *caller); -diff --git a/xbmc/network/linux/android-ifaddrs/Makefile b/xbmc/network/linux/android-ifaddrs/Makefile -new file mode 100644 -index 0000000..39e43ea ---- /dev/null -+++ b/xbmc/network/linux/android-ifaddrs/Makefile -@@ -0,0 +1,6 @@ -+SRCS=ifaddrs.c -+ -+LIB=android-ifaddrs.a -+ -+include ../../../../Makefile.include -+-include $(patsubst %.cpp,%.P,$(patsubst %.c,%.P,$(SRCS))) -diff --git a/xbmc/network/linux/android-ifaddrs/README.md b/xbmc/network/linux/android-ifaddrs/README.md -new file mode 100644 -index 0000000..dc05bdf ---- /dev/null -+++ b/xbmc/network/linux/android-ifaddrs/README.md -@@ -0,0 +1,6 @@ -+android-ifaddrs -+=============== -+ -+An implementation of getifaddrs() for Android, since the NDK does not natively support it. -+ -+Works just like you would expect on regular Linux. License information is present in each file (BSD license). -diff --git a/xbmc/network/linux/android-ifaddrs/ifaddrs.c b/xbmc/network/linux/android-ifaddrs/ifaddrs.c -new file mode 100644 -index 0000000..c59d8bc ---- /dev/null -+++ b/xbmc/network/linux/android-ifaddrs/ifaddrs.c -@@ -0,0 +1,663 @@ -+/* -+Copyright (c) 2013, Kenneth MacKay -+All rights reserved. -+ -+Redistribution and use in source and binary forms, with or without modification, -+are permitted provided that the following conditions are met: -+ * Redistributions of source code must retain the above copyright notice, this -+ list of conditions and the following disclaimer. -+ * Redistributions in binary form must reproduce the above copyright notice, -+ this list of conditions and the following disclaimer in the documentation -+ and/or other materials provided with the distribution. -+ -+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR -+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -+*/ -+ -+#include "ifaddrs.h" -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+typedef struct NetlinkList -+{ -+ struct NetlinkList *m_next; -+ struct nlmsghdr *m_data; -+ unsigned int m_size; -+} NetlinkList; -+ -+static int netlink_socket(void) -+{ -+ int l_socket = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE); -+ if(l_socket < 0) -+ { -+ return -1; -+ } -+ -+ struct sockaddr_nl l_addr; -+ memset(&l_addr, 0, sizeof(l_addr)); -+ l_addr.nl_family = AF_NETLINK; -+ if(bind(l_socket, (struct sockaddr *)&l_addr, sizeof(l_addr)) < 0) -+ { -+ close(l_socket); -+ return -1; -+ } -+ -+ return l_socket; -+} -+ -+static int netlink_send(int p_socket, int p_request) -+{ -+ struct -+ { -+ struct nlmsghdr m_hdr; -+ struct rtgenmsg m_msg; -+ } l_data; -+ -+ memset(&l_data, 0, sizeof(l_data)); -+ -+ l_data.m_hdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtgenmsg)); -+ l_data.m_hdr.nlmsg_type = p_request; -+ l_data.m_hdr.nlmsg_flags = NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST; -+ l_data.m_hdr.nlmsg_pid = 0; -+ l_data.m_hdr.nlmsg_seq = p_socket; -+ l_data.m_msg.rtgen_family = AF_UNSPEC; -+ -+ struct sockaddr_nl l_addr; -+ memset(&l_addr, 0, sizeof(l_addr)); -+ l_addr.nl_family = AF_NETLINK; -+ return (sendto(p_socket, &l_data.m_hdr, l_data.m_hdr.nlmsg_len, 0, (struct sockaddr *)&l_addr, sizeof(l_addr))); -+} -+ -+static int netlink_recv(int p_socket, void *p_buffer, size_t p_len) -+{ -+ struct msghdr l_msg; -+ struct iovec l_iov = { p_buffer, p_len }; -+ struct sockaddr_nl l_addr; -+ -+ for(;;) -+ { -+ l_msg.msg_name = (void *)&l_addr; -+ l_msg.msg_namelen = sizeof(l_addr); -+ l_msg.msg_iov = &l_iov; -+ l_msg.msg_iovlen = 1; -+ l_msg.msg_control = NULL; -+ l_msg.msg_controllen = 0; -+ l_msg.msg_flags = 0; -+ int l_result = recvmsg(p_socket, &l_msg, 0); -+ -+ if(l_result < 0) -+ { -+ if(errno == EINTR) -+ { -+ continue; -+ } -+ return -2; -+ } -+ -+ if(l_msg.msg_flags & MSG_TRUNC) -+ { // buffer was too small -+ return -1; -+ } -+ return l_result; -+ } -+} -+ -+static struct nlmsghdr *getNetlinkResponse(int p_socket, int *p_size, int *p_done) -+{ -+ size_t l_size = 4096; -+ void *l_buffer = NULL; -+ -+ for(;;) -+ { -+ free(l_buffer); -+ l_buffer = malloc(l_size); -+ if (l_buffer == NULL) -+ { -+ return NULL; -+ } -+ -+ int l_read = netlink_recv(p_socket, l_buffer, l_size); -+ *p_size = l_read; -+ if(l_read == -2) -+ { -+ free(l_buffer); -+ return NULL; -+ } -+ if(l_read >= 0) -+ { -+ pid_t l_pid = getpid(); -+ struct nlmsghdr *l_hdr; -+ for(l_hdr = (struct nlmsghdr *)l_buffer; NLMSG_OK(l_hdr, (unsigned int)l_read); l_hdr = (struct nlmsghdr *)NLMSG_NEXT(l_hdr, l_read)) -+ { -+ if((pid_t)l_hdr->nlmsg_pid != l_pid || (int)l_hdr->nlmsg_seq != p_socket) -+ { -+ continue; -+ } -+ -+ if(l_hdr->nlmsg_type == NLMSG_DONE) -+ { -+ *p_done = 1; -+ break; -+ } -+ -+ if(l_hdr->nlmsg_type == NLMSG_ERROR) -+ { -+ free(l_buffer); -+ return NULL; -+ } -+ } -+ return l_buffer; -+ } -+ -+ l_size *= 2; -+ } -+} -+ -+static NetlinkList *newListItem(struct nlmsghdr *p_data, unsigned int p_size) -+{ -+ NetlinkList *l_item = malloc(sizeof(NetlinkList)); -+ if (l_item == NULL) -+ { -+ return NULL; -+ } -+ -+ l_item->m_next = NULL; -+ l_item->m_data = p_data; -+ l_item->m_size = p_size; -+ return l_item; -+} -+ -+static void freeResultList(NetlinkList *p_list) -+{ -+ NetlinkList *l_cur; -+ while(p_list) -+ { -+ l_cur = p_list; -+ p_list = p_list->m_next; -+ free(l_cur->m_data); -+ free(l_cur); -+ } -+} -+ -+static NetlinkList *getResultList(int p_socket, int p_request) -+{ -+ if(netlink_send(p_socket, p_request) < 0) -+ { -+ return NULL; -+ } -+ -+ NetlinkList *l_list = NULL; -+ NetlinkList *l_end = NULL; -+ int l_size; -+ int l_done = 0; -+ while(!l_done) -+ { -+ struct nlmsghdr *l_hdr = getNetlinkResponse(p_socket, &l_size, &l_done); -+ if(!l_hdr) -+ { // error -+ freeResultList(l_list); -+ return NULL; -+ } -+ -+ NetlinkList *l_item = newListItem(l_hdr, l_size); -+ if (!l_item) -+ { -+ freeResultList(l_list); -+ return NULL; -+ } -+ if(!l_list) -+ { -+ l_list = l_item; -+ } -+ else -+ { -+ l_end->m_next = l_item; -+ } -+ l_end = l_item; -+ } -+ return l_list; -+} -+ -+static size_t maxSize(size_t a, size_t b) -+{ -+ return (a > b ? a : b); -+} -+ -+static size_t calcAddrLen(sa_family_t p_family, int p_dataSize) -+{ -+ switch(p_family) -+ { -+ case AF_INET: -+ return sizeof(struct sockaddr_in); -+ case AF_INET6: -+ return sizeof(struct sockaddr_in6); -+ case AF_PACKET: -+ return maxSize(sizeof(struct sockaddr_ll), offsetof(struct sockaddr_ll, sll_addr) + p_dataSize); -+ default: -+ return maxSize(sizeof(struct sockaddr), offsetof(struct sockaddr, sa_data) + p_dataSize); -+ } -+} -+ -+static void makeSockaddr(sa_family_t p_family, struct sockaddr *p_dest, void *p_data, size_t p_size) -+{ -+ switch(p_family) -+ { -+ case AF_INET: -+ memcpy(&((struct sockaddr_in*)p_dest)->sin_addr, p_data, p_size); -+ break; -+ case AF_INET6: -+ memcpy(&((struct sockaddr_in6*)p_dest)->sin6_addr, p_data, p_size); -+ break; -+ case AF_PACKET: -+ memcpy(((struct sockaddr_ll*)p_dest)->sll_addr, p_data, p_size); -+ ((struct sockaddr_ll*)p_dest)->sll_halen = p_size; -+ break; -+ default: -+ memcpy(p_dest->sa_data, p_data, p_size); -+ break; -+ } -+ p_dest->sa_family = p_family; -+} -+ -+static void addToEnd(struct ifaddrs **p_resultList, struct ifaddrs *p_entry) -+{ -+ if(!*p_resultList) -+ { -+ *p_resultList = p_entry; -+ } -+ else -+ { -+ struct ifaddrs *l_cur = *p_resultList; -+ while(l_cur->ifa_next) -+ { -+ l_cur = l_cur->ifa_next; -+ } -+ l_cur->ifa_next = p_entry; -+ } -+} -+ -+static int interpretLink(struct nlmsghdr *p_hdr, struct ifaddrs **p_resultList) -+{ -+ struct ifinfomsg *l_info = (struct ifinfomsg *)NLMSG_DATA(p_hdr); -+ -+ size_t l_nameSize = 0; -+ size_t l_addrSize = 0; -+ size_t l_dataSize = 0; -+ -+ size_t l_rtaSize = NLMSG_PAYLOAD(p_hdr, sizeof(struct ifinfomsg)); -+ struct rtattr *l_rta; -+ for(l_rta = IFLA_RTA(l_info); RTA_OK(l_rta, l_rtaSize); l_rta = RTA_NEXT(l_rta, l_rtaSize)) -+ { -+ void *l_rtaData = RTA_DATA(l_rta); -+ size_t l_rtaDataSize = RTA_PAYLOAD(l_rta); -+ switch(l_rta->rta_type) -+ { -+ case IFLA_ADDRESS: -+ case IFLA_BROADCAST: -+ l_addrSize += NLMSG_ALIGN(calcAddrLen(AF_PACKET, l_rtaDataSize)); -+ break; -+ case IFLA_IFNAME: -+ l_nameSize += NLMSG_ALIGN(l_rtaSize + 1); -+ break; -+ case IFLA_STATS: -+ l_dataSize += NLMSG_ALIGN(l_rtaSize); -+ break; -+ default: -+ break; -+ } -+ } -+ -+ struct ifaddrs *l_entry = malloc(sizeof(struct ifaddrs) + sizeof(int) + l_nameSize + l_addrSize + l_dataSize); -+ if (l_entry == NULL) -+ { -+ return -1; -+ } -+ memset(l_entry, 0, sizeof(struct ifaddrs)); -+ l_entry->ifa_name = ""; -+ -+ char *l_index = ((char *)l_entry) + sizeof(struct ifaddrs); -+ char *l_name = l_index + sizeof(int); -+ char *l_addr = l_name + l_nameSize; -+ char *l_data = l_addr + l_addrSize; -+ -+ // save the interface index so we can look it up when handling the addresses. -+ memcpy(l_index, &l_info->ifi_index, sizeof(int)); -+ -+ l_entry->ifa_flags = l_info->ifi_flags; -+ -+ l_rtaSize = NLMSG_PAYLOAD(p_hdr, sizeof(struct ifinfomsg)); -+ for(l_rta = IFLA_RTA(l_info); RTA_OK(l_rta, l_rtaSize); l_rta = RTA_NEXT(l_rta, l_rtaSize)) -+ { -+ void *l_rtaData = RTA_DATA(l_rta); -+ size_t l_rtaDataSize = RTA_PAYLOAD(l_rta); -+ switch(l_rta->rta_type) -+ { -+ case IFLA_ADDRESS: -+ case IFLA_BROADCAST: -+ { -+ size_t l_addrLen = calcAddrLen(AF_PACKET, l_rtaDataSize); -+ makeSockaddr(AF_PACKET, (struct sockaddr *)l_addr, l_rtaData, l_rtaDataSize); -+ ((struct sockaddr_ll *)l_addr)->sll_ifindex = l_info->ifi_index; -+ ((struct sockaddr_ll *)l_addr)->sll_hatype = l_info->ifi_type; -+ if(l_rta->rta_type == IFLA_ADDRESS) -+ { -+ l_entry->ifa_addr = (struct sockaddr *)l_addr; -+ } -+ else -+ { -+ l_entry->ifa_broadaddr = (struct sockaddr *)l_addr; -+ } -+ l_addr += NLMSG_ALIGN(l_addrLen); -+ break; -+ } -+ case IFLA_IFNAME: -+ strncpy(l_name, l_rtaData, l_rtaDataSize); -+ l_name[l_rtaDataSize] = '\0'; -+ l_entry->ifa_name = l_name; -+ break; -+ case IFLA_STATS: -+ memcpy(l_data, l_rtaData, l_rtaDataSize); -+ l_entry->ifa_data = l_data; -+ break; -+ default: -+ break; -+ } -+ } -+ -+ addToEnd(p_resultList, l_entry); -+ return 0; -+} -+ -+static struct ifaddrs *findInterface(int p_index, struct ifaddrs **p_links, int p_numLinks) -+{ -+ int l_num = 0; -+ struct ifaddrs *l_cur = *p_links; -+ while(l_cur && l_num < p_numLinks) -+ { -+ char *l_indexPtr = ((char *)l_cur) + sizeof(struct ifaddrs); -+ int l_index; -+ memcpy(&l_index, l_indexPtr, sizeof(int)); -+ if(l_index == p_index) -+ { -+ return l_cur; -+ } -+ -+ l_cur = l_cur->ifa_next; -+ ++l_num; -+ } -+ return NULL; -+} -+ -+static int interpretAddr(struct nlmsghdr *p_hdr, struct ifaddrs **p_resultList, int p_numLinks) -+{ -+ struct ifaddrmsg *l_info = (struct ifaddrmsg *)NLMSG_DATA(p_hdr); -+ struct ifaddrs *l_interface = findInterface(l_info->ifa_index, p_resultList, p_numLinks); -+ -+ if(l_info->ifa_family == AF_PACKET) -+ { -+ return 0; -+ } -+ -+ size_t l_nameSize = 0; -+ size_t l_addrSize = 0; -+ -+ int l_addedNetmask = 0; -+ -+ size_t l_rtaSize = NLMSG_PAYLOAD(p_hdr, sizeof(struct ifaddrmsg)); -+ struct rtattr *l_rta; -+ for(l_rta = IFA_RTA(l_info); RTA_OK(l_rta, l_rtaSize); l_rta = RTA_NEXT(l_rta, l_rtaSize)) -+ { -+ void *l_rtaData = RTA_DATA(l_rta); -+ size_t l_rtaDataSize = RTA_PAYLOAD(l_rta); -+ -+ switch(l_rta->rta_type) -+ { -+ case IFA_ADDRESS: -+ case IFA_LOCAL: -+ if((l_info->ifa_family == AF_INET || l_info->ifa_family == AF_INET6) && !l_addedNetmask) -+ { // make room for netmask -+ l_addrSize += NLMSG_ALIGN(calcAddrLen(l_info->ifa_family, l_rtaDataSize)); -+ l_addedNetmask = 1; -+ } -+ case IFA_BROADCAST: -+ l_addrSize += NLMSG_ALIGN(calcAddrLen(l_info->ifa_family, l_rtaDataSize)); -+ break; -+ case IFA_LABEL: -+ l_nameSize += NLMSG_ALIGN(l_rtaSize + 1); -+ break; -+ default: -+ break; -+ } -+ } -+ -+ struct ifaddrs *l_entry = malloc(sizeof(struct ifaddrs) + l_nameSize + l_addrSize); -+ if (l_entry == NULL) -+ { -+ return -1; -+ } -+ memset(l_entry, 0, sizeof(struct ifaddrs)); -+ l_entry->ifa_name = (l_interface ? l_interface->ifa_name : ""); -+ -+ char *l_name = ((char *)l_entry) + sizeof(struct ifaddrs); -+ char *l_addr = l_name + l_nameSize; -+ -+ l_entry->ifa_flags = l_info->ifa_flags; -+ if(l_interface) -+ { -+ l_entry->ifa_flags |= l_interface->ifa_flags; -+ } -+ -+ l_rtaSize = NLMSG_PAYLOAD(p_hdr, sizeof(struct ifaddrmsg)); -+ for(l_rta = IFA_RTA(l_info); RTA_OK(l_rta, l_rtaSize); l_rta = RTA_NEXT(l_rta, l_rtaSize)) -+ { -+ void *l_rtaData = RTA_DATA(l_rta); -+ size_t l_rtaDataSize = RTA_PAYLOAD(l_rta); -+ switch(l_rta->rta_type) -+ { -+ case IFA_ADDRESS: -+ case IFA_BROADCAST: -+ case IFA_LOCAL: -+ { -+ size_t l_addrLen = calcAddrLen(l_info->ifa_family, l_rtaDataSize); -+ makeSockaddr(l_info->ifa_family, (struct sockaddr *)l_addr, l_rtaData, l_rtaDataSize); -+ if(l_info->ifa_family == AF_INET6) -+ { -+ if(IN6_IS_ADDR_LINKLOCAL((struct in6_addr *)l_rtaData) || IN6_IS_ADDR_MC_LINKLOCAL((struct in6_addr *)l_rtaData)) -+ { -+ ((struct sockaddr_in6 *)l_addr)->sin6_scope_id = l_info->ifa_index; -+ } -+ } -+ -+ if(l_rta->rta_type == IFA_ADDRESS) -+ { // apparently in a point-to-point network IFA_ADDRESS contains the dest address and IFA_LOCAL contains the local address -+ if(l_entry->ifa_addr) -+ { -+ l_entry->ifa_dstaddr = (struct sockaddr *)l_addr; -+ } -+ else -+ { -+ l_entry->ifa_addr = (struct sockaddr *)l_addr; -+ } -+ } -+ else if(l_rta->rta_type == IFA_LOCAL) -+ { -+ if(l_entry->ifa_addr) -+ { -+ l_entry->ifa_dstaddr = l_entry->ifa_addr; -+ } -+ l_entry->ifa_addr = (struct sockaddr *)l_addr; -+ } -+ else -+ { -+ l_entry->ifa_broadaddr = (struct sockaddr *)l_addr; -+ } -+ l_addr += NLMSG_ALIGN(l_addrLen); -+ break; -+ } -+ case IFA_LABEL: -+ strncpy(l_name, l_rtaData, l_rtaDataSize); -+ l_name[l_rtaDataSize] = '\0'; -+ l_entry->ifa_name = l_name; -+ break; -+ default: -+ break; -+ } -+ } -+ -+ if(l_entry->ifa_addr && (l_entry->ifa_addr->sa_family == AF_INET || l_entry->ifa_addr->sa_family == AF_INET6)) -+ { -+ unsigned l_maxPrefix = (l_entry->ifa_addr->sa_family == AF_INET ? 32 : 128); -+ unsigned l_prefix = (l_info->ifa_prefixlen > l_maxPrefix ? l_maxPrefix : l_info->ifa_prefixlen); -+ char l_mask[16] = {0}; -+ unsigned i; -+ for(i=0; i<(l_prefix/8); ++i) -+ { -+ l_mask[i] = 0xff; -+ } -+ if(l_prefix % 8) -+ { -+ l_mask[i] = 0xff << (8 - (l_prefix % 8)); -+ } -+ -+ makeSockaddr(l_entry->ifa_addr->sa_family, (struct sockaddr *)l_addr, l_mask, l_maxPrefix / 8); -+ l_entry->ifa_netmask = (struct sockaddr *)l_addr; -+ } -+ -+ addToEnd(p_resultList, l_entry); -+ return 0; -+} -+ -+static int interpretLinks(int p_socket, NetlinkList *p_netlinkList, struct ifaddrs **p_resultList) -+{ -+ int l_numLinks = 0; -+ pid_t l_pid = getpid(); -+ for(; p_netlinkList; p_netlinkList = p_netlinkList->m_next) -+ { -+ unsigned int l_nlsize = p_netlinkList->m_size; -+ struct nlmsghdr *l_hdr; -+ for(l_hdr = p_netlinkList->m_data; NLMSG_OK(l_hdr, l_nlsize); l_hdr = NLMSG_NEXT(l_hdr, l_nlsize)) -+ { -+ if((pid_t)l_hdr->nlmsg_pid != l_pid || (int)l_hdr->nlmsg_seq != p_socket) -+ { -+ continue; -+ } -+ -+ if(l_hdr->nlmsg_type == NLMSG_DONE) -+ { -+ break; -+ } -+ -+ if(l_hdr->nlmsg_type == RTM_NEWLINK) -+ { -+ if(interpretLink(l_hdr, p_resultList) == -1) -+ { -+ return -1; -+ } -+ ++l_numLinks; -+ } -+ } -+ } -+ return l_numLinks; -+} -+ -+static int interpretAddrs(int p_socket, NetlinkList *p_netlinkList, struct ifaddrs **p_resultList, int p_numLinks) -+{ -+ pid_t l_pid = getpid(); -+ for(; p_netlinkList; p_netlinkList = p_netlinkList->m_next) -+ { -+ unsigned int l_nlsize = p_netlinkList->m_size; -+ struct nlmsghdr *l_hdr; -+ for(l_hdr = p_netlinkList->m_data; NLMSG_OK(l_hdr, l_nlsize); l_hdr = NLMSG_NEXT(l_hdr, l_nlsize)) -+ { -+ if((pid_t)l_hdr->nlmsg_pid != l_pid || (int)l_hdr->nlmsg_seq != p_socket) -+ { -+ continue; -+ } -+ -+ if(l_hdr->nlmsg_type == NLMSG_DONE) -+ { -+ break; -+ } -+ -+ if(l_hdr->nlmsg_type == RTM_NEWADDR) -+ { -+ if (interpretAddr(l_hdr, p_resultList, p_numLinks) == -1) -+ { -+ return -1; -+ } -+ } -+ } -+ } -+ return 0; -+} -+ -+int getifaddrs(struct ifaddrs **ifap) -+{ -+ if(!ifap) -+ { -+ return -1; -+ } -+ *ifap = NULL; -+ -+ int l_socket = netlink_socket(); -+ if(l_socket < 0) -+ { -+ return -1; -+ } -+ -+ NetlinkList *l_linkResults = getResultList(l_socket, RTM_GETLINK); -+ if(!l_linkResults) -+ { -+ close(l_socket); -+ return -1; -+ } -+ -+ NetlinkList *l_addrResults = getResultList(l_socket, RTM_GETADDR); -+ if(!l_addrResults) -+ { -+ close(l_socket); -+ freeResultList(l_linkResults); -+ return -1; -+ } -+ -+ int l_result = 0; -+ int l_numLinks = interpretLinks(l_socket, l_linkResults, ifap); -+ if(l_numLinks == -1 || interpretAddrs(l_socket, l_addrResults, ifap, l_numLinks) == -1) -+ { -+ l_result = -1; -+ } -+ -+ freeResultList(l_linkResults); -+ freeResultList(l_addrResults); -+ close(l_socket); -+ return l_result; -+} -+ -+void freeifaddrs(struct ifaddrs *ifa) -+{ -+ struct ifaddrs *l_cur; -+ while(ifa) -+ { -+ l_cur = ifa; -+ ifa = ifa->ifa_next; -+ free(l_cur); -+ } -+} -diff --git a/xbmc/network/linux/android-ifaddrs/ifaddrs.h b/xbmc/network/linux/android-ifaddrs/ifaddrs.h -new file mode 100644 -index 0000000..9cd19fe ---- /dev/null -+++ b/xbmc/network/linux/android-ifaddrs/ifaddrs.h -@@ -0,0 +1,54 @@ -+/* -+ * Copyright (c) 1995, 1999 -+ * Berkeley Software Design, Inc. All rights reserved. -+ * -+ * Redistribution and use in source and binary forms, with or without -+ * modification, are permitted provided that the following conditions -+ * are met: -+ * 1. Redistributions of source code must retain the above copyright -+ * notice, this list of conditions and the following disclaimer. -+ * -+ * THIS SOFTWARE IS PROVIDED BY Berkeley Software Design, Inc. ``AS IS'' AND -+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -+ * ARE DISCLAIMED. IN NO EVENT SHALL Berkeley Software Design, Inc. BE LIABLE -+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS -+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF -+ * SUCH DAMAGE. -+ * -+ * BSDI ifaddrs.h,v 2.5 2000/02/23 14:51:59 dab Exp -+ */ -+ -+#ifndef _IFADDRS_H_ -+#define _IFADDRS_H_ -+ -+struct ifaddrs { -+ struct ifaddrs *ifa_next; -+ char *ifa_name; -+ unsigned int ifa_flags; -+ struct sockaddr *ifa_addr; -+ struct sockaddr *ifa_netmask; -+ struct sockaddr *ifa_dstaddr; -+ void *ifa_data; -+}; -+ -+/* -+ * This may have been defined in . Note that if is -+ * to be included it must be included before this header file. -+ */ -+#ifndef ifa_broadaddr -+#define ifa_broadaddr ifa_dstaddr /* broadcast address interface */ -+#endif -+ -+#include -+ -+__BEGIN_DECLS -+extern int getifaddrs(struct ifaddrs **ifap); -+extern void freeifaddrs(struct ifaddrs *ifa); -+__END_DECLS -+ -+#endif -diff --git a/xbmc/network/osx/priv_netlink.h b/xbmc/network/osx/priv_netlink.h -new file mode 100644 -index 0000000..9630969 ---- /dev/null -+++ b/xbmc/network/osx/priv_netlink.h -@@ -0,0 +1,120 @@ -+/* -+ * wpa_supplicant - Private copy of Linux netlink/rtnetlink definitions. -+ * Copyright (c) 2003-2005, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include -+ -+#ifndef PRIV_NETLINK_H -+#define PRIV_NETLINK_H -+ -+/* -+ * This should be replaced with user space header once one is available with C -+ * library, etc.. -+ */ -+ -+#ifndef IFF_LOWER_UP -+#define IFF_LOWER_UP 0x10000 /* driver signals L1 up */ -+#endif -+#ifndef IFF_DORMANT -+#define IFF_DORMANT 0x20000 /* driver signals dormant */ -+#endif -+ -+#ifndef IFLA_IFNAME -+#define IFLA_IFNAME 3 -+#endif -+#ifndef IFLA_WIRELESS -+#define IFLA_WIRELESS 11 -+#endif -+#ifndef IFLA_OPERSTATE -+#define IFLA_OPERSTATE 16 -+#endif -+#ifndef IFLA_LINKMODE -+#define IFLA_LINKMODE 17 -+#define IF_OPER_DORMANT 5 -+#define IF_OPER_UP 6 -+#endif -+ -+#define NLM_F_REQUEST 1 -+ -+#define NETLINK_ROUTE 0 -+#define RTMGRP_LINK 1 -+#define RTM_BASE 0x10 -+#define RTM_NEWLINK (RTM_BASE + 0) -+#define RTM_DELLINK (RTM_BASE + 1) -+#define RTM_SETLINK (RTM_BASE + 3) -+ -+#define NLMSG_ALIGNTO 4 -+#define NLMSG_ALIGN(len) (((len) + NLMSG_ALIGNTO - 1) & ~(NLMSG_ALIGNTO - 1)) -+#define NLMSG_HDRLEN ((int) NLMSG_ALIGN(sizeof(struct nlmsghdr))) -+#define NLMSG_LENGTH(len) ((len) + NLMSG_ALIGN(sizeof(struct nlmsghdr))) -+#define NLMSG_SPACE(len) NLMSG_ALIGN(NLMSG_LENGTH(len)) -+#define NLMSG_DATA(nlh) ((void*) (((char*) nlh) + NLMSG_LENGTH(0))) -+#define NLMSG_NEXT(nlh,len) ((len) -= NLMSG_ALIGN((nlh)->nlmsg_len), \ -+ (struct nlmsghdr *) \ -+ (((char *)(nlh)) + NLMSG_ALIGN((nlh)->nlmsg_len))) -+#define NLMSG_OK(nlh,len) ((len) >= (int) sizeof(struct nlmsghdr) && \ -+ (nlh)->nlmsg_len >= sizeof(struct nlmsghdr) && \ -+ (int) (nlh)->nlmsg_len <= (len)) -+#define NLMSG_PAYLOAD(nlh,len) ((nlh)->nlmsg_len - NLMSG_SPACE((len))) -+ -+#define RTA_ALIGNTO 4 -+#define RTA_ALIGN(len) (((len) + RTA_ALIGNTO - 1) & ~(RTA_ALIGNTO - 1)) -+#define RTA_OK(rta,len) \ -+((len) > 0 && (rta)->rta_len >= sizeof(struct rtattr) && \ -+(rta)->rta_len <= (len)) -+#define RTA_NEXT(rta,attrlen) \ -+((attrlen) -= RTA_ALIGN((rta)->rta_len), \ -+(struct rtattr *) (((char *)(rta)) + RTA_ALIGN((rta)->rta_len))) -+#define RTA_LENGTH(len) (RTA_ALIGN(sizeof(struct rtattr)) + (len)) -+#define RTA_DATA(rta) ((void *) (((char *) (rta)) + RTA_LENGTH(0))) -+ -+#define PF_NETLINK PF_ROUTE -+#define AF_NETLINK AF_ROUTE -+ -+typedef int32_t u32; -+typedef int16_t u16; -+ -+struct sockaddr_nl -+{ -+ sa_family_t nl_family; -+ unsigned short nl_pad; -+ u32 nl_pid; -+ u32 nl_groups; -+}; -+ -+struct nlmsghdr -+{ -+ u32 nlmsg_len; -+ u16 nlmsg_type; -+ u16 nlmsg_flags; -+ u32 nlmsg_seq; -+ u32 nlmsg_pid; -+}; -+ -+struct ifinfomsg -+{ -+ unsigned char ifi_family; -+ unsigned char __ifi_pad; -+ unsigned short ifi_type; -+ int ifi_index; -+ unsigned ifi_flags; -+ unsigned ifi_change; -+}; -+ -+struct rtattr -+{ -+ unsigned short rta_len; -+ unsigned short rta_type; -+}; -+ -+#endif /* PRIV_NETLINK_H */ -diff --git a/xbmc/peripherals/PeripheralTypes.h b/xbmc/peripherals/PeripheralTypes.h -index f93adc2..efcd352 100644 ---- a/xbmc/peripherals/PeripheralTypes.h -+++ b/xbmc/peripherals/PeripheralTypes.h -@@ -40,11 +40,13 @@ namespace PERIPHERALS - PERIPHERAL_BUS_USB, - PERIPHERAL_BUS_PCI, - PERIPHERAL_BUS_RPI, -+ PERIPHERAL_BUS_IMX, - PERIPHERAL_BUS_CEC, - PERIPHERAL_BUS_ADDON, - #ifdef TARGET_ANDROID - PERIPHERAL_BUS_ANDROID, - #endif -+ PERIPHERAL_BUS_PLATFORM, - }; - - enum PeripheralFeature -@@ -59,6 +61,7 @@ namespace PERIPHERALS - FEATURE_TUNER, - FEATURE_IMON, - FEATURE_JOYSTICK, -+ FEATURE_CABLESTATE, - }; - - enum PeripheralType -@@ -73,6 +76,7 @@ namespace PERIPHERALS - PERIPHERAL_TUNER, - PERIPHERAL_IMON, - PERIPHERAL_JOYSTICK, -+ PERIPHERAL_VIDEO, - }; - - class CPeripheralAddon; -@@ -126,6 +130,8 @@ namespace PERIPHERALS - return "imon"; - case PERIPHERAL_JOYSTICK: - return "joystick"; -+ case PERIPHERAL_VIDEO: -+ return "video"; - default: - return "unknown"; - } -@@ -154,6 +160,8 @@ namespace PERIPHERALS - return PERIPHERAL_IMON; - else if (strTypeLowerCase == "joystick") - return PERIPHERAL_JOYSTICK; -+ else if (strTypeLowerCase == "video") -+ return PERIPHERAL_VIDEO; - - return PERIPHERAL_UNKNOWN; - }; -@@ -168,6 +176,8 @@ namespace PERIPHERALS - return "pci"; - case PERIPHERAL_BUS_RPI: - return "rpi"; -+ case PERIPHERAL_BUS_IMX: -+ return "imx"; - case PERIPHERAL_BUS_CEC: - return "cec"; - case PERIPHERAL_BUS_ADDON: -@@ -176,6 +186,8 @@ namespace PERIPHERALS - case PERIPHERAL_BUS_ANDROID: - return "android"; - #endif -+ case PERIPHERAL_BUS_PLATFORM: -+ return "platform"; - default: - return "unknown"; - } -@@ -192,6 +204,8 @@ namespace PERIPHERALS - return PERIPHERAL_BUS_PCI; - else if (strTypeLowerCase == "rpi") - return PERIPHERAL_BUS_RPI; -+ else if (strTypeLowerCase == "imx") -+ return PERIPHERAL_BUS_IMX; - else if (strTypeLowerCase == "cec") - return PERIPHERAL_BUS_CEC; - else if (strTypeLowerCase == "addon") -@@ -200,6 +214,8 @@ namespace PERIPHERALS - else if (strTypeLowerCase == "android") - return PERIPHERAL_BUS_ANDROID; - #endif -+ else if (strTypeLowerCase == "platform") -+ return PERIPHERAL_BUS_PLATFORM; - - return PERIPHERAL_BUS_UNKNOWN; - }; -@@ -220,6 +236,14 @@ namespace PERIPHERALS - - strHexString = StringUtils::Format("%04X", iVal); - }; -+ -+ static void UeventToName(std::string &uevent, std::string &name) -+ { -+ std::vector data = StringUtils::Split(uevent, "\n"); -+ for (size_t i = 0; i < data.size(); i++) -+ if (StringUtils::StartsWith(data[i], "OF_NAME=")) -+ name = data[i].substr(8, data[i].length()); -+ }; - }; - - class PeripheralScanResult -diff --git a/xbmc/peripherals/Peripherals.cpp b/xbmc/peripherals/Peripherals.cpp -index 51cd664..20a4aae 100644 ---- a/xbmc/peripherals/Peripherals.cpp -+++ b/xbmc/peripherals/Peripherals.cpp -@@ -39,6 +39,7 @@ - #include "devices/PeripheralNIC.h" - #include "devices/PeripheralNyxboard.h" - #include "devices/PeripheralTuner.h" -+#include "devices/PeripheralVideo.h" - #include "dialogs/GUIDialogKaiToast.h" - #include "dialogs/GUIDialogOK.h" - #include "dialogs/GUIDialogPeripheralSettings.h" -@@ -325,6 +326,10 @@ CPeripheral *CPeripherals::CreatePeripheral(CPeripheralBus &bus, const Periphera - peripheral = new CPeripheralJoystick(mappedResult, &bus); - break; - -+ case PERIPHERAL_VIDEO: -+ peripheral = new CPeripheralVideo(mappedResult, &bus); -+ break; -+ - default: - break; - } -@@ -896,3 +901,10 @@ int CPeripherals::GetMessageMask() - { - return TMSG_MASK_PERIPHERALS; - } -+ -+void CPeripherals::CreatePeripheralBus(PeripheralBusPtr bus) -+{ -+ CSingleLock bussesLock(m_critSectionBusses); -+ m_busses.push_back(bus); -+ bus->Initialise(); -+} -diff --git a/xbmc/peripherals/Peripherals.h b/xbmc/peripherals/Peripherals.h -index 311af06..ea5201e 100644 ---- a/xbmc/peripherals/Peripherals.h -+++ b/xbmc/peripherals/Peripherals.h -@@ -214,6 +214,8 @@ namespace PERIPHERALS - */ - EventRateHandle SetEventScanRate(float rateHz) { return m_eventScanner.SetRate(rateHz); } - -+ virtual void CreatePeripheralBus(PeripheralBusPtr bus); -+ - bool SupportsCEC() const - { - #if defined(HAVE_LIBCEC) -diff --git a/xbmc/peripherals/bus/Makefile.in b/xbmc/peripherals/bus/Makefile.in -index df5250c..d7b0e93 100644 ---- a/xbmc/peripherals/bus/Makefile.in -+++ b/xbmc/peripherals/bus/Makefile.in -@@ -8,6 +8,7 @@ endif - - ifeq (@USE_LIBUDEV@,1) - SRCS += linux/PeripheralBusUSBLibUdev.cpp -+SRCS += linux/PeripheralBusPLATFORMLibUdev.cpp - endif - - ifeq (@USE_LIBUSB@,1) -diff --git a/xbmc/peripherals/bus/PeripheralBus.cpp b/xbmc/peripherals/bus/PeripheralBus.cpp -index b58696b..3cddd2e 100644 ---- a/xbmc/peripherals/bus/PeripheralBus.cpp -+++ b/xbmc/peripherals/bus/PeripheralBus.cpp -@@ -123,6 +123,15 @@ void CPeripheralBus::RegisterNewDevices(const PeripheralScanResults &results) - } - } - -+CPeripheral *CPeripheralBus::RegisterNewDevice(const PeripheralScanResult &result) -+{ -+ CSingleLock lock(m_critSection); -+ if (!HasPeripheral(result.m_strLocation)) -+ return g_peripherals.CreatePeripheral(*this, result); -+ else -+ return GetPeripheral(result.m_strLocation); -+} -+ - bool CPeripheralBus::ScanForDevices(void) - { - bool bReturn(false); -@@ -210,6 +219,13 @@ size_t CPeripheralBus::GetNumberOfPeripheralsWithId(const int iVendorId, const i - return iReturn; - } - -+size_t CPeripheralBus::GetNumberOfPeripheralsWithFeature(const PeripheralFeature feature) const -+{ -+ std::vector peripherals; -+ GetPeripheralsWithFeature(peripherals, feature); -+ return peripherals.size(); -+} -+ - void CPeripheralBus::Process(void) - { - while (!m_bStop) -diff --git a/xbmc/peripherals/bus/PeripheralBus.h b/xbmc/peripherals/bus/PeripheralBus.h -index 8093ca2..49f25bc 100644 ---- a/xbmc/peripherals/bus/PeripheralBus.h -+++ b/xbmc/peripherals/bus/PeripheralBus.h -@@ -80,6 +80,7 @@ namespace PERIPHERALS - - virtual size_t GetNumberOfPeripherals() const; - virtual size_t GetNumberOfPeripheralsWithId(const int iVendorId, const int iProductId) const; -+ virtual size_t GetNumberOfPeripheralsWithFeature(const PeripheralFeature feature) const; - - /*! - * @brief Get all features that are supported by devices on this bus. -@@ -156,6 +157,8 @@ namespace PERIPHERALS - */ - virtual void ProcessEvents(void) { } - -+ virtual CPeripheral *RegisterNewDevice(const PeripheralScanResult &result); -+ - protected: - virtual void Process(void); - virtual bool ScanForDevices(void); -diff --git a/xbmc/peripherals/bus/linux/PeripheralBusPLATFORMLibUdev.cpp b/xbmc/peripherals/bus/linux/PeripheralBusPLATFORMLibUdev.cpp -new file mode 100644 -index 0000000..44762c7 ---- /dev/null -+++ b/xbmc/peripherals/bus/linux/PeripheralBusPLATFORMLibUdev.cpp -@@ -0,0 +1,142 @@ -+/* -+ -+ * 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 "PeripheralBusPLATFORMLibUdev.h" -+#include "peripherals/Peripherals.h" -+extern "C" { -+#include -+} -+#include -+#include "utils/log.h" -+ -+using namespace PERIPHERALS; -+ -+CPeripheralBusPLATFORM::CPeripheralBusPLATFORM(CPeripherals *manager, const std::string &threadname, PeripheralBusType type) : -+ CPeripheralBusUSB(manager, threadname, type) -+{ -+ m_bNeedsPolling = false; -+ udev_monitor_filter_add_match_subsystem_devtype(m_udevMon, "platform", NULL); -+ udev_monitor_filter_update(m_udevMon); -+ Create(); -+} -+ -+void CPeripheralBusPLATFORM::Clear(void) -+{ -+ StopThread(false); -+} -+ -+bool CPeripheralBusPLATFORM::PerformDeviceScan(PeripheralScanResults &results) -+{ -+ struct udev_enumerate *enumerate; -+ struct udev_list_entry *devices, *dev_list_entry; -+ struct udev_device *dev(NULL); -+ enumerate = udev_enumerate_new(m_udev); -+ udev_enumerate_scan_devices(enumerate); -+ devices = udev_enumerate_get_list_entry(enumerate); -+ -+ bool bContinue(true); -+ std::string strPath, t; -+ udev_list_entry_foreach(dev_list_entry, devices) -+ { -+ strPath = udev_list_entry_get_name(dev_list_entry); -+ dev = udev_device_new_from_syspath(m_udev, strPath.c_str()); -+ if (strPath.empty() || !dev) -+ bContinue = false; -+ -+ if (bContinue) -+ { -+ bContinue = false; -+ if (GetCableState(udev_device_get_syspath(dev))) -+ bContinue = true; -+ } -+ -+ if (bContinue) -+ { -+ PeripheralScanResult result(m_type); -+ result.m_strLocation = udev_device_get_syspath(dev); -+ result.m_iSequence = GetNumberOfPeripheralsWithFeature(FEATURE_CABLESTATE); -+ result.m_type = PERIPHERAL_VIDEO; -+ -+ t = udev_device_get_sysattr_value(dev, "uevent"); -+ PeripheralTypeTranslator::UeventToName(t, result.m_strDeviceName); -+ if (result.m_strDeviceName.empty()) -+ result.m_strDeviceName += "generic_video"; -+ -+ result.m_iVendorId = 0; -+ result.m_iProductId = 0; -+ -+ if (!results.ContainsResult(result)) -+ results.m_results.push_back(result); -+ } -+ -+ bContinue = true; -+ } -+ /* Free the enumerator object */ -+ udev_enumerate_unref(enumerate); -+ -+ return true; -+} -+ -+int CPeripheralBusPLATFORM::GetCableState(const std::string &strLocation) -+{ -+ struct udev_device *dev = udev_device_new_from_syspath(m_udev, strLocation.c_str()); -+ std::string files[] = { "cable_state", "status", "state" }; -+ std::vector cableState(files, files + 3); -+ -+ std::string t; -+ int state = CABLE_UNKNOWN; -+ -+ if (!dev) -+ return state; -+ -+ for (std::vector::iterator f = cableState.begin() ; f != cableState.end(); ++f) -+ { -+ if (udev_device_get_sysattr_value(dev, f->c_str())) -+ t = udev_device_get_sysattr_value(dev, f->c_str()); -+ -+ if (!t.empty() && (t.find("disconnected") != std::string::npos || t.find("plugout") != std::string::npos)) -+ state = CABLE_DISCONNECTED; -+ if (!t.empty() && (t.find("connected") != std::string::npos || t.find("plugin") != std::string::npos)) -+ state = CABLE_CONNECTED; -+ -+ if (state) -+ break; -+ } -+ -+ return state; -+} -+ -+void CPeripheralBusPLATFORM::Process(void) -+{ -+ ScanForDevices(); -+ while (!m_bStop) -+ WaitForUpdate(); -+ -+ m_bIsStarted = false; -+} -+ -+void CPeripheralBusPLATFORM::OnDeviceChanged(const std::string &strLocation) -+{ -+ CSingleLock lock(m_critSection); -+ CPeripheral *peripheral = GetPeripheral(strLocation); -+ if (peripheral) -+ peripheral->OnDeviceChanged(GetCableState(strLocation)); -+} -diff --git a/xbmc/peripherals/bus/linux/PeripheralBusPLATFORMLibUdev.h b/xbmc/peripherals/bus/linux/PeripheralBusPLATFORMLibUdev.h -new file mode 100644 -index 0000000..32a181a ---- /dev/null -+++ b/xbmc/peripherals/bus/linux/PeripheralBusPLATFORMLibUdev.h -@@ -0,0 +1,47 @@ -+#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 "peripherals/bus/linux/PeripheralBusUSBLibUdev.h" -+ -+struct udev_device; -+ -+namespace PERIPHERALS -+{ -+ class CPeripherals; -+ -+ class CPeripheralBusPLATFORM : public CPeripheralBusUSB -+ { -+ public: -+ CPeripheralBusPLATFORM(CPeripherals *manager, const std::string &threadname = "PeripBusPLATFORMUdev", PeripheralBusType type = PERIPHERAL_BUS_PLATFORM); -+ virtual ~CPeripheralBusPLATFORM(void) {}; -+ -+ virtual void Clear(void) override; -+ -+ bool PerformDeviceScan(PeripheralScanResults &results); -+ -+ virtual void OnDeviceChanged(const std::string &strLocation) override; -+ void OnDeviceAdded(const std::string &strLocation) {}; -+ int GetCableState(const std::string &strLocation); -+ -+ protected: -+ virtual void Process(void) override; -+ }; -+} -diff --git a/xbmc/peripherals/bus/linux/PeripheralBusUSBLibUdev.cpp b/xbmc/peripherals/bus/linux/PeripheralBusUSBLibUdev.cpp -index 15709c6..636f579 100644 ---- a/xbmc/peripherals/bus/linux/PeripheralBusUSBLibUdev.cpp -+++ b/xbmc/peripherals/bus/linux/PeripheralBusUSBLibUdev.cpp -@@ -76,8 +76,8 @@ extern "C" { - - using namespace PERIPHERALS; - --CPeripheralBusUSB::CPeripheralBusUSB(CPeripherals *manager) : -- CPeripheralBus("PeripBusUSBUdev", manager, PERIPHERAL_BUS_USB) -+CPeripheralBusUSB::CPeripheralBusUSB(CPeripherals *manager, const std::string &threadname, PeripheralBusType type) : -+ CPeripheralBus(threadname, manager, type) - { - /* the Process() method in this class overrides the one in CPeripheralBus, so leave this set to true */ - m_bNeedsPolling = true; -@@ -95,12 +95,13 @@ CPeripheralBusUSB::CPeripheralBusUSB(CPeripherals *manager) : - m_udevMon = udev_monitor_new_from_netlink(m_udev, "udev"); - udev_monitor_enable_receiving(m_udevMon); - -- CLog::Log(LOGDEBUG, "%s - initialised udev monitor", __FUNCTION__); -+ CLog::Log(LOGDEBUG, "%s - initialised %s monitor", __FUNCTION__, threadname.c_str()); - } - - CPeripheralBusUSB::~CPeripheralBusUSB(void) - { -- StopThread(true); -+ if(IsRunning()) -+ StopThread(true); - udev_monitor_unref(m_udevMon); - udev_unref(m_udev); - } -@@ -246,7 +247,10 @@ bool CPeripheralBusUSB::WaitForUpdate() - /* we have to read the message from the queue, even though we're not actually using it */ - struct udev_device *dev = udev_monitor_receive_device(m_udevMon); - if (dev) -+ { -+ OnDeviceChanged(udev_device_get_syspath(dev)); - udev_device_unref(dev); -+ } - else - { - CLog::Log(LOGERROR, "%s - failed to get device from udev_monitor_receive_device()", __FUNCTION__); -diff --git a/xbmc/peripherals/bus/linux/PeripheralBusUSBLibUdev.h b/xbmc/peripherals/bus/linux/PeripheralBusUSBLibUdev.h -index b7715ce..eed2134 100644 ---- a/xbmc/peripherals/bus/linux/PeripheralBusUSBLibUdev.h -+++ b/xbmc/peripherals/bus/linux/PeripheralBusUSBLibUdev.h -@@ -32,7 +32,7 @@ namespace PERIPHERALS - class CPeripheralBusUSB : public CPeripheralBus - { - public: -- CPeripheralBusUSB(CPeripherals *manager); -+ CPeripheralBusUSB(CPeripherals *manager, const std::string &threadname = "PeripBusUSBUdev", PeripheralBusType type = PERIPHERAL_BUS_USB); - virtual ~CPeripheralBusUSB(void); - - virtual void Clear(void); -diff --git a/xbmc/peripherals/bus/virtual/PeripheralBusCEC.cpp b/xbmc/peripherals/bus/virtual/PeripheralBusCEC.cpp -index b04fe00..3dc3d0e 100644 ---- a/xbmc/peripherals/bus/virtual/PeripheralBusCEC.cpp -+++ b/xbmc/peripherals/bus/virtual/PeripheralBusCEC.cpp -@@ -102,6 +102,10 @@ bool CPeripheralBusCEC::PerformDeviceScan(PeripheralScanResults &results) - /** the Pi's adapter cannot be removed, no need to rescan */ - m_bNeedsPolling = false; - break; -+ case ADAPTERTYPE_IMX: -+ result.m_mappedBusType = PERIPHERAL_BUS_IMX; -+ m_bNeedsPolling = false; -+ break; - default: - break; - } -diff --git a/xbmc/peripherals/devices/Makefile.in b/xbmc/peripherals/devices/Makefile.in -index b79d94a..0743986 100644 ---- a/xbmc/peripherals/devices/Makefile.in -+++ b/xbmc/peripherals/devices/Makefile.in -@@ -7,6 +7,7 @@ SRCS += PeripheralJoystick.cpp - SRCS += PeripheralNIC.cpp - SRCS += PeripheralNyxboard.cpp - SRCS += PeripheralTuner.cpp -+SRCS += PeripheralVideo.cpp - - ifeq (@USE_LIBCEC@,1) - SRCS += PeripheralCecAdapter.cpp -diff --git a/xbmc/peripherals/devices/Peripheral.h b/xbmc/peripherals/devices/Peripheral.h -index 1b9da9b..e79306d 100644 ---- a/xbmc/peripherals/devices/Peripheral.h -+++ b/xbmc/peripherals/devices/Peripheral.h -@@ -46,6 +46,13 @@ namespace PERIPHERALS - STATE_STANDBY - } CecStateChange; - -+ typedef enum -+ { -+ CABLE_UNKNOWN = 0, -+ CABLE_DISCONNECTED, -+ CABLE_CONNECTED -+ } ScreenCableState; -+ - class CPeripheral - { - friend class CGUIDialogPeripheralSettings; -@@ -105,6 +112,11 @@ namespace PERIPHERALS - virtual void OnSettingChanged(const std::string &strChangedSetting) {}; - - /*! -+ * @brief Called when this device is changed. -+ */ -+ virtual void OnDeviceChanged(int state) {}; -+ -+ /*! - * @brief Called when this device is removed, before calling the destructor. - */ - virtual void OnDeviceRemoved(void) {} -diff --git a/xbmc/peripherals/devices/PeripheralCecAdapter.cpp b/xbmc/peripherals/devices/PeripheralCecAdapter.cpp -index af84e7a..a54a794 100644 ---- a/xbmc/peripherals/devices/PeripheralCecAdapter.cpp -+++ b/xbmc/peripherals/devices/PeripheralCecAdapter.cpp -@@ -35,6 +35,7 @@ - #include "utils/JobManager.h" - #include "utils/log.h" - #include "utils/Variant.h" -+#include "utils/Screen.h" - - #include - -@@ -170,6 +171,9 @@ void CPeripheralCecAdapter::Announce(AnnouncementFlag flag, const char *sender, - m_configuration.bActivateSource == 1) - { - ActivateSource(); -+ if (!m_configuration.wakeDevices.IsEmpty() && m_configuration.wakeDevices.primary == CECDEVICE_AUDIOSYSTEM && -+ GetAudioSystemConnected()) -+ m_cecAdapter->PowerOnDevices(CECDEVICE_AUDIOSYSTEM); - } - } - else if (flag == GUI && !strcmp(sender, "xbmc") && !strcmp(message, "OnScreensaverActivated") && m_bIsReady) -@@ -180,6 +184,8 @@ void CPeripheralCecAdapter::Announce(AnnouncementFlag flag, const char *sender, - // only power off when we're the active source - if (m_cecAdapter->IsLibCECActiveSource()) - StandbyDevices(); -+ if (!(CEC_POWER_STATUS_ON == m_cecAdapter->GetDevicePowerStatus(CECDEVICE_TV) && m_cecAdapter->IsLibCECActiveSource())) -+ g_screen.SetOff(); - } - } - else if (flag == System && !strcmp(sender, "xbmc") && !strcmp(message, "OnSleep")) -@@ -334,8 +340,6 @@ bool CPeripheralCecAdapter::OpenConnection(void) - if (!bConnectionFailedDisplayed) - CGUIDialogKaiToast::QueueNotification(CGUIDialogKaiToast::Error, g_localizeStrings.Get(36000), g_localizeStrings.Get(36012)); - bConnectionFailedDisplayed = true; -- -- Sleep(10000); - } - } - -@@ -386,7 +390,7 @@ void CPeripheralCecAdapter::Process(void) - ProcessStandbyDevices(); - - if (!m_bStop) -- Sleep(5); -+ Sleep(20); - } - - m_queryThread->StopThread(true); -@@ -449,6 +453,12 @@ void CPeripheralCecAdapter::SetAudioSystemConnected(bool bSetTo) - m_bHasConnectedAudioSystem = bSetTo; - } - -+bool CPeripheralCecAdapter::GetAudioSystemConnected() -+{ -+ CSingleLock lock(m_critSection); -+ return m_bHasConnectedAudioSystem; -+} -+ - void CPeripheralCecAdapter::ProcessVolumeChange(void) - { - bool bSendRelease(false); -@@ -634,6 +644,12 @@ int CPeripheralCecAdapter::CecCommand(void *cbParam, const cec_command command) - else if (adapter->m_configuration.bShutdownOnStandby == 1) - g_application.ExecuteXBMCAction("Shutdown"); - } -+ if (command.initiator == CECDEVICE_TV) -+ { -+ if (adapter->GetSettingInt("standby_pc_on_tv_standby") == 13007) -+ CecEventPostAction(cbParam, 0, true); -+ g_screen.SetOff(); -+ } - break; - case CEC_OPCODE_SET_MENU_LANGUAGE: - if (adapter->m_configuration.bUseTVMenuLanguage == 1 && command.initiator == CECDEVICE_TV && command.parameters.size == 3) -@@ -1150,16 +1166,13 @@ void CPeripheralCecAdapter::OnSettingChanged(const std::string &strChangedSettin - } - } - --void CPeripheralCecAdapter::CecSourceActivated(void *cbParam, const CEC::cec_logical_address address, const uint8_t activated) -+ -+void CPeripheralCecAdapter::CecEventPostAction(void *cbParam, const uint8_t activated, bool wait) - { - CPeripheralCecAdapter *adapter = (CPeripheralCecAdapter *)cbParam; - if (!adapter) - return; - -- // wake up the screensaver, so the user doesn't switch to a black screen -- if (activated == 1) -- g_application.WakeUpScreenSaverAndDPMS(); -- - if (adapter->GetSettingInt("pause_or_stop_playback_on_deactivate") != LOCALISED_ID_NONE) - { - bool bShowingSlideshow = (g_windowManager.GetActiveWindow() == WINDOW_SLIDESHOW); -@@ -1183,7 +1183,7 @@ void CPeripheralCecAdapter::CecSourceAct - pSlideShow->OnAction(CAction(ACTION_PAUSE)); - else - // pause/resume player -- CApplicationMessenger::GetInstance().SendMsg(TMSG_MEDIA_PAUSE); -+ CApplicationMessenger::GetInstance().SendMsg(TMSG_MEDIA_PAUSE, wait); - } - else if (bPlayingAndDeactivated - && adapter->GetSettingInt("pause_or_stop_playback_on_deactivate") == LOCALISED_ID_STOP) -@@ -1191,11 +1191,27 @@ void CPeripheralCecAdapter::CecSourceAct - if (pSlideShow) - pSlideShow->OnAction(CAction(ACTION_STOP)); - else -- CApplicationMessenger::GetInstance().SendMsg(TMSG_MEDIA_STOP); -+ CApplicationMessenger::GetInstance().SendMsg(TMSG_MEDIA_STOP, wait); - } - } - } - -+void CPeripheralCecAdapter::CecSourceActivated(void *cbParam, const CEC::cec_logical_address address, const uint8_t activated) -+{ -+ CPeripheralCecAdapter *adapter = (CPeripheralCecAdapter *)cbParam; -+ if (!adapter) -+ return; -+ -+ // wake up the screensaver, so the user doesn't switch to a black screen -+ if (activated == 1) -+ g_application.WakeUpScreenSaverAndDPMS(); -+ -+ CecEventPostAction(cbParam, activated, true); -+ -+ if (activated != 1) -+ g_screen.SetOff(); -+} -+ - int CPeripheralCecAdapter::CecLogMessage(void *cbParam, const cec_log_message message) - { - CPeripheralCecAdapter *adapter = (CPeripheralCecAdapter *)cbParam; - -@@ -1219,8 +1249,7 @@ int CPeripheralCecAdapter::CecLogMessage(void *cbParam, const cec_log_message me - break; - } - -- if (iLevel >= CEC_LOG_NOTICE || (iLevel >= 0 && CLog::IsLogLevelLogged(LOGDEBUG) && g_advancedSettings.CanLogComponent(LOGCEC))) -- CLog::Log(iLevel, "%s - %s", __FUNCTION__, message.message); -+ CLog::Log(iLevel | LOGCEC, "%s - %s", __FUNCTION__, message.message); - - return 1; - } -@@ -1294,7 +1323,7 @@ void CPeripheralCecAdapter::SetConfigurationFromLibCEC(const CEC::libcec_configu - - bChanged |= SetSetting("standby_pc_on_tv_standby", - m_configuration.bPowerOffOnStandby == 1 ? 13011 : -- m_configuration.bShutdownOnStandby == 1 ? 13005 : 36028); -+ m_configuration.bShutdownOnStandby == 1 ? 13005 : GetSettingInt("standby_pc_on_tv_standby")); - - if (bChanged) - CLog::Log(LOGDEBUG, "SetConfigurationFromLibCEC - settings updated by libCEC"); -@@ -1317,6 +1346,11 @@ void CPeripheralCecAdapter::SetConfigurationFromSettings(void) - iDeviceType = (int)CEC_DEVICE_TYPE_RECORDING_DEVICE; - m_configuration.deviceTypes.Add((cec_device_type)iDeviceType); - -+ // add all other remaining device types - in case we have already 3 recorders -+ // XBMC would fail obtaining LA -+ m_configuration.deviceTypes.Add((cec_device_type)CEC_DEVICE_TYPE_PLAYBACK_DEVICE); -+ m_configuration.deviceTypes.Add((cec_device_type)CEC_DEVICE_TYPE_TUNER); -+ - // always try to autodetect the address. - // when the firmware supports this, it will override the physical address, connected device and hdmi port settings - m_configuration.bAutodetectAddress = CEC_DEFAULT_SETTING_AUTODETECT_ADDRESS; -@@ -1383,7 +1417,7 @@ void CPeripheralCecAdapter::SetConfigurationFromSettings(void) - - #if defined(CEC_DOUBLE_TAP_TIMEOUT_MS_OLD) - // double tap prevention timeout in ms. libCEC uses 50ms units for this in 2.2.0, so divide by 50 -- m_configuration.iDoubleTapTimeout50Ms = GetSettingInt("double_tap_timeout_ms") / 50; -+ m_configuration.iDoubleTapTimeout50Ms = (GetSettingInt("double_tap_timeout_ms") / 50 > 10) ? 4 : GetSettingInt("double_tap_timeout_ms") / 50; - #else - // backwards compatibility. will be removed once the next major release of libCEC is out - m_configuration.iDoubleTapTimeoutMs = GetSettingInt("double_tap_timeout_ms"); -@@ -1423,8 +1457,8 @@ void CPeripheralCecAdapter::ReadLogicalAddresses(int iLocalisedId, cec_logical_a - addresses.Set(CECDEVICE_AUDIOSYSTEM); - break; - case LOCALISED_ID_TV_AVR: -- addresses.Set(CECDEVICE_TV); - addresses.Set(CECDEVICE_AUDIOSYSTEM); -+ addresses.Set(CECDEVICE_TV); - break; - case LOCALISED_ID_NONE: - default: -@@ -1505,9 +1539,12 @@ bool CPeripheralCecAdapterUpdateThread::WaitReady(void) - if (m_configuration.wakeDevices.IsEmpty() && m_configuration.bActivateSource == 0) - return true; - -+ CTimer m_timer(this); -+ m_timer.Start(30000); -+ - // wait for the TV if we're configured to become the active source. - // wait for the first device in the wake list otherwise. -- cec_logical_address waitFor = (m_configuration.bActivateSource == 1) ? -+ cec_logical_address waitFor = (m_configuration.bActivateSource == 1 && m_adapter->m_bActiveSourcePending) ? - CECDEVICE_TV : - m_configuration.wakeDevices.primary; - -@@ -1571,38 +1608,48 @@ std::string CPeripheralCecAdapterUpdateThread::UpdateAudioSystemStatus(void) - - bool CPeripheralCecAdapterUpdateThread::SetInitialConfiguration(void) - { -- // the option to make XBMC the active source is set -- if (m_configuration.bActivateSource == 1) -- m_adapter->m_cecAdapter->SetActiveSource(); -+ std::string strNotification; -+ std::string strAmpName = UpdateAudioSystemStatus(); -+ if (!strAmpName.empty()) -+ strNotification += StringUtils::Format("- %s", strAmpName.c_str()); - - // devices to wake are set -- cec_logical_addresses tvOnly; -- tvOnly.Clear(); tvOnly.Set(CECDEVICE_TV); -- if (!m_configuration.wakeDevices.IsEmpty() && (m_configuration.wakeDevices != tvOnly || m_configuration.bActivateSource == 0)) -- m_adapter->m_cecAdapter->PowerOnDevices(CECDEVICE_BROADCAST); -+ if (!m_configuration.wakeDevices.IsEmpty() && (m_configuration.wakeDevices.primary != CECDEVICE_TV || m_configuration.bActivateSource == 0)) -+ { -+ m_adapter->m_cecAdapter->PowerOnDevices(m_configuration.wakeDevices.primary); -+ if (m_configuration.wakeDevices.primary == CECDEVICE_AUDIOSYSTEM && m_adapter->GetAudioSystemConnected()) -+ WaitReady(); -+ } -+ -+ // the option to make XBMC the active source is set -+ if (m_configuration.bActivateSource == 1) -+ m_adapter->ActivateSource(); - -- // wait until devices are powered up -+ // wait until power up - if (!WaitReady()) - return false; - - UpdateMenuLanguage(); -+ CTimer m_timer(this); -+ m_timer.Start(10000); -+ // wait until we get active source -+ bool bContinue(true); -+ while (!m_adapter->m_cecAdapter->IsLibCECActiveSource() && -+ bContinue) -+ bContinue = !m_event.WaitMSec(1000); -+ -+ { -+ CSingleLock lock(m_critSection); -+ m_adapter->m_bIsReady = true; -+ m_bIsUpdating = false; -+ } - - // request the OSD name of the TV -- std::string strNotification; - cec_osd_name tvName = m_adapter->m_cecAdapter->GetDeviceOSDName(CECDEVICE_TV); -- strNotification = StringUtils::Format("%s: %s", g_localizeStrings.Get(36016).c_str(), tvName.name); -- -- std::string strAmpName = UpdateAudioSystemStatus(); -- if (!strAmpName.empty()) -- strNotification += StringUtils::Format("- %s", strAmpName.c_str()); -- -- m_adapter->m_bIsReady = true; -+ strNotification = StringUtils::Format("%s: %s", /*g_localizeStrings.Get(36016).c_str()*/"Connected", tvName.name); - - // and let the gui know that we're done -- CGUIDialogKaiToast::QueueNotification(CGUIDialogKaiToast::Info, g_localizeStrings.Get(36000), strNotification); -- -- CSingleLock lock(m_critSection); -- m_bIsUpdating = false; -+ CGUIDialogKaiToast::QueueNotification(CGUIDialogKaiToast::Info, /*g_localizeStrings.Get(36000)*/"Pulse-Eight CEC adapter", strNotification); - return true; - } - -diff --git a/xbmc/peripherals/devices/PeripheralCecAdapter.h b/xbmc/peripherals/devices/PeripheralCecAdapter.h -index 2f1aa12..af84e42 100644 ---- a/xbmc/peripherals/devices/PeripheralCecAdapter.h -+++ b/xbmc/peripherals/devices/PeripheralCecAdapter.h -@@ -48,6 +48,7 @@ namespace PERIPHERALS - #include "PeripheralHID.h" - #include "interfaces/AnnouncementManager.h" - #include "threads/Thread.h" -+#include "threads/Timer.h" - #include "threads/CriticalSection.h" - #include - -@@ -142,8 +143,11 @@ namespace PERIPHERALS - void GetNextKey(void); - - void SetAudioSystemConnected(bool bSetTo); -+ bool GetAudioSystemConnected(); - void SetMenuLanguage(const char *strLanguage); - -+ static void CecEventPostAction(void *cbParam, const uint8_t activated, bool wait); -+ - // callbacks from libCEC - static int CecLogMessage(void *cbParam, const CEC::cec_log_message message); - static int CecCommand(void *cbParam, const CEC::cec_command command); -@@ -183,7 +187,7 @@ namespace PERIPHERALS - std::string m_strComPort; - }; - -- class CPeripheralCecAdapterUpdateThread : public CThread -+ class CPeripheralCecAdapterUpdateThread : public CThread, ITimerCallback - { - public: - CPeripheralCecAdapterUpdateThread(CPeripheralCecAdapter *adapter, CEC::libcec_configuration *configuration); -@@ -198,6 +202,7 @@ namespace PERIPHERALS - bool WaitReady(void); - bool SetInitialConfiguration(void); - void Process(void); -+ void OnTimeout() { m_event.Set(); }; - - CPeripheralCecAdapter * m_adapter; - CEvent m_event; -diff --git a/xbmc/peripherals/devices/PeripheralVideo.cpp b/xbmc/peripherals/devices/PeripheralVideo.cpp -new file mode 100644 -index 0000000..b2a433b ---- /dev/null -+++ b/xbmc/peripherals/devices/PeripheralVideo.cpp -@@ -0,0 +1,121 @@ -+/* -+ * 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 "PeripheralVideo.h" -+#include "utils/log.h" -+#include "utils/Screen.h" -+#include "guilib/GraphicContext.h" -+#include "dialogs/GUIDialogKaiToast.h" -+#include "guilib/LocalizeStrings.h" -+#include "settings/Settings.h" -+#include "xbmc/utils/SysfsUtils.h" -+#include "messaging/ApplicationMessenger.h" -+#include "Application.h" -+#include -+ -+using namespace PERIPHERALS; -+using namespace KODI::MESSAGING; -+ -+int CPeripheralVideo::m_cableState = 0; -+ -+CPeripheralVideo::CPeripheralVideo(const PeripheralScanResult& scanResult, CPeripheralBus* bus) -+ : CPeripheral(scanResult, bus) -+ , m_timer(this) -+{ -+ m_features.push_back(FEATURE_CABLESTATE); -+} -+ -+CPeripheralVideo::~CPeripheralVideo() -+{ -+} -+ -+void CPeripheralVideo::OnDeviceChanged(int state) -+{ -+ if (g_application.m_bStop) -+ return; -+ -+ if (!GetSettingBool("pass_events")) -+ return; -+ -+ CLog::Log(LOGDEBUG, "%s - state %s over %s, timer %s", __FUNCTION__, stateToStr(state), stateToStr(m_cableState), !m_timer.IsRunning() ? "will be started" : "is already running"); -+ -+ m_cableState = state; -+ -+ if (m_timer.IsRunning()) -+ m_timer.Restart(); -+ else -+ m_timer.Start(3000); -+} -+ -+bool CPeripheralVideo::IsQuantRangeLimited() -+{ -+#ifdef HAS_IMXVPU -+ std::string value; -+ std::string from = "/sys/devices/soc0/soc/20e0000.hdmi_video/rgb_quant_range"; -+ -+ std::ifstream file(from); -+ if (!file.is_open()) -+ { -+ from = "/sys/devices/soc0/soc.1/20e0000.hdmi_video/rgb_quant_range"; -+ } -+ file.close(); -+ -+ SysfsUtils::GetString(from, value); -+ if (value.find("limited") != std::string::npos) -+ return true; -+#endif -+ return false; -+} -+ -+void CPeripheralVideo::OnSettingChanged(const std::string &strChangedSetting) -+{ -+ bool configSet = false; -+ -+ CGUIDialogKaiToast::QueueNotification(CGUIDialogKaiToast::Info, "VIDEO", g_localizeStrings.Get(configSet ? 36023 : 36024)); -+} -+ -+bool CPeripheralVideo::InitialiseFeature(const PeripheralFeature feature) -+{ -+ return CPeripheral::InitialiseFeature(feature); -+} -+ -+void CPeripheralVideo::OnTimeout() -+{ -+ switch (m_cableState) -+ { -+ case CABLE_CONNECTED: -+ CSettings::GetInstance().SetBool("videoscreen.limitedrange", IsQuantRangeLimited()); -+ -+ if (CSettings::GetInstance().GetBool("videoscreen.updateresolutions")) -+ { -+ CApplicationMessenger::GetInstance().PostMsg(TMSG_DISPLAY_RECONFIGURE); -+ CGUIDialogKaiToast::QueueNotification(CGUIDialogKaiToast::Info, "VIDEO", g_localizeStrings.Get(13288)); -+ } -+ -+ g_screen.SetOn(); -+ -+ break; -+ case CABLE_DISCONNECTED: -+ g_screen.SetOff(); -+ -+ default: -+ ; -+ } -+} -diff --git a/xbmc/peripherals/devices/PeripheralVideo.h b/xbmc/peripherals/devices/PeripheralVideo.h -new file mode 100644 -index 0000000..bbbfcfd ---- /dev/null -+++ b/xbmc/peripherals/devices/PeripheralVideo.h -@@ -0,0 +1,62 @@ -+#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 "Peripheral.h" -+#include "peripherals/Peripherals.h" -+#include "threads/Timer.h" -+ -+namespace PERIPHERALS -+{ -+ class CPeripheralVideo : public CPeripheral, protected ITimerCallback -+ { -+ public: -+ CPeripheralVideo(const PeripheralScanResult& scanResult, CPeripheralBus* bus); -+ virtual ~CPeripheralVideo(void); -+ -+ virtual void OnDeviceChanged(int state); -+ virtual void OnTimeout(); -+ -+ void OnSettingChanged(const std::string &strChangedSetting); -+ bool InitialiseFeature(const PeripheralFeature feature); -+ -+ static bool IsQuantRangeLimited(); -+ -+ static const char *stateToStr(const int state) -+ { -+ switch (state) -+ { -+ case CABLE_CONNECTED: -+ return "connected"; -+ case CABLE_DISCONNECTED: -+ return "disconnected"; -+ default: -+ return "unknown"; -+ } -+ } -+ -+ public: -+ static int m_cableState; -+ protected: -+ CTimer m_timer; -+ -+ }; -+} -+ -diff --git a/xbmc/platform/xbmc.cpp b/xbmc/platform/xbmc.cpp -index 0c7a4d1..19de6b8 100644 ---- a/xbmc/platform/xbmc.cpp -+++ b/xbmc/platform/xbmc.cpp -@@ -20,6 +20,9 @@ - - #include "Application.h" - #include "settings/AdvancedSettings.h" -+#include "stdlib.h" -+#include -+#include "utils/log.h" - - #ifdef TARGET_RASPBERRY_PI - #include "linux/RBP.h" -@@ -41,6 +44,14 @@ - extern "C" int XBMC_Run(bool renderGUI) - { - int status = -1; -+ bool showXBMCSplash = true; -+ std::string filename = "/usr/bin/splash"; -+ struct stat buf; -+ if (stat(filename.c_str(), &buf) != -1) -+ { -+ system("/usr/bin/splash --force -i -m 'starting kodi...'"); -+ showXBMCSplash = false; -+ } - - if (!g_advancedSettings.Initialized()) - { -@@ -78,7 +89,7 @@ extern "C" int XBMC_Run(bool renderGUI) - g_RBP.LogFirmwareVerison(); - #endif - -- if (renderGUI && !g_application.CreateGUI()) -+ if (renderGUI && !g_application.CreateGUI(showXBMCSplash)) - { - CMessagePrinter::DisplayError("ERROR: Unable to create GUI. Exiting"); - return status; -@@ -101,6 +112,9 @@ extern "C" int XBMC_Run(bool renderGUI) - } - #endif - -+ CLog::Log(LOGNOTICE, "XBian: notifying Upstart that i'm well"); -+ system("sudo /sbin/start -n -q xbmc-loaded"); -+ - try - { - status = g_application.Run(); -diff --git a/xbmc/powermanagement/linux/LogindUPowerSyscall.cpp b/xbmc/powermanagement/linux/LogindUPowerSyscall.cpp -index 4e5bcc6..0212306 100644 ---- a/xbmc/powermanagement/linux/LogindUPowerSyscall.cpp -+++ b/xbmc/powermanagement/linux/LogindUPowerSyscall.cpp -@@ -50,11 +50,15 @@ CLogindUPowerSyscall::CLogindUPowerSyscall() - if (!m_hasUPower) - CLog::Log(LOGINFO, "LogindUPowerSyscall - UPower not found, battery information will not be available"); - -- m_canPowerdown = LogindCheckCapability("CanPowerOff"); -- m_canReboot = LogindCheckCapability("CanReboot"); -+ m_canPowerdown = true; -+ m_canReboot = true; -+#if defined(HAS_IMXVPU) || defined(TARGET_RASPBERRY_PI) -+ m_canHibernate = false; -+ m_canSuspend = false; -+#else - m_canHibernate = LogindCheckCapability("CanHibernate"); - m_canSuspend = LogindCheckCapability("CanSuspend"); -- -+#endif - InhibitDelayLock(); - - m_batteryLevel = 0; -diff --git a/xbmc/powermanagement/linux/UPowerSyscall.cpp b/xbmc/powermanagement/linux/UPowerSyscall.cpp -index 28ce475..20175e7 100644 ---- a/xbmc/powermanagement/linux/UPowerSyscall.cpp -+++ b/xbmc/powermanagement/linux/UPowerSyscall.cpp -@@ -62,6 +62,9 @@ CUPowerSyscall::CUPowerSyscall() - - m_lowBattery = false; - -+ m_CanPowerdown = true; -+ m_CanReboot = true; -+ - dbus_error_init (&m_error); - // TODO: do not use dbus_connection_pop_message() that requires the use of a - // private connection -@@ -83,9 +86,6 @@ CUPowerSyscall::CUPowerSyscall() - m_connection = NULL; - } - -- m_CanPowerdown = false; -- m_CanReboot = false; -- - UpdateCapabilities(); - - EnumeratePowerSources(); -@@ -262,8 +262,13 @@ bool CUPowerSyscall::PumpPowerEvents(IPowerEventsCallback *callback) - - void CUPowerSyscall::UpdateCapabilities() - { -+#if defined(HAS_IMXVPU) || defined(TARGET_RASPBERRY_PI) -+ m_CanSuspend = false; -+ m_CanHibernate = false; -+#else - m_CanSuspend = CDBusUtil::GetVariant("org.freedesktop.UPower", "/org/freedesktop/UPower", "org.freedesktop.UPower", "CanSuspend").asBoolean(false); - m_CanHibernate = CDBusUtil::GetVariant("org.freedesktop.UPower", "/org/freedesktop/UPower", "org.freedesktop.UPower", "CanHibernate").asBoolean(false); -+#endif - } - - #endif -diff --git a/xbmc/settings/DisplaySettings.cpp b/xbmc/settings/DisplaySettings.cpp -index c5ba807..6ce42fa 100644 ---- a/xbmc/settings/DisplaySettings.cpp -+++ b/xbmc/settings/DisplaySettings.cpp -@@ -591,16 +591,10 @@ std::string CDisplaySettings::GetStringFromResolution(RESOLUTION resolution, flo - if (resolution >= RES_DESKTOP && resolution < (RESOLUTION)CDisplaySettings::GetInstance().ResolutionInfoSize()) - { - const RESOLUTION_INFO &info = CDisplaySettings::GetInstance().GetResolutionInfo(resolution); -- // also handle RES_DESKTOP resolutions with non-default refresh rates -- if (resolution != RES_DESKTOP || (refreshrate > 0.0f && refreshrate != info.fRefreshRate)) -- { -- return StringUtils::Format("%1i%05i%05i%09.5f%s", info.iScreen, -- info.iScreenWidth, info.iScreenHeight, -- refreshrate > 0.0f ? refreshrate : info.fRefreshRate, ModeFlagsToString(info.dwFlags, true).c_str()); -- } -+ return StringUtils::Format("%1i%05i%05i%09.5f%s", info.iScreen, -+ info.iScreenWidth, info.iScreenHeight, -+ refreshrate > 0.0f ? refreshrate : info.fRefreshRate, ModeFlagsToString(info.dwFlags, true).c_str()); - } -- -- return "DESKTOP"; - } - - RESOLUTION CDisplaySettings::GetResolutionForScreen() -@@ -673,7 +667,9 @@ void CDisplaySettings::SettingOptionsResolutionsFiller(const CSetting *setting, - std::vector resolutions = g_Windowing.ScreenResolutions(info.iScreen, info.fRefreshRate); - for (std::vector::const_iterator resolution = resolutions.begin(); resolution != resolutions.end(); ++resolution) - { -- list.push_back(std::make_pair( -+ if (resolution->ResInfo_Index == RES_DESKTOP) -+ continue; -+ list.push_back(make_pair( - StringUtils::Format("%dx%d%s", resolution->width, resolution->height, - ModeFlagsToString(resolution->flags, false).c_str()), - resolution->ResInfo_Index)); -diff --git a/xbmc/settings/Settings.cpp b/xbmc/settings/Settings.cpp -index 4e63c15..5ed7391 100644 ---- a/xbmc/settings/Settings.cpp -+++ b/xbmc/settings/Settings.cpp -@@ -182,6 +182,10 @@ const std::string CSettings::SETTING_VIDEOPLAYER_USEMMAL = "videoplayer.usemmal" - const std::string CSettings::SETTING_VIDEOPLAYER_USESTAGEFRIGHT = "videoplayer.usestagefright"; - const std::string CSettings::SETTING_VIDEOPLAYER_LIMITGUIUPDATE = "videoplayer.limitguiupdate"; - const std::string CSettings::SETTING_VIDEOPLAYER_SUPPORTMVC = "videoplayer.supportmvc"; -+const std::string CSettings::SETTING_VIDEOPLAYER_ADJUSTRESOLUTION = "videoplayer.adjustresolution"; -+const std::string CSettings::SETTING_VIDEOPLAYER_ADJUSTRESOLUTIONINTERLACED = "videoplayer.adjustresolutioninterlaced"; -+const std::string CSettings::SETTING_VIDEOPLAYER_MINIMUMVERTICAL = "videoplayer.minimumvertical"; -+const std::string CSettings::SETTING_VIDEOPLAYER_ADJUSTALLOWNONCEA = "videoplayer.adjustallownoncea"; - const std::string CSettings::SETTING_MYVIDEOS_SELECTACTION = "myvideos.selectaction"; - const std::string CSettings::SETTING_MYVIDEOS_EXTRACTFLAGS = "myvideos.extractflags"; - const std::string CSettings::SETTING_MYVIDEOS_EXTRACTCHAPTERTHUMBS = "myvideos.extractchapterthumbs"; -@@ -216,6 +220,7 @@ const std::string CSettings::SETTING_ACCESSIBILITY_SUBHEARING = "accessibility.s - const std::string CSettings::SETTING_SCRAPERS_MOVIESDEFAULT = "scrapers.moviesdefault"; - const std::string CSettings::SETTING_SCRAPERS_TVSHOWSDEFAULT = "scrapers.tvshowsdefault"; - const std::string CSettings::SETTING_SCRAPERS_MUSICVIDEOSDEFAULT = "scrapers.musicvideosdefault"; -+const std::string CSettings::SETTING_PVRMANAGER_ENABLED = "pvrmanager.enabled"; - const std::string CSettings::SETTING_PVRMANAGER_HIDECONNECTIONLOSTWARNING = "pvrmanager.hideconnectionlostwarning"; - const std::string CSettings::SETTING_PVRMANAGER_SYNCCHANNELGROUPS = "pvrmanager.syncchannelgroups"; - const std::string CSettings::SETTING_PVRMANAGER_BACKENDCHANNELORDER = "pvrmanager.backendchannelorder"; -@@ -345,6 +350,7 @@ const std::string CSettings::SETTING_VIDEOSCREEN_GUICALIBRATION = "videoscreen.g - const std::string CSettings::SETTING_VIDEOSCREEN_TESTPATTERN = "videoscreen.testpattern"; - const std::string CSettings::SETTING_VIDEOSCREEN_LIMITEDRANGE = "videoscreen.limitedrange"; - const std::string CSettings::SETTING_VIDEOSCREEN_FRAMEPACKING = "videoscreen.framepacking"; -+const std::string CSettings::SETTING_VIDEOSCREEN_BLANKCURRENT = "videoscreen.blankcurrent"; - const std::string CSettings::SETTING_AUDIOOUTPUT_AUDIODEVICE = "audiooutput.audiodevice"; - const std::string CSettings::SETTING_AUDIOOUTPUT_CHANNELS = "audiooutput.channels"; - const std::string CSettings::SETTING_AUDIOOUTPUT_CONFIG = "audiooutput.config"; -@@ -380,6 +386,7 @@ const std::string CSettings::SETTING_NETWORK_HTTPPROXYPORT = "network.httpproxyp - const std::string CSettings::SETTING_NETWORK_HTTPPROXYUSERNAME = "network.httpproxyusername"; - const std::string CSettings::SETTING_NETWORK_HTTPPROXYPASSWORD = "network.httpproxypassword"; - const std::string CSettings::SETTING_NETWORK_BANDWIDTH = "network.bandwidth"; -+const std::string CSettings::SETTING_NETWORK_RESTARTSERVICES = "network.restartservices"; - const std::string CSettings::SETTING_POWERMANAGEMENT_DISPLAYSOFF = "powermanagement.displaysoff"; - const std::string CSettings::SETTING_POWERMANAGEMENT_SHUTDOWNTIME = "powermanagement.shutdowntime"; - const std::string CSettings::SETTING_POWERMANAGEMENT_SHUTDOWNSTATE = "powermanagement.shutdownstate"; -@@ -1030,6 +1037,7 @@ void CSettings::InitializeISettingCallbacks() - settingSet.insert(CSettings::SETTING_VIDEOSCREEN_MONITOR); - settingSet.insert(CSettings::SETTING_VIDEOSCREEN_PREFEREDSTEREOSCOPICMODE); - m_settingsManager->RegisterCallback(&CDisplaySettings::GetInstance(), settingSet); -+ m_settingsManager->RegisterCallback(&g_application, settingSet); - - settingSet.clear(); - settingSet.insert(CSettings::SETTING_VIDEOPLAYER_SEEKDELAY); -diff --git a/xbmc/settings/Settings.h b/xbmc/settings/Settings.h -index e80e328..ac97d25 100644 ---- a/xbmc/settings/Settings.h -+++ b/xbmc/settings/Settings.h -@@ -139,6 +139,10 @@ public: - static const std::string SETTING_VIDEOPLAYER_USESTAGEFRIGHT; - static const std::string SETTING_VIDEOPLAYER_LIMITGUIUPDATE; - static const std::string SETTING_VIDEOPLAYER_SUPPORTMVC; -+ static const std::string SETTING_VIDEOPLAYER_ADJUSTRESOLUTION; -+ static const std::string SETTING_VIDEOPLAYER_ADJUSTRESOLUTIONINTERLACED; -+ static const std::string SETTING_VIDEOPLAYER_MINIMUMVERTICAL; -+ static const std::string SETTING_VIDEOPLAYER_ADJUSTALLOWNONCEA; - static const std::string SETTING_MYVIDEOS_SELECTACTION; - static const std::string SETTING_MYVIDEOS_EXTRACTFLAGS; - static const std::string SETTING_MYVIDEOS_EXTRACTCHAPTERTHUMBS; -@@ -173,6 +177,7 @@ public: - static const std::string SETTING_SCRAPERS_MOVIESDEFAULT; - static const std::string SETTING_SCRAPERS_TVSHOWSDEFAULT; - static const std::string SETTING_SCRAPERS_MUSICVIDEOSDEFAULT; -+ static const std::string SETTING_PVRMANAGER_ENABLED; - static const std::string SETTING_PVRMANAGER_HIDECONNECTIONLOSTWARNING; - static const std::string SETTING_PVRMANAGER_SYNCCHANNELGROUPS; - static const std::string SETTING_PVRMANAGER_BACKENDCHANNELORDER; -@@ -302,6 +307,7 @@ public: - static const std::string SETTING_VIDEOSCREEN_TESTPATTERN; - static const std::string SETTING_VIDEOSCREEN_LIMITEDRANGE; - static const std::string SETTING_VIDEOSCREEN_FRAMEPACKING; -+ static const std::string SETTING_VIDEOSCREEN_BLANKCURRENT; - static const std::string SETTING_AUDIOOUTPUT_AUDIODEVICE; - static const std::string SETTING_AUDIOOUTPUT_CHANNELS; - static const std::string SETTING_AUDIOOUTPUT_CONFIG; -@@ -337,6 +343,7 @@ public: - static const std::string SETTING_NETWORK_HTTPPROXYUSERNAME; - static const std::string SETTING_NETWORK_HTTPPROXYPASSWORD; - static const std::string SETTING_NETWORK_BANDWIDTH; -+ static const std::string SETTING_NETWORK_RESTARTSERVICES; - static const std::string SETTING_POWERMANAGEMENT_DISPLAYSOFF; - static const std::string SETTING_POWERMANAGEMENT_SHUTDOWNTIME; - static const std::string SETTING_POWERMANAGEMENT_SHUTDOWNSTATE; -diff --git a/xbmc/threads/platform/pthreads/ThreadImpl.cpp b/xbmc/threads/platform/pthreads/ThreadImpl.cpp -index 99c3dbe..7c315cf 100644 ---- a/xbmc/threads/platform/pthreads/ThreadImpl.cpp -+++ b/xbmc/threads/platform/pthreads/ThreadImpl.cpp -@@ -144,6 +144,9 @@ int CThread::GetNormalPriority(void) - - bool CThread::SetPriority(const int iPriority) - { -+#if 1 -+ bool bReturn = true; -+#else - bool bReturn = false; - - // wait until thread is running, it needs to get its lwp id -@@ -195,6 +198,7 @@ bool CThread::SetPriority(const int iPriority) - if (logger) logger->Log(LOGERROR, "%s: error %s", __FUNCTION__, strerror(errno)); - } - #endif -+#endif - - return bReturn; - } -diff --git a/xbmc/utils/CPUInfo.cpp b/xbmc/utils/CPUInfo.cpp -index a2a775f..734d262 100644 ---- a/xbmc/utils/CPUInfo.cpp -+++ b/xbmc/utils/CPUInfo.cpp -@@ -375,7 +375,7 @@ CCPUInfo::CCPUInfo(void) - StringUtils::Trim(m_cores[nCurrId].m_strModel); - } - } -- else if (strncmp(buffer, "flags", 5) == 0) -+ else if (strncmp(buffer, "flags", 5) == 0 || strncmp(buffer, "Features", 8) == 0) - { - char* needle = strchr(buffer, ':'); - if (needle) -@@ -406,6 +406,10 @@ CCPUInfo::CCPUInfo(void) - m_cpuFeatures |= CPU_FEATURE_3DNOW; - else if (0 == strcmp(tok, "3dnowext")) - m_cpuFeatures |= CPU_FEATURE_3DNOWEXT; -+ else if (0 == strcmp(tok, "neon")) -+ m_cpuFeatures |= CPU_FEATURE_NEON; -+ else if (0 == strcmp(tok, "thumb")) -+ m_cpuFeatures |= CPU_FEATURE_THUMB; - tok = strtok_r(NULL, " ", &save); - } - } -@@ -459,10 +463,6 @@ CCPUInfo::CCPUInfo(void) - // Set MMX2 when SSE is present as SSE is a superset of MMX2 and Intel doesn't set the MMX2 cap - if (m_cpuFeatures & CPU_FEATURE_SSE) - m_cpuFeatures |= CPU_FEATURE_MMX2; -- -- if (HasNeon()) -- m_cpuFeatures |= CPU_FEATURE_NEON; -- - } - - CCPUInfo::~CCPUInfo() -@@ -946,27 +946,7 @@ bool CCPUInfo::HasNeon() - has_neon = 1; - - #elif defined(TARGET_LINUX) && defined(__ARM_NEON__) -- if (has_neon == -1) -- { -- has_neon = 0; -- // why are we not looking at the Features in -- // /proc/cpuinfo for neon ? -- int fd = open("/proc/self/auxv", O_RDONLY); -- if (fd >= 0) -- { -- Elf32_auxv_t auxv; -- while (read(fd, &auxv, sizeof(Elf32_auxv_t)) == sizeof(Elf32_auxv_t)) -- { -- if (auxv.a_type == AT_HWCAP) -- { -- has_neon = (auxv.a_un.a_val & HWCAP_NEON) ? 1 : 0; -- break; -- } -- } -- close(fd); -- } -- } -- -+ has_neon = ((g_cpuInfo.GetCPUFeatures() & CPU_FEATURE_NEON) == CPU_FEATURE_NEON) ? 1 : 0; - #endif - - return has_neon == 1; -diff --git a/xbmc/utils/CPUInfo.h b/xbmc/utils/CPUInfo.h -index 1c5e5ba..5f3e2f9 100644 ---- a/xbmc/utils/CPUInfo.h -+++ b/xbmc/utils/CPUInfo.h -@@ -47,6 +47,7 @@ class CTemperature; - #define CPU_FEATURE_3DNOWEXT 1 << 9 - #define CPU_FEATURE_ALTIVEC 1 << 10 - #define CPU_FEATURE_NEON 1 << 11 -+#define CPU_FEATURE_THUMB 1 << 12 - - struct CoreInfo - { -diff --git a/xbmc/utils/Makefile.in b/xbmc/utils/Makefile.in -index afc8dfa..686d947 100644 ---- a/xbmc/utils/Makefile.in -+++ b/xbmc/utils/Makefile.in -@@ -52,6 +52,7 @@ SRCS += RssReader.cpp - SRCS += SaveFileStateJob.cpp - SRCS += ScraperParser.cpp - SRCS += ScraperUrl.cpp -+SRCS += Screen.cpp - SRCS += Screenshot.cpp - SRCS += SeekHandler.cpp - SRCS += SortUtils.cpp -diff --git a/xbmc/utils/RssReader.cpp b/xbmc/utils/RssReader.cpp -index 9186f56..114a18c 100644 ---- a/xbmc/utils/RssReader.cpp -+++ b/xbmc/utils/RssReader.cpp -@@ -146,7 +146,7 @@ void CRssReader::Process() - - // we wait for the network to come up - if ((url.IsProtocol("http") || url.IsProtocol("https")) && -- !g_application.getNetwork().IsAvailable()) -+ !g_application.getNetwork().IsConnected()) - { - CLog::Log(LOGWARNING, "RSS: No network connection"); - strXML = ""+g_localizeStrings.Get(15301)+""; -diff --git a/xbmc/utils/Screen.cpp b/xbmc/utils/Screen.cpp -new file mode 100644 -index 0000000..b350fa8 ---- /dev/null -+++ b/xbmc/utils/Screen.cpp -@@ -0,0 +1,147 @@ -+/* -+ * 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 "Application.h" -+#include "utils/log.h" -+#include "settings/Settings.h" -+//#include "video/VideoReferenceClock.h" -+#include "guilib/GUIWindowManager.h" -+#include "utils/Screen.h" -+#include "windowing/WindowingFactory.h" -+#include "threads/SingleLock.h" -+#ifdef HAS_IMXVPU -+#include "cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecIMX.h" -+#elif defined(TARGET_RASPBERRY_PI) -+#include "linux/RBP.h" -+#endif -+#include "cores/AudioEngine/AEFactory.h" -+ -+using namespace ANNOUNCEMENT; -+ -+CScreen g_screen; -+ -+CScreen::CScreen() -+ : m_state(false) -+ , m_changedBlank(false) -+{ -+} -+ -+void CScreen::RegisterToAnnouncer() -+{ -+ CAnnouncementManager::GetInstance().AddAnnouncer(this); -+} -+ -+CScreen::~CScreen() -+{ -+} -+ -+void CScreen::Announce(AnnouncementFlag flag, const char *sender, const char *message, const CVariant &data) -+{ -+ if (flag == System && !strcmp(sender, "xbmc") && !strcmp(message, "OnQuit")) -+ g_application.SetRenderGUI(true); -+ else if (flag == GUI && !strcmp(sender, "xbmc") && !strcmp(message, "OnScreensaverDeactivated")) -+ g_screen.SetOn(); -+ else if (flag == GUI && !strcmp(sender, "xbmc") && !strcmp(message, "OnScreensaverActivated") && CSettings::GetInstance().GetString("screensaver.mode") == "screensaver.xbmc.builtin.black") -+ { -+ if ((g_application.m_pPlayer->IsPlaying() && g_application.m_pPlayer->IsPausedPlayback() && -+ !CSettings::GetInstance().GetBool(CSettings::SETTING_SCREENSAVER_USEDIMONPAUSE)) -+ || !g_application.m_pPlayer->IsPlaying()) -+ g_screen.SetOff(); -+ } -+/* -+ else if (flag == Player && !strcmp(sender, "xbmc") && !strcmp(message, "OnPlay")) -+ g_VideoReferenceClock.Start(); -+ else if (flag == Player && !strcmp(sender, "xbmc") && !strcmp(message, "OnPause")) -+ g_VideoReferenceClock.Stop(); -+*/ -+} -+ -+void CScreen::ScreenPowerOff(bool doBlank) -+{ -+ if (!doBlank || !CSettings::GetInstance().GetBool(CSettings::SETTING_VIDEOSCREEN_BLANKCURRENT)) -+ return; -+ -+ m_changedBlank = true; -+#if defined(TARGET_RASPBERRY_PI) -+ g_RBP.SuspendVideoOutput(); -+#elif HAS_IMXVPU -+ CAEFactory::Suspend(); -+ // calling CIMXContext::Blank() tells CodecIMX -+ // fb1 is not ready -+ g_IMXContext.Blank(); -+ g_Windowing.Hide(); -+#endif -+} -+ -+void CScreen::ScreenPowerOn(bool doBlank) -+{ -+ if (!doBlank || !m_changedBlank) -+ return; -+ -+ m_changedBlank = false; -+#if defined(TARGET_RASPBERRY_PI) -+ g_RBP.ResumeVideoOutput(); -+#elif HAS_IMXVPU -+ g_Windowing.Show(); -+ g_IMXContext.Unblank(); -+ CAEFactory::Resume(); -+#endif -+} -+ -+void CScreen::SetState(bool state, bool doBlank) -+{ -+ if (g_application.m_bStop) -+ { -+ g_application.SetRenderGUI(true); -+ return; -+ } -+ -+ CSingleLock lock(m_critSection); -+ if (state == m_state) -+ return; -+ -+ CLog::Log(LOGDEBUG, "%s - set standby %d, screensaver is %s", __FUNCTION__, (int)state, g_application.IsInScreenSaver() ? "active" : "inactive"); -+ -+ m_state = state; -+ -+ switch (state) -+ { -+ case true: -+ if (g_application.m_pPlayer->IsPlaying() && !g_application.m_pPlayer->IsPausedPlayback()) -+ return; -+ -+// g_VideoReferenceClock.Stop(); -+ ScreenPowerOff(doBlank); -+ if (!g_application.IsInScreenSaver()) -+ g_application.ActivateScreenSaver(); -+ -+ break; -+ case false: -+ g_application.WakeUpScreenSaverAndDPMS(); -+ ScreenPowerOn(doBlank); -+// if (g_application.m_pPlayer->IsPlayingVideo()) -+// g_VideoReferenceClock.Start(); -+ -+ default: -+ ; -+ } -+ -+ g_application.SetRenderGUI(!m_state); -+} -diff --git a/xbmc/utils/Screen.h b/xbmc/utils/Screen.h -new file mode 100644 -index 0000000..9ef0c48 ---- /dev/null -+++ b/xbmc/utils/Screen.h -@@ -0,0 +1,52 @@ -+#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 "interfaces/AnnouncementManager.h" -+#include "threads/CriticalSection.h" -+#include "threads/Timer.h" -+ -+class CScreen : public ANNOUNCEMENT::IAnnouncer -+{ -+public: -+ CScreen(); -+ ~CScreen(); -+ -+ void Announce(ANNOUNCEMENT::AnnouncementFlag flag, const char *sender, const char *message, const CVariant &data); -+ -+ void SetOff(bool doBlank = true) { SetState(true, doBlank); }; -+ void SetOn() { SetState(false); }; -+ void SwitchState() { SetState(!m_state, m_changedBlank); }; -+ -+ bool GetScreenState() { return m_state; } -+ -+ void RegisterToAnnouncer(); -+ -+private: -+ void SetState(bool status, bool doBlank = true); -+ void ScreenPowerOn(bool doBlank); -+ void ScreenPowerOff(bool doBlank); -+ -+ bool m_state; -+ bool m_changedBlank; -+ CCriticalSection m_critSection; -+}; -+ -+extern CScreen g_screen; -diff --git a/xbmc/utils/URIUtils.cpp b/xbmc/utils/URIUtils.cpp -index 06b2068..f569a0c 100644 ---- a/xbmc/utils/URIUtils.cpp -+++ b/xbmc/utils/URIUtils.cpp -@@ -631,9 +631,9 @@ bool URIUtils::IsOnLAN(const std::string& strPath) - - static bool addr_match(uint32_t addr, const char* target, const char* submask) - { -- uint32_t addr2 = ntohl(inet_addr(target)); -- uint32_t mask = ntohl(inet_addr(submask)); -- return (addr & mask) == (addr2 & mask); -+ struct in_addr in = { htonl(addr) }; -+ std::string address = inet_ntoa(in); -+ return CNetwork::AddrMatch(address, target, submask); - } - - bool URIUtils::IsHostOnLAN(const std::string& host, bool offLineCheck) -@@ -646,32 +646,19 @@ bool URIUtils::IsHostOnLAN(const std::string& host, bool offLineCheck) - if(host.find('.') == std::string::npos) - return true; - -- uint32_t address = ntohl(inet_addr(host.c_str())); -- if(address == INADDR_NONE) -- { -- std::string ip; -- if(CDNSNameCache::Lookup(host, ip)) -- address = ntohl(inet_addr(ip.c_str())); -- } -+ std::string address; -+ if (!CDNSNameCache::Lookup(host, address)) -+ return false; - -- if(address != INADDR_NONE) -- { -- if (offLineCheck) // check if in private range, ref https://en.wikipedia.org/wiki/Private_network -- { -- if ( -- addr_match(address, "192.168.0.0", "255.255.0.0") || -- addr_match(address, "10.0.0.0", "255.0.0.0") || -- addr_match(address, "172.16.0.0", "255.240.0.0") -- ) -- return true; -- } -- // check if we are on the local subnet -- if (!g_application.getNetwork().GetFirstConnectedInterface()) -- return false; -+ if (offLineCheck && /* check if in private range, ref https://en.wikipedia.org/wiki/Private_network */ -+ (CNetwork::AddrMatch(address, "192.168.0.0", "255.255.0.0") || -+ CNetwork::AddrMatch(address, "10.0.0.0", "255.0.0.0") || -+ CNetwork::AddrMatch(address, "172.16.0.0", "255.240.0.0")) -+ ) -+ return true; - -- if (g_application.getNetwork().HasInterfaceForIP(address)) -- return true; -- } -+ if (g_application.getNetwork().HasInterfaceForIP(address)) -+ return true; - - return false; - } -@@ -1005,6 +992,22 @@ bool URIUtils::IsNfs(const std::string& strFile) - return IsProtocol(strFile, "nfs"); - } - -+bool URIUtils::IsAfp(const std::string& strFile) -+{ -+ if (IsStack(strFile)) -+ return IsAfp(CStackDirectory::GetFirstStackedFile(strFile)); -+ -+ if (IsSpecial(strFile)) -+ return IsAfp(CSpecialProtocol::TranslatePath(strFile)); -+ -+ CURL url(strFile); -+ if (HasParentInHostname(url)) -+ return IsAfp(url.GetHostName()); -+ -+ return IsProtocol(strFile, "afp"); -+} -+ -+ - bool URIUtils::IsVideoDb(const std::string& strFile) - { - return IsProtocol(strFile, "videodb"); -@@ -1356,3 +1359,18 @@ bool URIUtils::IsUsingFastSwitch(const std::string& strFile) - { - return IsUDP(strFile) || IsTCP(strFile) || IsPVRChannel(strFile); - } -+ -+bool URIUtils::ConvIPv6(const std::string &address, struct sockaddr_in6 *sa) -+{ -+ return CNetwork::ConvIPv6(address, sa); -+} -+ -+bool URIUtils::ConvIPv4(const std::string &address, struct sockaddr_in *sa) -+{ -+ return CNetwork::ConvIPv4(address, sa); -+} -+ -+std::string URIUtils::CanonizeIPv6(const std::string &address) -+{ -+ return CNetwork::CanonizeIPv6(address); -+} -diff --git a/xbmc/utils/URIUtils.h b/xbmc/utils/URIUtils.h -index f6be769..467eee4 100644 ---- a/xbmc/utils/URIUtils.h -+++ b/xbmc/utils/URIUtils.h -@@ -142,6 +142,7 @@ public: - static bool IsMultiPath(const std::string& strPath); - static bool IsMusicDb(const std::string& strFile); - static bool IsNfs(const std::string& strFile); -+ static bool IsAfp(const std::string& strFile); - static bool IsOnDVD(const std::string& strFile); - static bool IsOnLAN(const std::string& strFile); - static bool IsHostOnLAN(const std::string& hostName, bool offLineCheck = false); -@@ -221,6 +222,10 @@ public: - */ - static bool UpdateUrlEncoding(std::string &strFilename); - -+ static bool ConvIPv6(const std::string &address, struct sockaddr_in6 *sa = NULL); -+ static bool ConvIPv4(const std::string &address, struct sockaddr_in *sa = NULL); -+ static std::string CanonizeIPv6(const std::string &address); -+ - private: - static std::string resolvePath(const std::string &path); - }; -diff --git a/xbmc/utils/Weather.cpp b/xbmc/utils/Weather.cpp -index 4e7621f..13f3fd9 100644 ---- a/xbmc/utils/Weather.cpp -+++ b/xbmc/utils/Weather.cpp -@@ -78,7 +78,7 @@ CWeatherJob::CWeatherJob(int location) - bool CWeatherJob::DoWork() - { - // wait for the network -- if (!g_application.getNetwork().IsAvailable()) -+ if (!g_application.getNetwork().IsConnected()) - return false; - - AddonPtr addon; -diff --git a/xbmc/utils/log.cpp b/xbmc/utils/log.cpp -index 3443f12..ba31766 100644 ---- a/xbmc/utils/log.cpp -+++ b/xbmc/utils/log.cpp -@@ -17,6 +17,7 @@ - * . - * - */ -+#undef _DEBUG - - #include "log.h" - #include "system.h" -@@ -24,6 +25,8 @@ - #include "threads/Thread.h" - #include "utils/StringUtils.h" - #include "CompileInfo.h" -+#include "utils/TimeUtils.cpp" -+#include "settings/AdvancedSettings.h" - - static const char* const levelNames[] = - {"DEBUG", "INFO", "NOTICE", "WARNING", "ERROR", "SEVERE", "FATAL", "NONE"}; -@@ -166,25 +169,24 @@ int CLog::GetLogLevel() - void CLog::SetExtraLogLevels(int level) - { - CSingleLock waitLock(s_globals.critSec); -- s_globals.m_extraLogLevels = level; -+ s_globals.m_extraLogLevels = level & ~LOGMASK; - } - - bool CLog::IsLogLevelLogged(int loglevel) - { - const int extras = (loglevel & ~LOGMASK); -- if (extras != 0 && (s_globals.m_extraLogLevels & extras) == 0) -- return false; -+ const bool canlog = (extras ? g_advancedSettings.CanLogComponent(extras) : true); - - #if defined(_DEBUG) || defined(PROFILE) - return true; - #else - if (s_globals.m_logLevel >= LOG_LEVEL_DEBUG) -- return true; -+ return canlog; - if (s_globals.m_logLevel <= LOG_LEVEL_NONE) - return false; - - // "m_logLevel" is "LOG_LEVEL_NORMAL" -- return (loglevel & LOGMASK) >= LOGNOTICE; -+ return ((loglevel & LOGMASK) >= LOGNOTICE) && canlog; - #endif - } - -@@ -198,21 +200,33 @@ void CLog::PrintDebugString(const std::string& line) - - bool CLog::WriteLogString(int logLevel, const std::string& logString) - { -+#if defined(TARGET_LINUX) -+ static const char* prefixFormat = "%02.2d:%02.2d:%02.2d %10.6f T:%" PRIu64" %7s: "; -+#else - static const char* prefixFormat = "%02.2d:%02.2d:%02.2d T:%" PRIu64" %7s: "; -- -+#endif - std::string strData(logString); - /* fixup newline alignment, number of spaces should equal prefix length */ - StringUtils::Replace(strData, "\n", "\n "); - - int hour, minute, second; - s_globals.m_platform.GetCurrentLocalTime(hour, minute, second); -- -+ -+#if defined(TARGET_LINUX) -+ struct timespec now; -+ clock_gettime(CLOCK_MONOTONIC, &now); -+ float Now = now.tv_sec + now.tv_nsec * 1e-9; -+#endif -+ - strData = StringUtils::Format(prefixFormat, - hour, - minute, - second, -+#if defined(TARGET_LINUX) -+ Now, -+#endif - (uint64_t)CThread::GetCurrentThreadId(), -- levelNames[logLevel]) + strData; -+ levelNames[logLevel & LOGMASK]) + strData; - - return s_globals.m_platform.WriteStringToLog(strData); - } -diff --git a/xbmc/video/VideoReferenceClock.cpp b/xbmc/video/VideoReferenceClock.cpp -index 4e566e4..4b19657 100644 ---- a/xbmc/video/VideoReferenceClock.cpp -+++ b/xbmc/video/VideoReferenceClock.cpp -@@ -195,7 +195,7 @@ void CVideoReferenceClock::UpdateClock(int NrVBlanks, bool CheckMissed) - m_VblankTime += m_SystemFrequency * static_cast(NrVBlanks) / MathUtils::round_int(m_RefreshRate); //set the vblank time forward - } - -- if (NrVBlanks > 0) //update the clock with the adjusted frequency if we have any vblanks -+ if (NrVBlanks > 0 && CheckMissed) //update the clock with the adjusted frequency if we have any vblanks - { - double increment = UpdateInterval() * NrVBlanks; - double integer = floor(increment); -@@ -265,6 +265,7 @@ void CVideoReferenceClock::SetSpeed(double Speed) - //VideoPlayer can change the speed to fit the rereshrate - if (m_UseVblank) - { -+ Speed = (Speed*100 - trunc(Speed*100)) / 100 + 1.0; - if (Speed != m_ClockSpeed) - { - m_ClockSpeed = Speed; -diff --git a/xbmc/video/dialogs/GUIDialogVideoOSD.cpp b/xbmc/video/dialogs/GUIDialogVideoOSD.cpp -index c1e99cf..5e3a31b 100644 ---- a/xbmc/video/dialogs/GUIDialogVideoOSD.cpp -+++ b/xbmc/video/dialogs/GUIDialogVideoOSD.cpp -@@ -30,7 +30,7 @@ using namespace PVR; - CGUIDialogVideoOSD::CGUIDialogVideoOSD(void) - : CGUIDialog(WINDOW_DIALOG_VIDEO_OSD, "VideoOSD.xml") - { -- m_loadType = KEEP_IN_MEMORY; -+ m_loadType = LOAD_ON_GUI_INIT; - } - - CGUIDialogVideoOSD::~CGUIDialogVideoOSD(void) -diff --git a/xbmc/video/dialogs/GUIDialogVideoSettings.cpp b/xbmc/video/dialogs/GUIDialogVideoSettings.cpp -index 3c0a157..d00165c 100644 ---- a/xbmc/video/dialogs/GUIDialogVideoSettings.cpp -+++ b/xbmc/video/dialogs/GUIDialogVideoSettings.cpp -@@ -290,6 +290,10 @@ void CGUIDialogVideoSettings::InitializeSettings() - entries.push_back(std::make_pair(16333, VS_INTERLACEMETHOD_MMAL_BOB_HALF)); - entries.push_back(std::make_pair(16334, VS_INTERLACEMETHOD_IMX_FASTMOTION)); - entries.push_back(std::make_pair(16335, VS_INTERLACEMETHOD_IMX_FASTMOTION_DOUBLE)); -+ entries.push_back(std::make_pair(16336, VS_INTERLACEMETHOD_IMX_FASTMOTION_DOUBLE_INVERTED)); -+ entries.push_back(std::make_pair(16337, VS_INTERLACEMETHOD_IMX_ADVMOTION)); -+ entries.push_back(std::make_pair(16338, VS_INTERLACEMETHOD_IMX_ADVMOTION_DOUBLE)); -+ entries.push_back(std::make_pair(16339, VS_INTERLACEMETHOD_IMX_WEAVE)); - - /* remove unsupported methods */ - for (StaticIntegerSettingOptions::iterator it = entries.begin(); it != entries.end(); ) -diff --git a/xbmc/windowing/WinEvents.cpp b/xbmc/windowing/WinEvents.cpp -index 36c5fab..001256d 100644 ---- a/xbmc/windowing/WinEvents.cpp -+++ b/xbmc/windowing/WinEvents.cpp -@@ -54,6 +54,7 @@ - static WinEventsType g_imp; - static CCriticalSection g_lock; - static bool g_init = false; -+static bool g_suspend = false; - - void Init() - { -@@ -65,8 +66,23 @@ void Init() - } - } - -+void CWinEvents::Stop(bool suspend) -+{ -+ CSingleLock lock(g_lock); -+ -+ if (suspend == g_suspend) -+ return; -+ -+ g_suspend = suspend; -+ if (suspend) -+ g_imp.CloseDevices(); -+} -+ - void CWinEvents::MessagePush(XBMC_Event* ev) - { -+ if (g_suspend) -+ return; -+ - if (!g_init) - Init(); - g_imp.MessagePush(ev); -@@ -74,6 +90,9 @@ void CWinEvents::MessagePush(XBMC_Event* ev) - - bool CWinEvents::MessagePump() - { -+ if (g_suspend) -+ return false; -+ - if (!g_init) - Init(); - return g_imp.MessagePump(); -diff --git a/xbmc/windowing/WinEvents.h b/xbmc/windowing/WinEvents.h -index e04631f..0902183 100644 ---- a/xbmc/windowing/WinEvents.h -+++ b/xbmc/windowing/WinEvents.h -@@ -43,6 +43,7 @@ class CWinEvents - static void MessagePush(XBMC_Event* ev); - static bool MessagePump(); - static size_t GetQueueSize(); -+ static void Stop(bool suspend); - }; - - #endif // WINDOW_EVENTS_H -diff --git a/xbmc/windowing/WinEventsLinux.cpp b/xbmc/windowing/WinEventsLinux.cpp -index a958a23..156348d 100644 ---- a/xbmc/windowing/WinEventsLinux.cpp -+++ b/xbmc/windowing/WinEventsLinux.cpp -@@ -42,6 +42,11 @@ void CWinEventsLinux::RefreshDevices() - m_devices.InitAvailable(); - } - -+void CWinEventsLinux::CloseDevices() -+{ -+ m_devices.Close(); -+} -+ - bool CWinEventsLinux::IsRemoteLowBattery() - { - return m_devices.IsRemoteLowBattery(); -diff --git a/xbmc/windowing/WinEventsLinux.h b/xbmc/windowing/WinEventsLinux.h -index 1b1d2f2..edc5ba6 100644 ---- a/xbmc/windowing/WinEventsLinux.h -+++ b/xbmc/windowing/WinEventsLinux.h -@@ -34,6 +34,7 @@ public: - size_t GetQueueSize(); - void MessagePush(XBMC_Event *ev); - void RefreshDevices(); -+ void CloseDevices(); - void Notify(const Observable &obs, const ObservableMessage msg) - { - if (msg == ObservableMessagePeripheralsChanged) -diff --git a/xbmc/windowing/WinSystem.cpp b/xbmc/windowing/WinSystem.cpp -index 50cf0a7..878557f 100644 ---- a/xbmc/windowing/WinSystem.cpp -+++ b/xbmc/windowing/WinSystem.cpp -@@ -180,7 +180,7 @@ std::vector CWinSystemBase::ScreenResolutions(int screen, float - - // Can't assume a sort order - // don't touch RES_DESKTOP which is index 0 -- sort(resolutions.begin()+1, resolutions.end(), resSortPredicate); -+ sort(resolutions.begin()+0, resolutions.end(), resSortPredicate); - - return resolutions; - } -@@ -242,7 +242,7 @@ REFRESHRATE CWinSystemBase::DefaultRefreshRate(int screen, std::vectorGetValue(); - #else -diff --git a/xbmc/windowing/egl/EGLEdid.cpp b/xbmc/windowing/egl/EGLEdid.cpp -new file mode 100644 -index 0000000..1e24c1d ---- /dev/null -+++ b/xbmc/windowing/egl/EGLEdid.cpp -@@ -0,0 +1,94 @@ -+/* -+ * 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 "system.h" -+#include "EGLEdid.h" -+#include "utils/log.h" -+#include "threads/SingleLock.h" -+#include "settings/DisplaySettings.h" -+ -+CEGLEdid g_EGLEdid; -+ -+CEGLEdid::CEGLEdid() -+ : m_fSar(0.0f) -+ , m_edidEmpty(true) -+{ -+ memset(&m_edid, 0, EDID_MAXSIZE); -+} -+ -+CEGLEdid::~CEGLEdid() -+{ -+} -+ -+float CEGLEdid::ValidateSAR(struct dt_dim *dtm, bool mb) -+{ -+ int Height = dtm->Height | (mb ? (dtm->msbits & 0x0f) << 8 : 0); -+ if (Height < 1) -+ return .0f; -+ -+ int Width = dtm->Width | (mb ? (dtm->msbits & 0xf0) << 4 : 0); -+ float t_sar = (float) Width / Height; -+ -+ if (t_sar < 0.33 || t_sar > 3.00) -+ t_sar = .0f; -+ else -+ CLog::Log(LOGINFO, "%s: Screen SAR: %.3f (from detailed: %s, %dx%d)",__FUNCTION__, t_sar, mb ? "yes" : "no", Width, Height); -+ -+ return t_sar; -+} -+ -+void CEGLEdid::CalcSAR() -+{ -+ CSingleLock lk(m_lock); -+ -+ m_fSar = .0f; -+ m_edidEmpty = true; -+ ReadEdidData(); -+ -+ // enumerate through (max four) detailed timing info blocks -+ // specs and lookup WxH [mm / in]. W and H are in 3 bytes, -+ // where 1st = W, 2nd = H, 3rd byte is 4bit/4bit. -+ // -+ // if DTM block starts with 0 - it is not DTM, skip -+ for (int i = EDID_DTM_START; i < 126 && m_fSar == 0 && *(m_edid +i); i += 18) -+ m_fSar = ValidateSAR((struct dt_dim *)(m_edid +i +EDID_DTM_OFFSET_DIMENSION), true); -+ -+ // fallback - info related to 'Basic display parameters.' is at offset 0x14-0x18. -+ // where W is 2nd byte, H 3rd. -+ if (m_fSar == 0) -+ m_fSar = ValidateSAR((struct dt_dim *)(m_edid +EDID_STRUCT_DISPLAY +1)); -+ -+ // if m_sar != 0, final SAR is usefull -+ // if it is 0, EDID info was missing or calculated -+ // SAR value wasn't sane -+ if (m_fSar == 0) -+ { -+ RESOLUTION_INFO res = CDisplaySettings::GetInstance().GetCurrentResolutionInfo(); -+ -+ CLog::Log(LOGWARNING, "%s: Screen SAR - not usable info",__FUNCTION__); -+ -+ if (res.iScreenWidth != 0) -+ m_fSar = res.iScreenHeight / res.iScreenWidth; -+ else -+ m_fSar = .0f; -+ } -+ -+ m_edidEmpty = false; -+} -diff --git a/xbmc/windowing/egl/EGLEdid.h b/xbmc/windowing/egl/EGLEdid.h -new file mode 100644 -index 0000000..e4b3287 ---- /dev/null -+++ b/xbmc/windowing/egl/EGLEdid.h -@@ -0,0 +1,71 @@ -+#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 "threads/CriticalSection.h" -+#include "threads/SingleLock.h" -+#include -+#include "guilib/GraphicContext.h" -+ -+#define EDID_STRUCT_DISPLAY 0x14 -+#define EDID_DTM_START 0x36 -+#define EDID_DTM_OFFSET_DIMENSION 0x0c -+#define EDID_EXTENSION_BLOCK_START 0x7e -+ -+#define EDID_STRUCT_DISPLAY 0x14 -+#define EDID_MAXSIZE 512 -+#define EDID_HEADERSIZE 8 -+ -+static const char EDID_HEADER[8] = { 0x0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0 }; -+ -+class CEGLEdid -+{ -+ struct dt_dim { -+ uint8_t Width; -+ uint8_t Height; -+ uint8_t msbits; -+ }; -+ -+public: -+ CEGLEdid(); -+ virtual ~CEGLEdid(); -+ -+ bool ReadEdidData(); -+ const uint8_t *GetRawEdid() { Lock(); if (m_edidEmpty) CalcSAR(); return m_edidEmpty ? NULL : &m_edid[0]; } -+ -+ float GetSAR() const { CSingleLock lk(m_lock); return m_fSar; } -+ void CalcSAR(); -+ -+ void Lock() { m_lock.lock(); } -+ void Unlock() { m_lock.unlock(); } -+ -+ uint8_t m_edid[EDID_MAXSIZE]; -+ -+protected: -+ float ValidateSAR(struct dt_dim *dtm, bool mb = false); -+ -+ float m_fSar; -+ bool m_edidEmpty; -+ -+ CCriticalSection m_lock; -+}; -+ -+extern CEGLEdid g_EGLEdid; -diff --git a/xbmc/windowing/egl/EGLNativeTypeIMX.cpp b/xbmc/windowing/egl/EGLNativeTypeIMX.cpp -index c7567a9..0bab5ad 100644 ---- a/xbmc/windowing/egl/EGLNativeTypeIMX.cpp -+++ b/xbmc/windowing/egl/EGLNativeTypeIMX.cpp -@@ -23,6 +23,7 @@ - #include "system.h" - #include - -+#include "Application.h" - #include "EGLNativeTypeIMX.h" - #include - #include -@@ -39,13 +40,27 @@ - #include "windowing/WindowingFactory.h" - #include "cores/AudioEngine/AEFactory.h" - #include -+#include -+#include "peripherals/Peripherals.h" -+#include "peripherals/bus/linux/PeripheralBusPLATFORMLibUdev.h" -+ -+#include "EGLEdid.h" -+ -+using namespace PERIPHERALS; - - CEGLNativeTypeIMX::CEGLNativeTypeIMX() -- : m_sar(0.0f) -- , m_show(true) -+#ifdef HAS_IMXVPU -+ : m_show(true) - , m_display(NULL) - , m_window(NULL) -+ , m_ntsc(0) -+ , m_ignorenext(false) -+#endif - { -+#ifdef HAS_IMXVPU -+ m_show = true; -+ m_readonly = true; -+#endif - } - - CEGLNativeTypeIMX::~CEGLNativeTypeIMX() -@@ -54,12 +69,17 @@ CEGLNativeTypeIMX::~CEGLNativeTypeIMX() - - bool CEGLNativeTypeIMX::CheckCompatibility() - { -+#ifdef HAS_IMXVPU - std::ifstream file("/sys/class/graphics/fb0/fsl_disp_dev_property"); - return file.is_open(); -+#else -+ return false; -+#endif - } - - void CEGLNativeTypeIMX::Initialize() - { -+#ifdef HAS_IMXVPU - int fd; - - // Check if we can change the framebuffer resolution -@@ -102,7 +122,7 @@ void CEGLNativeTypeIMX::Initialize() - CLog::Log(LOGERROR, "%s - Error while opening /dev/fb0.\n", __FUNCTION__); - return; - } --#ifdef HAS_IMXVPU -+ - struct mxcfb_color_key colorKey; - struct mxcfb_gbl_alpha gbl_alpha; - struct mxcfb_loc_alpha lalpha; -@@ -123,21 +143,20 @@ void CEGLNativeTypeIMX::Initialize() - colorKey.color_key = (16 << 16)|(8 << 8)|16; - if (ioctl(fd, MXCFB_SET_CLR_KEY, &colorKey) < 0) - CLog::Log(LOGERROR, "%s - Failed to setup color keying\n", __FUNCTION__); --#endif -- // 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 -+ if (!m_readonly) -+ GetNativeResolution(&m_init); - -- m_sar = GetMonitorSAR(); -+ close(fd); -+#endif - return; - } - - void CEGLNativeTypeIMX::Destroy() - { -+#ifdef HAS_IMXVPU -+ CLog::Log(LOGDEBUG, "%s\n", __FUNCTION__); - struct fb_fix_screeninfo fixed_info; - void *fb_buffer; - int fd; -@@ -161,20 +180,29 @@ void CEGLNativeTypeIMX::Destroy() - memset(fb_buffer, 0x0, fixed_info.smem_len); - munmap(fb_buffer, fixed_info.smem_len); - } -- - close(fd); - -+ if (!m_readonly) -+ SysfsUtils::SetString("/sys/class/graphics/fb0/mode", m_init.strId + "\n"); -+ SysfsUtils::SetInt("/sys/class/graphics/fb1/blank", 1); -+ -+ system("/usr/bin/splash --force -i -m 'stopping kodi...'"); -+#endif - return; - } - - bool CEGLNativeTypeIMX::CreateNativeDisplay() - { -+ CLog::Log(LOGDEBUG,": %s", __FUNCTION__); -+#ifdef HAS_IMXVPU -+ if (m_display) -+ return true; -+ - // Force double-buffering - CEnvironment::setenv("FB_MULTI_BUFFER", "2", 0); -- --#ifdef HAS_IMXVPU - // EGL will be rendered on fb0 -- m_display = fbGetDisplayByIndex(0); -+ if (!(m_display = fbGetDisplayByIndex(0))) -+ return false; - m_nativeDisplay = &m_display; - return true; - #else -@@ -184,8 +212,14 @@ bool CEGLNativeTypeIMX::CreateNativeDisplay() - - bool CEGLNativeTypeIMX::CreateNativeWindow() - { -+ CLog::Log(LOGDEBUG,": %s", __FUNCTION__); - #ifdef HAS_IMXVPU -- m_window = fbCreateWindow(m_display, 0, 0, 0, 0); -+ if (m_window) -+ return true; -+ -+ if (!(m_window = fbCreateWindow(m_display, 0, 0, 0, 0))) -+ return false; -+ - m_nativeWindow = &m_window; - return true; - #else -@@ -195,30 +229,39 @@ bool CEGLNativeTypeIMX::CreateNativeWindow() - - bool CEGLNativeTypeIMX::GetNativeDisplay(XBNativeDisplayType **nativeDisplay) const - { -- if (!nativeDisplay) -- return false; -+#ifdef HAS_IMXVPU - if (!m_nativeDisplay) - return false; -+ - *nativeDisplay = (XBNativeDisplayType*)m_nativeDisplay; - return true; -+#else -+ return false; -+#endif - } - - bool CEGLNativeTypeIMX::GetNativeWindow(XBNativeWindowType **nativeWindow) const - { -- if (!nativeWindow) -- return false; -- if (!m_nativeWindow || !m_window) -+#ifdef HAS_IMXVPU -+ if (!m_nativeWindow) - return false; -+ - *nativeWindow = (XBNativeWindowType*)m_nativeWindow; - return true; -+#else -+ return false; -+#endif - } - - bool CEGLNativeTypeIMX::DestroyNativeDisplay() - { -+ CLog::Log(LOGDEBUG,": %s", __FUNCTION__); - #ifdef HAS_IMXVPU - if (m_display) - fbDestroyDisplay(m_display); -- m_display = NULL; -+ -+ m_display = NULL; -+ m_nativeDisplay = NULL; - return true; - #else - return false; -@@ -227,47 +270,100 @@ bool CEGLNativeTypeIMX::DestroyNativeDisplay() - - bool CEGLNativeTypeIMX::DestroyNativeWindow() - { -+ CLog::Log(LOGDEBUG,": %s", __FUNCTION__); - #ifdef HAS_IMXVPU - if (m_window) - fbDestroyWindow(m_window); -- m_window = NULL; -+ -+ m_window = NULL; -+ m_nativeWindow = NULL; - return true; - #else - return false; - #endif - } - -+#ifdef HAS_IMXVPU -+bool ntsc_mode() -+{ -+ std::ifstream file("/sys/class/graphics/fb0/ntsc_mode"); -+ return file.is_open(); -+} -+ -+bool get_ntsc() -+{ -+ std::string mode; -+ SysfsUtils::GetString("/sys/class/graphics/fb0/ntsc_mode", mode); -+ return mode.find("active") != std::string::npos; -+} -+#endif -+ - bool CEGLNativeTypeIMX::GetNativeResolution(RESOLUTION_INFO *res) const - { -+#ifdef HAS_IMXVPU - std::string mode; - SysfsUtils::GetString("/sys/class/graphics/fb0/mode", mode); -- return ModeToResolution(mode, res); -+ CLog::Log(LOGDEBUG,": %s, %s", __FUNCTION__, mode.c_str()); -+ -+ bool ret = ModeToResolution(mode, res); -+ if (ntsc_mode() && get_ntsc()) -+ res->fRefreshRate = (float)res->refresh_rate * (1000.0f/1001.0f); -+ else if (!ntsc_mode()) -+ return ret; -+ -+ SetStrMode(res); -+ return ret; -+#else -+ return false; -+#endif - } - - bool CEGLNativeTypeIMX::SetNativeResolution(const RESOLUTION_INFO &res) - { -+#ifdef HAS_IMXVPU - if (m_readonly) - return false; - - std::string mode; -+ int new_ntsc; -+ -+ if (ntsc_mode()) -+ new_ntsc = fabs(res.refresh_rate - res.fRefreshRate) < FLT_EPSILON ? 0 : 1; -+ else -+ new_ntsc = 0; -+ - SysfsUtils::GetString("/sys/class/graphics/fb0/mode", mode); -- if (res.strId == mode) -- return false; -+ -+ if (res.strId == mode && m_ntsc == new_ntsc) -+ { -+ CLog::Log(LOGDEBUG,": %s - not changing res (%s vs %s)%s", __FUNCTION__, res.strId.c_str(), mode.c_str(), new_ntsc ? " mode NTSC" : ""); -+ return true; -+ } - - DestroyNativeWindow(); - DestroyNativeDisplay(); - -+ if (ntsc_mode()) -+ { -+ SysfsUtils::SetInt("/sys/class/graphics/fb0/ntsc_mode", new_ntsc); -+ m_ntsc = new_ntsc; -+ } -+ - ShowWindow(false); -+ CLog::Log(LOGDEBUG,": %s - changing resolution to %s%s", __FUNCTION__, res.strId.c_str(), new_ntsc ? " mode NTSC" : ""); - SysfsUtils::SetString("/sys/class/graphics/fb0/mode", res.strId + "\n"); - - CreateNativeDisplay(); - CreateNativeWindow(); - - CLog::Log(LOGDEBUG, "%s: %s",__FUNCTION__, res.strId.c_str()); -- - return true; -+#else -+ return false; -+#endif - } - -+#ifdef HAS_IMXVPU - bool CEGLNativeTypeIMX::FindMatchingResolution(const RESOLUTION_INFO &res, const std::vector &resolutions) - { - for (int i = 0; i < (int)resolutions.size(); i++) -@@ -282,9 +378,13 @@ bool CEGLNativeTypeIMX::FindMatchingResolution(const RESOLUTION_INFO &res, const - } - return false; - } -+#endif - - bool CEGLNativeTypeIMX::ProbeResolutions(std::vector &resolutions) - { -+#ifdef HAS_IMXVPU -+ g_EGLEdid.CalcSAR(); -+ - if (m_readonly) - return false; - -@@ -302,26 +402,53 @@ bool CEGLNativeTypeIMX::ProbeResolutions(std::vector &resolutio - RESOLUTION_INFO res; - for (size_t i = 0; i < probe_str.size(); i++) - { -- if(!StringUtils::StartsWith(probe_str[i], "S:") && !StringUtils::StartsWith(probe_str[i], "U:") && -- !StringUtils::StartsWith(probe_str[i], "V:") && !StringUtils::StartsWith(probe_str[i], "D:")) -+ if(!StringUtils::StartsWithNoCase(probe_str[i], "S:") && !StringUtils::StartsWithNoCase(probe_str[i], "U:") && -+ !StringUtils::StartsWithNoCase(probe_str[i], "V:") && !StringUtils::StartsWithNoCase(probe_str[i], "D:") && -+ !StringUtils::StartsWithNoCase(probe_str[i], "H:") && !StringUtils::StartsWithNoCase(probe_str[i], "T:")) - continue; - - if(ModeToResolution(probe_str[i], &res)) - if(!FindMatchingResolution(res, resolutions)) -+ { - resolutions.push_back(res); -+ if (!ntsc_mode()) -+ continue; -+ -+ if (res.refresh_rate == 24 || res.refresh_rate == 30 || res.refresh_rate == 60) -+ { -+ RESOLUTION_INFO res2 = res; -+ res2.fRefreshRate = (float)res.refresh_rate * (1000.0f/1001.0f); -+ SetStrMode(&res2); -+ resolutions.push_back(res2); -+ } -+ } - } - return resolutions.size() > 0; -+#else -+ return false; -+#endif - } - - bool CEGLNativeTypeIMX::GetPreferredResolution(RESOLUTION_INFO *res) const - { -+#ifdef HAS_IMXVPU - return GetNativeResolution(res); -+#else -+ return false; -+#endif - } - - bool CEGLNativeTypeIMX::ShowWindow(bool show) - { -- if (m_show == show) -+#ifdef HAS_IMXVPU -+ -+ if (m_ignorenext || (m_show == show)) -+ { -+ if (!show) -+ m_ignorenext ^= 1; -+ - return true; -+ } - - CLog::Log(LOGDEBUG, ": %s %s", __FUNCTION__, show?"show":"hide"); - SysfsUtils::SetInt("/sys/class/graphics/fb0/blank", show ? 0 : 1 ); -@@ -329,9 +456,13 @@ bool CEGLNativeTypeIMX::ShowWindow(bool show) - m_show = show; - - return true; -+#else -+ return false; -+#endif - } - --float CEGLNativeTypeIMX::GetMonitorSAR() -+#ifdef HAS_IMXVPU -+bool CEGLEdid::ReadEdidData() - { - FILE *f_edid; - char *str = NULL; -@@ -346,7 +477,7 @@ float CEGLNativeTypeIMX::GetMonitorSAR() - f_edid = fopen("/sys/devices/soc0/soc.1/20e0000.hdmi_video/edid", "r"); - - if(!f_edid) -- return 0; -+ return false; - - // first check if EDID is in binary format by reading 512bytes, compare 1st 8bytes - // against EDID 1.4 identificator [0x0,0xff,0xff,0xff,0xff,0xff,0xff,0x0] -@@ -390,20 +521,15 @@ float CEGLNativeTypeIMX::GetMonitorSAR() - } - fclose(f_edid); - -- // info related to 'Basic display parameters.' is at offset 0x14-0x18. -- // where W is 2nd byte, H 3rd. -- int cmWidth = (int)*(m_edid +EDID_STRUCT_DISPLAY +1); -- int cmHeight = (int)*(m_edid +EDID_STRUCT_DISPLAY +2); -- if (cmHeight > 0) -- { -- float t_sar = (float) cmWidth / cmHeight; -- if (t_sar >= 0.33 && t_sar <= 3.0) -- return t_sar; -- } -+ return true; -+} - -- // if we end up here, H/W values or final SAR are useless -- // return 0 and use 1.0f as PR for all resolutions -- return 0; -+void CEGLNativeTypeIMX::SetStrMode(RESOLUTION_INFO *res) const -+{ -+ res->strMode = StringUtils::Format("%4sx%4s @ %.3f%s - Full Screen %s (%.3f) %s", StringUtils::Format("%d", res->iScreenWidth).c_str(), -+ StringUtils::Format("%d", res->iScreenHeight).c_str(), res->fRefreshRate, -+ res->dwFlags & D3DPRESENTFLAG_INTERLACED ? "i" : " ", HDMI_RES_GROUP_NAME(GETFLAGS_GROUP(res->dwFlags)), res->fPixelRatio, -+ res->dwFlags & D3DPRESENTFLAG_MODE3DSBS ? "- 3DSBS" : res->dwFlags & D3DPRESENTFLAG_MODE3DTB ? "- 3DTB" : ""); - } - - bool CEGLNativeTypeIMX::ModeToResolution(std::string mode, RESOLUTION_INFO *res) const -@@ -420,6 +546,13 @@ bool CEGLNativeTypeIMX::ModeToResolution(std::string mode, RESOLUTION_INFO *res) - std::string fromMode = StringUtils::Mid(mode, 2); - StringUtils::Trim(fromMode); - -+ if (StringUtils::StartsWithNoCase(mode, "U:") || StringUtils::StartsWithNoCase(mode, "V:")) -+ res->dwFlags = HDMI_RES_GROUP_DMT; -+ else -+ res->dwFlags = HDMI_RES_GROUP_CEA; -+ -+ res->fPixelRatio = 1.0f; -+ - CRegExp split(true); - split.RegComp("([0-9]+)x([0-9]+)([pi])-([0-9]+)"); - if (split.RegFind(fromMode) < 0) -@@ -434,18 +567,30 @@ bool CEGLNativeTypeIMX::ModeToResolution(std::string mode, RESOLUTION_INFO *res) - res->iHeight= h; - res->iScreenWidth = w; - res->iScreenHeight= h; -- res->fRefreshRate = r; -- res->dwFlags = p[0] == 'p' ? D3DPRESENTFLAG_PROGRESSIVE : D3DPRESENTFLAG_INTERLACED; -+ if (!ntsc_mode() && StringUtils::isasciilowercaseletter(mode[0])) -+ res->fRefreshRate = (float)r * 1000 / 1001; -+ else -+ res->fRefreshRate = (float)r; -+ res->refresh_rate = (float)r; -+ -+ res->dwFlags = MAKEFLAGS(res->dwFlags, 0, p[0] != 'p' && p[0] != 'd'); -+ -+ if (StringUtils::StartsWithNoCase(mode, "H:")) { -+ res->dwFlags |= D3DPRESENTFLAG_MODE3DSBS; -+ res->fPixelRatio = 2.0f; -+ } else if (StringUtils::StartsWithNoCase(mode, "T:")) { -+ res->dwFlags |= D3DPRESENTFLAG_MODE3DTB; -+ res->fPixelRatio = 0.5f; -+ } - - res->iScreen = 0; - res->bFullScreen = true; - res->iSubtitles = (int)(0.965 * res->iHeight); - -- res->fPixelRatio = !m_sar ? 1.0f : (float)m_sar / res->iScreenWidth * res->iScreenHeight; -- res->strMode = StringUtils::Format("%dx%d @ %.2f%s - Full Screen", res->iScreenWidth, res->iScreenHeight, res->fRefreshRate, -- res->dwFlags & D3DPRESENTFLAG_INTERLACED ? "i" : ""); -+ res->fPixelRatio *= (g_EGLEdid.GetSAR() ? (float)g_EGLEdid.GetSAR() / res->iScreenWidth * res->iScreenHeight : (float)1.0f); - res->strId = mode; -+ SetStrMode(res); - - return res->iWidth > 0 && res->iHeight> 0; - } -- -+#endif -diff --git a/xbmc/windowing/egl/EGLNativeTypeIMX.h b/xbmc/windowing/egl/EGLNativeTypeIMX.h -index 84ff268..f7fcca8 100644 ---- a/xbmc/windowing/egl/EGLNativeTypeIMX.h -+++ b/xbmc/windowing/egl/EGLNativeTypeIMX.h -@@ -23,12 +23,7 @@ - - #include - #include "EGLNativeType.h" -- --#define EDID_STRUCT_DISPLAY 0x14 --#define EDID_MAXSIZE 512 --#define EDID_HEADERSIZE 8 -- --static const char EDID_HEADER[EDID_HEADERSIZE] = { 0x0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0 }; -+#include "windowing/egl/vc_hdmi.h" - - class CEGLNativeTypeIMX : public CEGLNativeType - { -@@ -54,17 +49,22 @@ public: - virtual bool ProbeResolutions(std::vector &resolutions); - virtual bool GetPreferredResolution(RESOLUTION_INFO *res) const; - -- virtual bool ShowWindow(bool show); -+ virtual bool ShowWindow(bool show = true); - -+#ifdef HAS_IMXVPU - protected: - bool m_readonly; -- float m_sar; - bool m_show; -+ RESOLUTION_INFO m_init; - bool ModeToResolution(std::string mode, RESOLUTION_INFO *res) const; - bool FindMatchingResolution(const RESOLUTION_INFO &res, const std::vector &resolutions); -- float GetMonitorSAR(); - - EGLNativeDisplayType m_display; - EGLNativeWindowType m_window; -- uint8_t m_edid[EDID_MAXSIZE]; -+ -+private: -+ void SetStrMode(RESOLUTION_INFO *res) const; -+ int m_ntsc; -+ bool m_ignorenext; -+#endif - }; -diff --git a/xbmc/windowing/egl/EGLWrapper.cpp b/xbmc/windowing/egl/EGLWrapper.cpp -index 0074027..76d1c4a 100644 ---- a/xbmc/windowing/egl/EGLWrapper.cpp -+++ b/xbmc/windowing/egl/EGLWrapper.cpp -@@ -85,6 +85,7 @@ bool CEGLWrapper::Initialize(const std::string &implementation) - { - CEGLNativeType *nativeGuess = NULL; - -+ system("/usr/bin/splash --force -b"); - // Try to create each backend in sequence and go with the first one - // that we know will work - if ( -diff --git a/xbmc/windowing/egl/Makefile.in b/xbmc/windowing/egl/Makefile.in -index 3754233..ffaec1c 100644 ---- a/xbmc/windowing/egl/Makefile.in -+++ b/xbmc/windowing/egl/Makefile.in -@@ -14,6 +14,7 @@ ifeq (@USE_IMXVPU@,1) - SRCS+= EGLNativeTypeIMX.cpp - endif - SRCS+= EGLWrapper.cpp -+SRCS+= EGLEdid.cpp - - LIB = windowing_egl.a - -diff --git a/xbmc/windowing/egl/WinSystemEGL.cpp b/xbmc/windowing/egl/WinSystemEGL.cpp -index a249277..302001f 100644 ---- a/xbmc/windowing/egl/WinSystemEGL.cpp -+++ b/xbmc/windowing/egl/WinSystemEGL.cpp -@@ -18,6 +18,7 @@ - * - */ - #include "system.h" -+#include "Application.h" - - #ifdef HAS_EGL - -@@ -29,6 +30,7 @@ - #include "settings/AdvancedSettings.h" - #include "settings/Settings.h" - #include "settings/DisplaySettings.h" -+#include "guilib/Resolution.h" - #include "guilib/DispResource.h" - #include "threads/SingleLock.h" - #ifdef HAS_IMXVPU -@@ -283,7 +285,9 @@ bool CWinSystemEGL::CreateNewWindow(const std::string& name, bool fullScreen, RE - m_stereo_mode == stereo_mode) - { - CLog::Log(LOGDEBUG, "CWinSystemEGL::CreateNewWindow: No need to create a new window"); -+#if !defined(TARGET_RASPBERRY_PI) - return true; -+#endif - } - - m_stereo_mode = stereo_mode; -@@ -347,7 +351,7 @@ void CWinSystemEGL::UpdateResolutions() - { - CWinSystemBase::UpdateResolutions(); - -- RESOLUTION_INFO resDesktop, curDisplay; -+ RESOLUTION_INFO curDisplay, resDesktop = CDisplaySettings::GetInstance().GetResolutionInfo(CDisplaySettings::GetInstance().GetCurrentResolution()); - std::vector resolutions; - - if (!m_egl->ProbeResolutions(resolutions) || resolutions.empty()) -@@ -366,14 +370,6 @@ void CWinSystemEGL::UpdateResolutions() - } - } - -- /* ProbeResolutions includes already all resolutions. -- * Only get desktop resolution so we can replace xbmc's desktop res -- */ -- if (m_egl->GetNativeResolution(&curDisplay)) -- resDesktop = curDisplay; -- -- -- RESOLUTION ResDesktop = RES_INVALID; - RESOLUTION res_index = RES_DESKTOP; - - for (size_t i = 0; i < resolutions.size(); i++) -@@ -389,41 +385,43 @@ void CWinSystemEGL::UpdateResolutions() - g_graphicsContext.ResetOverscan(resolutions[i]); - CDisplaySettings::GetInstance().GetResolutionInfo(res_index) = resolutions[i]; - -- CLog::Log(LOGNOTICE, "Found resolution %d x %d for display %d with %d x %d%s @ %f Hz\n", -- resolutions[i].iWidth, -- resolutions[i].iHeight, -- resolutions[i].iScreen, -- resolutions[i].iScreenWidth, -- resolutions[i].iScreenHeight, -- resolutions[i].dwFlags & D3DPRESENTFLAG_INTERLACED ? "i" : "", -- resolutions[i].fRefreshRate); -+ CLog::Log(LOGNOTICE, "Found resolution %s\n", resolutions[i].strMode.c_str()); - -+ res_index = (RESOLUTION)((int)res_index + 1); -+ } -+ -+ /* ProbeResolutions includes already all resolutions. -+ * Only get desktop resolution so we can replace xbmc's desktop res -+ */ -+ if (resDesktop.strMode.empty() || CDisplaySettings::GetInstance().GetCurrentResolution() != CDisplaySettings::GetInstance().GetDisplayResolution()) -+ resDesktop = CDisplaySettings::GetInstance().GetResolutionInfo(CDisplaySettings::GetInstance().GetDisplayResolution()); -+ if (CDisplaySettings::GetInstance().GetCurrentResolution() == RES_DESKTOP) -+ if (m_egl->GetNativeResolution(&curDisplay)) -+ resDesktop = curDisplay; -+ -+ CLog::Log(LOGDEBUG, "Looking for resolution %s", resDesktop.strMode.c_str()); -+ RESOLUTION ResDesktop = RES_INVALID; -+ -+ for (size_t i = 0; i < resolutions.size(); i++) - if(resDesktop.iWidth == resolutions[i].iWidth && - resDesktop.iHeight == resolutions[i].iHeight && - resDesktop.iScreenWidth == resolutions[i].iScreenWidth && - resDesktop.iScreenHeight == resolutions[i].iScreenHeight && - (resDesktop.dwFlags & D3DPRESENTFLAG_MODEMASK) == (resolutions[i].dwFlags & D3DPRESENTFLAG_MODEMASK) && -- fabs(resDesktop.fRefreshRate - resolutions[i].fRefreshRate) < FLT_EPSILON) -+ fabs(resDesktop.fRefreshRate - resolutions[i].fRefreshRate) < FLT_EPSILON && -+ fabs(resDesktop.fPixelRatio - resolutions[i].fPixelRatio) < FLT_EPSILON) - { -- ResDesktop = res_index; -+ ResDesktop = (RESOLUTION)(i + (int)RES_DESKTOP); - } - -- res_index = (RESOLUTION)((int)res_index + 1); -- } -- -- // swap desktop index for desktop res if available -- if (ResDesktop != RES_INVALID) -+ if (ResDesktop == RES_INVALID) - { -- CLog::Log(LOGNOTICE, "Found (%dx%d%s@%f) at %d, setting to RES_DESKTOP at %d", -- resDesktop.iWidth, resDesktop.iHeight, -- resDesktop.dwFlags & D3DPRESENTFLAG_INTERLACED ? "i" : "", -- resDesktop.fRefreshRate, -- (int)ResDesktop, (int)RES_DESKTOP); -- -- RESOLUTION_INFO desktop = CDisplaySettings::GetInstance().GetResolutionInfo(RES_DESKTOP); -- CDisplaySettings::GetInstance().GetResolutionInfo(RES_DESKTOP) = CDisplaySettings::GetInstance().GetResolutionInfo(ResDesktop); -- CDisplaySettings::GetInstance().GetResolutionInfo(ResDesktop) = desktop; -+ ResDesktop = CDisplaySettings::GetInstance().GetDisplayResolution(); -+ CLog::Log(LOGNOTICE, "New screen doesn't provide previous resolution. Will change to %d (%s)", ResDesktop, -+ CDisplaySettings::GetInstance().GetResolutionInfo(ResDesktop).strMode.c_str()); - } -+ -+ CDisplaySettings::GetInstance().SetCurrentResolution(ResDesktop); - } - - bool CWinSystemEGL::IsExtSupported(const char* extension) -diff --git a/xbmc/windowing/egl/vc_hdmi.h b/xbmc/windowing/egl/vc_hdmi.h -new file mode 100644 -index 0000000..c8e21ce ---- /dev/null -+++ b/xbmc/windowing/egl/vc_hdmi.h -@@ -0,0 +1,565 @@ -+/* -+Copyright (c) 2012, Broadcom Europe Ltd -+All rights reserved. -+ -+Redistribution and use in source and binary forms, with or without -+modification, are permitted provided that the following conditions are met: -+ * Redistributions of source code must retain the above copyright -+ notice, this list of conditions and the following disclaimer. -+ * Redistributions in binary form must reproduce the above copyright -+ notice, this list of conditions and the following disclaimer in the -+ documentation and/or other materials provided with the distribution. -+ * Neither the name of the copyright holder nor the -+ names of its contributors may be used to endorse or promote products -+ derived from this software without specific prior written permission. -+ -+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY -+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -+*/ -+ -+/* -+ * HDMI common host header for TV service, defines resolution code which host applications should -+ * use for power up command for HDMI -+ */ -+ -+#ifndef _VC_HDMI_H_ -+#define _VC_HDMI_H_ -+ -+#include "guilib/gui3d.h" -+ -+typedef int VC_HDMI_BOOL_T; -+ -+/** -+ * HDMI resolution groups. There are two main groups: -+ * CEA - the conventional HDMI ones like 720p -+ * DMT - computer monitor resolutions like XGA -+ */ -+typedef enum { -+ HDMI_RES_GROUP_INVALID = 0, /**< Initialised value */ -+ HDMI_RES_GROUP_CEA = 1, /**< CEA - HDMI device */ -+ HDMI_RES_GROUP_DMT = 2, /**< DMT - computer monitors */ -+ HDMI_RES_GROUP_CEA_3D = 3, /* deprecated */ -+ -+} HDMI_RES_GROUP_T; -+ -+ -+/** -+ * CEA 861 defined video code and aspect ratios for various HDMI modes -+ * Not all values are valid for AVI infoframe -+ */ -+typedef enum { -+ HDMI_ASPECT_UNKNOWN = 0, /**< Unknown aspect ratio, or not one of the values below */ -+ HDMI_ASPECT_4_3 = 1, /**< 4:3 */ -+ HDMI_ASPECT_14_9 = 2, /**< 14:9 */ -+ HDMI_ASPECT_16_9 = 3, /**< 16:9 */ -+ HDMI_ASPECT_5_4 = 4, /**< 5:4 */ -+ HDMI_ASPECT_16_10 = 5, /**< 16:10*/ -+ HDMI_ASPECT_15_9 = 6, /**< 15:9 */ -+ HDMI_ASPECT_64_27 = 7, /**< 64:27 */ -+ HDMI_ASPECT_21_9 = HDMI_ASPECT_64_27 /**< 21:9 is jargon, 64:27 is the actual aspect ratio */ -+ /* More aspect ratio values may be added here if defined by CEA in future */ -+} HDMI_ASPECT_T; -+ -+/** -+ * Display options set the bounding box (only used in CEA mode) -+ */ -+typedef struct { -+ uint16_t aspect; /**> 16) & 0xff )) -+#define GETFLAGS_MODE(f) ( ( (f) >>24 ) & 0xff ) -+ -+#define IS_3D(f) ( f & (D3DPRESENTFLAG_MODE3DSBS | D3DPRESENTFLAG_MODE3DTB) ) -+ -+#endif /*HDMI_RES_GROUP_NAME*/ -diff --git a/xbmc/windows/GUIMediaWindow.cpp b/xbmc/windows/GUIMediaWindow.cpp -index 9ba82cc..08e53a7 100644 ---- a/xbmc/windows/GUIMediaWindow.cpp -+++ b/xbmc/windows/GUIMediaWindow.cpp -@@ -1676,7 +1676,7 @@ const CFileItemList& CGUIMediaWindow::CurrentDirectory() const - - bool CGUIMediaWindow::WaitForNetwork() const - { -- if (g_application.getNetwork().IsAvailable()) -+ if (g_application.getNetwork().IsConnected()) - return true; - - CGUIDialogProgress *progress = (CGUIDialogProgress *)g_windowManager.GetWindow(WINDOW_DIALOG_PROGRESS); -@@ -1688,7 +1688,7 @@ bool CGUIMediaWindow::WaitForNetwork() const - progress->SetLine(1, CVariant{url.GetWithoutUserDetails()}); - progress->ShowProgressBar(false); - progress->Open(); -- while (!g_application.getNetwork().IsAvailable()) -+ while (!g_application.getNetwork().IsConnected()) - { - progress->Progress(); - if (progress->IsCanceled()) -diff --git a/xbmc/windows/GUIWindowSystemInfo.cpp b/xbmc/windows/GUIWindowSystemInfo.cpp -index 4184db0..fe40f1b 100644 ---- a/xbmc/windows/GUIWindowSystemInfo.cpp -+++ b/xbmc/windows/GUIWindowSystemInfo.cpp -@@ -100,7 +100,9 @@ void CGUIWindowSystemInfo::FrameMove() - SetControlLabel(i++, "%s %s", 13283, SYSTEM_OS_VERSION_INFO); - SetControlLabel(i++, "%s: %s", 12390, SYSTEM_UPTIME); - SetControlLabel(i++, "%s: %s", 12394, SYSTEM_TOTALUPTIME); -+#if 0 - SetControlLabel(i++, "%s: %s", 12395, SYSTEM_BATTERY_LEVEL); -+#endif - } - - else if (m_section == CONTROL_BT_STORAGE) --- -2.7.1 - -From 707e1060d31717ab2318f49d2289b4b7968b12db Mon Sep 17 00:00:00 2001 -From: Peter Vicman -Date: Tue, 2 Aug 2016 20:43:54 +0200 -Subject: [PATCH] small fixes for kodi-17.0-alpha3-fc46cf2 - ---- - .../VideoPlayer/VideoRenderers/HwDecRender/RendererIMX.cpp | 10 ---------- - .../cores/VideoPlayer/VideoRenderers/HwDecRender/RendererIMX.h | 1 - - xbmc/cores/VideoPlayer/VideoRenderers/RenderManager.cpp | 4 ++-- - 3 files changed, 2 insertions(+), 13 deletions(-) - -diff --git a/xbmc/cores/VideoPlayer/VideoRenderers/HwDecRender/RendererIMX.cpp b/xbmc/cores/VideoPlayer/VideoRenderers/HwDecRender/RendererIMX.cpp -index ffd807d..4873919 100644 ---- a/xbmc/cores/VideoPlayer/VideoRenderers/HwDecRender/RendererIMX.cpp -+++ b/xbmc/cores/VideoPlayer/VideoRenderers/HwDecRender/RendererIMX.cpp -@@ -102,16 +102,6 @@ bool CRendererIMX::Supports(EINTERLACEMETHOD method) - return false; - } - --bool CRendererIMX::Supports(EDEINTERLACEMODE mode) --{ -- if(mode == VS_DEINTERLACEMODE_AUTO -- || mode == VS_DEINTERLACEMODE_FORCE -- || mode == VS_DEINTERLACEMODE_OFF) -- return true; -- -- return false; --} -- - bool CRendererIMX::Supports(ESCALINGMETHOD method) - { - return method == VS_SCALINGMETHOD_AUTO; -diff --git a/xbmc/cores/VideoPlayer/VideoRenderers/HwDecRender/RendererIMX.h b/xbmc/cores/VideoPlayer/VideoRenderers/HwDecRender/RendererIMX.h -index 74f6888..ba9618d 100644 ---- a/xbmc/cores/VideoPlayer/VideoRenderers/HwDecRender/RendererIMX.h -+++ b/xbmc/cores/VideoPlayer/VideoRenderers/HwDecRender/RendererIMX.h -@@ -41,7 +41,6 @@ public: - - // Feature support - virtual bool Supports(EINTERLACEMETHOD method); -- virtual bool Supports(EDEINTERLACEMODE mode); - virtual bool Supports(ESCALINGMETHOD method); - - -diff --git a/xbmc/cores/VideoPlayer/VideoRenderers/RenderManager.cpp b/xbmc/cores/VideoPlayer/VideoRenderers/RenderManager.cpp -index 1ec8575..e9e69cc 100644 ---- a/xbmc/cores/VideoPlayer/VideoRenderers/RenderManager.cpp -+++ b/xbmc/cores/VideoPlayer/VideoRenderers/RenderManager.cpp -@@ -864,7 +864,7 @@ RESOLUTION CRenderManager::GetResolution() - return res; - - if (CSettings::GetInstance().GetInt(CSettings::SETTING_VIDEOPLAYER_ADJUSTREFRESHRATE) != ADJUST_REFRESHRATE_OFF) -- res = CResolutionUtils::ChooseBestResolution(m_fps, m_width, CONF_FLAGS_STEREO_MODE_MASK(m_flags)); -+ res = CResolutionUtils::ChooseBestResolution(m_fps, m_width, m_height, CONF_FLAGS_STEREO_MODE_MASK(m_flags), CONF_FLAGS_INTERLACED_MODE_MASK(m_flags)); - - return res; - } -@@ -1059,7 +1059,7 @@ void CRenderManager::UpdateResolution() - { - if (CSettings::GetInstance().GetInt(CSettings::SETTING_VIDEOPLAYER_ADJUSTREFRESHRATE) != ADJUST_REFRESHRATE_OFF && m_fps > 0.0f) - { -- RESOLUTION res = CResolutionUtils::ChooseBestResolution(m_fps, m_width, CONF_FLAGS_STEREO_MODE_MASK(m_flags)); -+ RESOLUTION res = CResolutionUtils::ChooseBestResolution(m_fps, m_width, m_height, CONF_FLAGS_STEREO_MODE_MASK(m_flags), CONF_FLAGS_INTERLACED_MODE_MASK(m_flags)); - g_graphicsContext.SetVideoResolution(res); - UpdateDisplayLatency(); - --- -2.7.1 diff --git a/projects/imx6/patches/kodi/kodi-100-master-fixes.patch b/projects/imx6/patches/kodi/kodi-100-master-fixes.patch new file mode 100644 index 0000000000..6a5c923f4a --- /dev/null +++ b/projects/imx6/patches/kodi/kodi-100-master-fixes.patch @@ -0,0 +1,26 @@ +diff -aurNp a/xbmc/linux/imx/IMX.cpp b/xbmc/linux/imx/IMX.cpp +--- a/xbmc/linux/imx/IMX.cpp 2016-08-21 23:42:23.000000000 +0200 ++++ b/xbmc/linux/imx/IMX.cpp 2016-09-02 12:51:09.516633817 +0200 +@@ -198,11 +198,6 @@ bool CIMXFps::Recalc() + + double frameNorm = CDVDCodecUtils::NormalizeFrameduration(frameDuration, &hasMatch); + +- if (hasMatch && !patternLength) +- m_patternLength = 1; +- else +- m_patternLength = patternLength; +- + if (!m_hasPattern && hasMatch) + m_frameDuration = frameNorm; + +diff -aurNp a/xbmc/windowing/egl/EGLNativeTypeIMX.cpp b/xbmc/windowing/egl/EGLNativeTypeIMX.cpp +--- a/xbmc/windowing/egl/EGLNativeTypeIMX.cpp 2016-08-21 23:42:23.000000000 +0200 ++++ b/xbmc/windowing/egl/EGLNativeTypeIMX.cpp 2016-09-02 12:42:54.443140655 +0200 +@@ -29,6 +29,7 @@ + #include + #ifdef HAS_IMXVPU + #include ++#include "cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecIMX.h" + #endif + #include "utils/log.h" + #include "utils/RegExp.h"