From e47d1541cb23c8667c0403003380ebd76a703251 Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Mon, 7 Apr 2014 18:19:32 +0100
Subject: [PATCH 001/100] [rbp/omxplayer] When opening a stream don't try to
 update gui so often

---
 xbmc/dialogs/GUIDialogBusy.cpp | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/xbmc/dialogs/GUIDialogBusy.cpp b/xbmc/dialogs/GUIDialogBusy.cpp
index 318ecec..59698f6 100644
--- a/xbmc/dialogs/GUIDialogBusy.cpp
+++ b/xbmc/dialogs/GUIDialogBusy.cpp
@@ -68,7 +68,11 @@ bool CGUIDialogBusy::WaitOnEvent(CEvent &event, unsigned int displaytime /* = 10
     if (dialog)
     {
       dialog->Show();
+#ifdef TARGET_RASPBERRY_PI
+      while(!event.WaitMSec(100))
+#else
       while(!event.WaitMSec(1))
+#endif
       {
         g_windowManager.ProcessRenderLoop(false);
         if (allowCancel && dialog->IsCanceled())

From f951f557431145e47108b7fb3c2c8f47a9c07893 Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Sat, 8 Mar 2014 15:36:06 +0000
Subject: [PATCH 003/100] [hifiberry] Hack: force it to be recognised as IEC958
 capable to enable passthrough options

---
 xbmc/cores/AudioEngine/Sinks/AESinkALSA.cpp | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/xbmc/cores/AudioEngine/Sinks/AESinkALSA.cpp b/xbmc/cores/AudioEngine/Sinks/AESinkALSA.cpp
index e22db7a..0120bd5 100644
--- a/xbmc/cores/AudioEngine/Sinks/AESinkALSA.cpp
+++ b/xbmc/cores/AudioEngine/Sinks/AESinkALSA.cpp
@@ -1342,6 +1342,10 @@ void CAESinkALSA::EnumerateDevice(AEDeviceInfoList &list, const std::string &dev
     if (snd_card_get_name(cardNr, &cardName) == 0)
       info.m_displayName = cardName;
 
+    // hack: hifiberry digi doesn't correctly report as iec958 device. Needs fixing in kernel driver
+    if (info.m_displayName == "snd_rpi_hifiberry_digi")
+      info.m_deviceType = AE_DEVTYPE_IEC958;
+
     if (info.m_deviceType == AE_DEVTYPE_HDMI && info.m_displayName.size() > 5 &&
         info.m_displayName.substr(info.m_displayName.size()-5) == " HDMI")
     {

From d2026ad2027d69138df4f058fb60a0a0cc305c7e Mon Sep 17 00:00:00 2001
From: Ben Avison <bavison@riscosopen.org>
Date: Thu, 1 May 2014 16:28:39 +0100
Subject: [PATCH 004/100] Improved file buffering in CArchive

Even though memcpy is typically inlined by the compiler into byte/word loads
and stores (at least for release builds), the frequency with which 1, 2 and 4
byte loads/stores are encountered in cases where the size is *not*
determinable at compile time is still high enough that it's worth handling
these specially. On the ARM1176JZF-S in the Raspberry Pi, this improves the
total time to open a library (in the case where it's fetched from a CArchive)
by around 4%.

It should be noted that this code uses 16-bit and 32-bit word loads and
stores that are not necessarily aligned to their respective widths. It is
possible that there are some architectures out there which do not support
this, although all ARMs since ARMv6 have supported it (and ARMs earlier than
that are probably not powerful enough to be good targets for XBMC).
---
 xbmc/utils/Archive.h | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)

diff --git a/xbmc/utils/Archive.h b/xbmc/utils/Archive.h
index 6ed0f8f..8506d95 100644
--- a/xbmc/utils/Archive.h
+++ b/xbmc/utils/Archive.h
@@ -154,9 +154,17 @@ class CArchive
      * than waiting until we attempt to put more data into an already full buffer */
     if (m_BufferRemain > size)
     {
+      switch (size)
+      {
+      case 1: *m_BufferPos++ = *ptr; m_BufferRemain--; break;
+      case 2: *(uint16_t *) m_BufferPos = *(const uint16_t *) ptr; m_BufferPos += 2; m_BufferRemain -= 2; break;
+      case 4: *(uint32_t *) m_BufferPos = *(const uint32_t *) ptr; m_BufferPos += 4; m_BufferRemain -= 4; break;
+      default:
       memcpy(m_BufferPos, ptr, size);
       m_BufferPos += size;
       m_BufferRemain -= size;
+      break;
+      }
       return *this;
     }
     else
@@ -171,9 +179,17 @@ class CArchive
     /* Note, refilling the buffer is deferred until we know we need to read more from it */
     if (m_BufferRemain >= size)
     {
+      switch (size)
+      {
+      case 1: *ptr = *m_BufferPos++; m_BufferRemain--; break;
+      case 2: *(uint16_t *) ptr = *(const uint16_t *) m_BufferPos; m_BufferPos += 2; m_BufferRemain -= 2; break;
+      case 4: *(uint32_t *) ptr = *(const uint32_t *) m_BufferPos; m_BufferPos += 4; m_BufferRemain -= 4; break;
+      default:
       memcpy(ptr, m_BufferPos, size);
       m_BufferPos += size;
       m_BufferRemain -= size;
+      break;
+      }
       return *this;
     }
     else

From 7a6f6fdb69f093b604e353f5fdf55e336d308a75 Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Tue, 12 Aug 2014 00:31:36 +0100
Subject: [PATCH 005/100] [omxcodec] Don't force software codec with dvds

---
 xbmc/cores/dvdplayer/DVDPlayer.cpp | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/xbmc/cores/dvdplayer/DVDPlayer.cpp b/xbmc/cores/dvdplayer/DVDPlayer.cpp
index f6ffe4e..74f3f9b 100644
--- a/xbmc/cores/dvdplayer/DVDPlayer.cpp
+++ b/xbmc/cores/dvdplayer/DVDPlayer.cpp
@@ -3417,7 +3417,9 @@ bool CDVDPlayer::OpenVideoStream(CDVDStreamInfo& hint, bool reset)
       hint.aspect = aspect;
       hint.forced_aspect = true;
     }
+#ifndef TARGET_RASPBERRY_PI
     hint.software = true;
+#endif
   }
   else if (m_pInputStream && m_pInputStream->IsStreamType(DVDSTREAM_TYPE_PVRMANAGER))
   {

From 7d01f78144c9bc8dc9df5ca8da03dcf5c33d86d9 Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Sun, 10 Aug 2014 16:45:16 +0100
Subject: [PATCH 006/100] filesystem: Make support of browsing into archives
 optional

The ability to browse, scan and play content in archives can cause problems on low powered/low memory devices.
It's quite common to see reports of a large rar file that causes xbmc to crash with an out-of-memory error when browsing or scanning.
It also can be slow as any archive in the directory is opened and extracted.

This causes issues for people who scan library with archives disabled, then subsequently enable it.
The library has the .rar files in which don't play without removing and re-adding.

We'll let people who don't use archives disable it manually
---
 addons/resource.language.en_gb/resources/strings.po | 9 +++++++++
 system/settings/settings.xml                        | 5 +++++
 xbmc/filesystem/FileDirectoryFactory.cpp            | 4 ++++
 3 files changed, 18 insertions(+)

diff --git a/addons/resource.language.en_gb/resources/strings.po b/addons/resource.language.en_gb/resources/strings.po
index faf423c..52117a2 100644
--- a/addons/resource.language.en_gb/resources/strings.po
+++ b/addons/resource.language.en_gb/resources/strings.po
@@ -16605,6 +16605,15 @@ msgstr ""
 #: system/settings/rbp.xml
 msgctxt "#38010"
 msgid "GPU accelerated"
+
+#: system/settings/settings.xml
+msgctxt "#38020"
+msgid "Support browsing into archives"
+msgstr ""
+
+#: system/settings/settings.xml
+msgctxt "#38021"
+msgid "Allow viewing and playing files in archives (e.g. zip, rar)"
 msgstr ""
 
 #. Setting #38011 "Videos -> Library -> Show All Items entry"
diff --git a/system/settings/settings.xml b/system/settings/settings.xml
index 3ef33e0..10e8552 100644
--- a/system/settings/settings.xml
+++ b/system/settings/settings.xml
@@ -304,6 +304,11 @@
           <default>false</default>
           <control type="toggle" />
         </setting>
+        <setting id="filelists.browsearchives" type="boolean" label="38020" help="38021">
+          <level>1</level>
+          <default>true</default>
+          <control type="toggle" />
+        </setting>
       </group>
     </category>
     <category id="screensaver" label="360" help="36128">
diff --git a/xbmc/filesystem/FileDirectoryFactory.cpp b/xbmc/filesystem/FileDirectoryFactory.cpp
index 5af92e7..568a1a8 100644
--- a/xbmc/filesystem/FileDirectoryFactory.cpp
+++ b/xbmc/filesystem/FileDirectoryFactory.cpp
@@ -39,6 +39,7 @@
 #include "playlists/PlayListFactory.h"
 #include "Directory.h"
 #include "File.h"
+#include "settings/Settings.h"
 #include "FileItem.h"
 #include "utils/StringUtils.h"
 #include "URL.h"
@@ -112,6 +113,8 @@ IFileDirectory* CFileDirectoryFactory::Create(const CURL& url, CFileItem* pItem,
     return NULL;
   }
 #endif
+  if (CSettings::Get().GetBool("filelists.browsearchives"))
+  {
   if (url.IsFileType("zip"))
   {
     CURL zipURL = URIUtils::CreateArchivePath("zip", url);
@@ -185,6 +188,7 @@ IFileDirectory* CFileDirectoryFactory::Create(const CURL& url, CFileItem* pItem,
     }
     return NULL;
   }
+  }
   if (url.IsFileType("xsp"))
   { // XBMC Smart playlist - just XML renamed to XSP
     // read the name of the playlist in

From 601a45ff9b262f64000ee50e1cfc6869b410c55e Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Mon, 27 Oct 2014 13:06:57 +0000
Subject: [PATCH 008/100] [rbp] Make cachemembuffersize default depend on
 memory size

---
 xbmc/linux/RBP.cpp                 | 10 ++++++++++
 xbmc/linux/RBP.h                   |  1 +
 xbmc/settings/AdvancedSettings.cpp | 12 +++++++++++-
 3 files changed, 22 insertions(+), 1 deletion(-)

diff --git a/xbmc/linux/RBP.cpp b/xbmc/linux/RBP.cpp
index 59dd1da..68d2694 100644
--- a/xbmc/linux/RBP.cpp
+++ b/xbmc/linux/RBP.cpp
@@ -23,6 +23,7 @@
 
 #include <assert.h>
 #include "settings/Settings.h"
+#include "settings/AdvancedSettings.h"
 #include "utils/log.h"
 
 #include "cores/omxplayer/OMXImage.h"
@@ -43,6 +44,12 @@ CRBP::~CRBP()
   delete m_DllBcmHost;
 }
 
+void CRBP::InitializeSettings()
+{
+  if (m_initialized && g_advancedSettings.m_cacheMemBufferSize == ~0U)
+    g_advancedSettings.m_cacheMemBufferSize = m_arm_mem < 256 ? 1024 * 1024 * 2 : 1024 * 1024 * 20;
+}
+
 bool CRBP::Initialize()
 {
   CSingleLock lock (m_critSection);
@@ -82,6 +89,8 @@ bool CRBP::Initialize()
   if (!m_gui_resolution_limit)
     m_gui_resolution_limit = m_gpu_mem < 128 ? 720:1080;
 
+  InitializeSettings();
+
   g_OMXImage.Initialize();
   m_omx_image_init = true;
   return true;
@@ -94,6 +103,7 @@ void CRBP::LogFirmwareVerison()
   response[sizeof(response) - 1] = '\0';
   CLog::Log(LOGNOTICE, "Raspberry PI firmware version: %s", response);
   CLog::Log(LOGNOTICE, "ARM mem: %dMB GPU mem: %dMB MPG2:%d WVC1:%d", m_arm_mem, m_gpu_mem, m_codec_mpg2_enabled, m_codec_wvc1_enabled);
+  CLog::Log(LOGNOTICE, "cacheMemBufferSize: %dMB",  g_advancedSettings.m_cacheMemBufferSize >> 20);
   m_DllBcmHost->vc_gencmd(response, sizeof response, "get_config int");
   response[sizeof(response) - 1] = '\0';
   CLog::Log(LOGNOTICE, "Config:\n%s", response);
diff --git a/xbmc/linux/RBP.h b/xbmc/linux/RBP.h
index 9559914..7fc8b42 100644
--- a/xbmc/linux/RBP.h
+++ b/xbmc/linux/RBP.h
@@ -48,6 +48,7 @@ class CRBP
   ~CRBP();
 
   bool Initialize();
+  void InitializeSettings();
   void LogFirmwareVerison();
   void Deinitialize();
   int GetArmMem() { return m_arm_mem; }
diff --git a/xbmc/settings/AdvancedSettings.cpp b/xbmc/settings/AdvancedSettings.cpp
index 2e3282c..d1606a2 100644
--- a/xbmc/settings/AdvancedSettings.cpp
+++ b/xbmc/settings/AdvancedSettings.cpp
@@ -43,6 +43,9 @@
 #if defined(TARGET_DARWIN_IOS)
 #include "osx/DarwinUtils.h"
 #endif
+#if defined(TARGET_RASPBERRY_PI)
+#include "linux/RBP.h"
+#endif
 
 using namespace ADDON;
 using namespace XFILE;
@@ -350,7 +353,12 @@ void CAdvancedSettings::Initialize()
   m_bPVRAutoScanIconsUserSet       = false;
   m_iPVRNumericChannelSwitchTimeout = 1000;
 
+#ifdef TARGET_RASPBERRY_PI
+  // want default to be memory dependent, but interface to gpu not available yet, so set in RBP.cpp
+  m_cacheMemBufferSize = ~0;
+#else
   m_cacheMemBufferSize = 1024 * 1024 * 20;
+#endif
   m_networkBufferMode = 0; // Default (buffer all internet streams/filesystems)
   // the following setting determines the readRate of a player data
   // as multiply of the default data read rate
@@ -405,7 +413,9 @@ void CAdvancedSettings::Initialize()
   #endif
 
   m_userAgent = g_sysinfo.GetUserAgent();
-
+#ifdef TARGET_RASPBERRY_PI
+  g_RBP.InitializeSettings();
+#endif
   m_initialized = true;
 }
 

From 4e426c5505fb01f64a272f191ca22eb542483de9 Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Fri, 30 May 2014 14:58:43 +0100
Subject: [PATCH 010/100] [settings] Experiment: Report DESKTOP resolution in
 video settings

---
 xbmc/settings/DisplaySettings.cpp | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/xbmc/settings/DisplaySettings.cpp b/xbmc/settings/DisplaySettings.cpp
index 4376463..fc4e5ea 100644
--- a/xbmc/settings/DisplaySettings.cpp
+++ b/xbmc/settings/DisplaySettings.cpp
@@ -674,6 +674,9 @@ void CDisplaySettings::SettingOptionsResolutionsFiller(const CSetting *setting,
     vector<RESOLUTION_WHR> resolutions = g_Windowing.ScreenResolutions(info.iScreen, info.fRefreshRate);
     for (vector<RESOLUTION_WHR>::const_iterator resolution = resolutions.begin(); resolution != resolutions.end(); ++resolution)
     {
+if (resolution->ResInfo_Index == RES_DESKTOP)
+      list.push_back(make_pair(StringUtils::Format("DESKTOP"), resolution->ResInfo_Index));
+else
       list.push_back(make_pair(
         StringUtils::Format("%dx%d%s", resolution->width, resolution->height,
                             ModeFlagsToString(resolution->flags, false).c_str()),

From 047f52b5ba5f87c6a05fc49f0ff47f964cc2151a Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Tue, 9 Sep 2014 12:04:26 +0100
Subject: [PATCH 011/100] egl: Treat unknown display aspect ratio as square
 pixel

---
 xbmc/windowing/egl/EGLNativeTypeRaspberryPI.cpp | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/xbmc/windowing/egl/EGLNativeTypeRaspberryPI.cpp b/xbmc/windowing/egl/EGLNativeTypeRaspberryPI.cpp
index bda7430..68fc647 100644
--- a/xbmc/windowing/egl/EGLNativeTypeRaspberryPI.cpp
+++ b/xbmc/windowing/egl/EGLNativeTypeRaspberryPI.cpp
@@ -447,7 +447,7 @@ bool CEGLNativeTypeRaspberryPI::ProbeResolutions(std::vector<RESOLUTION_INFO> &r
       m_desktopRes.iScreenWidth = tv_state.display.hdmi.width;
       m_desktopRes.iScreenHeight= tv_state.display.hdmi.height;
       m_desktopRes.dwFlags      = MAKEFLAGS(tv_state.display.hdmi.group, tv_state.display.hdmi.mode, tv_state.display.hdmi.scan_mode);
-      m_desktopRes.fPixelRatio  = get_display_aspect_ratio((HDMI_ASPECT_T)tv_state.display.hdmi.display_options.aspect) / ((float)m_desktopRes.iScreenWidth / (float)m_desktopRes.iScreenHeight);
+      m_desktopRes.fPixelRatio  = tv_state.display.hdmi.display_options.aspect == 0 ? 1.0f : get_display_aspect_ratio((HDMI_ASPECT_T)tv_state.display.hdmi.display_options.aspect) / ((float)m_desktopRes.iScreenWidth / (float)m_desktopRes.iScreenHeight);
       // Also add 3D flags
       if (tv_state.display.hdmi.format_3d == HDMI_3D_FORMAT_SBS_HALF)
       {
@@ -474,7 +474,7 @@ bool CEGLNativeTypeRaspberryPI::ProbeResolutions(std::vector<RESOLUTION_INFO> &r
       m_desktopRes.iScreenHeight= tv_state.display.sdtv.height;
       m_desktopRes.dwFlags      = D3DPRESENTFLAG_INTERLACED;
       m_desktopRes.fRefreshRate = (float)tv_state.display.sdtv.frame_rate;
-      m_desktopRes.fPixelRatio  = get_display_aspect_ratio((SDTV_ASPECT_T)tv_state.display.sdtv.display_options.aspect) / ((float)m_desktopRes.iScreenWidth / (float)m_desktopRes.iScreenHeight);
+      m_desktopRes.fPixelRatio  = tv_state.display.hdmi.display_options.aspect == 0 ? 1.0f : get_display_aspect_ratio((SDTV_ASPECT_T)tv_state.display.sdtv.display_options.aspect) / ((float)m_desktopRes.iScreenWidth / (float)m_desktopRes.iScreenHeight);
     }
 
     SetResolutionString(m_desktopRes);

From 5f56f492ee9849b8745a88007c392bed8e042989 Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Fri, 19 Sep 2014 11:54:49 +0100
Subject: [PATCH 012/100] [dvdplayer/rbp] Add pi specific option to maintain
 vsync with pll adjustment

New A/V sync option in settings/video/playback to do "Adjust PLL".
This uses video clock (so perfect video syncing) but avoids having to resample
or drop/dupe audio packets which is normally required.

Needed updated firmware

[dvdplayeraudio] Add advancedsetting for configuring max pll adjustment

[dvdplayer] Allow pll adjustment to go higher, but tail off more gradually
---
 .../resource.language.en_gb/resources/strings.po   | 24 ++++++++++++++-
 system/settings/settings.xml                       | 14 +++++++++
 xbmc/cores/AudioEngine/Utils/AEUtil.h              |  3 +-
 xbmc/cores/dvdplayer/DVDPlayerAudio.cpp            | 36 +++++++++++++++++++---
 xbmc/cores/dvdplayer/DVDPlayerAudio.h              |  3 ++
 xbmc/linux/RBP.cpp                                 | 14 +++++++++
 xbmc/linux/RBP.h                                   |  1 +
 xbmc/settings/AdvancedSettings.cpp                 |  2 ++
 xbmc/settings/AdvancedSettings.h                   |  1 +
 9 files changed, 91 insertions(+), 7 deletions(-)

diff --git a/addons/resource.language.en_gb/resources/strings.po b/addons/resource.language.en_gb/resources/strings.po
index 52117a2..530b3d4 100644
--- a/addons/resource.language.en_gb/resources/strings.po
+++ b/addons/resource.language.en_gb/resources/strings.po
@@ -6321,7 +6321,22 @@ msgctxt "#13459"
 msgid "Use OMXPlayer for decoding of video files."
 msgstr ""
 
-#empty strings from id 13460 to 13504
+#empty strings from id 13460 to 13499
+
+#: system/settings/settings.xml
+msgctxt "#13500"
+msgid "A/V sync method"
+msgstr ""
+
+#: system/settings/settings.xml
+msgctxt "#13503"
+msgid "Resample audio"
+msgstr ""
+
+#: system/settings/settings.xml
+msgctxt "#13504"
+msgid "Adjust PLL"
+msgstr ""
 
 #: system/settings/settings.xml
 msgctxt "#13505"
@@ -16651,3 +16666,10 @@ msgstr ""
 msgctxt "#38016"
 msgid "%d fps"
 msgstr ""
+
+#. Description of setting "Videos -> Playback -> A/V sync method" with label #13500
+#: system/settings/settings.xml
+msgctxt "#38006"
+msgid "Audio has to stay in sync, this can either be done by resampling, or adjusting the PLL"
+msgstr ""
+
diff --git a/system/settings/settings.xml b/system/settings/settings.xml
index 10e8552..f493675 100644
--- a/system/settings/settings.xml
+++ b/system/settings/settings.xml
@@ -572,6 +572,20 @@
           <default>false</default>
           <control type="toggle" />
         </setting>
+        <setting id="videoplayer.synctype" type="integer" parent="videoplayer.usedisplayasclock" label="13500" help="38006">
+          <level>2</level>
+          <default>2</default> <!-- SYNC_RESAMPLE -->
+          <constraints>
+            <options>
+              <option label="13503">2</option> <!-- SYNC_RESAMPLE -->
+              <option label="13504">3</option> <!-- SYNC_PLLADJUST -->
+            </options>
+          </constraints>
+          <dependencies>
+            <dependency type="enable" setting="videoplayer.usedisplayasclock" operator="is">true</dependency>
+          </dependencies>
+          <control type="spinner" format="string" />
+        </setting>
         <setting id="videoplayer.errorinaspect" type="integer" label="22021" help="36170">
           <level>2</level>
           <default>0</default>
diff --git a/xbmc/cores/AudioEngine/Utils/AEUtil.h b/xbmc/cores/AudioEngine/Utils/AEUtil.h
index 782a9ba..3e0390c 100644
--- a/xbmc/cores/AudioEngine/Utils/AEUtil.h
+++ b/xbmc/cores/AudioEngine/Utils/AEUtil.h
@@ -57,7 +57,8 @@ enum AVSync
 {
   SYNC_DISCON   = 0,
   SYNC_SKIPDUP,
-  SYNC_RESAMPLE
+  SYNC_RESAMPLE,
+  SYNC_PLLADJUST
 };
 
 struct AEDelayStatus
diff --git a/xbmc/cores/dvdplayer/DVDPlayerAudio.cpp b/xbmc/cores/dvdplayer/DVDPlayerAudio.cpp
index 145a622..7b7a223 100644
--- a/xbmc/cores/dvdplayer/DVDPlayerAudio.cpp
+++ b/xbmc/cores/dvdplayer/DVDPlayerAudio.cpp
@@ -24,6 +24,7 @@
 #include "DVDCodecs/Audio/DVDAudioCodec.h"
 #include "DVDCodecs/DVDFactoryCodec.h"
 #include "settings/Settings.h"
+#include "settings/AdvancedSettings.h"
 #include "video/VideoReferenceClock.h"
 #include "utils/log.h"
 #include "utils/MathUtils.h"
@@ -111,6 +112,9 @@ CDVDPlayerAudio::CDVDPlayerAudio(CDVDClock* pClock, CDVDMessageQueue& parent)
   m_started = false;
   m_silence = false;
   m_resampleratio = 1.0;
+  m_plladjust = 1.0;
+  m_last_plladjust = 1.0;
+  m_last_error = 0.0;
   m_synctype = SYNC_DISCON;
   m_setsynctype = SYNC_DISCON;
   m_prevsynctype = -1;
@@ -184,11 +188,13 @@ void CDVDPlayerAudio::OpenStream( CDVDStreamInfo &hints, CDVDAudioCodec* codec )
   m_synctype = SYNC_DISCON;
   m_setsynctype = SYNC_DISCON;
   if (CSettings::Get().GetBool("videoplayer.usedisplayasclock"))
-    m_setsynctype = SYNC_RESAMPLE;
+    m_setsynctype = CSettings::Get().GetInt("videoplayer.synctype");
   m_prevsynctype = -1;
 
   m_error = 0;
   m_errors.Flush();
+  m_plladjust = 1.0;
+  m_last_plladjust = 1.0;
   m_integral = 0;
   m_prevskipped = false;
   m_syncclock = true;
@@ -231,7 +237,6 @@ void CDVDPlayerAudio::CloseStream(bool bWaitForBuffers)
 
   // uninit queue
   m_messageQueue.End();
-
   CLog::Log(LOGNOTICE, "Deleting audio codec");
   if (m_pAudioCodec)
   {
@@ -484,7 +489,11 @@ void CDVDPlayerAudio::UpdatePlayerInfo()
   //print the inverse of the resample ratio, since that makes more sense
   //if the resample ratio is 0.5, then we're playing twice as fast
   if (m_synctype == SYNC_RESAMPLE)
-    s << ", rr:" << fixed << setprecision(5) << 1.0 / m_resampleratio;
+    s << ", rr:" << fixed << setprecision(5) << 1.0 / m_resampleratio << ", err:" << fixed << setprecision(1) << m_last_error * 1e-3 << "ms";
+  if (m_synctype == SYNC_SKIPDUP)
+    s << ", err:" << fixed << setprecision(1) << m_last_error * 1e-3 << "ms";
+  if (m_synctype == SYNC_PLLADJUST)
+    s << ", pll:" << fixed << setprecision(5) << m_last_plladjust << ", err:" << fixed << setprecision(1) << m_last_error * 1e-3 << "ms";
 
   s << ", att:" << fixed << setprecision(1) << log(GetCurrentAttenuation()) * 20.0f << " dB";
 
@@ -639,8 +648,8 @@ void CDVDPlayerAudio::SetSyncType(bool passthrough)
 
   if (m_synctype != m_prevsynctype)
   {
-    const char *synctypes[] = {"clock feedback", "skip/duplicate", "resample", "invalid"};
-    int synctype = (m_synctype >= 0 && m_synctype <= 2) ? m_synctype : 3;
+    const char *synctypes[] = {"clock feedback", "skip/duplicate", "resample", "pll adjust", "invalid"};
+    int synctype = (m_synctype >= 0 && m_synctype <= 3) ? m_synctype : 4;
     CLog::Log(LOGDEBUG, "CDVDPlayerAudio:: synctype set to %i: %s", m_synctype, synctypes[synctype]);
     m_prevsynctype = m_synctype;
   }
@@ -750,7 +759,19 @@ void CDVDPlayerAudio::HandleSyncError(double duration)
       proportional = m_error / DVD_TIME_BASE / proportionaldiv;
     }
     m_resampleratio = 1.0 / m_pClock->GetClockSpeed() + proportional + m_integral;
+    CLog::Log(LOGDEBUG, "CDVDPlayerAudio::%s rr:%.5f error:%.3fms", __FUNCTION__, m_resampleratio, m_error * 1e-3);
+  }
+  else if (m_synctype == SYNC_PLLADJUST)
+  {
+#if defined(TARGET_RASPBERRY_PI)
+    double e = std::max(std::min(m_error / DVD_MSEC_TO_TIME(50), 1.0), -1.0);
+    double adjust = g_advancedSettings.m_maxPllAdjust * 1e-6;
+    m_plladjust = 1.0 + e * adjust;
+    m_last_plladjust = g_RBP.AdjustHDMIClock(m_plladjust);
+    CLog::Log(LOGDEBUG, "CDVDPlayerAudio::%s pll:%.5f (%.5f) error:%.6f e:%.6f a:%f", __FUNCTION__, m_plladjust, m_last_plladjust, m_error, e * adjust, adjust );
+#endif
   }
+  m_last_error = m_error;
 }
 
 bool CDVDPlayerAudio::OutputPacket(DVDAudioFrame &audioframe)
@@ -803,6 +824,7 @@ bool CDVDPlayerAudio::OutputPacket(DVDAudioFrame &audioframe)
     {
       m_dvdAudio.AddPackets(audioframe);
     }
+    m_plladjust = 1.0;
   }
   else if (m_synctype == SYNC_DISCON)
   {
@@ -837,6 +859,10 @@ bool CDVDPlayerAudio::OutputPacket(DVDAudioFrame &audioframe)
     m_dvdAudio.SetResampleRatio(m_resampleratio);
     m_dvdAudio.AddPackets(audioframe);
   }
+  else if (m_synctype == SYNC_PLLADJUST)
+  {
+    m_dvdAudio.AddPackets(audioframe);
+  }
 
   return true;
 }
diff --git a/xbmc/cores/dvdplayer/DVDPlayerAudio.h b/xbmc/cores/dvdplayer/DVDPlayerAudio.h
index 1122a1d..7389754 100644
--- a/xbmc/cores/dvdplayer/DVDPlayerAudio.h
+++ b/xbmc/cores/dvdplayer/DVDPlayerAudio.h
@@ -228,6 +228,9 @@ class CDVDPlayerAudio : public CThread, public IDVDStreamPlayerAudio
   bool   m_prevskipped;
   double m_maxspeedadjust;
   double m_resampleratio; //resample ratio when using SYNC_RESAMPLE, used for the codec info
+  double m_plladjust;    // for display using SYNC_PLLADJUST
+  double m_last_error;    // for display using SYNC_PLLADJUST
+  double m_last_plladjust;    // for display using SYNC_PLLADJUST
 
   struct SInfo
   {
diff --git a/xbmc/linux/RBP.cpp b/xbmc/linux/RBP.cpp
index 68d2694..096ea18 100644
--- a/xbmc/linux/RBP.cpp
+++ b/xbmc/linux/RBP.cpp
@@ -225,4 +225,18 @@ void CRBP::Deinitialize()
   m_initialized     = false;
   m_omx_initialized = false;
 }
+
+double CRBP::AdjustHDMIClock(double adjust)
+{
+  char response[80];
+  vc_gencmd(response, sizeof response, "hdmi_adjust_clock %f", adjust);
+  float new_adjust = 1.0f;
+  char *p = strchr(response, '=');
+  if (p)
+    new_adjust = atof(p+1);
+  CLog::Log(LOGDEBUG, "CRBP::%s(%.4f) = %.4f", __func__, adjust, new_adjust);
+  return new_adjust;
+}
+
+
 #endif
diff --git a/xbmc/linux/RBP.h b/xbmc/linux/RBP.h
index 7fc8b42..b422c89 100644
--- a/xbmc/linux/RBP.h
+++ b/xbmc/linux/RBP.h
@@ -64,6 +64,7 @@ class CRBP
   unsigned char *CaptureDisplay(int width, int height, int *stride, bool swap_red_blue, bool video_only = true);
   DllOMX *GetDllOMX() { return m_OMX ? m_OMX->GetDll() : NULL; }
   void WaitVsync();
+  double AdjustHDMIClock(double adjust);
 
 private:
   DllBcmHost *m_DllBcmHost;
diff --git a/xbmc/settings/AdvancedSettings.cpp b/xbmc/settings/AdvancedSettings.cpp
index d1606a2..344e91b 100644
--- a/xbmc/settings/AdvancedSettings.cpp
+++ b/xbmc/settings/AdvancedSettings.cpp
@@ -111,6 +111,7 @@ void CAdvancedSettings::Initialize()
   m_audioHeadRoom = 0;
   m_ac3Gain = 12.0f;
   m_audioApplyDrc = -1.0f;
+  m_maxPllAdjust = 1000;
   m_dvdplayerIgnoreDTSinWAV = false;
 
   //default hold time of 25 ms, this allows a 20 hertz sine to pass undistorted
@@ -473,6 +474,7 @@ void CAdvancedSettings::ParseSettingsFile(const std::string &file)
   if (pElement)
   {
     XMLUtils::GetFloat(pElement, "ac3downmixgain", m_ac3Gain, -96.0f, 96.0f);
+    XMLUtils::GetInt(pElement, "maxplladjust", m_maxPllAdjust, 0, 1000000);
     XMLUtils::GetInt(pElement, "headroom", m_audioHeadRoom, 0, 12);
     XMLUtils::GetString(pElement, "defaultplayer", m_audioDefaultPlayer);
     // 101 on purpose - can be used to never automark as watched
diff --git a/xbmc/settings/AdvancedSettings.h b/xbmc/settings/AdvancedSettings.h
index 7df1bf7..732b69d 100644
--- a/xbmc/settings/AdvancedSettings.h
+++ b/xbmc/settings/AdvancedSettings.h
@@ -141,6 +141,7 @@ class CAdvancedSettings : public ISettingCallback, public ISettingsHandler
 
     int m_audioHeadRoom;
     float m_ac3Gain;
+    int m_maxPllAdjust;
     std::string m_audioDefaultPlayer;
     float m_audioPlayCountMinimumPercent;
     bool m_dvdplayerIgnoreDTSinWAV;

From 258c2af821a608c1ed92f95e8e063da8d0083a1f Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Wed, 24 Sep 2014 23:13:52 +0100
Subject: [PATCH 013/100] [audio] Add settings option to boost centre channel
 when downmixing

This allows a dB volume increase to be added to centre channel.
This can help improve dialgue in the presence of background music/effects.
It can go up to 30dB for testing purposes, but value of 6 is probably more reasonable.
It is recommended to ensure "Normalise levels on downmix" is enabled when boosting by large values to avoid clipping.

Should work with Pi Sink (dvdplayer/paplayer) and omxplayer
---
 addons/resource.language.en_gb/resources/strings.po        | 14 ++++++++++++++
 system/settings/settings.xml                               | 12 ++++++++++++
 .../Engines/ActiveAE/ActiveAEResampleFFMPEG.cpp            |  7 +++++++
 .../AudioEngine/Engines/ActiveAE/ActiveAEResamplePi.cpp    |  6 ++++++
 xbmc/cores/omxplayer/OMXAudio.cpp                          |  6 ++++++
 5 files changed, 45 insertions(+)

diff --git a/addons/resource.language.en_gb/resources/strings.po b/addons/resource.language.en_gb/resources/strings.po
index 530b3d4..bedbd87 100644
--- a/addons/resource.language.en_gb/resources/strings.po
+++ b/addons/resource.language.en_gb/resources/strings.po
@@ -16673,3 +16673,17 @@ msgctxt "#38006"
 msgid "Audio has to stay in sync, this can either be done by resampling, or adjusting the PLL"
 msgstr ""
 
+#: system/settings/settings.xml
+msgctxt "#38007"
+msgid "Boost centre channel when downmixing"
+msgstr ""
+
+#: system/settings/settings.xml
+msgctxt "#38008"
+msgid "Increase this value to make the dialogue louder compared to background sounds when downmixing multichannel audio"
+msgstr ""
+
+#: system/settings/settings.xml
+msgctxt "#38009"
+msgid "%i dB"
+msgstr ""
diff --git a/system/settings/settings.xml b/system/settings/settings.xml
index f493675..4843ab8 100644
--- a/system/settings/settings.xml
+++ b/system/settings/settings.xml
@@ -2597,6 +2597,18 @@
           <default>true</default>
           <control type="toggle" />
         </setting>
+         <setting id="audiooutput.boostcenter" type="integer" label="38007" help="38008">
+          <level>2</level>
+          <default>0</default>
+          <constraints>
+            <minimum>0</minimum>
+            <step>1</step>
+            <maximum>30</maximum>
+          </constraints>
+          <control type="spinner" format="string">
+            <formatlabel>38009</formatlabel>
+          </control>
+        </setting>
         <setting id="audiooutput.processquality" type="integer" label="13505" help="36169">
           <requirement>HAS_AE_QUALITY_LEVELS</requirement>
           <level>2</level>
diff --git a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEResampleFFMPEG.cpp b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEResampleFFMPEG.cpp
index e4ddf9e..34d0152 100644
--- a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEResampleFFMPEG.cpp
+++ b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEResampleFFMPEG.cpp
@@ -20,6 +20,7 @@
 
 #include "cores/AudioEngine/Utils/AEUtil.h"
 #include "ActiveAEResampleFFMPEG.h"
+#include "settings/Settings.h"
 #include "utils/log.h"
 
 extern "C" {
@@ -105,6 +106,12 @@ bool CActiveAEResampleFFMPEG::Init(uint64_t dst_chan_layout, int dst_channels, i
   {
      av_opt_set_double(m_pContext, "rematrix_maxval", 1.0, 0);
   }
+  int boost_center = CSettings::Get().GetInt("audiooutput.boostcenter");
+  if (boost_center)
+  {
+    float gain = pow(10.0f, ((float)(-3 + boost_center))/20.0f);
+    av_opt_set_double(m_pContext, "center_mix_level", gain, 0);
+  }
 
   if (remapLayout)
   {
diff --git a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEResamplePi.cpp b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEResamplePi.cpp
index 78071493..759ba7b 100644
--- a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEResamplePi.cpp
+++ b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEResamplePi.cpp
@@ -164,6 +164,12 @@ bool CActiveAEResamplePi::Init(uint64_t dst_chan_layout, int dst_channels, int d
   {
     av_opt_set_double(m_pContext, "rematrix_maxval", 1.0, 0);
   }
+  int boost_center = CSettings::Get().GetInt("audiooutput.boostcenter");
+  if (boost_center)
+  {
+    float gain = pow(10.0f, ((float)(-3 + boost_center))/20.0f);
+    av_opt_set_double(m_pContext, "center_mix_level", gain, 0);
+  }
 
   if (remapLayout)
   {
diff --git a/xbmc/cores/omxplayer/OMXAudio.cpp b/xbmc/cores/omxplayer/OMXAudio.cpp
index f99c0e6..1911189 100644
--- a/xbmc/cores/omxplayer/OMXAudio.cpp
+++ b/xbmc/cores/omxplayer/OMXAudio.cpp
@@ -641,6 +641,12 @@ bool COMXAudio::Initialize(AEAudioFormat format, OMXClock *clock, CDVDStreamInfo
     {
        av_opt_set_double(m_pContext, "rematrix_maxval", 1.0, 0);
     }
+    int boost_center = CSettings::Get().GetInt("audiooutput.boostcenter");
+    if (boost_center)
+    {
+      float gain = pow(10.0f, ((float)(-3 + boost_center))/20.0f);
+      av_opt_set_double(m_pContext, "center_mix_level", gain, 0);
+    }
 
     // stereo upmix
     if (upmix && m_src_channels == 2 && m_dst_channels > 2)

From 1b614d6e694731175e5f4d3dcc98c306bdad9605 Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Mon, 27 Oct 2014 15:23:51 +0000
Subject: [PATCH 014/100] [rbp] Default extract thumbnails to false

It can take 80 seconds for a single file on a Pi. It can cause crashes with out-of-memory errors.
It genereates a lot of support issues. Best to default to disabled and let users enable it if they must
---
 system/settings/rbp.xml | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/system/settings/rbp.xml b/system/settings/rbp.xml
index 50fe36a..a54a4c4 100644
--- a/system/settings/rbp.xml
+++ b/system/settings/rbp.xml
@@ -35,6 +35,16 @@
         </setting>
       </group>
     </category>
+    <category id="myvideos">
+      <group id="1">
+        <setting id="myvideos.extractflags">
+          <default>false</default>
+        </setting>
+        <setting id="myvideos.extractthumb">
+          <default>false</default>
+        </setting>
+      </group>
+    </category>
   </section>
 
   <section id="system">

From c45f209653ef09eeb39dc379e1905c5b303c416f Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Tue, 10 Feb 2015 15:29:16 +0000
Subject: [PATCH 015/100] [libcec] Add repeating keypress patch from
 popcornmix' repo

---
 tools/depends/target/libcec/Makefile         |   1 +
 tools/depends/target/libcec/popcornmix.patch | 859 +++++++++++++++++++++++++++
 2 files changed, 860 insertions(+)
 create mode 100644 tools/depends/target/libcec/popcornmix.patch

diff --git a/tools/depends/target/libcec/Makefile b/tools/depends/target/libcec/Makefile
index f54af9e..ddf9963 100644
--- a/tools/depends/target/libcec/Makefile
+++ b/tools/depends/target/libcec/Makefile
@@ -21,6 +21,7 @@ $(TARBALLS_LOCATION)/$(ARCHIVE):
 $(PLATFORM): $(TARBALLS_LOCATION)/$(ARCHIVE) $(DEPS)
 	rm -rf $(PLATFORM); mkdir -p $(PLATFORM)/build
 	cd $(PLATFORM); $(ARCHIVE_TOOL) $(ARCHIVE_TOOL_FLAGS) $(TARBALLS_LOCATION)/$(ARCHIVE)
+	cd $(PLATFORM); patch -p1 < ../popcornmix.patch
 	cd $(PLATFORM)/build; $(CMAKE) -DBUILD_SHARED_LIBS=1 -DSKIP_PYTHON_WRAPPER:STRING=1 -DCMAKE_INSTALL_LIBDIR=$(PREFIX)/lib ..
 
 $(LIBDYLIB): $(PLATFORM)
diff --git a/tools/depends/target/libcec/popcornmix.patch b/tools/depends/target/libcec/popcornmix.patch
new file mode 100644
index 0000000..8366a69
--- /dev/null
+++ b/tools/depends/target/libcec/popcornmix.patch
@@ -0,0 +1,859 @@
+From ec982e9800ae312972d306b67779215a2add6cde Mon Sep 17 00:00:00 2001
+From: popcornmix <popcornmix@gmail.com>
+Date: Fri, 24 Oct 2014 13:45:21 +0100
+Subject: [PATCH 1/6] Make released key polling wait for exact time until key
+ gets released
+
+---
+ src/libcec/CECClient.cpp    | 16 ++++++++++++++--
+ src/libcec/CECClient.h      |  2 +-
+ src/libcec/CECProcessor.cpp |  8 +++++---
+ src/libcec/LibCEC.cpp       | 10 ++++++++--
+ src/libcec/LibCEC.h         |  4 +++-
+ 5 files changed, 31 insertions(+), 9 deletions(-)
+
+diff --git a/src/libcec/CECClient.cpp b/src/libcec/CECClient.cpp
+index 35c2d3e..e307c0e 100644
+--- a/src/libcec/CECClient.cpp
++++ b/src/libcec/CECClient.cpp
+@@ -1067,7 +1067,7 @@ void CCECClient::SetCurrentButton(const cec_user_control_code iButtonCode)
+   AddKey(key);
+ }
+ 
+-void CCECClient::CheckKeypressTimeout(void)
++uint16_t CCECClient::CheckKeypressTimeout(void)
+ {
+   cec_keypress key;
+ 
+@@ -1091,12 +1091,24 @@ void CCECClient::CheckKeypressTimeout(void)
+     }
+     else
+     {
+-      return;
++      // time when this keypress will be released and we'd like to be called again
++      unsigned int timeout = CEC_PROCESSOR_SIGNAL_WAIT_TIME;
++      if (m_iCurrentButton != CEC_USER_CONTROL_CODE_UNKNOWN && m_iCurrentButton == comboKey && iTimeoutMs > 0)
++        timeout = iTimeoutMs - (iNow - m_buttontime) + 1;
++      else if (m_iCurrentButton != CEC_USER_CONTROL_CODE_UNKNOWN && m_iCurrentButton != comboKey)
++        timeout = CEC_BUTTON_TIMEOUT - (iNow - m_buttontime) + 1;
++      if (timeout > CEC_PROCESSOR_SIGNAL_WAIT_TIME)
++      {
++        LIB_CEC->AddLog(CEC_LOG_ERROR, "Unexpected timeout: %d (%.3f %.3f %.3f) k:%02x", timeout, iNow*1e-3, m_buttontime*1e-3, CEC_BUTTON_TIMEOUT*1e-3, m_iCurrentButton);
++        timeout = CEC_PROCESSOR_SIGNAL_WAIT_TIME;
++      }
++      return timeout;
+     }
+   }
+ 
+   LIB_CEC->AddLog(CEC_LOG_DEBUG, "key auto-released: %s (%1x)", ToString(key.keycode), key.keycode);
+   QueueAddKey(key);
++  return CEC_PROCESSOR_SIGNAL_WAIT_TIME;
+ }
+ 
+ bool CCECClient::EnableCallbacks(void *cbParam, ICECCallbacks *callbacks)
+diff --git a/src/libcec/CECClient.h b/src/libcec/CECClient.h
+index 12f8a3b..c9ce5e3 100644
+--- a/src/libcec/CECClient.h
++++ b/src/libcec/CECClient.h
+@@ -272,7 +272,7 @@ namespace CEC
+     virtual void                  AddKey(bool bSendComboKey = false);
+     virtual void                  AddKey(const cec_keypress &key);
+     virtual void                  SetCurrentButton(const cec_user_control_code iButtonCode);
+-    virtual void                  CheckKeypressTimeout(void);
++    virtual uint16_t              CheckKeypressTimeout(void);
+     virtual void                  SourceActivated(const cec_logical_address logicalAddress);
+     virtual void                  SourceDeactivated(const cec_logical_address logicalAddress);
+ 
+diff --git a/src/libcec/CECProcessor.cpp b/src/libcec/CECProcessor.cpp
+index 99f71aa..604b950 100644
+--- a/src/libcec/CECProcessor.cpp
++++ b/src/libcec/CECProcessor.cpp
+@@ -52,7 +52,6 @@
+ using namespace CEC;
+ using namespace PLATFORM;
+ 
+-#define CEC_PROCESSOR_SIGNAL_WAIT_TIME 1000
+ #define ACTIVE_SOURCE_CHECK_INTERVAL   500
+ #define TV_PRESENT_CHECK_INTERVAL      30000
+ 
+@@ -260,6 +259,7 @@ bool CCECProcessor::OnCommandReceived(const cec_command &command)
+ 
+ void *CCECProcessor::Process(void)
+ {
++  uint16_t timeout = CEC_PROCESSOR_SIGNAL_WAIT_TIME;
+   m_libcec->AddLog(CEC_LOG_DEBUG, "processor thread started");
+ 
+   if (!m_connCheck)
+@@ -274,13 +274,13 @@ void *CCECProcessor::Process(void)
+   while (!IsStopped() && m_communication->IsOpen())
+   {
+     // wait for a new incoming command, and process it
+-    if (m_inBuffer.Pop(command, CEC_PROCESSOR_SIGNAL_WAIT_TIME))
++    if (m_inBuffer.Pop(command, timeout))
+       ProcessCommand(command);
+ 
+     if (CECInitialised() && !IsStopped())
+     {
+       // check clients for keypress timeouts
+-      m_libcec->CheckKeypressTimeout();
++      timeout = m_libcec->CheckKeypressTimeout();
+ 
+       // check if we need to replace handlers
+       ReplaceHandlers();
+@@ -311,6 +311,8 @@ void *CCECProcessor::Process(void)
+         tvPresentCheck.Init(TV_PRESENT_CHECK_INTERVAL);
+       }
+     }
++    else
++      timeout = CEC_PROCESSOR_SIGNAL_WAIT_TIME;
+   }
+ 
+   return NULL;
+diff --git a/src/libcec/LibCEC.cpp b/src/libcec/LibCEC.cpp
+index af36b79..5ccb8dd 100644
+--- a/src/libcec/LibCEC.cpp
++++ b/src/libcec/LibCEC.cpp
+@@ -361,11 +361,17 @@ bool CLibCEC::IsValidPhysicalAddress(uint16_t iPhysicalAddress)
+          iPhysicalAddress <= CEC_MAX_PHYSICAL_ADDRESS;
+ }
+ 
+-void CLibCEC::CheckKeypressTimeout(void)
++uint16_t CLibCEC::CheckKeypressTimeout(void)
+ {
++  uint16_t timeout = CEC_PROCESSOR_SIGNAL_WAIT_TIME;
+   // check all clients
+   for (std::vector<CECClientPtr>::iterator it = m_clients.begin(); it != m_clients.end(); it++)
+-    (*it)->CheckKeypressTimeout();
++  {
++    uint16_t t = (*it)->CheckKeypressTimeout();
++    if (t < timeout)
++      timeout = t;
++  }
++  return timeout;
+ }
+ 
+ void CLibCEC::AddLog(const cec_log_level level, const char *strFormat, ...)
+diff --git a/src/libcec/LibCEC.h b/src/libcec/LibCEC.h
+index 6d9a229..d9d1e7b 100644
+--- a/src/libcec/LibCEC.h
++++ b/src/libcec/LibCEC.h
+@@ -39,6 +39,8 @@
+ #include "CECTypeUtils.h"
+ #include <memory>
+ 
++#define CEC_PROCESSOR_SIGNAL_WAIT_TIME 1000
++
+ namespace CEC
+ {
+   class CAdapterCommunication;
+@@ -125,7 +127,7 @@ namespace CEC
+ 
+       void AddLog(const cec_log_level level, const char *strFormat, ...);
+       void AddCommand(const cec_command &command);
+-      void CheckKeypressTimeout(void);
++      uint16_t CheckKeypressTimeout(void);
+       void Alert(const libcec_alert type, const libcec_parameter &param);
+ 
+       static bool IsValidPhysicalAddress(uint16_t iPhysicalAddress);
+-- 
+1.9.1
+
+
+From 41f0f3ec9ac136da3565c96fd5a7075499f3938d Mon Sep 17 00:00:00 2001
+From: popcornmix <popcornmix@gmail.com>
+Date: Fri, 24 Oct 2014 13:51:34 +0100
+Subject: [PATCH 2/6] Keep track of time since initial button press and last
+ button update
+
+---
+ src/libcec/CECClient.cpp | 44 +++++++++++++++++++++++++++-----------------
+ src/libcec/CECClient.h   |  3 ++-
+ 2 files changed, 29 insertions(+), 18 deletions(-)
+
+diff --git a/src/libcec/CECClient.cpp b/src/libcec/CECClient.cpp
+index e307c0e..e7935b9 100644
+--- a/src/libcec/CECClient.cpp
++++ b/src/libcec/CECClient.cpp
+@@ -54,7 +54,8 @@ CCECClient::CCECClient(CCECProcessor *processor, const libcec_configuration &con
+     m_bInitialised(false),
+     m_bRegistered(false),
+     m_iCurrentButton(CEC_USER_CONTROL_CODE_UNKNOWN),
+-    m_buttontime(0),
++    m_initialButtontime(0),
++    m_updateButtontime(0),
+     m_iPreventForwardingPowerOffCommand(0),
+     m_iLastKeypressTime(0)
+ {
+@@ -981,9 +982,10 @@ void CCECClient::AddKey(bool bSendComboKey /* = false */)
+     CLockObject lock(m_mutex);
+     if (m_iCurrentButton != CEC_USER_CONTROL_CODE_UNKNOWN)
+     {
+-      key.duration = (unsigned int) (GetTimeMs() - m_buttontime);
++      unsigned int duration = (unsigned int) (GetTimeMs() - m_updateButtontime);
++      key.duration = (unsigned int) (GetTimeMs() - m_initialButtontime);
+ 
+-      if (key.duration > m_configuration.iComboKeyTimeoutMs ||
++      if (duration > m_configuration.iComboKeyTimeoutMs ||
+           m_configuration.iComboKeyTimeoutMs == 0 ||
+           m_iCurrentButton != m_configuration.comboKey ||
+           bSendComboKey)
+@@ -991,14 +993,15 @@ void CCECClient::AddKey(bool bSendComboKey /* = false */)
+         key.keycode = m_iCurrentButton;
+ 
+         m_iCurrentButton = CEC_USER_CONTROL_CODE_UNKNOWN;
+-        m_buttontime = 0;
++        m_initialButtontime = 0;
++        m_updateButtontime = 0;
+       }
+     }
+   }
+ 
+   if (key.keycode != CEC_USER_CONTROL_CODE_UNKNOWN)
+   {
+-    LIB_CEC->AddLog(CEC_LOG_DEBUG, "key released: %s (%1x)", ToString(key.keycode), key.keycode);
++    LIB_CEC->AddLog(CEC_LOG_DEBUG, "key released: %s (%1x) D:%dms", ToString(key.keycode), key.keycode, key.duration);
+     QueueAddKey(key);
+   }
+ }
+@@ -1012,7 +1015,7 @@ void CCECClient::AddKey(const cec_keypress &key)
+     AddKey();
+     return;
+   }
+-
++  bool isrepeat = false;
+   cec_keypress transmitKey(key);
+   cec_user_control_code comboKey(m_configuration.clientVersion >= LIBCEC_VERSION_TO_UINT(2, 0, 5) ?
+       m_configuration.comboKey : CEC_USER_CONTROL_CODE_STOP);
+@@ -1035,22 +1038,27 @@ void CCECClient::AddKey(const cec_keypress &key)
+         AddKey(true);
+     }
+ 
++    LIB_CEC->AddLog(CEC_LOG_DEBUG, "key pressed: %s (%1x) current(%lx) duration(%d)", ToString(transmitKey.keycode), transmitKey.keycode, m_iCurrentButton, key.duration);
++
+     if (m_iCurrentButton == key.keycode)
+     {
+-      m_buttontime = GetTimeMs();
++      m_updateButtontime = GetTimeMs();
++      isrepeat = true;
+     }
+     else
+     {
+-      AddKey();
++      if (m_iCurrentButton != transmitKey.keycode)
++        AddKey();
+       if (key.duration == 0)
+       {
+         m_iCurrentButton = transmitKey.keycode;
+-        m_buttontime = m_iCurrentButton == CEC_USER_CONTROL_CODE_UNKNOWN || key.duration > 0 ? 0 : GetTimeMs();
++        m_initialButtontime = m_iCurrentButton == CEC_USER_CONTROL_CODE_UNKNOWN || key.duration > 0 ? 0 : GetTimeMs();
++        m_updateButtontime = m_initialButtontime;
+       }
+     }
+   }
+ 
+-  if (key.keycode != comboKey || key.duration > 0)
++  if (!isrepeat && (key.keycode != comboKey || key.duration > 0))
+   {
+     LIB_CEC->AddLog(CEC_LOG_DEBUG, "key pressed: %s (%1x)", ToString(transmitKey.keycode), transmitKey.keycode);
+     QueueAddKey(transmitKey);
+@@ -1074,32 +1082,34 @@ uint16_t CCECClient::CheckKeypressTimeout(void)
+   {
+     CLockObject lock(m_mutex);
+     uint64_t iNow = GetTimeMs();
++    LIB_CEC->AddLog(CEC_LOG_DEBUG, "%s T:%.3f", __FUNCTION__, iNow*1e-3);
+     cec_user_control_code comboKey(m_configuration.clientVersion >= LIBCEC_VERSION_TO_UINT(2, 0, 5) ?
+         m_configuration.comboKey : CEC_USER_CONTROL_CODE_STOP);
+     uint32_t iTimeoutMs(m_configuration.clientVersion >= LIBCEC_VERSION_TO_UINT(2, 0, 5) ?
+         m_configuration.iComboKeyTimeoutMs : CEC_DEFAULT_COMBO_TIMEOUT_MS);
+ 
+     if (m_iCurrentButton != CEC_USER_CONTROL_CODE_UNKNOWN &&
+-          ((m_iCurrentButton == comboKey && iTimeoutMs > 0 && iNow - m_buttontime > iTimeoutMs) ||
+-          (m_iCurrentButton != comboKey && iNow - m_buttontime > CEC_BUTTON_TIMEOUT)))
++          ((m_iCurrentButton == comboKey && iTimeoutMs > 0 && iNow - m_updateButtontime > iTimeoutMs) ||
++          (m_iCurrentButton != comboKey && iNow - m_updateButtontime > CEC_BUTTON_TIMEOUT)))
+     {
+-      key.duration = (unsigned int) (iNow - m_buttontime);
++      key.duration = (unsigned int) (iNow - m_initialButtontime);
+       key.keycode = m_iCurrentButton;
+ 
+       m_iCurrentButton = CEC_USER_CONTROL_CODE_UNKNOWN;
+-      m_buttontime = 0;
++      m_initialButtontime = 0;
++      m_updateButtontime = 0;
+     }
+     else
+     {
+       // time when this keypress will be released and we'd like to be called again
+       unsigned int timeout = CEC_PROCESSOR_SIGNAL_WAIT_TIME;
+       if (m_iCurrentButton != CEC_USER_CONTROL_CODE_UNKNOWN && m_iCurrentButton == comboKey && iTimeoutMs > 0)
+-        timeout = iTimeoutMs - (iNow - m_buttontime) + 1;
++        timeout = iTimeoutMs - (iNow - m_updateButtontime) + 1;
+       else if (m_iCurrentButton != CEC_USER_CONTROL_CODE_UNKNOWN && m_iCurrentButton != comboKey)
+-        timeout = CEC_BUTTON_TIMEOUT - (iNow - m_buttontime) + 1;
++        timeout = CEC_BUTTON_TIMEOUT - (iNow - m_updateButtontime) + 1;
+       if (timeout > CEC_PROCESSOR_SIGNAL_WAIT_TIME)
+       {
+-        LIB_CEC->AddLog(CEC_LOG_ERROR, "Unexpected timeout: %d (%.3f %.3f %.3f) k:%02x", timeout, iNow*1e-3, m_buttontime*1e-3, CEC_BUTTON_TIMEOUT*1e-3, m_iCurrentButton);
++        LIB_CEC->AddLog(CEC_LOG_ERROR, "Unexpected timeout: %d (%.3f %.3f %.3f) k:%02x", timeout, iNow*1e-3, m_updateButtontime*1e-3, CEC_BUTTON_TIMEOUT*1e-3, m_iCurrentButton);
+         timeout = CEC_PROCESSOR_SIGNAL_WAIT_TIME;
+       }
+       return timeout;
+diff --git a/src/libcec/CECClient.h b/src/libcec/CECClient.h
+index c9ce5e3..611c68b 100644
+--- a/src/libcec/CECClient.h
++++ b/src/libcec/CECClient.h
+@@ -404,7 +404,8 @@ namespace CEC
+     PLATFORM::CMutex      m_mutex;                             /**< mutex for changes to this instance */
+     PLATFORM::CMutex      m_cbMutex;                           /**< mutex that is held when doing anything with callbacks */
+     cec_user_control_code m_iCurrentButton;                    /**< the control code of the button that's currently held down (if any) */
+-    int64_t               m_buttontime;                        /**< the timestamp when the button was pressed (in seconds since epoch), or 0 if none was pressed. */
++    int64_t               m_initialButtontime;                 /**< the timestamp when the button was initially pressed (in seconds since epoch), or 0 if none was pressed. */
++    int64_t               m_updateButtontime;                  /**< the timestamp when the button was updated (in seconds since epoch), or 0 if none was pressed. */
+     int64_t               m_iPreventForwardingPowerOffCommand; /**< prevent forwarding standby commands until this time */
+     int64_t               m_iLastKeypressTime;                 /**< last time a key press was sent to the client */
+     cec_keypress          m_lastKeypress;                      /**< the last key press that was sent to the client */
+-- 
+1.9.1
+
+
+From 273ead6980b69eddf98810eb1eb33d94a7d74fce Mon Sep 17 00:00:00 2001
+From: popcornmix <popcornmix@gmail.com>
+Date: Tue, 28 Oct 2014 00:09:18 +0000
+Subject: [PATCH 3/6] Support repeating button presses with configurable repeat
+ rate
+
+---
+ include/cectypes.h                               |   6 ++
+ src/libcec/CECClient.cpp                         | 100 +++++++++++++++++++----
+ src/libcec/CECClient.h                           |   6 +-
+ src/libcec/implementations/CECCommandHandler.cpp |   2 +-
+ 4 files changed, 96 insertions(+), 18 deletions(-)
+
+diff --git a/include/cectypes.h b/include/cectypes.h
+index acff259..8f098ef 100644
+--- a/include/cectypes.h
++++ b/include/cectypes.h
+@@ -1493,6 +1493,8 @@ struct libcec_configuration
+                                                    XXX changed meaning in 2.2.0 to not break binary compatibility. next major (3.0) release will fix it in a nicer way */
+   cec_user_control_code comboKey;             /*!< key code that initiates combo keys. defaults to CEC_USER_CONTROL_CODE_F1_BLUE. CEC_USER_CONTROL_CODE_UNKNOWN to disable. added in 2.0.5 */
+   uint32_t              iComboKeyTimeoutMs;   /*!< timeout until the combo key is sent as normal keypress */
++  uint32_t              iButtonRepeatRateMs;  /*!< rate at which buttons autorepeat. 0 means rely on CEC device */
++  uint32_t              iButtonReleaseDelayMs;/*!< duration after last update until a button is considered released */
+ 
+ #ifdef __cplusplus
+    libcec_configuration(void) { Clear(); }
+@@ -1527,6 +1529,8 @@ struct libcec_configuration
+                  cecVersion                == other.cecVersion &&
+                  adapterType               == other.adapterType &&
+                  iDoubleTapTimeout50Ms     == other.iDoubleTapTimeout50Ms &&
++                 iButtonRepeatRateMs       == other.iButtonRepeatRateMs &&
++                 iButtonReleaseDelayMs     == other.iButtonReleaseDelayMs &&
+                  (other.clientVersion <= LIBCEC_VERSION_TO_UINT(2, 0, 4) || comboKey            == other.comboKey) &&
+                  (other.clientVersion <= LIBCEC_VERSION_TO_UINT(2, 0, 4) || iComboKeyTimeoutMs  == other.iComboKeyTimeoutMs) &&
+                  (other.clientVersion <  LIBCEC_VERSION_TO_UINT(2, 1, 0) || bPowerOnScreensaver == other.bPowerOnScreensaver));
+@@ -1567,6 +1571,8 @@ struct libcec_configuration
+     iDoubleTapTimeout50Ms =           CEC_DOUBLE_TAP_TIMEOUT_50_MS;
+     comboKey =                        CEC_USER_CONTROL_CODE_STOP;
+     iComboKeyTimeoutMs =              CEC_DEFAULT_COMBO_TIMEOUT_MS;
++    iButtonRepeatRateMs =             0;
++    iButtonReleaseDelayMs =           CEC_BUTTON_TIMEOUT;
+ 
+     memset(strDeviceName, 0, 13);
+     deviceTypes.Clear();
+diff --git a/src/libcec/CECClient.cpp b/src/libcec/CECClient.cpp
+index e7935b9..598628d 100644
+--- a/src/libcec/CECClient.cpp
++++ b/src/libcec/CECClient.cpp
+@@ -56,6 +56,10 @@ CCECClient::CCECClient(CCECProcessor *processor, const libcec_configuration &con
+     m_iCurrentButton(CEC_USER_CONTROL_CODE_UNKNOWN),
+     m_initialButtontime(0),
+     m_updateButtontime(0),
++    m_repeatButtontime(0),
++    m_releaseButtontime(0),
++    m_pressedButtoncount(0),
++    m_releasedButtoncount(0),
+     m_iPreventForwardingPowerOffCommand(0),
+     m_iLastKeypressTime(0)
+ {
+@@ -851,6 +855,9 @@ bool CCECClient::GetCurrentConfiguration(libcec_configuration &configuration)
+   configuration.bMonitorOnly              = m_configuration.bMonitorOnly;
+   configuration.cecVersion                = m_configuration.cecVersion;
+   configuration.adapterType               = m_configuration.adapterType;
++  configuration.iDoubleTapTimeout50Ms     = m_configuration.iDoubleTapTimeout50Ms;
++  configuration.iButtonRepeatRateMs       = m_configuration.iButtonRepeatRateMs;
++  configuration.iButtonReleaseDelayMs     = m_configuration.iButtonReleaseDelayMs;
+ 
+   return true;
+ }
+@@ -894,6 +901,9 @@ bool CCECClient::SetConfiguration(const libcec_configuration &configuration)
+     m_configuration.cecVersion                 = configuration.cecVersion;
+     m_configuration.adapterType                = configuration.adapterType;
+     m_configuration.iDoubleTapTimeout50Ms      = configuration.iDoubleTapTimeout50Ms;
++    m_configuration.iButtonRepeatRateMs        = configuration.iButtonRepeatRateMs;
++    m_configuration.iButtonReleaseDelayMs      = configuration.iButtonReleaseDelayMs;
++
+     m_configuration.deviceTypes.Add(configuration.deviceTypes[0]);
+ 
+     if (m_configuration.clientVersion >= LIBCEC_VERSION_TO_UINT(2, 0, 5))
+@@ -950,6 +960,7 @@ bool CCECClient::SetConfiguration(const libcec_configuration &configuration)
+     primary->ActivateSource();
+   }
+ 
++  LIB_CEC->AddLog(CEC_LOG_DEBUG, "%s: %d:%d:%d", __FUNCTION__, DoubleTapTimeoutMS(), m_configuration.iButtonRepeatRateMs, m_configuration.iButtonReleaseDelayMs);
+   return true;
+ }
+ 
+@@ -973,11 +984,15 @@ void CCECClient::AddCommand(const cec_command &command)
+   }
+ }
+ 
+-void CCECClient::AddKey(bool bSendComboKey /* = false */)
++void CCECClient::AddKey(bool bSendComboKey /* = false */, bool bButtonRelease /* = false */)
+ {
+   cec_keypress key;
+   key.keycode = CEC_USER_CONTROL_CODE_UNKNOWN;
+ 
++  // we ignore button releases when supporting repeating keys
++  if (bButtonRelease && m_configuration.iButtonRepeatRateMs && m_configuration.iButtonReleaseDelayMs)
++    return;
++
+   {
+     CLockObject lock(m_mutex);
+     if (m_iCurrentButton != CEC_USER_CONTROL_CODE_UNKNOWN)
+@@ -995,6 +1010,10 @@ void CCECClient::AddKey(bool bSendComboKey /* = false */)
+         m_iCurrentButton = CEC_USER_CONTROL_CODE_UNKNOWN;
+         m_initialButtontime = 0;
+         m_updateButtontime = 0;
++        m_repeatButtontime = 0;
++        m_releaseButtontime = 0;
++        m_pressedButtoncount = 0;
++        m_releasedButtoncount = 0;
+       }
+     }
+   }
+@@ -1012,6 +1031,7 @@ void CCECClient::AddKey(const cec_keypress &key)
+       key.keycode < CEC_USER_CONTROL_CODE_SELECT)
+   {
+     // send back the previous key if there is one
++    LIB_CEC->AddLog(CEC_LOG_DEBUG, "Unexpected key %s (%1x) D:%dms", ToString(key.keycode), key.keycode, key.duration);
+     AddKey();
+     return;
+   }
+@@ -1035,7 +1055,10 @@ void CCECClient::AddKey(const cec_keypress &key)
+         transmitKey.keycode = CEC_USER_CONTROL_CODE_DOT;
+       // default, send back the previous key
+       else
++      {
++        LIB_CEC->AddLog(CEC_LOG_DEBUG, "Combo key %s (%1x) D%dms:", ToString(key.keycode), key.keycode, key.duration);
+         AddKey(true);
++      }
+     }
+ 
+     LIB_CEC->AddLog(CEC_LOG_DEBUG, "key pressed: %s (%1x) current(%lx) duration(%d)", ToString(transmitKey.keycode), transmitKey.keycode, m_iCurrentButton, key.duration);
+@@ -1043,17 +1066,44 @@ void CCECClient::AddKey(const cec_keypress &key)
+     if (m_iCurrentButton == key.keycode)
+     {
+       m_updateButtontime = GetTimeMs();
+-      isrepeat = true;
++      m_releaseButtontime = m_updateButtontime + (m_configuration.iButtonReleaseDelayMs ? m_configuration.iButtonReleaseDelayMs : CEC_BUTTON_TIMEOUT);
++      // want to have seen some updated before considering a repeat
++      if (m_configuration.iButtonRepeatRateMs)
++      {
++        if (!m_repeatButtontime && m_pressedButtoncount > 1)
++          m_repeatButtontime = m_initialButtontime + DoubleTapTimeoutMS();
++        isrepeat = true;
++      }
++      m_pressedButtoncount++;
+     }
+     else
+     {
+       if (m_iCurrentButton != transmitKey.keycode)
++      {
++        LIB_CEC->AddLog(CEC_LOG_DEBUG, "Changed key %s (%1x) D:%dms cur:%lx", ToString(transmitKey.keycode), transmitKey.keycode, transmitKey.duration, m_iCurrentButton);
+         AddKey();
++      }
+       if (key.duration == 0)
+       {
+         m_iCurrentButton = transmitKey.keycode;
+-        m_initialButtontime = m_iCurrentButton == CEC_USER_CONTROL_CODE_UNKNOWN || key.duration > 0 ? 0 : GetTimeMs();
+-        m_updateButtontime = m_initialButtontime;
++        if (m_iCurrentButton == CEC_USER_CONTROL_CODE_UNKNOWN)
++        {
++          m_initialButtontime = 0;
++          m_updateButtontime = 0;
++          m_repeatButtontime = 0;
++          m_releaseButtontime = 0;
++          m_pressedButtoncount = 0;
++          m_releasedButtoncount = 0;
++        }
++        else
++        {
++          m_initialButtontime = GetTimeMs();
++          m_updateButtontime = m_initialButtontime;
++          m_repeatButtontime = 0; // set this on next update
++          m_releaseButtontime = m_initialButtontime + (m_configuration.iButtonReleaseDelayMs ? m_configuration.iButtonReleaseDelayMs : CEC_BUTTON_TIMEOUT);
++          m_pressedButtoncount = 1;
++          m_releasedButtoncount = 0;
++        }
+       }
+     }
+   }
+@@ -1072,12 +1122,16 @@ void CCECClient::SetCurrentButton(const cec_user_control_code iButtonCode)
+   key.duration = 0;
+   key.keycode = iButtonCode;
+ 
++  LIB_CEC->AddLog(CEC_LOG_DEBUG, "SetCurrentButton %s (%1x) D:%dms cur:%lx", ToString(key.keycode), key.keycode, key.duration);
+   AddKey(key);
+ }
+ 
+ uint16_t CCECClient::CheckKeypressTimeout(void)
+ {
++  // time when we'd like to be called again
++  unsigned int timeout = CEC_PROCESSOR_SIGNAL_WAIT_TIME;
+   cec_keypress key;
++  key.keycode = CEC_USER_CONTROL_CODE_UNKNOWN;
+ 
+   {
+     CLockObject lock(m_mutex);
+@@ -1089,8 +1143,8 @@ uint16_t CCECClient::CheckKeypressTimeout(void)
+         m_configuration.iComboKeyTimeoutMs : CEC_DEFAULT_COMBO_TIMEOUT_MS);
+ 
+     if (m_iCurrentButton != CEC_USER_CONTROL_CODE_UNKNOWN &&
+-          ((m_iCurrentButton == comboKey && iTimeoutMs > 0 && iNow - m_updateButtontime > iTimeoutMs) ||
+-          (m_iCurrentButton != comboKey && iNow - m_updateButtontime > CEC_BUTTON_TIMEOUT)))
++          ((m_iCurrentButton == comboKey && iTimeoutMs > 0 && iNow - m_updateButtontime >= iTimeoutMs) ||
++          (m_iCurrentButton != comboKey && m_releaseButtontime && iNow >= (uint64_t)m_releaseButtontime)))
+     {
+       key.duration = (unsigned int) (iNow - m_initialButtontime);
+       key.keycode = m_iCurrentButton;
+@@ -1098,27 +1152,41 @@ uint16_t CCECClient::CheckKeypressTimeout(void)
+       m_iCurrentButton = CEC_USER_CONTROL_CODE_UNKNOWN;
+       m_initialButtontime = 0;
+       m_updateButtontime = 0;
++      m_repeatButtontime = 0;
++      m_releaseButtontime = 0;
++      m_pressedButtoncount = 0;
++      m_releasedButtoncount = 0;
++    }
++    else if (m_iCurrentButton != CEC_USER_CONTROL_CODE_UNKNOWN &&
++          (m_iCurrentButton != comboKey && m_repeatButtontime && iNow >= (uint64_t)m_repeatButtontime))
++    {
++      key.duration = 0;
++      key.keycode = m_iCurrentButton;
++      m_repeatButtontime = iNow + m_configuration.iButtonRepeatRateMs;
++      timeout = std::min((uint64_t)timeout, m_repeatButtontime - iNow);
+     }
+     else
+     {
+-      // time when this keypress will be released and we'd like to be called again
+-      unsigned int timeout = CEC_PROCESSOR_SIGNAL_WAIT_TIME;
+       if (m_iCurrentButton != CEC_USER_CONTROL_CODE_UNKNOWN && m_iCurrentButton == comboKey && iTimeoutMs > 0)
+-        timeout = iTimeoutMs - (iNow - m_updateButtontime) + 1;
+-      else if (m_iCurrentButton != CEC_USER_CONTROL_CODE_UNKNOWN && m_iCurrentButton != comboKey)
+-        timeout = CEC_BUTTON_TIMEOUT - (iNow - m_updateButtontime) + 1;
++        timeout = std::min((uint64_t)timeout, m_updateButtontime - iNow + iTimeoutMs);
++      if (m_iCurrentButton != CEC_USER_CONTROL_CODE_UNKNOWN && m_iCurrentButton != comboKey && m_releaseButtontime)
++        timeout = std::min((uint64_t)timeout, m_releaseButtontime - iNow);
++      if (m_iCurrentButton != CEC_USER_CONTROL_CODE_UNKNOWN && m_iCurrentButton != comboKey && m_repeatButtontime)
++        timeout = std::min((uint64_t)timeout, m_repeatButtontime - iNow);
+       if (timeout > CEC_PROCESSOR_SIGNAL_WAIT_TIME)
+       {
+-        LIB_CEC->AddLog(CEC_LOG_ERROR, "Unexpected timeout: %d (%.3f %.3f %.3f) k:%02x", timeout, iNow*1e-3, m_updateButtontime*1e-3, CEC_BUTTON_TIMEOUT*1e-3, m_iCurrentButton);
++        LIB_CEC->AddLog(CEC_LOG_ERROR, "Unexpected timeout: %d (%.3f %.3f %.3f) k:%02x", timeout, iNow*1e-3, m_updateButtontime*1e-3, m_releaseButtontime*1e-3, m_iCurrentButton);
+         timeout = CEC_PROCESSOR_SIGNAL_WAIT_TIME;
+       }
+-      return timeout;
+     }
++    LIB_CEC->AddLog(CEC_LOG_DEBUG, "key %s: %s (%1x) timeout:%dms (rel:%d,rep:%d,prs:%d,rel:%d)", key.keycode == CEC_USER_CONTROL_CODE_UNKNOWN ? "idle" : key.duration ? "released" : "repeated",
++        ToString(m_iCurrentButton), m_iCurrentButton, timeout, (int)(m_releaseButtontime ? m_releaseButtontime - iNow : 0), (int)(m_repeatButtontime ? m_repeatButtontime - iNow : 0), m_pressedButtoncount, m_releasedButtoncount);
+   }
+ 
+-  LIB_CEC->AddLog(CEC_LOG_DEBUG, "key auto-released: %s (%1x)", ToString(key.keycode), key.keycode);
+-  QueueAddKey(key);
+-  return CEC_PROCESSOR_SIGNAL_WAIT_TIME;
++  if (key.keycode != CEC_USER_CONTROL_CODE_UNKNOWN)
++    QueueAddKey(key);
++
++  return timeout;
+ }
+ 
+ bool CCECClient::EnableCallbacks(void *cbParam, ICECCallbacks *callbacks)
+diff --git a/src/libcec/CECClient.h b/src/libcec/CECClient.h
+index 611c68b..adeb5af 100644
+--- a/src/libcec/CECClient.h
++++ b/src/libcec/CECClient.h
+@@ -269,7 +269,7 @@ namespace CEC
+     // callbacks
+     virtual void                  Alert(const libcec_alert type, const libcec_parameter &param) { QueueAlert(type, param); }
+     virtual void                  AddLog(const cec_log_message &message) { QueueAddLog(message); }
+-    virtual void                  AddKey(bool bSendComboKey = false);
++    virtual void                  AddKey(bool bSendComboKey = false, bool bButtonRelease = false);
+     virtual void                  AddKey(const cec_keypress &key);
+     virtual void                  SetCurrentButton(const cec_user_control_code iButtonCode);
+     virtual uint16_t              CheckKeypressTimeout(void);
+@@ -406,6 +406,10 @@ namespace CEC
+     cec_user_control_code m_iCurrentButton;                    /**< the control code of the button that's currently held down (if any) */
+     int64_t               m_initialButtontime;                 /**< the timestamp when the button was initially pressed (in seconds since epoch), or 0 if none was pressed. */
+     int64_t               m_updateButtontime;                  /**< the timestamp when the button was updated (in seconds since epoch), or 0 if none was pressed. */
++    int64_t               m_repeatButtontime;                  /**< the timestamp when the button will next repeat (in seconds since epoch), or 0 if repeat is disabled. */
++    int64_t               m_releaseButtontime;                 /**< the timestamp when the button will be released (in seconds since epoch), or 0 if none was pressed. */
++    int32_t               m_pressedButtoncount;                /**< the number of times a button released message has been seen for this press. */
++    int32_t               m_releasedButtoncount;               /**< the number of times a button pressed message has been seen for this press. */
+     int64_t               m_iPreventForwardingPowerOffCommand; /**< prevent forwarding standby commands until this time */
+     int64_t               m_iLastKeypressTime;                 /**< last time a key press was sent to the client */
+     cec_keypress          m_lastKeypress;                      /**< the last key press that was sent to the client */
+diff --git a/src/libcec/implementations/CECCommandHandler.cpp b/src/libcec/implementations/CECCommandHandler.cpp
+index 6d6244e..d64186f 100644
+--- a/src/libcec/implementations/CECCommandHandler.cpp
++++ b/src/libcec/implementations/CECCommandHandler.cpp
+@@ -770,7 +770,7 @@ int CCECCommandHandler::HandleUserControlRelease(const cec_command &command)
+ 
+   CECClientPtr client = m_processor->GetClient(command.destination);
+   if (client)
+-    client->AddKey();
++    client->AddKey(false, true);
+ 
+   return COMMAND_HANDLED;
+ }
+-- 
+1.9.1
+
+
+From 3336d0827f7fd159430f3431642b07090c06c869 Mon Sep 17 00:00:00 2001
+From: popcornmix <popcornmix@gmail.com>
+Date: Tue, 28 Oct 2014 01:21:35 +0000
+Subject: [PATCH 4/6] Skip double press removal. It is handled through other
+ means.
+
+---
+ src/libcec/CECClient.cpp | 18 +-----------------
+ src/libcec/CECClient.h   |  2 --
+ 2 files changed, 1 insertion(+), 19 deletions(-)
+
+diff --git a/src/libcec/CECClient.cpp b/src/libcec/CECClient.cpp
+index 598628d..dccd874 100644
+--- a/src/libcec/CECClient.cpp
++++ b/src/libcec/CECClient.cpp
+@@ -60,11 +60,8 @@ CCECClient::CCECClient(CCECProcessor *processor, const libcec_configuration &con
+     m_releaseButtontime(0),
+     m_pressedButtoncount(0),
+     m_releasedButtoncount(0),
+-    m_iPreventForwardingPowerOffCommand(0),
+-    m_iLastKeypressTime(0)
++    m_iPreventForwardingPowerOffCommand(0)
+ {
+-  m_lastKeypress.keycode = CEC_USER_CONTROL_CODE_UNKNOWN;
+-  m_lastKeypress.duration = 0;
+   m_configuration.Clear();
+   // set the initial configuration
+   SetConfiguration(configuration);
+@@ -1647,20 +1644,7 @@ void CCECClient::CallbackAddKey(const cec_keypress &key)
+ {
+   CLockObject lock(m_cbMutex);
+   if (m_configuration.callbacks && m_configuration.callbacks->CBCecKeyPress)
+-  {
+-    // prevent double taps
+-    int64_t now = GetTimeMs();
+-    if (m_lastKeypress.keycode != key.keycode ||
+-        key.duration > 0 ||
+-        now - m_iLastKeypressTime >= DoubleTapTimeoutMS())
+-    {
+-      // no double tap
+-      if (key.duration == 0)
+-        m_iLastKeypressTime = now;
+-      m_lastKeypress = key;
+       m_configuration.callbacks->CBCecKeyPress(m_configuration.callbackParam, key);
+-    }
+-  }
+ }
+ 
+ void CCECClient::CallbackAddLog(const cec_log_message &message)
+diff --git a/src/libcec/CECClient.h b/src/libcec/CECClient.h
+index adeb5af..43a713b 100644
+--- a/src/libcec/CECClient.h
++++ b/src/libcec/CECClient.h
+@@ -411,8 +411,6 @@ namespace CEC
+     int32_t               m_pressedButtoncount;                /**< the number of times a button released message has been seen for this press. */
+     int32_t               m_releasedButtoncount;               /**< the number of times a button pressed message has been seen for this press. */
+     int64_t               m_iPreventForwardingPowerOffCommand; /**< prevent forwarding standby commands until this time */
+-    int64_t               m_iLastKeypressTime;                 /**< last time a key press was sent to the client */
+-    cec_keypress          m_lastKeypress;                      /**< the last key press that was sent to the client */
+     PLATFORM::SyncedBuffer<CCallbackWrap*> m_callbackCalls;
+   };
+ }
+-- 
+1.9.1
+
+
+From 0dd0234f620a546bfa843172648383f83d88088c Mon Sep 17 00:00:00 2001
+From: popcornmix <popcornmix@gmail.com>
+Date: Mon, 3 Nov 2014 23:28:04 +0000
+Subject: [PATCH 5/6] Pass through duration on all button repeats
+
+---
+ src/libcec/CECClient.cpp | 34 ++++++++++++++++++++++++----------
+ 1 file changed, 24 insertions(+), 10 deletions(-)
+
+diff --git a/src/libcec/CECClient.cpp b/src/libcec/CECClient.cpp
+index dccd874..1946148 100644
+--- a/src/libcec/CECClient.cpp
++++ b/src/libcec/CECClient.cpp
+@@ -986,10 +986,6 @@ void CCECClient::AddKey(bool bSendComboKey /* = false */, bool bButtonRelease /*
+   cec_keypress key;
+   key.keycode = CEC_USER_CONTROL_CODE_UNKNOWN;
+ 
+-  // we ignore button releases when supporting repeating keys
+-  if (bButtonRelease && m_configuration.iButtonRepeatRateMs && m_configuration.iButtonReleaseDelayMs)
+-    return;
+-
+   {
+     CLockObject lock(m_mutex);
+     if (m_iCurrentButton != CEC_USER_CONTROL_CODE_UNKNOWN)
+@@ -1015,6 +1011,10 @@ void CCECClient::AddKey(bool bSendComboKey /* = false */, bool bButtonRelease /*
+     }
+   }
+ 
++  // we don't forward releases when supporting repeating keys
++  if (bButtonRelease && m_configuration.iButtonRepeatRateMs)
++    return;
++
+   if (key.keycode != CEC_USER_CONTROL_CODE_UNKNOWN)
+   {
+     LIB_CEC->AddLog(CEC_LOG_DEBUG, "key released: %s (%1x) D:%dms", ToString(key.keycode), key.keycode, key.duration);
+@@ -1107,7 +1107,7 @@ void CCECClient::AddKey(const cec_keypress &key)
+ 
+   if (!isrepeat && (key.keycode != comboKey || key.duration > 0))
+   {
+-    LIB_CEC->AddLog(CEC_LOG_DEBUG, "key pressed: %s (%1x)", ToString(transmitKey.keycode), transmitKey.keycode);
++    LIB_CEC->AddLog(CEC_LOG_DEBUG, "key pressed: %s (%1x, %d)", ToString(transmitKey.keycode), transmitKey.keycode, transmitKey.duration);
+     QueueAddKey(transmitKey);
+   }
+ }
+@@ -1129,6 +1129,7 @@ uint16_t CCECClient::CheckKeypressTimeout(void)
+   unsigned int timeout = CEC_PROCESSOR_SIGNAL_WAIT_TIME;
+   cec_keypress key;
+   key.keycode = CEC_USER_CONTROL_CODE_UNKNOWN;
++  key.duration = 0;
+ 
+   {
+     CLockObject lock(m_mutex);
+@@ -1140,8 +1141,7 @@ uint16_t CCECClient::CheckKeypressTimeout(void)
+         m_configuration.iComboKeyTimeoutMs : CEC_DEFAULT_COMBO_TIMEOUT_MS);
+ 
+     if (m_iCurrentButton != CEC_USER_CONTROL_CODE_UNKNOWN &&
+-          ((m_iCurrentButton == comboKey && iTimeoutMs > 0 && iNow - m_updateButtontime >= iTimeoutMs) ||
+-          (m_iCurrentButton != comboKey && m_releaseButtontime && iNow >= (uint64_t)m_releaseButtontime)))
++          m_iCurrentButton == comboKey && iTimeoutMs > 0 && iNow - m_updateButtontime >= iTimeoutMs)
+     {
+       key.duration = (unsigned int) (iNow - m_initialButtontime);
+       key.keycode = m_iCurrentButton;
+@@ -1155,9 +1155,23 @@ uint16_t CCECClient::CheckKeypressTimeout(void)
+       m_releasedButtoncount = 0;
+     }
+     else if (m_iCurrentButton != CEC_USER_CONTROL_CODE_UNKNOWN &&
++          m_iCurrentButton != comboKey && m_releaseButtontime && iNow >= (uint64_t)m_releaseButtontime)
++    {
++      key.duration = (unsigned int) (iNow - m_initialButtontime);
++      key.keycode = CEC_USER_CONTROL_CODE_UNKNOWN;
++
++      m_iCurrentButton = CEC_USER_CONTROL_CODE_UNKNOWN;
++      m_initialButtontime = 0;
++      m_updateButtontime = 0;
++      m_repeatButtontime = 0;
++      m_releaseButtontime = 0;
++      m_pressedButtoncount = 0;
++      m_releasedButtoncount = 0;
++    }
++    else if (m_iCurrentButton != CEC_USER_CONTROL_CODE_UNKNOWN &&
+           (m_iCurrentButton != comboKey && m_repeatButtontime && iNow >= (uint64_t)m_repeatButtontime))
+     {
+-      key.duration = 0;
++      key.duration = (unsigned int) (iNow - m_initialButtontime);
+       key.keycode = m_iCurrentButton;
+       m_repeatButtontime = iNow + m_configuration.iButtonRepeatRateMs;
+       timeout = std::min((uint64_t)timeout, m_repeatButtontime - iNow);
+@@ -1176,8 +1190,8 @@ uint16_t CCECClient::CheckKeypressTimeout(void)
+         timeout = CEC_PROCESSOR_SIGNAL_WAIT_TIME;
+       }
+     }
+-    LIB_CEC->AddLog(CEC_LOG_DEBUG, "key %s: %s (%1x) timeout:%dms (rel:%d,rep:%d,prs:%d,rel:%d)", key.keycode == CEC_USER_CONTROL_CODE_UNKNOWN ? "idle" : key.duration ? "released" : "repeated",
+-        ToString(m_iCurrentButton), m_iCurrentButton, timeout, (int)(m_releaseButtontime ? m_releaseButtontime - iNow : 0), (int)(m_repeatButtontime ? m_repeatButtontime - iNow : 0), m_pressedButtoncount, m_releasedButtoncount);
++    LIB_CEC->AddLog(CEC_LOG_DEBUG, "Key %s: %s (duration:%d) (%1x) timeout:%dms (rel:%d,rep:%d,prs:%d,rel:%d)", ToString(m_iCurrentButton), key.keycode == CEC_USER_CONTROL_CODE_UNKNOWN ? "idle" : m_repeatButtontime ? "repeated" : "released", key.duration,
++        m_iCurrentButton, timeout, (int)(m_releaseButtontime ? m_releaseButtontime - iNow : 0), (int)(m_repeatButtontime ? m_repeatButtontime - iNow : 0), m_pressedButtoncount, m_releasedButtoncount);
+   }
+ 
+   if (key.keycode != CEC_USER_CONTROL_CODE_UNKNOWN)
+-- 
+1.9.1
+
+
+From 1ea01f59d8186d4d53af41961aaccbbc11651115 Mon Sep 17 00:00:00 2001
+From: popcornmix <popcornmix@gmail.com>
+Date: Wed, 5 Nov 2014 21:04:25 +0000
+Subject: [PATCH 6/6] squash: Fix for stop needing to be pressed twice
+
+---
+ src/libcec/CECClient.cpp | 17 ++++++++---------
+ 1 file changed, 8 insertions(+), 9 deletions(-)
+
+diff --git a/src/libcec/CECClient.cpp b/src/libcec/CECClient.cpp
+index 1946148..f4f114b 100644
+--- a/src/libcec/CECClient.cpp
++++ b/src/libcec/CECClient.cpp
+@@ -1131,6 +1131,8 @@ uint16_t CCECClient::CheckKeypressTimeout(void)
+   key.keycode = CEC_USER_CONTROL_CODE_UNKNOWN;
+   key.duration = 0;
+ 
++  if (m_iCurrentButton == CEC_USER_CONTROL_CODE_UNKNOWN)
++    return timeout;
+   {
+     CLockObject lock(m_mutex);
+     uint64_t iNow = GetTimeMs();
+@@ -1140,8 +1142,7 @@ uint16_t CCECClient::CheckKeypressTimeout(void)
+     uint32_t iTimeoutMs(m_configuration.clientVersion >= LIBCEC_VERSION_TO_UINT(2, 0, 5) ?
+         m_configuration.iComboKeyTimeoutMs : CEC_DEFAULT_COMBO_TIMEOUT_MS);
+ 
+-    if (m_iCurrentButton != CEC_USER_CONTROL_CODE_UNKNOWN &&
+-          m_iCurrentButton == comboKey && iTimeoutMs > 0 && iNow - m_updateButtontime >= iTimeoutMs)
++    if (m_iCurrentButton == comboKey && iTimeoutMs > 0 && iNow - m_updateButtontime >= iTimeoutMs)
+     {
+       key.duration = (unsigned int) (iNow - m_initialButtontime);
+       key.keycode = m_iCurrentButton;
+@@ -1154,8 +1155,7 @@ uint16_t CCECClient::CheckKeypressTimeout(void)
+       m_pressedButtoncount = 0;
+       m_releasedButtoncount = 0;
+     }
+-    else if (m_iCurrentButton != CEC_USER_CONTROL_CODE_UNKNOWN &&
+-          m_iCurrentButton != comboKey && m_releaseButtontime && iNow >= (uint64_t)m_releaseButtontime)
++    else if (m_iCurrentButton != comboKey && m_releaseButtontime && iNow >= (uint64_t)m_releaseButtontime)
+     {
+       key.duration = (unsigned int) (iNow - m_initialButtontime);
+       key.keycode = CEC_USER_CONTROL_CODE_UNKNOWN;
+@@ -1168,8 +1168,7 @@ uint16_t CCECClient::CheckKeypressTimeout(void)
+       m_pressedButtoncount = 0;
+       m_releasedButtoncount = 0;
+     }
+-    else if (m_iCurrentButton != CEC_USER_CONTROL_CODE_UNKNOWN &&
+-          (m_iCurrentButton != comboKey && m_repeatButtontime && iNow >= (uint64_t)m_repeatButtontime))
++    else if (m_iCurrentButton != comboKey && m_repeatButtontime && iNow >= (uint64_t)m_repeatButtontime)
+     {
+       key.duration = (unsigned int) (iNow - m_initialButtontime);
+       key.keycode = m_iCurrentButton;
+@@ -1178,11 +1177,11 @@ uint16_t CCECClient::CheckKeypressTimeout(void)
+     }
+     else
+     {
+-      if (m_iCurrentButton != CEC_USER_CONTROL_CODE_UNKNOWN && m_iCurrentButton == comboKey && iTimeoutMs > 0)
++      if (m_iCurrentButton == comboKey && iTimeoutMs > 0)
+         timeout = std::min((uint64_t)timeout, m_updateButtontime - iNow + iTimeoutMs);
+-      if (m_iCurrentButton != CEC_USER_CONTROL_CODE_UNKNOWN && m_iCurrentButton != comboKey && m_releaseButtontime)
++      if (m_iCurrentButton != comboKey && m_releaseButtontime)
+         timeout = std::min((uint64_t)timeout, m_releaseButtontime - iNow);
+-      if (m_iCurrentButton != CEC_USER_CONTROL_CODE_UNKNOWN && m_iCurrentButton != comboKey && m_repeatButtontime)
++      if (m_iCurrentButton != comboKey && m_repeatButtontime)
+         timeout = std::min((uint64_t)timeout, m_repeatButtontime - iNow);
+       if (timeout > CEC_PROCESSOR_SIGNAL_WAIT_TIME)
+       {
+-- 
+1.9.1
+

From 37dcb167b785348191b06076280a03ab2a5781bd Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Tue, 28 Oct 2014 00:19:40 +0000
Subject: [PATCH 016/100] [cec] Add settings for configuring button repeats

---
 addons/resource.language.en_gb/resources/strings.po | 15 +++++++++++++++
 system/peripherals.xml                              |  4 +++-
 xbmc/peripherals/devices/PeripheralCecAdapter.cpp   | 16 ++++++++++++++++
 3 files changed, 34 insertions(+), 1 deletion(-)

diff --git a/addons/resource.language.en_gb/resources/strings.po b/addons/resource.language.en_gb/resources/strings.po
index bedbd87..6db61ed 100644
--- a/addons/resource.language.en_gb/resources/strings.po
+++ b/addons/resource.language.en_gb/resources/strings.po
@@ -16687,3 +16687,18 @@ msgstr ""
 msgctxt "#38009"
 msgid "%i dB"
 msgstr ""
+
+#: system/peripherals.xml
+msgctxt "#38050"
+msgid "Remote button press delay before repeating (ms)"
+msgstr ""
+
+#: system/peripherals.xml
+msgctxt "#38051"
+msgid "Remote button press repeat rate (ms)"
+msgstr ""
+
+#: system/peripherals.xml
+msgctxt "#38052"
+msgid "Remote button press release time (ms)"
+msgstr ""
diff --git a/system/peripherals.xml b/system/peripherals.xml
index a67dc2f..6841bda 100644
--- a/system/peripherals.xml
+++ b/system/peripherals.xml
@@ -30,7 +30,9 @@
     <setting key="device_type" type="int" value="1" configurable="0" />
     <setting key="wake_devices_advanced" type="string" value="" configurable="0" />
     <setting key="standby_devices_advanced" type="string" value="" configurable="0" />
-    <setting key="double_tap_timeout_ms" type="int" min="0" value="300" configurable="0" />
+    <setting key="double_tap_timeout_ms" type="int" min="50" max="1000" step="50" value="300" label="38050" order="16" />
+    <setting key="button_repeat_rate_ms" type="int" min="0" max="250" step="10" value="0" label="38051" order="17" />
+    <setting key="button_release_delay_ms" type="int" min="0" max="500" step="50" value="0" label="38052" order="18" />
   </peripheral>
 
   <peripheral vendor_product="2548:1001,2548:1002" bus="usb" name="Pulse-Eight CEC Adapter" mapTo="cec">
diff --git a/xbmc/peripherals/devices/PeripheralCecAdapter.cpp b/xbmc/peripherals/devices/PeripheralCecAdapter.cpp
index ea702e5..b5ff693 100644
--- a/xbmc/peripherals/devices/PeripheralCecAdapter.cpp
+++ b/xbmc/peripherals/devices/PeripheralCecAdapter.cpp
@@ -1267,6 +1267,20 @@ void CPeripheralCecAdapter::SetConfigurationFromLibCEC(const CEC::libcec_configu
   m_configuration.bSendInactiveSource = config.bSendInactiveSource;
   bChanged |= SetSetting("send_inactive_source", m_configuration.bSendInactiveSource == 1);
 
+#if defined(CEC_DOUBLE_TAP_TIMEOUT_MS_OLD)
+  m_configuration.iDoubleTapTimeout50Ms = config.iDoubleTapTimeout50Ms;
+  bChanged |= SetSetting("double_tap_timeout_ms", (int)m_configuration.iDoubleTapTimeout50Ms * 50);
+#else
+  m_configuration.iDoubleTapTimeoutMs = config.iDoubleTapTimeoutMs;
+  bChanged |= SetSetting("double_tap_timeout_ms", (int)m_configuration.iDoubleTapTimeoutMs;
+#endif
+
+  m_configuration.iButtonRepeatRateMs = config.iButtonRepeatRateMs;
+  bChanged |= SetSetting("button_repeat_rate_ms", (int)m_configuration.iButtonRepeatRateMs);
+
+  m_configuration.iButtonReleaseDelayMs = config.iButtonReleaseDelayMs;
+  bChanged |= SetSetting("button_release_delay_ms", (int)m_configuration.iButtonReleaseDelayMs);
+
   m_configuration.iFirmwareVersion = config.iFirmwareVersion;
   m_configuration.bShutdownOnStandby = config.bShutdownOnStandby;
 
@@ -1371,6 +1385,8 @@ void CPeripheralCecAdapter::SetConfigurationFromSettings(void)
   // backwards compatibility. will be removed once the next major release of libCEC is out
   m_configuration.iDoubleTapTimeoutMs = GetSettingInt("double_tap_timeout_ms");
 #endif
+  m_configuration.iButtonRepeatRateMs = GetSettingInt("button_repeat_rate_ms");
+  m_configuration.iButtonReleaseDelayMs = GetSettingInt("button_release_delay_ms");
 }
 
 void CPeripheralCecAdapter::ReadLogicalAddresses(const std::string &strString, cec_logical_addresses &addresses)

From 0316bb54444adacdfca76490a4778df1a719dd42 Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Mon, 3 Nov 2014 23:17:46 +0000
Subject: [PATCH 017/100] [cec] Don't discard buttons when repeat mode is
 enabled

---
 xbmc/peripherals/devices/PeripheralCecAdapter.cpp | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/xbmc/peripherals/devices/PeripheralCecAdapter.cpp b/xbmc/peripherals/devices/PeripheralCecAdapter.cpp
index b5ff693..6086bf5 100644
--- a/xbmc/peripherals/devices/PeripheralCecAdapter.cpp
+++ b/xbmc/peripherals/devices/PeripheralCecAdapter.cpp
@@ -767,7 +767,10 @@ void CPeripheralCecAdapter::PushCecKeypress(const CecButtonPress &key)
   CLog::Log(LOGDEBUG, "%s - received key %2x duration %d", __FUNCTION__, key.iButton, key.iDuration);
 
   CSingleLock lock(m_critSection);
-  if (key.iDuration > 0)
+  // avoid the queue getting too long
+  if (m_configuration.iButtonRepeatRateMs && m_buttonQueue.size() > 5)
+    return;
+  if (m_configuration.iButtonRepeatRateMs == 0 && key.iDuration > 0)
   {
     if (m_currentButton.iButton == key.iButton && m_currentButton.iDuration == 0)
     {

From 661701e323eea8a09ddc5cbf7dfccf928b2d7af5 Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Tue, 4 Nov 2014 18:50:00 +0000
Subject: [PATCH 018/100] [cec] Temp - more logging

---
 xbmc/peripherals/devices/PeripheralCecAdapter.cpp | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/xbmc/peripherals/devices/PeripheralCecAdapter.cpp b/xbmc/peripherals/devices/PeripheralCecAdapter.cpp
index 6086bf5..417b0d8 100644
--- a/xbmc/peripherals/devices/PeripheralCecAdapter.cpp
+++ b/xbmc/peripherals/devices/PeripheralCecAdapter.cpp
@@ -764,12 +764,15 @@ void CPeripheralCecAdapter::GetNextKey(void)
 
 void CPeripheralCecAdapter::PushCecKeypress(const CecButtonPress &key)
 {
-  CLog::Log(LOGDEBUG, "%s - received key %2x duration %d", __FUNCTION__, key.iButton, key.iDuration);
+  CLog::Log(LOGDEBUG, "%s - received key %2x duration %d (rep:%d size:%d)", __FUNCTION__, key.iButton, key.iDuration, m_configuration.iButtonRepeatRateMs, m_buttonQueue.size());
 
   CSingleLock lock(m_critSection);
   // avoid the queue getting too long
   if (m_configuration.iButtonRepeatRateMs && m_buttonQueue.size() > 5)
+  {
+    CLog::Log(LOGDEBUG, "%s - discarded key %2x", __FUNCTION__, key.iButton);
     return;
+  }
   if (m_configuration.iButtonRepeatRateMs == 0 && key.iDuration > 0)
   {
     if (m_currentButton.iButton == key.iButton && m_currentButton.iDuration == 0)
@@ -778,6 +781,7 @@ void CPeripheralCecAdapter::PushCecKeypress(const CecButtonPress &key)
       if (m_bHasButton)
         m_currentButton.iDuration = key.iDuration;
       // ignore this one, since it's already been handled by xbmc
+      CLog::Log(LOGDEBUG, "%s - ignored key %2x", __FUNCTION__, key.iButton);
       return;
     }
     // if we received a keypress with a duration set, try to find the same one without a duration set, and replace it
@@ -788,6 +792,7 @@ void CPeripheralCecAdapter::PushCecKeypress(const CecButtonPress &key)
         if ((*it).iDuration == 0)
         {
           // replace this entry
+          CLog::Log(LOGDEBUG, "%s - replaced key %2x", __FUNCTION__, key.iButton);
           (*it).iDuration = key.iDuration;
           return;
         }
@@ -797,6 +802,7 @@ void CPeripheralCecAdapter::PushCecKeypress(const CecButtonPress &key)
     }
   }
 
+  CLog::Log(LOGDEBUG, "%s - added key %2x", __FUNCTION__, key.iButton);
   m_buttonQueue.push_back(key);
 }
 

From b3aecd497b997fa71927edd39446994057081df7 Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Sat, 15 Nov 2014 12:03:34 +0000
Subject: [PATCH 019/100] [dvdplayer] Add lock for player creation

---
 xbmc/cores/dvdplayer/DVDPlayer.cpp | 3 +++
 xbmc/cores/dvdplayer/DVDPlayer.h   | 1 +
 2 files changed, 4 insertions(+)

diff --git a/xbmc/cores/dvdplayer/DVDPlayer.cpp b/xbmc/cores/dvdplayer/DVDPlayer.cpp
index 74f3f9b..3118be2 100644
--- a/xbmc/cores/dvdplayer/DVDPlayer.cpp
+++ b/xbmc/cores/dvdplayer/DVDPlayer.cpp
@@ -517,6 +517,7 @@ int CSelectionStreams::CountSource(StreamType type, StreamSource source) const
 
 void CDVDPlayer::CreatePlayers()
 {
+  CSingleLock lock(m_players_lock);
 #ifdef HAS_OMXPLAYER
   if (m_omxplayer_mode && OMXPlayerUnsuitable(m_HasVideo, m_HasAudio, m_pDemuxer, m_pInputStream, m_SelectionStreams))
   {
@@ -546,6 +547,7 @@ void CDVDPlayer::CreatePlayers()
 
 void CDVDPlayer::DestroyPlayers()
 {
+  CSingleLock lock(m_players_lock);
   if (!m_players_created)
     return;
   delete m_dvdPlayerVideo;
@@ -4251,6 +4253,7 @@ double CDVDPlayer::GetQueueTime()
 
 void CDVDPlayer::GetVideoStreamInfo(SPlayerVideoStreamInfo &info)
 {
+  CSingleLock lock(m_players_lock);
   info.bitrate = m_dvdPlayerVideo->GetVideoBitrate();
 
   std::string retVal;
diff --git a/xbmc/cores/dvdplayer/DVDPlayer.h b/xbmc/cores/dvdplayer/DVDPlayer.h
index ab6a228..32e76c1 100644
--- a/xbmc/cores/dvdplayer/DVDPlayer.h
+++ b/xbmc/cores/dvdplayer/DVDPlayer.h
@@ -557,4 +557,5 @@ class CDVDPlayer : public IPlayer, public CThread, public IDVDPlayer
   // omxplayer variables
   struct SOmxPlayerState m_OmxPlayerState;
   bool m_omxplayer_mode;            // using omxplayer acceleration
+  CCriticalSection m_players_lock;
 };

From ee762026329d0d0c0ff8e312cf04ecf9957b0fd0 Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Mon, 24 Nov 2014 22:07:25 +0000
Subject: [PATCH 020/100] [dvdplayervideo] Prod decoder when in stills mode

An asynchronous hardware decoder doesn't only produce output pictures when new packets arrive.
In dvd stills mode give it a chance to return pictures that weren't ready when frame was decoded.
---
 xbmc/cores/dvdplayer/DVDPlayerVideo.cpp | 46 ++++++++++++++++++++-------------
 1 file changed, 28 insertions(+), 18 deletions(-)

diff --git a/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp b/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp
index 0fe56c3..6ad751f 100644
--- a/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp
+++ b/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp
@@ -314,7 +314,8 @@ void CDVDPlayerVideo::Process()
 
   while (!m_bStop)
   {
-    int iQueueTimeOut = (int)(m_stalled ? frametime / 4 : frametime * 10) / 1000;
+    bool bPictureWaiting = m_hints.stills && (m_pVideoCodec->Decode(NULL, 0, DVD_NOPTS_VALUE, DVD_NOPTS_VALUE) & VC_PICTURE);
+    int iQueueTimeOut = (int)(bPictureWaiting ? 0 : (m_hints.stills || m_stalled) ? frametime / 4 : frametime * 10) / 1000;
     int iPriority = (m_speed == DVD_PLAYSPEED_PAUSE && m_started) ? 1 : 0;
 
     CDVDMsg* pMsg;
@@ -331,27 +332,36 @@ void CDVDPlayerVideo::Process()
       if( iPriority )
         continue;
 
-      //Okey, start rendering at stream fps now instead, we are likely in a stillframe
-      if( !m_stalled )
+      // check for picture waiting
+      if (bPictureWaiting)
       {
-        if(m_started)
-          CLog::Log(LOGINFO, "CDVDPlayerVideo - Stillframe detected, switching to forced %f fps", m_fFrameRate);
-        m_stalled = true;
-        pts+= frametime*4;
+        // create a dummy demuxer packet to prod the decode logic
+        pMsg = new CDVDMsgDemuxerPacket(CDVDDemuxUtils::AllocateDemuxPacket(0), false);
       }
-
-      //Waiting timed out, output last picture
-      if( picture.iFlags & DVP_FLAG_ALLOCATED )
+      else
       {
-        //Remove interlaced flag before outputting
-        //no need to output this as if it was interlaced
-        picture.iFlags &= ~DVP_FLAG_INTERLACED;
-        picture.iFlags |= DVP_FLAG_NOSKIP;
-        OutputPicture(&picture, pts);
-        pts+= frametime;
-      }
+        //Okey, start rendering at stream fps now instead, we are likely in a stillframe
+        if( !m_stalled )
+        {
+          if(m_started)
+            CLog::Log(LOGINFO, "CDVDPlayerVideo - Stillframe detected, switching to forced %f fps", m_fFrameRate);
+          m_stalled = true;
+          pts+= frametime*4;
+        }
 
-      continue;
+        //Waiting timed out, output last picture
+        if( picture.iFlags & DVP_FLAG_ALLOCATED )
+        {
+          //Remove interlaced flag before outputting
+          //no need to output this as if it was interlaced
+          picture.iFlags &= ~DVP_FLAG_INTERLACED;
+          picture.iFlags |= DVP_FLAG_NOSKIP;
+          OutputPicture(&picture, pts);
+          pts+= frametime;
+        }
+
+        continue;
+      }
     }
 
     if (pMsg->IsType(CDVDMsg::GENERAL_SYNCHRONIZE))

From 4003daa7468e7fc4d1d03ac9052556e85dad5257 Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Thu, 27 Nov 2014 16:31:56 +0000
Subject: [PATCH 021/100] [languageinvoker] Reduce priority of python threads

---
 xbmc/interfaces/generic/LanguageInvokerThread.cpp | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/xbmc/interfaces/generic/LanguageInvokerThread.cpp b/xbmc/interfaces/generic/LanguageInvokerThread.cpp
index fcdd063..16f0c89 100644
--- a/xbmc/interfaces/generic/LanguageInvokerThread.cpp
+++ b/xbmc/interfaces/generic/LanguageInvokerThread.cpp
@@ -50,6 +50,11 @@ bool CLanguageInvokerThread::execute(const std::string &script, const std::vecto
   m_args = arguments;
 
   Create();
+  #ifdef TARGET_RASPBERRY_PI
+  /* low prio */
+  SetPriority(GetPriority()-1);
+  #endif
+
   return true;
 }
 

From 9418301c4366ecd2523be64ab449d99c76bfab34 Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Sat, 14 Dec 2013 16:55:05 +0000
Subject: [PATCH 022/100] logging: Add microsecond timer to log messages

---
 xbmc/utils/log.cpp | 17 +++++++++++++++--
 1 file changed, 15 insertions(+), 2 deletions(-)

diff --git a/xbmc/utils/log.cpp b/xbmc/utils/log.cpp
index 3443f12..31c4a99 100644
--- a/xbmc/utils/log.cpp
+++ b/xbmc/utils/log.cpp
@@ -24,6 +24,7 @@
 #include "threads/Thread.h"
 #include "utils/StringUtils.h"
 #include "CompileInfo.h"
+#include "utils/TimeUtils.cpp"
 
 static const char* const levelNames[] =
 {"DEBUG", "INFO", "NOTICE", "WARNING", "ERROR", "SEVERE", "FATAL", "NONE"};
@@ -198,19 +199,31 @@ 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;
 

From c14e940dfd1abdf2bd2eb7e3c5caa25714254844 Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Sat, 29 Nov 2014 15:25:16 +0000
Subject: [PATCH 023/100] [rbp] hack: wait for splash to complete before
 changing hdmi mode

---
 xbmc/windowing/egl/EGLNativeTypeRaspberryPI.cpp | 49 +++++++++++++++++++++++++
 1 file changed, 49 insertions(+)

diff --git a/xbmc/windowing/egl/EGLNativeTypeRaspberryPI.cpp b/xbmc/windowing/egl/EGLNativeTypeRaspberryPI.cpp
index 68fc647..c80114e 100644
--- a/xbmc/windowing/egl/EGLNativeTypeRaspberryPI.cpp
+++ b/xbmc/windowing/egl/EGLNativeTypeRaspberryPI.cpp
@@ -214,12 +214,61 @@ int CEGLNativeTypeRaspberryPI::AddUniqueResolution(RESOLUTION_INFO &res, std::ve
 }
 #endif
 
+#include <dirent.h>
+
+pid_t proc_find(const char* name)
+{
+    DIR* dir;
+    struct dirent* ent;
+    char buf[512];
+
+    long  pid;
+    char pname[100] = {0,};
+    char state;
+    FILE *fp=NULL;
+
+    if (!(dir = opendir("/proc"))) {
+        perror("can't open /proc");
+        return -1;
+    }
+
+    while((ent = readdir(dir)) != NULL) {
+        long lpid = atol(ent->d_name);
+        if(lpid < 0)
+            continue;
+        snprintf(buf, sizeof(buf), "/proc/%ld/stat", lpid);
+        fp = fopen(buf, "r");
+
+        if (fp) {
+            if ( (fscanf(fp, "%ld (%[^)]) %c", &pid, pname, &state)) != 3 ){
+                printf("fscanf failed \n");
+                fclose(fp);
+                closedir(dir);
+                return -1;
+            }
+            if (!strcmp(pname, name)) {
+                fclose(fp);
+                closedir(dir);
+                return (pid_t)lpid;
+            }
+            fclose(fp);
+        }
+    }
+
+    closedir(dir);
+    return -1;
+}
+
+
 bool CEGLNativeTypeRaspberryPI::SetNativeResolution(const RESOLUTION_INFO &res)
 {
 #if defined(TARGET_RASPBERRY_PI)
   if(!m_DllBcmHost || !m_nativeWindow)
     return false;
 
+  while (proc_find("hello_video.bin") >= 0)
+    Sleep(100);
+
   DestroyDispmaxWindow();
 
   if(!m_fixedMode && GETFLAGS_GROUP(res.dwFlags) && GETFLAGS_MODE(res.dwFlags))

From a26352b358cb4a77073a81ad9d1b0fa20aa5b894 Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Thu, 11 Dec 2014 17:00:57 +0000
Subject: [PATCH 024/100] Fix for UI not showing both extractflags and
 extractthumb

---
 addons/resource.language.en_gb/resources/strings.po | 11 ++++++++---
 system/settings/settings.xml                        |  4 ++--
 2 files changed, 10 insertions(+), 5 deletions(-)

diff --git a/addons/resource.language.en_gb/resources/strings.po b/addons/resource.language.en_gb/resources/strings.po
index 6db61ed..9f2eb3c 100644
--- a/addons/resource.language.en_gb/resources/strings.po
+++ b/addons/resource.language.en_gb/resources/strings.po
@@ -11015,7 +11015,7 @@ msgstr ""
 
 #: system/settings/settings.xml
 msgctxt "#20433"
-msgid "Extract thumbnails and video information"
+msgid "Extract video information from files"
 msgstr ""
 
 #: xbmc/dialogs/GUIDialogSmartPlaylistRule.cpp
@@ -14572,7 +14572,7 @@ msgstr ""
 #. Description of setting "Videos -> File lists -> Extract thumbnails and video information" with label #20433
 #: system/settings/settings.xml
 msgctxt "#36178"
-msgid "Extract thumbnails and metadata information such as codec and aspect ratio from videos."
+msgid "Extract metadata information such as codec and aspect ratio from videos."
 msgstr ""
 
 #. Description of setting "Videos -> File lists -> Replace file names with library titles" with label #20419
@@ -14584,7 +14584,7 @@ msgstr ""
 #. Description of setting "Videos -> File lists -> Extract thumbnails and video information" with label #20433
 #: system/settings/settings.xml
 msgctxt "#36180"
-msgid "Extract thumbnails and information, such as codecs and aspect ratio, to display in library mode."
+msgid "Extract thumbnails, to display in library Mode."
 msgstr ""
 
 #: system/settings/settings.xml
@@ -16702,3 +16702,8 @@ msgstr ""
 msgctxt "#38052"
 msgid "Remote button press release time (ms)"
 msgstr ""
+
+#: system/settings/settings.xml
+msgctxt "#38103"
+msgid "Extract thumbnails from video files"
+msgstr ""
diff --git a/system/settings/settings.xml b/system/settings/settings.xml
index 4843ab8..f1cbefa 100644
--- a/system/settings/settings.xml
+++ b/system/settings/settings.xml
@@ -861,8 +861,8 @@
           <default>true</default>
           <control type="toggle" />
         </setting>
-        <setting id="myvideos.extractthumb" type="boolean" label="20433" help="36180">
-          <level>4</level>
+        <setting id="myvideos.extractthumb" type="boolean" label="38103" help="36180">
+          <level>1</level>
           <default>true</default>
           <control type="toggle" />
         </setting>

From b8b1bae07104af45f1945aca34f0424191271be1 Mon Sep 17 00:00:00 2001
From: anaconda <anaconda@menakite.eu>
Date: Thu, 11 Sep 2014 21:30:43 +0200
Subject: [PATCH 025/100] Disable autoscrolling while on screensaver and while
 opening streams.

---
 xbmc/Application.cpp                | 10 ++++++++++
 xbmc/Application.h                  |  2 ++
 xbmc/guilib/GUIFadeLabelControl.cpp |  4 +++-
 xbmc/guilib/GUIFont.cpp             |  4 ++++
 xbmc/guilib/GUILabel.cpp            |  4 +++-
 xbmc/guilib/GUITextBox.cpp          |  3 ++-
 6 files changed, 24 insertions(+), 3 deletions(-)

diff --git a/xbmc/Application.cpp b/xbmc/Application.cpp
index a891be6..a1e3a3f 100644
--- a/xbmc/Application.cpp
+++ b/xbmc/Application.cpp
@@ -4981,3 +4981,13 @@ bool CApplication::NotifyActionListeners(const CAction &action) const
   
   return false;
 }
+
+bool CApplication::ScreenSaverDisablesAutoScrolling()
+{
+  bool onBlackDimScreenSaver = IsInScreenSaver() && m_screenSaver &&
+    (m_screenSaver->ID() == "screensaver.xbmc.builtin.black" ||
+     m_screenSaver->ID() == "screensaver.xbmc.builtin.dim");
+  bool openingStreams = m_pPlayer->IsPlaying() && g_windowManager.IsWindowActive(WINDOW_DIALOG_BUSY);
+
+  return onBlackDimScreenSaver || openingStreams;
+}
diff --git a/xbmc/Application.h b/xbmc/Application.h
index 362dd7a..9f9a115 100644
--- a/xbmc/Application.h
+++ b/xbmc/Application.h
@@ -384,6 +384,8 @@ class CApplication : public CXBApplicationEx, public IPlayerCallback, public IMs
    */
   void UnregisterActionListener(IActionListener *listener);
 
+  bool ScreenSaverDisablesAutoScrolling();
+
 protected:
   virtual bool OnSettingsSaving() const;
 
diff --git a/xbmc/guilib/GUIFadeLabelControl.cpp b/xbmc/guilib/GUIFadeLabelControl.cpp
index 9eadbe4..b2b5f13 100644
--- a/xbmc/guilib/GUIFadeLabelControl.cpp
+++ b/xbmc/guilib/GUIFadeLabelControl.cpp
@@ -20,6 +20,8 @@
 
 #include "GUIFadeLabelControl.h"
 
+#include "Application.h"
+
 using namespace std;
 
 CGUIFadeLabelControl::CGUIFadeLabelControl(int parentID, int controlID, float posX, float posY, float width, float height, const CLabelInfo& labelInfo, bool scrollOut, unsigned int timeToDelayAtEnd, bool resetOnLabelChange)
@@ -102,7 +104,7 @@ void CGUIFadeLabelControl::Process(unsigned int currentTime, CDirtyRegionList &d
     m_lastLabel = m_currentLabel;
   }
 
-  if (m_infoLabels.size() > 1 || !m_shortText)
+  if ((m_infoLabels.size() > 1 || !m_shortText) && !g_application.ScreenSaverDisablesAutoScrolling())
   { // have scrolling text
     MarkDirtyRegion();
 
diff --git a/xbmc/guilib/GUIFont.cpp b/xbmc/guilib/GUIFont.cpp
index 7f11089..1192b74 100644
--- a/xbmc/guilib/GUIFont.cpp
+++ b/xbmc/guilib/GUIFont.cpp
@@ -22,6 +22,7 @@
 #include "GUIFontTTF.h"
 #include "GraphicContext.h"
 
+#include "Application.h"
 #include "threads/SingleLock.h"
 #include "utils/TimeUtils.h"
 #include "utils/MathUtils.h"
@@ -128,6 +129,9 @@ bool CGUIFont::UpdateScrollInfo(const vecText &text, CScrollInfo &scrollInfo)
   //   If the string is smaller than the viewport, then it may be plotted even
   //   more times than that.
   //
+  if (g_application.ScreenSaverDisablesAutoScrolling())
+    return false;
+
   if (scrollInfo.waitTime)
   {
     scrollInfo.waitTime--;
diff --git a/xbmc/guilib/GUILabel.cpp b/xbmc/guilib/GUILabel.cpp
index 759ac09..bed6ad2 100644
--- a/xbmc/guilib/GUILabel.cpp
+++ b/xbmc/guilib/GUILabel.cpp
@@ -21,6 +21,8 @@
 #include "GUILabel.h"
 #include <limits>
 
+#include "Application.h"
+
 CGUILabel::CGUILabel(float posX, float posY, float width, float height, const CLabelInfo& labelInfo, CGUILabel::OVER_FLOW overflow)
     : m_label(labelInfo)
     , m_textLayout(labelInfo.font, overflow == OVER_FLOW_WRAP, height)
@@ -104,7 +106,7 @@ void CGUILabel::Render()
   color_t color = GetColor();
   bool renderSolid = (m_color == COLOR_DISABLED);
   bool overFlows = (m_renderRect.Width() + 0.5f < m_textLayout.GetTextWidth()); // 0.5f to deal with floating point rounding issues
-  if (overFlows && m_scrolling && !renderSolid)
+  if (overFlows && m_scrolling && !renderSolid && !g_application.ScreenSaverDisablesAutoScrolling())
     m_textLayout.RenderScrolling(m_renderRect.x1, m_renderRect.y1, m_label.angle, color, m_label.shadowColor, 0, m_renderRect.Width(), m_scrollInfo);
   else
   {
diff --git a/xbmc/guilib/GUITextBox.cpp b/xbmc/guilib/GUITextBox.cpp
index 2cdbf1c..42be75d 100644
--- a/xbmc/guilib/GUITextBox.cpp
+++ b/xbmc/guilib/GUITextBox.cpp
@@ -23,6 +23,7 @@
 #include "utils/XBMCTinyXML.h"
 #include "utils/MathUtils.h"
 #include "utils/StringUtils.h"
+#include "Application.h"
 
 #include <algorithm>
 
@@ -134,7 +135,7 @@ void CGUITextBox::Process(unsigned int currentTime, CDirtyRegionList &dirtyregio
   // update our auto-scrolling as necessary
   if (m_autoScrollTime && m_lines.size() > m_itemsPerPage)
   {
-    if (!m_autoScrollCondition || m_autoScrollCondition->Get())
+    if ((!m_autoScrollCondition || m_autoScrollCondition->Get()) && !g_application.ScreenSaverDisablesAutoScrolling())
     {
       if (m_lastRenderTime)
         m_autoScrollDelayTime += currentTime - m_lastRenderTime;

From ee6e4e8972c094ac86c7fba991e6df8ff747b194 Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Sat, 13 Dec 2014 18:35:20 +0000
Subject: [PATCH 026/100] [demuxer] Avoid memcpy on every demuxer packet

Avoids an unnecessary memcpy on every demuxer packet which for
high bitrate videos can be significant.
---
 xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.cpp | 14 +++++++++-----
 xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxPacket.h   |  3 +++
 xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxUtils.cpp  |  7 ++++++-
 3 files changed, 18 insertions(+), 6 deletions(-)

diff --git a/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.cpp b/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.cpp
index 74ff31f..f9b3232 100644
--- a/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.cpp
+++ b/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.cpp
@@ -738,7 +738,7 @@ DemuxPacket* CDVDDemuxFFmpeg::Read()
           {
             if(m_pkt.pkt.stream_index == (int)m_pFormatContext->programs[m_program]->stream_index[i])
             {
-              pPacket = CDVDDemuxUtils::AllocateDemuxPacket(m_pkt.pkt.size);
+              pPacket = CDVDDemuxUtils::AllocateDemuxPacket(0);
               break;
             }
           }
@@ -747,7 +747,7 @@ DemuxPacket* CDVDDemuxFFmpeg::Read()
             bReturnEmpty = true;
         }
         else
-          pPacket = CDVDDemuxUtils::AllocateDemuxPacket(m_pkt.pkt.size);
+          pPacket = CDVDDemuxUtils::AllocateDemuxPacket(0);
       }
       else
         bReturnEmpty = true;
@@ -789,9 +789,13 @@ DemuxPacket* CDVDDemuxFFmpeg::Read()
         // copy contents into our own packet
         pPacket->iSize = m_pkt.pkt.size;
 
-        // maybe we can avoid a memcpy here by detecting where pkt.destruct is pointing too?
         if (m_pkt.pkt.data)
-          memcpy(pPacket->pData, m_pkt.pkt.data, pPacket->iSize);
+        {
+          pPacket->pData = m_pkt.pkt.data;
+          // so we can free AVPacket when DemuxPacket is freed
+          pPacket->pkt = new AVPacket(m_pkt.pkt);
+        }
+
 
         pPacket->pts = ConvertTimestamp(m_pkt.pkt.pts, stream->time_base.den, stream->time_base.num);
         pPacket->dts = ConvertTimestamp(m_pkt.pkt.dts, stream->time_base.den, stream->time_base.num);
@@ -826,7 +830,7 @@ DemuxPacket* CDVDDemuxFFmpeg::Read()
         pPacket->iStreamId = m_pkt.pkt.stream_index;
       }
       m_pkt.result = -1;
-      av_free_packet(&m_pkt.pkt);
+      memset(&m_pkt.pkt, 0, sizeof(AVPacket));
     }
   }
   } // end of lock scope
diff --git a/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxPacket.h b/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxPacket.h
index d64fbb3..012a7d1 100644
--- a/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxPacket.h
+++ b/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxPacket.h
@@ -23,6 +23,8 @@
 #define DMX_SPECIALID_STREAMINFO    -10
 #define DMX_SPECIALID_STREAMCHANGE  -11
 
+struct AVPacket;
+
  typedef struct DemuxPacket
 {
   unsigned char* pData;   // data
@@ -33,4 +35,5 @@
   double pts; // pts in DVD_TIME_BASE
   double dts; // dts in DVD_TIME_BASE
   double duration; // duration in DVD_TIME_BASE if available
+  AVPacket *pkt; // to allow packet to be freed
 } DemuxPacket;
diff --git a/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxUtils.cpp b/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxUtils.cpp
index ab298b2..10c5ee0 100644
--- a/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxUtils.cpp
+++ b/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxUtils.cpp
@@ -34,7 +34,12 @@ void CDVDDemuxUtils::FreeDemuxPacket(DemuxPacket* pPacket)
   if (pPacket)
   {
     try {
-      if (pPacket->pData) _aligned_free(pPacket->pData);
+      if (pPacket->pkt)
+      {
+        av_free_packet(pPacket->pkt);
+        delete pPacket->pkt;
+      }
+      else if (pPacket->pData) _aligned_free(pPacket->pData);
       delete pPacket;
     }
     catch(...) {

From a5664b17a3642e79b35fb7b3171efa1e6622713f Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Sun, 15 Feb 2015 14:06:12 +0000
Subject: [PATCH 027/100] [mmal] Allow mmal codec for dvd stills

---
 xbmc/cores/dvdplayer/DVDCodecs/DVDFactoryCodec.cpp | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/xbmc/cores/dvdplayer/DVDCodecs/DVDFactoryCodec.cpp b/xbmc/cores/dvdplayer/DVDCodecs/DVDFactoryCodec.cpp
index 4c363cf..b90237b 100644
--- a/xbmc/cores/dvdplayer/DVDCodecs/DVDFactoryCodec.cpp
+++ b/xbmc/cores/dvdplayer/DVDCodecs/DVDFactoryCodec.cpp
@@ -50,6 +50,9 @@
 #include "Video/DVDVideoCodecAndroidMediaCodec.h"
 #include "android/activity/AndroidFeatures.h"
 #endif
+#if defined(HAS_MMAL)
+#include "linux/RBP.h"
+#endif
 #include "Audio/DVDAudioCodecFFmpeg.h"
 #include "Audio/DVDAudioCodecPassthrough.h"
 #include "Overlay/DVDOverlayCodecSSA.h"
@@ -201,6 +204,10 @@ CDVDVideoCodec* CDVDFactoryCodec::CreateVideoCodec(CDVDStreamInfo &hint, const C
 #endif
   CLog::Log(LOGDEBUG, "CDVDFactoryCodec: compiled in hardware support: %s", hwSupport.c_str());
 
+#if defined(HAS_MMAL)
+  // mmal can handle dvd playback including stills
+  if (!CSettings::Get().GetBool("videoplayer.usemmal") || !g_RBP.GetCodecMpg2())
+#endif
   if (hint.stills && (hint.codec == AV_CODEC_ID_MPEG2VIDEO || hint.codec == AV_CODEC_ID_MPEG1VIDEO))
   {
      // If dvd is an mpeg2 and hint.stills

From efc5a90bf03956e838be61999b255d7cbbddf187 Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Tue, 31 Mar 2015 17:31:47 +0100
Subject: [PATCH 028/100] [mmalrenderer] Add SetCodecControl function and
 prefer to return pictures when renderer is low (disabled)

---
 xbmc/cores/dvdplayer/DVDCodecs/Video/MMALCodec.cpp | 13 +++++++++++++
 xbmc/cores/dvdplayer/DVDCodecs/Video/MMALCodec.h   |  2 ++
 2 files changed, 15 insertions(+)

diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/MMALCodec.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/MMALCodec.cpp
index 95584aa..c37f321 100644
--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/MMALCodec.cpp
+++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/MMALCodec.cpp
@@ -124,6 +124,7 @@ CMMALVideo::CMMALVideo()
   m_es_format = mmal_format_alloc();
   m_preroll = true;
   m_speed = DVD_PLAYSPEED_NORMAL;
+  m_codecControlFlags = 0;
 }
 
 CMMALVideo::~CMMALVideo()
@@ -865,6 +866,9 @@ int CMMALVideo::Decode(uint8_t* pData, int iSize, double dts, double pts)
     if (g_advancedSettings.CanLogComponent(LOGVIDEO))
       CLog::Log(LOGDEBUG, "%s::%s -  got output picture:%d", CLASSNAME, __func__, m_output_ready.size());
     ret |= VC_PICTURE;
+    // renderer is low - give priority to returning pictures
+    if (0 && m_codecControlFlags & DVD_CODEC_CTRL_DRAIN)
+      ret &= ~VC_BUFFER;
   }
   if (!ret)
   {
@@ -943,6 +947,7 @@ void CMMALVideo::Reset(void)
   m_startframe = false;
   m_decoderPts = DVD_NOPTS_VALUE;
   m_preroll = !m_hints.stills && (m_speed == DVD_PLAYSPEED_NORMAL || m_speed == DVD_PLAYSPEED_PAUSE);
+  m_codecControlFlags = 0;
 }
 
 void CMMALVideo::SetSpeed(int iSpeed)
@@ -1058,3 +1063,11 @@ bool CMMALVideo::GetCodecStats(double &pts, int &droppedPics)
   droppedPics= -1;
   return false;
 }
+
+void CMMALVideo::SetCodecControl(int flags)
+{
+  CSingleLock lock(m_sharedSection);
+  m_codecControlFlags = flags;
+  if (g_advancedSettings.CanLogComponent(LOGVIDEO))
+    CLog::Log(LOGDEBUG, "%s::%s flags:%x", CLASSNAME, __func__, flags);
+}
diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/MMALCodec.h b/xbmc/cores/dvdplayer/DVDCodecs/Video/MMALCodec.h
index 51a64d1..bde8c06 100644
--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/MMALCodec.h
+++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/MMALCodec.h
@@ -86,6 +86,7 @@ class CMMALVideo : public CDVDVideoCodec
   virtual void SetDropState(bool bDrop);
   virtual const char* GetName(void) { return m_pFormatName ? m_pFormatName:"mmal-xxx"; }
   virtual bool GetCodecStats(double &pts, int &droppedPics);
+  virtual void SetCodecControl(int flags);
   virtual void SetSpeed(int iSpeed);
 
   // MMAL decoder callback routines.
@@ -130,6 +131,7 @@ class CMMALVideo : public CDVDVideoCodec
   double            m_decoderPts;
   int               m_speed;
   bool              m_preroll;
+  int               m_codecControlFlags;
 
   CCriticalSection m_sharedSection;
   MMAL_COMPONENT_T *m_dec;

From 89064f91aa8be8e9e519d349e778edf3b399d656 Mon Sep 17 00:00:00 2001
From: anaconda <anaconda@menakite.eu>
Date: Wed, 25 Feb 2015 18:22:21 +0100
Subject: [PATCH 029/100] Load OSD dialogs on startup.

Fixes skipped frames the first time they're loaded in memory on less powered
devices, like a Raspberry Pi, when using DVDPlayer.
See http://forum.kodi.tv/showthread.php?tid=211501&pid=1938811#pid1938811
---
 xbmc/pvr/dialogs/GUIDialogPVRChannelsOSD.cpp          | 1 +
 xbmc/pvr/dialogs/GUIDialogPVRGuideOSD.cpp             | 1 +
 xbmc/video/dialogs/GUIDialogAudioSubtitleSettings.cpp | 4 +++-
 xbmc/video/dialogs/GUIDialogSubtitles.cpp             | 2 +-
 xbmc/video/dialogs/GUIDialogVideoOSD.cpp              | 2 +-
 xbmc/video/dialogs/GUIDialogVideoSettings.cpp         | 4 +++-
 6 files changed, 10 insertions(+), 4 deletions(-)

diff --git a/xbmc/pvr/dialogs/GUIDialogPVRChannelsOSD.cpp b/xbmc/pvr/dialogs/GUIDialogPVRChannelsOSD.cpp
index 0aaeebc..200dc5f 100644
--- a/xbmc/pvr/dialogs/GUIDialogPVRChannelsOSD.cpp
+++ b/xbmc/pvr/dialogs/GUIDialogPVRChannelsOSD.cpp
@@ -48,6 +48,7 @@ CGUIDialogPVRChannelsOSD::CGUIDialogPVRChannelsOSD() :
     CGUIDialog(WINDOW_DIALOG_PVR_OSD_CHANNELS, "DialogPVRChannelsOSD.xml"),
     Observer()
 {
+  m_loadType = LOAD_ON_GUI_INIT;
   m_vecItems = new CFileItemList;
 }
 
diff --git a/xbmc/pvr/dialogs/GUIDialogPVRGuideOSD.cpp b/xbmc/pvr/dialogs/GUIDialogPVRGuideOSD.cpp
index 1670190..329a3b8 100644
--- a/xbmc/pvr/dialogs/GUIDialogPVRGuideOSD.cpp
+++ b/xbmc/pvr/dialogs/GUIDialogPVRGuideOSD.cpp
@@ -35,6 +35,7 @@ using namespace PVR;
 CGUIDialogPVRGuideOSD::CGUIDialogPVRGuideOSD()
     : CGUIDialog(WINDOW_DIALOG_PVR_OSD_GUIDE, "DialogPVRGuideOSD.xml")
 {
+  m_loadType = LOAD_ON_GUI_INIT;
   m_vecItems = new CFileItemList;
 }
 
diff --git a/xbmc/video/dialogs/GUIDialogAudioSubtitleSettings.cpp b/xbmc/video/dialogs/GUIDialogAudioSubtitleSettings.cpp
index fcbafae..6ab155e 100644
--- a/xbmc/video/dialogs/GUIDialogAudioSubtitleSettings.cpp
+++ b/xbmc/video/dialogs/GUIDialogAudioSubtitleSettings.cpp
@@ -62,7 +62,9 @@ using namespace std;
 CGUIDialogAudioSubtitleSettings::CGUIDialogAudioSubtitleSettings()
   : CGUIDialogSettingsManualBase(WINDOW_DIALOG_AUDIO_OSD_SETTINGS, "VideoOSDSettings.xml"),
     m_passthrough(false)
-{ }
+{
+  m_loadType = LOAD_ON_GUI_INIT;
+}
 
 CGUIDialogAudioSubtitleSettings::~CGUIDialogAudioSubtitleSettings()
 { }
diff --git a/xbmc/video/dialogs/GUIDialogSubtitles.cpp b/xbmc/video/dialogs/GUIDialogSubtitles.cpp
index 6dad844..a3e820c 100644
--- a/xbmc/video/dialogs/GUIDialogSubtitles.cpp
+++ b/xbmc/video/dialogs/GUIDialogSubtitles.cpp
@@ -98,7 +98,7 @@ class CSubtitlesJob: public CJob
 CGUIDialogSubtitles::CGUIDialogSubtitles(void)
     : CGUIDialog(WINDOW_DIALOG_SUBTITLES, "DialogSubtitles.xml")
 {
-  m_loadType  = KEEP_IN_MEMORY;
+  m_loadType  = LOAD_ON_GUI_INIT;
   m_subtitles = new CFileItemList;
   m_serviceItems = new CFileItemList;
   m_pausedOnRun = false;
diff --git a/xbmc/video/dialogs/GUIDialogVideoOSD.cpp b/xbmc/video/dialogs/GUIDialogVideoOSD.cpp
index 7316936..7033124 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 9f25fa5..3ece45b 100644
--- a/xbmc/video/dialogs/GUIDialogVideoSettings.cpp
+++ b/xbmc/video/dialogs/GUIDialogVideoSettings.cpp
@@ -63,7 +63,9 @@ using namespace std;
 CGUIDialogVideoSettings::CGUIDialogVideoSettings()
     : CGUIDialogSettingsManualBase(WINDOW_DIALOG_VIDEO_OSD_SETTINGS, "VideoOSDSettings.xml"),
       m_viewModeChanged(false)
-{ }
+{
+  m_loadType = LOAD_ON_GUI_INIT;
+}
 
 CGUIDialogVideoSettings::~CGUIDialogVideoSettings()
 { }

From 42a4147584fc33654b862212362f17ee751713ee Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Sat, 7 Mar 2015 22:46:21 +0000
Subject: [PATCH 030/100] configure: Add raspberry-pi2 platform

---
 configure.ac                                      | 14 +++++++--
 m4/xbmc_arch.m4                                   |  8 ++---
 tools/depends/Makefile.include.in                 |  2 +-
 tools/depends/configure.ac                        | 38 ++++++++++++++++-------
 tools/depends/target/Toolchain.cmake.in           |  2 +-
 tools/depends/target/Toolchain_binaddons.cmake.in |  2 +-
 6 files changed, 44 insertions(+), 22 deletions(-)

diff --git a/configure.ac b/configure.ac
index fe689d6..78f4add 100644
--- a/configure.ac
+++ b/configure.ac
@@ -744,8 +744,17 @@ case $use_platform in
   raspberry-pi)
      target_platform=target_raspberry_pi
      use_neon=no
-     use_arch="arm"
      use_cpu=arm1176jzf-s
+     ;;
+  raspberry-pi2)
+     target_platform=target_raspberry_pi
+     use_neon=yes
+     use_cpu=cortex-a7
+     ;;
+esac
+
+if test "$target_platform" = "target_raspberry_pi" ; then
+     use_arch="arm"
      use_hardcoded_tables="yes"
      use_openmax=no
      ARCH="arm"
@@ -754,8 +763,7 @@ case $use_platform in
      USE_MMAL=1; AC_DEFINE([HAS_MMAL],[1],["Define to 1 if MMAL libs is enabled"])
      CFLAGS="$CFLAGS"
      CXXFLAGS="$CXXFLAGS"
-     ;;
-esac
+fi
 
 if test "$host_vendor" = "apple"; then
   use_avahi=no
diff --git a/m4/xbmc_arch.m4 b/m4/xbmc_arch.m4
index 0b66a82..adb8e97 100644
--- a/m4/xbmc_arch.m4
+++ b/m4/xbmc_arch.m4
@@ -77,9 +77,7 @@ if test "$target_platform" = "target_android" ; then
   AC_SUBST(ARCH_DEFINES, "-DTARGET_POSIX -DTARGET_LINUX -D_LINUX -DTARGET_ANDROID")
 fi
 
-case $use_platform in
-  raspberry-pi)
-     AC_SUBST(ARCH_DEFINES, "-DTARGET_POSIX -DTARGET_LINUX -D_LINUX -D_ARMEL -DTARGET_RASPBERRY_PI")
-     ;;
-esac
+if test "$target_platform" = "target_raspberry_pi" ; then
+  AC_SUBST(ARCH_DEFINES, "-DTARGET_POSIX -DTARGET_LINUX -D_LINUX -D_ARMEL -DTARGET_RASPBERRY_PI")
+fi
 ])
diff --git a/tools/depends/Makefile.include.in b/tools/depends/Makefile.include.in
index e1ac05c..d60cccf 100644
--- a/tools/depends/Makefile.include.in
+++ b/tools/depends/Makefile.include.in
@@ -20,7 +20,7 @@ NATIVE_OS=@build_os@
 CROSS_COMPILING=@cross_compiling@
 ARCH_DEFINES=@ARCH_DEFINES@
 NATIVE_ARCH_DEFINES=@NATIVE_ARCH_DEFINES@
-TARGET_PLATFORM=@use_platform@
+TARGET_PLATFORM=@target_platform@
 XCODE_VERSION=@use_xcode@
 AAPT=@AAPT@
 DX=@DX@
diff --git a/tools/depends/configure.ac b/tools/depends/configure.ac
index 9435fca..4eff331 100644
--- a/tools/depends/configure.ac
+++ b/tools/depends/configure.ac
@@ -17,7 +17,8 @@ AC_ARG_WITH([toolchain],
 AC_ARG_WITH([platform],
   [AS_HELP_STRING([--with-platform],
   [target platform [auto]])],
-  [use_platform=$withval])
+  [use_platform=$withval],
+  [target_platform=$withval])
 
 AC_ARG_WITH([firmware],
   [AS_HELP_STRING([--with-firmware],
@@ -300,34 +301,49 @@ case $host in
     AC_MSG_ERROR(unsupported host ($use_host))
 esac
 
-if test "$use_platform" = "raspberry-pi"; then
+case $use_platform in
+  raspberry-pi)
+     target_platform=raspberry_pi
+     use_neon=no
+     use_cpu=arm1176jzf-s
+     platform_cflags="-mcpu=arm1176jzf-s -mtune=arm1176jzf-s -mfloat-abi=hard -mfpu=vfp"
+     platform_cxxflags="-mcpu=arm1176jzf-s -mtune=arm1176jzf-s -mfloat-abi=hard -mfpu=vfp"
+     platform_ldflags=""
+     ;;
+  raspberry-pi2)
+     target_platform=raspberry_pi
+     use_neon=yes
+     use_cpu=cortex-a7
+     platform_cflags="-fPIC -mcpu=cortex-a7 -mfloat-abi=hard -mfpu=neon-vfpv4"
+     platform_cxxflags="-fPIC -mcpu=cortex-a7 -mfloat-abi=hard -mfpu=neon-vfpv4"
+     platform_ldflags="-lpthread"
+     ;;
+esac
+
+if test "$target_platform" = "raspberry_pi" ; then
   if test -d "${use_firmware}/opt/vc/include"; then
     :
   else
     AC_MSG_ERROR([Raspberry Pi firmware not found])
   fi
-  use_neon=no
   use_arch="arm"
-  use_cpu="arm1176jzf-s"
   use_hardcoded_tables="yes"
-  use_alsa="no"
   ARCH="arm"
   platform_os="linux"
   cross_compiling="yes"
   use_host="arm-linux-gnueabihf"
   deps_dir="$use_host"
-  platform_cflags="-pipe -mcpu=arm1176jzf-s -mtune=arm1176jzf-s -mfloat-abi=hard \
-   -mfpu=vfp -mabi=aapcs-linux -Wno-psabi -Wa,-mno-warn-deprecated \
-   -Wno-deprecated-declarations -isystem${use_firmware}/opt/vc/include \
+  platform_cflags+=" -pipe -mabi=aapcs-linux -Wno-psabi \
+   -Wa,-mno-warn-deprecated -Wno-deprecated-declarations \
+   -isystem${use_firmware}/opt/vc/include \
    -isystem${use_firmware}/opt/vc/include/interface/vcos/pthreads \
    -isystem${use_firmware}/opt/vc/include/interface/vmcs_host/linux"
-  platform_cxxflags="-pipe -mcpu=arm1176jzf-s -mtune=arm1176jzf-s \
-   -mfloat-abi=hard -mfpu=vfp -mabi=aapcs-linux -Wno-psabi \
+  platform_cxxflags+=" -pipe -mabi=aapcs-linux -Wno-psabi \
    -Wa,-mno-warn-deprecated -Wno-deprecated-declarations \
    -isystem${use_firmware}/opt/vc/include \
    -isystem${use_firmware}/opt/vc/include/interface/vcos/pthreads \
    -isystem${use_firmware}/opt/vc/include/interface/vmcs_host/linux"
-  platform_ldflags="-L${use_firmware}/opt/vc/lib -lEGL -lGLESv2 -lbcm_host -lvcos \
+  platform_ldflags+=" -L${use_firmware}/opt/vc/lib -lEGL -lGLESv2 -lbcm_host -lvcos \
    -lvchiq_arm"
 fi
 
diff --git a/tools/depends/target/Toolchain.cmake.in b/tools/depends/target/Toolchain.cmake.in
index 943be73..59385e8 100644
--- a/tools/depends/target/Toolchain.cmake.in
+++ b/tools/depends/target/Toolchain.cmake.in
@@ -1,6 +1,6 @@
 SET(OS "@platform_os@")
 SET(CPU "@use_cpu@")
-SET(PLATFORM "@use_platform@")
+SET(PLATFORM "@target_platform@")
 IF("${OS}" STREQUAL "linux" OR "${OS}" STREQUAL "android")
 SET(CMAKE_SYSTEM_NAME Linux)
 ENDIF()
diff --git a/tools/depends/target/Toolchain_binaddons.cmake.in b/tools/depends/target/Toolchain_binaddons.cmake.in
index cdc2fe4..379bd1d 100644
--- a/tools/depends/target/Toolchain_binaddons.cmake.in
+++ b/tools/depends/target/Toolchain_binaddons.cmake.in
@@ -1,7 +1,7 @@
 set(CMAKE_SYSTEM_VERSION 1)
 set(OS "@platform_os@")
 set(CPU "@use_cpu@")
-set(PLATFORM "@use_platform@")
+set(PLATFORM "@target_platform@")
 if("${OS}" STREQUAL "linux" OR "${OS}" STREQUAL "android")
   set(CMAKE_SYSTEM_NAME Linux)
 endif()

From e14488115b0b428a646e6a9da85aee8028e11565 Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Tue, 10 Mar 2015 17:05:18 +0000
Subject: [PATCH 031/100] [players] Add settings option to enable MVC support

---
 addons/resource.language.en_gb/resources/strings.po | 10 ++++++++++
 system/settings/rbp.xml                             |  7 +++++++
 xbmc/cores/dvdplayer/DVDCodecs/Video/MMALCodec.cpp  |  5 +++++
 xbmc/cores/omxplayer/OMXVideo.cpp                   |  5 +++++
 4 files changed, 27 insertions(+)

diff --git a/addons/resource.language.en_gb/resources/strings.po b/addons/resource.language.en_gb/resources/strings.po
index 9f2eb3c..bf956f7 100644
--- a/addons/resource.language.en_gb/resources/strings.po
+++ b/addons/resource.language.en_gb/resources/strings.po
@@ -16703,6 +16703,16 @@ msgctxt "#38052"
 msgid "Remote button press release time (ms)"
 msgstr ""
 
+#: system/settings/rbp.xml
+msgctxt "#38110"
+msgid "Support MVC video (full frame 3D)"
+msgstr ""
+
+#: system/settings/rbp.xml
+msgctxt "#38111"
+msgid "This option decodes frames for both eyes of MVC video. Disabling may improve performance if you don't require 3D"
+msgstr ""
+
 #: system/settings/settings.xml
 msgctxt "#38103"
 msgid "Extract thumbnails from video files"
diff --git a/system/settings/rbp.xml b/system/settings/rbp.xml
index a54a4c4..31a6bcc 100644
--- a/system/settings/rbp.xml
+++ b/system/settings/rbp.xml
@@ -27,6 +27,13 @@
           <control type="edit" format="integer" />
         </setting>
       </group>
+      <group id="3">
+        <setting id="videoplayer.supportmvc" type="boolean" label="38110" help="38111">
+          <level>2</level>
+          <default>true</default>
+          <control type="toggle" />
+        </setting>
+      </group>
     </category>
     <category id="myvideos">
       <group id="1">
diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/MMALCodec.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/MMALCodec.cpp
index c37f321..a583450 100644
--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/MMALCodec.cpp
+++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/MMALCodec.cpp
@@ -537,6 +537,11 @@ bool CMMALVideo::Open(CDVDStreamInfo &hints, CDVDCodecOptions &options)
       // H.264
       m_codingType = MMAL_ENCODING_H264;
       m_pFormatName = "mmal-h264";
+      if (CSettings::Get().GetBool("videoplayer.supportmvc"))
+      {
+        m_codingType = MMAL_ENCODING_MVC;
+        m_pFormatName= "mmal-mvc";
+      }
     break;
     case AV_CODEC_ID_H263:
     case AV_CODEC_ID_MPEG4:
diff --git a/xbmc/cores/omxplayer/OMXVideo.cpp b/xbmc/cores/omxplayer/OMXVideo.cpp
index e4f6d86..5d324f4 100644
--- a/xbmc/cores/omxplayer/OMXVideo.cpp
+++ b/xbmc/cores/omxplayer/OMXVideo.cpp
@@ -430,6 +430,11 @@ bool COMXVideo::Open(CDVDStreamInfo &hints, OMXClock *clock, EDEINTERLACEMODE de
           break;
       }
     }
+    if (CSettings::Get().GetBool("videoplayer.supportmvc"))
+    {
+      m_codingType = OMX_VIDEO_CodingMVC;
+      m_video_codec_name = "omx-mvc";
+    }
     break;
     case AV_CODEC_ID_MPEG4:
       // (role name) video_decoder.mpeg4

From 0c601d3f8b448e1504bbe2e929204b74f1a0fa58 Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Sat, 14 Mar 2015 12:38:08 +0000
Subject: [PATCH 032/100] [mmalrenderer] Switch to using transform flags for 3d
 modes

---
 .../resource.language.en_gb/resources/strings.po   | 10 +++
 system/settings/rbp.xml                            |  8 ++
 xbmc/cores/VideoRenderers/MMALRenderer.cpp         | 92 ++++++----------------
 xbmc/cores/omxplayer/OMXPlayerVideo.cpp            | 46 ++---------
 xbmc/cores/omxplayer/OMXVideo.cpp                  | 36 ++++-----
 xbmc/cores/omxplayer/OMXVideo.h                    |  2 +-
 xbmc/windowing/egl/EGLNativeTypeRaspberryPI.cpp    | 11 ++-
 7 files changed, 75 insertions(+), 130 deletions(-)

diff --git a/addons/resource.language.en_gb/resources/strings.po b/addons/resource.language.en_gb/resources/strings.po
index bf956f7..530d882 100644
--- a/addons/resource.language.en_gb/resources/strings.po
+++ b/addons/resource.language.en_gb/resources/strings.po
@@ -16713,6 +16713,16 @@ msgctxt "#38111"
 msgid "This option decodes frames for both eyes of MVC video. Disabling may improve performance if you don't require 3D"
 msgstr ""
 
+#: system/settings/rbp.xml
+msgctxt "#38112"
+msgid "Use Full HD HDMI modes for 3D"
+msgstr ""
+
+#: system/settings/rbp.xml
+msgctxt "#38113"
+msgid "This option uses frame-packing to output full resolution for 3D through HDMI"
+msgstr ""
+
 #: system/settings/settings.xml
 msgctxt "#38103"
 msgid "Extract thumbnails from video files"
diff --git a/system/settings/rbp.xml b/system/settings/rbp.xml
index 31a6bcc..b5af261 100644
--- a/system/settings/rbp.xml
+++ b/system/settings/rbp.xml
@@ -33,6 +33,14 @@
           <default>true</default>
           <control type="toggle" />
         </setting>
+        <setting id="videoplayer.framepacking" type="boolean" label="38112" help="38113">
+          <dependencies>
+            <dependency type="enable" setting="videoplayer.supportmvc">true</dependency>
+          </dependencies>
+          <level>2</level>
+          <default>true</default>
+          <control type="toggle" />
+        </setting>
       </group>
     </category>
     <category id="myvideos">
diff --git a/xbmc/cores/VideoRenderers/MMALRenderer.cpp b/xbmc/cores/VideoRenderers/MMALRenderer.cpp
index 9f1f803..6cde0c5 100644
--- a/xbmc/cores/VideoRenderers/MMALRenderer.cpp
+++ b/xbmc/cores/VideoRenderers/MMALRenderer.cpp
@@ -366,11 +366,7 @@ void CMMALRenderer::RenderUpdate(bool clear, DWORD flags, DWORD alpha)
 
   if (!m_bConfigured) return;
 
-  if (g_graphicsContext.GetStereoMode())
-    g_graphicsContext.SetStereoView(RENDER_STEREO_VIEW_LEFT);
   ManageDisplay();
-  if (g_graphicsContext.GetStereoMode())
-    g_graphicsContext.SetStereoView(RENDER_STEREO_VIEW_OFF);
 
   // if running bypass, then the player might need the src/dst rects
   // for sizing video playback on a layer other than the gles layer.
@@ -581,10 +577,8 @@ EINTERLACEMETHOD CMMALRenderer::AutoInterlaceMethod()
 
 void CMMALRenderer::SetVideoRect(const CRect& InSrcRect, const CRect& InDestRect)
 {
-  // we get called twice a frame for left/right. Can ignore the rights.
-  if (g_graphicsContext.GetStereoView() == RENDER_STEREO_VIEW_RIGHT)
-    return;
   CSingleLock lock(m_sharedSection);
+  assert(g_graphicsContext.GetStereoView() != RENDER_STEREO_VIEW_RIGHT);
 
   if (!m_vout_input)
     return;
@@ -626,41 +620,10 @@ void CMMALRenderer::SetVideoRect(const CRect& InSrcRect, const CRect& InDestRect
   CRect gui(0, 0, CDisplaySettings::Get().GetResolutionInfo(res).iWidth, CDisplaySettings::Get().GetResolutionInfo(res).iHeight);
   CRect display(0, 0, CDisplaySettings::Get().GetResolutionInfo(res).iScreenWidth, CDisplaySettings::Get().GetResolutionInfo(res).iScreenHeight);
 
-  if (display_stereo_mode != RENDER_STEREO_MODE_OFF && display_stereo_mode != RENDER_STEREO_MODE_MONO)
-  switch (video_stereo_mode)
-  {
-  case RENDER_STEREO_MODE_SPLIT_VERTICAL:
-    // optimisation - use simpler display mode in common case of unscaled 3d with same display mode
-    if (video_stereo_mode == display_stereo_mode && DestRect.x1 == 0.0f && DestRect.x2 * 2.0f == gui.Width() && !stereo_invert)
-    {
-      SrcRect.x2 *= 2.0f;
-      DestRect.x2 *= 2.0f;
-      video_stereo_mode = RENDER_STEREO_MODE_OFF;
-      display_stereo_mode = RENDER_STEREO_MODE_OFF;
-    }
-    else if (display_stereo_mode == RENDER_STEREO_MODE_ANAGLYPH_RED_CYAN || display_stereo_mode == RENDER_STEREO_MODE_ANAGLYPH_GREEN_MAGENTA || display_stereo_mode == RENDER_STEREO_MODE_ANAGLYPH_YELLOW_BLUE)
-    {
-      SrcRect.x2 *= 2.0f;
-    }
-    break;
-
-  case RENDER_STEREO_MODE_SPLIT_HORIZONTAL:
-    // optimisation - use simpler display mode in common case of unscaled 3d with same display mode
-    if (video_stereo_mode == display_stereo_mode && DestRect.y1 == 0.0f && DestRect.y2 * 2.0f == gui.Height() && !stereo_invert)
-    {
-      SrcRect.y2 *= 2.0f;
-      DestRect.y2 *= 2.0f;
-      video_stereo_mode = RENDER_STEREO_MODE_OFF;
-      display_stereo_mode = RENDER_STEREO_MODE_OFF;
-    }
-    else if (display_stereo_mode == RENDER_STEREO_MODE_ANAGLYPH_RED_CYAN || display_stereo_mode == RENDER_STEREO_MODE_ANAGLYPH_GREEN_MAGENTA || display_stereo_mode == RENDER_STEREO_MODE_ANAGLYPH_YELLOW_BLUE)
-    {
-      SrcRect.y2 *= 2.0f;
-    }
-    break;
-
-  default: break;
-  }
+  if (display_stereo_mode == RENDER_STEREO_MODE_SPLIT_VERTICAL)
+    DestRect.x2 *= 2.0f;
+  else if (display_stereo_mode == RENDER_STEREO_MODE_SPLIT_HORIZONTAL)
+    DestRect.y2 *= 2.0f;
 
   if (gui != display)
   {
@@ -675,7 +638,7 @@ void CMMALRenderer::SetVideoRect(const CRect& InSrcRect, const CRect& InDestRect
   MMAL_DISPLAYREGION_T region;
   memset(&region, 0, sizeof region);
 
-  region.set                 = MMAL_DISPLAY_SET_DEST_RECT|MMAL_DISPLAY_SET_SRC_RECT|MMAL_DISPLAY_SET_FULLSCREEN|MMAL_DISPLAY_SET_NOASPECT|MMAL_DISPLAY_SET_MODE;
+  region.set                 = MMAL_DISPLAY_SET_DEST_RECT|MMAL_DISPLAY_SET_SRC_RECT|MMAL_DISPLAY_SET_FULLSCREEN|MMAL_DISPLAY_SET_NOASPECT|MMAL_DISPLAY_SET_MODE|MMAL_DISPLAY_SET_TRANSFORM;
   region.dest_rect.x         = lrintf(DestRect.x1);
   region.dest_rect.y         = lrintf(DestRect.y1);
   region.dest_rect.width     = lrintf(DestRect.Width());
@@ -688,35 +651,32 @@ void CMMALRenderer::SetVideoRect(const CRect& InSrcRect, const CRect& InDestRect
 
   region.fullscreen = MMAL_FALSE;
   region.noaspect = MMAL_TRUE;
+  region.mode = MMAL_DISPLAY_MODE_LETTERBOX;
+
+  if (m_renderOrientation == 90)
+    region.transform = MMAL_DISPLAY_ROT90;
+  else if (m_renderOrientation == 180)
+    region.transform = MMAL_DISPLAY_ROT180;
+  else if (m_renderOrientation == 270)
+    region.transform = MMAL_DISPLAY_ROT270;
+  else
+    region.transform = MMAL_DISPLAY_ROT0;
 
-  if (m_renderOrientation)
-  {
-    region.set |= MMAL_DISPLAY_SET_TRANSFORM;
-    if (m_renderOrientation == 90)
-      region.transform = MMAL_DISPLAY_ROT90;
-    else if (m_renderOrientation == 180)
-      region.transform = MMAL_DISPLAY_ROT180;
-    else if (m_renderOrientation == 270)
-      region.transform = MMAL_DISPLAY_ROT270;
-    else assert(0);
-  }
-
-  if (video_stereo_mode == RENDER_STEREO_MODE_SPLIT_HORIZONTAL && display_stereo_mode == RENDER_STEREO_MODE_SPLIT_HORIZONTAL)
-    region.mode = MMAL_DISPLAY_MODE_STEREO_TOP_TO_TOP;
-  else if (video_stereo_mode == RENDER_STEREO_MODE_SPLIT_HORIZONTAL && display_stereo_mode == RENDER_STEREO_MODE_SPLIT_VERTICAL)
-    region.mode = MMAL_DISPLAY_MODE_STEREO_TOP_TO_LEFT;
-  else if (video_stereo_mode == RENDER_STEREO_MODE_SPLIT_VERTICAL && display_stereo_mode == RENDER_STEREO_MODE_SPLIT_HORIZONTAL)
-    region.mode = MMAL_DISPLAY_MODE_STEREO_LEFT_TO_TOP;
-  else if (video_stereo_mode == RENDER_STEREO_MODE_SPLIT_VERTICAL && display_stereo_mode == RENDER_STEREO_MODE_SPLIT_VERTICAL)
-    region.mode = MMAL_DISPLAY_MODE_STEREO_LEFT_TO_LEFT;
+  if (m_video_stereo_mode == RENDER_STEREO_MODE_SPLIT_HORIZONTAL)
+    region.transform = (MMAL_DISPLAYTRANSFORM_T)(region.transform | DISPMANX_STEREOSCOPIC_TB);
+  else if (m_video_stereo_mode == RENDER_STEREO_MODE_SPLIT_VERTICAL)
+    region.transform = (MMAL_DISPLAYTRANSFORM_T)(region.transform | DISPMANX_STEREOSCOPIC_SBS);
   else
-    region.mode = MMAL_DISPLAY_MODE_LETTERBOX;
+    region.transform = (MMAL_DISPLAYTRANSFORM_T)(region.transform | DISPMANX_STEREOSCOPIC_MONO);
+
+  if (m_StereoInvert)
+    region.transform = (MMAL_DISPLAYTRANSFORM_T)(region.transform | DISPMANX_STEREOSCOPIC_INVERT);
 
   MMAL_STATUS_T status = mmal_util_set_display_region(m_vout_input, &region);
   if (status != MMAL_SUCCESS)
     CLog::Log(LOGERROR, "%s::%s Failed to set display region (status=%x %s)", CLASSNAME, __func__, status, mmal_status_to_string(status));
 
-  CLog::Log(LOGDEBUG, "%s::%s %d,%d,%d,%d -> %d,%d,%d,%d mode:%d", CLASSNAME, __func__,
+  CLog::Log(LOGDEBUG, "%s::%s %d,%d,%d,%d -> %d,%d,%d,%d t:%x", CLASSNAME, __func__,
       region.src_rect.x, region.src_rect.y, region.src_rect.width, region.src_rect.height,
-      region.dest_rect.x, region.dest_rect.y, region.dest_rect.width, region.dest_rect.height, region.mode);
+      region.dest_rect.x, region.dest_rect.y, region.dest_rect.width, region.dest_rect.height, region.transform);
 }
diff --git a/xbmc/cores/omxplayer/OMXPlayerVideo.cpp b/xbmc/cores/omxplayer/OMXPlayerVideo.cpp
index 212a89b..ba17a46 100644
--- a/xbmc/cores/omxplayer/OMXPlayerVideo.cpp
+++ b/xbmc/cores/omxplayer/OMXPlayerVideo.cpp
@@ -649,9 +649,7 @@ int OMXPlayerVideo::GetFreeSpace()
 
 void OMXPlayerVideo::SetVideoRect(const CRect &InSrcRect, const CRect &InDestRect)
 {
-  // we get called twice a frame for left/right. Can ignore the rights.
-  if (g_graphicsContext.GetStereoView() == RENDER_STEREO_VIEW_RIGHT)
-    return;
+  assert(g_graphicsContext.GetStereoView() != RENDER_STEREO_VIEW_RIGHT);
 
   CRect SrcRect = InSrcRect, DestRect = InDestRect;
   unsigned flags = GetStereoModeFlags(GetStereoMode());
@@ -691,42 +689,10 @@ void OMXPlayerVideo::SetVideoRect(const CRect &InSrcRect, const CRect &InDestRec
   CRect gui(0, 0, CDisplaySettings::Get().GetResolutionInfo(res).iWidth, CDisplaySettings::Get().GetResolutionInfo(res).iHeight);
   CRect display(0, 0, CDisplaySettings::Get().GetResolutionInfo(res).iScreenWidth, CDisplaySettings::Get().GetResolutionInfo(res).iScreenHeight);
 
-  switch (video_stereo_mode)
-  {
-  case RENDER_STEREO_MODE_SPLIT_VERTICAL:
-    // optimisation - use simpler display mode in common case of unscaled 3d with same display mode
-    if (video_stereo_mode == display_stereo_mode && DestRect.x1 == 0.0f && DestRect.x2 * 2.0f == gui.Width() && !stereo_invert)
-    {
-      SrcRect.x2 *= 2.0f;
-      DestRect.x2 *= 2.0f;
-      video_stereo_mode = RENDER_STEREO_MODE_OFF;
-      display_stereo_mode = RENDER_STEREO_MODE_OFF;
-    }
-    else if (stereo_invert)
-    {
-      SrcRect.x1 += m_hints.width / 2;
-      SrcRect.x2 += m_hints.width / 2;
-    }
-    break;
-
-  case RENDER_STEREO_MODE_SPLIT_HORIZONTAL:
-    // optimisation - use simpler display mode in common case of unscaled 3d with same display mode
-    if (video_stereo_mode == display_stereo_mode && DestRect.y1 == 0.0f && DestRect.y2 * 2.0f == gui.Height() && !stereo_invert)
-    {
-      SrcRect.y2 *= 2.0f;
-      DestRect.y2 *= 2.0f;
-      video_stereo_mode = RENDER_STEREO_MODE_OFF;
-      display_stereo_mode = RENDER_STEREO_MODE_OFF;
-    }
-    else if (stereo_invert)
-    {
-      SrcRect.y1 += m_hints.height / 2;
-      SrcRect.y2 += m_hints.height / 2;
-    }
-    break;
-
-  default: break;
-  }
+  if (display_stereo_mode == RENDER_STEREO_MODE_SPLIT_VERTICAL)
+    DestRect.x2 *= 2.0f;
+  else if (display_stereo_mode == RENDER_STEREO_MODE_SPLIT_HORIZONTAL)
+    DestRect.y2 *= 2.0f;
 
   if (gui != display)
   {
@@ -737,7 +703,7 @@ void OMXPlayerVideo::SetVideoRect(const CRect &InSrcRect, const CRect &InDestRec
     DestRect.y1 *= yscale;
     DestRect.y2 *= yscale;
   }
-  m_omxVideo.SetVideoRect(SrcRect, DestRect, video_stereo_mode, display_stereo_mode);
+  m_omxVideo.SetVideoRect(SrcRect, DestRect, m_video_stereo_mode, m_display_stereo_mode, m_StereoInvert);
 }
 
 void OMXPlayerVideo::RenderUpdateCallBack(const void *ctx, const CRect &SrcRect, const CRect &DestRect)
diff --git a/xbmc/cores/omxplayer/OMXVideo.cpp b/xbmc/cores/omxplayer/OMXVideo.cpp
index 5d324f4..832a9c9 100644
--- a/xbmc/cores/omxplayer/OMXVideo.cpp
+++ b/xbmc/cores/omxplayer/OMXVideo.cpp
@@ -220,15 +220,6 @@ bool COMXVideo::PortSettingsChanged()
   OMX_INIT_STRUCTURE(configDisplay);
   configDisplay.nPortIndex = m_omx_render.GetInputPort();
 
-  configDisplay.set = OMX_DISPLAY_SET_TRANSFORM;
-  configDisplay.transform = m_transform;
-  omx_err = m_omx_render.SetConfig(OMX_IndexConfigDisplayRegion, &configDisplay);
-  if(omx_err != OMX_ErrorNone)
-  {
-    CLog::Log(LOGWARNING, "%s::%s - could not set transform : %d", CLASSNAME, __func__, m_transform);
-    return false;
-  }
-
   if(m_hdmi_clock_sync)
   {
     OMX_CONFIG_LATENCYTARGETTYPE latencyTarget;
@@ -845,7 +836,7 @@ void COMXVideo::Reset(void)
 }
 
 ///////////////////////////////////////////////////////////////////////////////////////////
-void COMXVideo::SetVideoRect(const CRect& SrcRect, const CRect& DestRect, RENDER_STEREO_MODE video_mode, RENDER_STEREO_MODE display_mode)
+void COMXVideo::SetVideoRect(const CRect& SrcRect, const CRect& DestRect, RENDER_STEREO_MODE video_mode, RENDER_STEREO_MODE display_mode, bool stereo_invert)
 {
   CSingleLock lock (m_critSection);
   if(!m_is_open)
@@ -855,7 +846,7 @@ void COMXVideo::SetVideoRect(const CRect& SrcRect, const CRect& DestRect, RENDER
 
   OMX_INIT_STRUCTURE(configDisplay);
   configDisplay.nPortIndex = m_omx_render.GetInputPort();
-  configDisplay.set                 = (OMX_DISPLAYSETTYPE)(OMX_DISPLAY_SET_DEST_RECT|OMX_DISPLAY_SET_SRC_RECT|OMX_DISPLAY_SET_FULLSCREEN|OMX_DISPLAY_SET_NOASPECT|OMX_DISPLAY_SET_MODE);
+  configDisplay.set                 = (OMX_DISPLAYSETTYPE)(OMX_DISPLAY_SET_DEST_RECT|OMX_DISPLAY_SET_SRC_RECT|OMX_DISPLAY_SET_FULLSCREEN|OMX_DISPLAY_SET_NOASPECT|OMX_DISPLAY_SET_MODE|OMX_DISPLAY_SET_TRANSFORM);
   configDisplay.dest_rect.x_offset  = lrintf(DestRect.x1);
   configDisplay.dest_rect.y_offset  = lrintf(DestRect.y1);
   configDisplay.dest_rect.width     = lrintf(DestRect.Width());
@@ -868,23 +859,24 @@ void COMXVideo::SetVideoRect(const CRect& SrcRect, const CRect& DestRect, RENDER
 
   configDisplay.fullscreen = OMX_FALSE;
   configDisplay.noaspect = OMX_TRUE;
+  configDisplay.mode = OMX_DISPLAY_MODE_LETTERBOX;
+  configDisplay.transform = m_transform;
 
-  if (video_mode == RENDER_STEREO_MODE_SPLIT_HORIZONTAL && display_mode == RENDER_STEREO_MODE_SPLIT_HORIZONTAL)
-    configDisplay.mode = OMX_DISPLAY_MODE_STEREO_TOP_TO_TOP;
-  else if (video_mode == RENDER_STEREO_MODE_SPLIT_HORIZONTAL && display_mode == RENDER_STEREO_MODE_SPLIT_VERTICAL)
-    configDisplay.mode = OMX_DISPLAY_MODE_STEREO_TOP_TO_LEFT;
-  else if (video_mode == RENDER_STEREO_MODE_SPLIT_VERTICAL && display_mode == RENDER_STEREO_MODE_SPLIT_HORIZONTAL)
-    configDisplay.mode = OMX_DISPLAY_MODE_STEREO_LEFT_TO_TOP;
-  else if (video_mode == RENDER_STEREO_MODE_SPLIT_VERTICAL && display_mode == RENDER_STEREO_MODE_SPLIT_VERTICAL)
-    configDisplay.mode = OMX_DISPLAY_MODE_STEREO_LEFT_TO_LEFT;
+  if (video_mode == RENDER_STEREO_MODE_SPLIT_HORIZONTAL)
+    configDisplay.transform = (OMX_DISPLAYTRANSFORMTYPE)(configDisplay.transform | DISPMANX_STEREOSCOPIC_TB);
+  else if (video_mode == RENDER_STEREO_MODE_SPLIT_VERTICAL)
+    configDisplay.transform = (OMX_DISPLAYTRANSFORMTYPE)(configDisplay.transform | DISPMANX_STEREOSCOPIC_SBS);
   else
-    configDisplay.mode = OMX_DISPLAY_MODE_LETTERBOX;
+    configDisplay.transform = (OMX_DISPLAYTRANSFORMTYPE)(configDisplay.transform | DISPMANX_STEREOSCOPIC_MONO);
+
+  if (stereo_invert)
+    configDisplay.transform = (OMX_DISPLAYTRANSFORMTYPE)(configDisplay.transform | DISPMANX_STEREOSCOPIC_INVERT);
 
   m_omx_render.SetConfig(OMX_IndexConfigDisplayRegion, &configDisplay);
 
-  CLog::Log(LOGDEBUG, "%s::%s %d,%d,%d,%d -> %d,%d,%d,%d mode:%d", CLASSNAME, __func__,
+  CLog::Log(LOGDEBUG, "%s::%s %d,%d,%d,%d -> %d,%d,%d,%d t:%x", CLASSNAME, __func__,
       configDisplay.src_rect.x_offset, configDisplay.src_rect.y_offset, configDisplay.src_rect.width, configDisplay.src_rect.height,
-      configDisplay.dest_rect.x_offset, configDisplay.dest_rect.y_offset, configDisplay.dest_rect.width, configDisplay.dest_rect.height, configDisplay.mode);
+      configDisplay.dest_rect.x_offset, configDisplay.dest_rect.y_offset, configDisplay.dest_rect.width, configDisplay.dest_rect.height, configDisplay.transform);
 }
 
 int COMXVideo::GetInputBufferSize()
diff --git a/xbmc/cores/omxplayer/OMXVideo.h b/xbmc/cores/omxplayer/OMXVideo.h
index d0634bb..86e94ce 100644
--- a/xbmc/cores/omxplayer/OMXVideo.h
+++ b/xbmc/cores/omxplayer/OMXVideo.h
@@ -59,7 +59,7 @@ class COMXVideo
   void Reset(void);
   void SetDropState(bool bDrop);
   std::string GetDecoderName() { return m_video_codec_name; };
-  void SetVideoRect(const CRect& SrcRect, const CRect& DestRect, RENDER_STEREO_MODE video_mode, RENDER_STEREO_MODE display_mode);
+  void SetVideoRect(const CRect& SrcRect, const CRect& DestRect, RENDER_STEREO_MODE video_mode, RENDER_STEREO_MODE display_mode, bool stereo_invert);
   int GetInputBufferSize();
   bool GetPlayerInfo(double &match, double &phase, double &pll);
   void SubmitEOS();
diff --git a/xbmc/windowing/egl/EGLNativeTypeRaspberryPI.cpp b/xbmc/windowing/egl/EGLNativeTypeRaspberryPI.cpp
index c80114e..3816b55 100644
--- a/xbmc/windowing/egl/EGLNativeTypeRaspberryPI.cpp
+++ b/xbmc/windowing/egl/EGLNativeTypeRaspberryPI.cpp
@@ -281,7 +281,9 @@ bool CEGLNativeTypeRaspberryPI::SetNativeResolution(const RESOLUTION_INFO &res)
       /* inform TV of any 3D settings. Note this property just applies to next hdmi mode change, so no need to call for 2D modes */
       HDMI_PROPERTY_PARAM_T property;
       property.property = HDMI_PROPERTY_3D_STRUCTURE;
-      if (res.dwFlags & D3DPRESENTFLAG_MODE3DSBS)
+      if (CSettings::Get().GetBool("videoplayer.framepacking") && CSettings::Get().GetBool("videoplayer.supportmvc"))
+        property.param1 = HDMI_3D_FORMAT_FRAME_PACKING;
+      else if (res.dwFlags & D3DPRESENTFLAG_MODE3DSBS)
         property.param1 = HDMI_3D_FORMAT_SBS_HALF;
       else if (res.dwFlags & D3DPRESENTFLAG_MODE3DTB)
         property.param1 = HDMI_3D_FORMAT_TB_HALF;
@@ -354,6 +356,13 @@ bool CEGLNativeTypeRaspberryPI::SetNativeResolution(const RESOLUTION_INFO &res)
   DISPMANX_TRANSFORM_T transform = DISPMANX_NO_ROTATE;
   DISPMANX_UPDATE_HANDLE_T dispman_update = m_DllBcmHost->vc_dispmanx_update_start(0);
 
+  if (res.dwFlags & D3DPRESENTFLAG_MODE3DSBS)
+    transform = DISPMANX_STEREOSCOPIC_SBS;
+  else if (res.dwFlags & D3DPRESENTFLAG_MODE3DTB)
+    transform = DISPMANX_STEREOSCOPIC_TB;
+  else
+    transform = DISPMANX_STEREOSCOPIC_MONO;
+
   CLog::Log(LOGDEBUG, "EGL set resolution %dx%d -> %dx%d @ %.2f fps (%d,%d) flags:%x aspect:%.2f\n",
       m_width, m_height, dst_rect.width, dst_rect.height, res.fRefreshRate, GETFLAGS_GROUP(res.dwFlags), GETFLAGS_MODE(res.dwFlags), (int)res.dwFlags, res.fPixelRatio);
 

From e580c75ce004451233fd7aed98610257ce8516fc Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Tue, 14 Apr 2015 20:51:14 +0100
Subject: [PATCH 035/100] [gui] Also limit GUI updates when in non full-screen
 video mode

---
 xbmc/Application.cpp | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/xbmc/Application.cpp b/xbmc/Application.cpp
index a1e3a3f..a2a8691 100644
--- a/xbmc/Application.cpp
+++ b/xbmc/Application.cpp
@@ -2489,7 +2489,7 @@ void CApplication::FrameMove(bool processEvents, bool processGUI)
 #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() && g_renderManager.IsVideoLayer())
+    if (m_pPlayer->IsPlayingVideo() && !m_pPlayer->IsPausedPlayback() && g_renderManager.IsVideoLayer())
       fps = CSettings::Get().GetInt("videoplayer.limitguiupdate");
 #endif
 
@@ -2502,6 +2502,8 @@ void CApplication::FrameMove(bool processEvents, bool processGUI)
     {
       if (!m_skipGuiRender)
         g_windowManager.Process(CTimeUtils::GetFrameTime());
+      else if (!g_graphicsContext.IsFullScreenVideo())
+        g_renderManager.FrameMove();
     }
     g_windowManager.FrameMove();
   }

From 6fd33b1d1fdbf9a4b8a2a1242c6151a3ae704e8e Mon Sep 17 00:00:00 2001
From: macrule <macrule2001@yahoo.de>
Date: Thu, 11 Apr 2013 18:24:42 +0200
Subject: [PATCH 036/100] Added some vc_tv_* functions that were missing in
 DllBCM.

---
 xbmc/linux/DllBCM.h | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/xbmc/linux/DllBCM.h b/xbmc/linux/DllBCM.h
index b92fdb8..9c7e293 100644
--- a/xbmc/linux/DllBCM.h
+++ b/xbmc/linux/DllBCM.h
@@ -48,6 +48,9 @@ class DllBcmHostInterface
   virtual void bcm_host_init() = 0;
   virtual void bcm_host_deinit() = 0;
   virtual int32_t graphics_get_display_size( const uint16_t display_number, uint32_t *width, uint32_t *height) = 0;
+  virtual int vc_tv_power_off() = 0;
+  virtual int vc_tv_sdtv_power_on(SDTV_MODE_T mode, SDTV_OPTIONS_T *options) = 0;
+  virtual int vc_tv_hdmi_power_on_preferred() = 0;
   virtual int vc_tv_hdmi_power_on_best(uint32_t width, uint32_t height, uint32_t frame_rate,
                                        HDMI_INTERLACED_T scan_mode, EDID_MODE_MATCH_FLAG_T match_flags) = 0;
   virtual int vc_tv_hdmi_power_on_best_3d(uint32_t width, uint32_t height, uint32_t frame_rate,
@@ -92,6 +95,12 @@ class DllBcmHost : public DllDynamic, DllBcmHostInterface
     { return ::bcm_host_deinit(); };
   virtual int32_t graphics_get_display_size( const uint16_t display_number, uint32_t *width, uint32_t *height)
     { return ::graphics_get_display_size(display_number, width, height); };
+  virtual int vc_tv_power_off()
+    { return ::vc_tv_power_off(); }
+  virtual int vc_tv_sdtv_power_on(SDTV_MODE_T mode, SDTV_OPTIONS_T *options)
+    { return ::vc_tv_sdtv_power_on(mode, options); }
+  virtual int vc_tv_hdmi_power_on_preferred()
+    { return ::vc_tv_hdmi_power_on_preferred(); }
   virtual int vc_tv_hdmi_power_on_best(uint32_t width, uint32_t height, uint32_t frame_rate,
                                        HDMI_INTERLACED_T scan_mode, EDID_MODE_MATCH_FLAG_T match_flags)
     { return ::vc_tv_hdmi_power_on_best(width, height, frame_rate, scan_mode, match_flags); };

From 8902d26970b4364d73a022f6977521d5e3931cab Mon Sep 17 00:00:00 2001
From: macrule <macrule2001@yahoo.de>
Date: Thu, 11 Apr 2013 18:29:03 +0200
Subject: [PATCH 037/100] Added private utility function to map a float display
 aspect, to the respective SDTV_ASPECT_* enum value.

---
 xbmc/windowing/egl/EGLNativeTypeRaspberryPI.cpp | 22 ++++++++++++++++++++++
 1 file changed, 22 insertions(+)

diff --git a/xbmc/windowing/egl/EGLNativeTypeRaspberryPI.cpp b/xbmc/windowing/egl/EGLNativeTypeRaspberryPI.cpp
index 3816b55..520bf95 100644
--- a/xbmc/windowing/egl/EGLNativeTypeRaspberryPI.cpp
+++ b/xbmc/windowing/egl/EGLNativeTypeRaspberryPI.cpp
@@ -60,7 +60,10 @@
 # define DLOG(fmt, args...)
 #endif
 
+#if defined(TARGET_RASPBERRY_PI)
 static void SetResolutionString(RESOLUTION_INFO &res);
+static SDTV_ASPECT_T get_sdtv_aspect_from_display_aspect(float display_aspect);
+#endif
 
 CEGLNativeTypeRaspberryPI::CEGLNativeTypeRaspberryPI()
 {
@@ -470,6 +473,25 @@ static void SetResolutionString(RESOLUTION_INFO &res)
     res.dwFlags & D3DPRESENTFLAG_MODE3DTB   ? " 3DTB" : "",
     res.dwFlags & D3DPRESENTFLAG_MODE3DSBS  ? " 3DSBS" : "");
 }
+
+static SDTV_ASPECT_T get_sdtv_aspect_from_display_aspect(float display_aspect)
+{
+  SDTV_ASPECT_T aspect;
+  const float delta = 1e-3;
+  if(fabs(get_display_aspect_ratio(SDTV_ASPECT_16_9) - display_aspect) < delta)
+  {
+    aspect = SDTV_ASPECT_16_9;
+  }
+  else if(fabs(get_display_aspect_ratio(SDTV_ASPECT_14_9) - display_aspect) < delta)
+  {
+    aspect = SDTV_ASPECT_14_9;
+  }
+  else
+  {
+    aspect = SDTV_ASPECT_4_3;
+  }
+  return aspect;
+}
 #endif
 
 bool CEGLNativeTypeRaspberryPI::ProbeResolutions(std::vector<RESOLUTION_INFO> &resolutions)

From bc161d805562033507630fb1fb3961015e65debb Mon Sep 17 00:00:00 2001
From: macrule <macrule2001@yahoo.de>
Date: Thu, 11 Apr 2013 19:50:58 +0200
Subject: [PATCH 038/100] Changed SDTV resolutions to be treated similarly to
 HDMI resolutions in SetNativeResolution. This means that the SDTV interface
 is powered up and set to the right mode.

---
 xbmc/windowing/egl/EGLNativeTypeRaspberryPI.cpp | 36 ++++++++++++++++++++-----
 xbmc/windowing/egl/EGLNativeTypeRaspberryPI.h   |  1 -
 2 files changed, 29 insertions(+), 8 deletions(-)

diff --git a/xbmc/windowing/egl/EGLNativeTypeRaspberryPI.cpp b/xbmc/windowing/egl/EGLNativeTypeRaspberryPI.cpp
index 520bf95..a1f67fd 100644
--- a/xbmc/windowing/egl/EGLNativeTypeRaspberryPI.cpp
+++ b/xbmc/windowing/egl/EGLNativeTypeRaspberryPI.cpp
@@ -274,7 +274,7 @@ bool CEGLNativeTypeRaspberryPI::SetNativeResolution(const RESOLUTION_INFO &res)
 
   DestroyDispmaxWindow();
 
-  if(!m_fixedMode && GETFLAGS_GROUP(res.dwFlags) && GETFLAGS_MODE(res.dwFlags))
+  if(GETFLAGS_GROUP(res.dwFlags) && GETFLAGS_MODE(res.dwFlags))
   {
     sem_init(&m_tv_synced, 0, 0);
     m_DllBcmHost->vc_tv_register_callback(CallbackTvServiceCallback, this);
@@ -330,6 +330,33 @@ bool CEGLNativeTypeRaspberryPI::SetNativeResolution(const RESOLUTION_INFO &res)
 
     m_desktopRes = res;
   }
+  else if(!GETFLAGS_GROUP(res.dwFlags) && GETFLAGS_MODE(res.dwFlags))
+  {
+    sem_init(&m_tv_synced, 0, 0);
+    m_DllBcmHost->vc_tv_register_callback(CallbackTvServiceCallback, this);
+
+    SDTV_OPTIONS_T options;
+    options.aspect = get_sdtv_aspect_from_display_aspect((float)res.iScreenWidth / (float)res.iScreenHeight);
+
+    int success = m_DllBcmHost->vc_tv_sdtv_power_on((SDTV_MODE_T)GETFLAGS_MODE(res.dwFlags), &options);
+
+    if (success == 0)
+    {
+      CLog::Log(LOGDEBUG, "EGL set SDTV mode (%d,%d)=%d\n",
+                          GETFLAGS_GROUP(res.dwFlags), GETFLAGS_MODE(res.dwFlags), success);
+
+      sem_wait(&m_tv_synced);
+    }
+    else
+    {
+      CLog::Log(LOGERROR, "EGL failed to set SDTV mode (%d,%d)=%d\n",
+                          GETFLAGS_GROUP(res.dwFlags), GETFLAGS_MODE(res.dwFlags), success);
+    }
+    m_DllBcmHost->vc_tv_unregister_callback(CallbackTvServiceCallback);
+    sem_destroy(&m_tv_synced);
+
+    m_desktopRes = res;
+  }
 
   m_dispman_display = g_RBP.OpenDisplay(0);
 
@@ -502,8 +529,6 @@ bool CEGLNativeTypeRaspberryPI::ProbeResolutions(std::vector<RESOLUTION_INFO> &r
   if(!m_DllBcmHost)
     return false;
 
-  m_fixedMode               = false;
-
   /* read initial desktop resolution before probe resolutions.
    * probing will replace the desktop resolution when it finds the same one.
    * we raplace it because probing will generate more detailed 
@@ -552,7 +577,7 @@ bool CEGLNativeTypeRaspberryPI::ProbeResolutions(std::vector<RESOLUTION_INFO> &r
       m_desktopRes.iHeight      = tv_state.display.sdtv.height;
       m_desktopRes.iScreenWidth = tv_state.display.sdtv.width;
       m_desktopRes.iScreenHeight= tv_state.display.sdtv.height;
-      m_desktopRes.dwFlags      = D3DPRESENTFLAG_INTERLACED;
+      m_desktopRes.dwFlags      = MAKEFLAGS(HDMI_RES_GROUP_INVALID, tv_state.display.sdtv.mode, 1);
       m_desktopRes.fRefreshRate = (float)tv_state.display.sdtv.frame_rate;
       m_desktopRes.fPixelRatio  = tv_state.display.hdmi.display_options.aspect == 0 ? 1.0f : get_display_aspect_ratio((SDTV_ASPECT_T)tv_state.display.sdtv.display_options.aspect) / ((float)m_desktopRes.iScreenWidth / (float)m_desktopRes.iScreenHeight);
     }
@@ -575,9 +600,6 @@ bool CEGLNativeTypeRaspberryPI::ProbeResolutions(std::vector<RESOLUTION_INFO> &r
     CLog::Log(LOGDEBUG, "EGL probe resolution %s:%x\n", m_desktopRes.strMode.c_str(), m_desktopRes.dwFlags);
   }
 
-  if(resolutions.size() < 2)
-    m_fixedMode = true;
-
   DLOG("CEGLNativeTypeRaspberryPI::ProbeResolutions\n");
   return true;
 #else
diff --git a/xbmc/windowing/egl/EGLNativeTypeRaspberryPI.h b/xbmc/windowing/egl/EGLNativeTypeRaspberryPI.h
index 59401f5..a0acb1a 100644
--- a/xbmc/windowing/egl/EGLNativeTypeRaspberryPI.h
+++ b/xbmc/windowing/egl/EGLNativeTypeRaspberryPI.h
@@ -59,7 +59,6 @@ class CEGLNativeTypeRaspberryPI : public CEGLNativeType
   DISPMANX_ELEMENT_HANDLE_T     m_dispman_element;
   TV_GET_STATE_RESP_T           m_tv_state;
   sem_t                         m_tv_synced;
-  bool                          m_fixedMode;
   RESOLUTION_INFO               m_desktopRes;
   int                           m_width;
   int                           m_height;

From f2f7d13d99a2a07e7ff50e22a0c8ef347372f2e0 Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Sun, 21 Jun 2015 17:11:09 +0100
Subject: [PATCH 039/100] Revert "[3D] don't back out from 3D handling on
 resolution changes if we're switching to a different 3D mode"

This reverts commit 3c4c236a799dab8369b4bb74ff9993bc58a61a72.
---
 xbmc/guilib/GraphicContext.cpp | 11 ++++-------
 1 file changed, 4 insertions(+), 7 deletions(-)

diff --git a/xbmc/guilib/GraphicContext.cpp b/xbmc/guilib/GraphicContext.cpp
index bd7dff9..fc4cc95 100644
--- a/xbmc/guilib/GraphicContext.cpp
+++ b/xbmc/guilib/GraphicContext.cpp
@@ -436,17 +436,14 @@ void CGraphicContext::SetVideoResolutionInternal(RESOLUTION res, bool forceUpdat
 
   RENDER_STEREO_MODE stereo_mode = m_stereoMode;
 
-  // if the new resolution is an actual stereo mode, switch to that
-  // if the old resolution was an actual stereo mode and renderer is still in old 3D mode, switch to no 3d mode
+  // if the new mode is an actual stereo mode, switch to that
+  // if the old mode was an actual stereo mode, switch to no 3d mode
   if (info_org.dwFlags & D3DPRESENTFLAG_MODE3DTB)
     stereo_mode = RENDER_STEREO_MODE_SPLIT_HORIZONTAL;
   else if (info_org.dwFlags & D3DPRESENTFLAG_MODE3DSBS)
     stereo_mode = RENDER_STEREO_MODE_SPLIT_VERTICAL;
-  else if ((info_last.dwFlags & D3DPRESENTFLAG_MODE3DTB)
-        && m_stereoMode == RENDER_STEREO_MODE_SPLIT_HORIZONTAL)
-    stereo_mode = RENDER_STEREO_MODE_OFF;
-  else if ((info_last.dwFlags & D3DPRESENTFLAG_MODE3DSBS)
-        && m_stereoMode == RENDER_STEREO_MODE_SPLIT_VERTICAL)
+  else if ((info_last.dwFlags & D3DPRESENTFLAG_MODE3DSBS) != 0
+        || (info_last.dwFlags & D3DPRESENTFLAG_MODE3DTB)  != 0)
     stereo_mode = RENDER_STEREO_MODE_OFF;
 
   if(stereo_mode != m_stereoMode)

From 322a3a3b109d52d38cf047410a7b09cae368754b Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Wed, 10 Jun 2015 20:42:03 +0100
Subject: [PATCH 040/100] [rbp] Fix zoom modes with stereoscopic videos

---
 xbmc/cores/VideoRenderers/MMALRenderer.cpp | 12 ++++++++++--
 xbmc/cores/omxplayer/OMXPlayerVideo.cpp    | 12 ++++++++++--
 2 files changed, 20 insertions(+), 4 deletions(-)

diff --git a/xbmc/cores/VideoRenderers/MMALRenderer.cpp b/xbmc/cores/VideoRenderers/MMALRenderer.cpp
index 6cde0c5..5fc68d2 100644
--- a/xbmc/cores/VideoRenderers/MMALRenderer.cpp
+++ b/xbmc/cores/VideoRenderers/MMALRenderer.cpp
@@ -621,9 +621,17 @@ void CMMALRenderer::SetVideoRect(const CRect& InSrcRect, const CRect& InDestRect
   CRect display(0, 0, CDisplaySettings::Get().GetResolutionInfo(res).iScreenWidth, CDisplaySettings::Get().GetResolutionInfo(res).iScreenHeight);
 
   if (display_stereo_mode == RENDER_STEREO_MODE_SPLIT_VERTICAL)
-    DestRect.x2 *= 2.0f;
+  {
+    float width = DestRect.x2 - DestRect.x1;
+    DestRect.x1 *= 2.0f;
+    DestRect.x2 = DestRect.x1 + 2.0f * width;
+  }
   else if (display_stereo_mode == RENDER_STEREO_MODE_SPLIT_HORIZONTAL)
-    DestRect.y2 *= 2.0f;
+  {
+    float height = DestRect.y2 - DestRect.y1;
+    DestRect.y1 *= 2.0f;
+    DestRect.y2 = DestRect.y1 + 2.0f * height;
+  }
 
   if (gui != display)
   {
diff --git a/xbmc/cores/omxplayer/OMXPlayerVideo.cpp b/xbmc/cores/omxplayer/OMXPlayerVideo.cpp
index ba17a46..298eaff 100644
--- a/xbmc/cores/omxplayer/OMXPlayerVideo.cpp
+++ b/xbmc/cores/omxplayer/OMXPlayerVideo.cpp
@@ -690,9 +690,17 @@ void OMXPlayerVideo::SetVideoRect(const CRect &InSrcRect, const CRect &InDestRec
   CRect display(0, 0, CDisplaySettings::Get().GetResolutionInfo(res).iScreenWidth, CDisplaySettings::Get().GetResolutionInfo(res).iScreenHeight);
 
   if (display_stereo_mode == RENDER_STEREO_MODE_SPLIT_VERTICAL)
-    DestRect.x2 *= 2.0f;
+  {
+    float width = DestRect.x2 - DestRect.x1;
+    DestRect.x1 *= 2.0f;
+    DestRect.x2 = DestRect.x1 + 2.0f * width;
+  }
   else if (display_stereo_mode == RENDER_STEREO_MODE_SPLIT_HORIZONTAL)
-    DestRect.y2 *= 2.0f;
+  {
+    float height = DestRect.y2 - DestRect.y1;
+    DestRect.y1 *= 2.0f;
+    DestRect.y2 = DestRect.y1 + 2.0f * height;
+  }
 
   if (gui != display)
   {

From d26ddebf3aa9030c9af5444402312a00454087d7 Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Sun, 21 Jun 2015 17:42:03 +0100
Subject: [PATCH 041/100] [WinSystemEGL] Remove unused Support3D function

---
 xbmc/windowing/egl/WinSystemEGL.cpp | 29 -----------------------------
 xbmc/windowing/egl/WinSystemEGL.h   |  1 -
 2 files changed, 30 deletions(-)

diff --git a/xbmc/windowing/egl/WinSystemEGL.cpp b/xbmc/windowing/egl/WinSystemEGL.cpp
index c3bdb6a..c43c4d0 100644
--- a/xbmc/windowing/egl/WinSystemEGL.cpp
+++ b/xbmc/windowing/egl/WinSystemEGL.cpp
@@ -531,35 +531,6 @@ EGLConfig CWinSystemEGL::GetEGLConfig()
   return m_config;
 }
 
-// the logic in this function should match whether CBaseRenderer::FindClosestResolution picks a 3D mode
-bool CWinSystemEGL::Support3D(int width, int height, uint32_t mode) const
-{
-  RESOLUTION_INFO &curr = CDisplaySettings::Get().GetResolutionInfo(g_graphicsContext.GetVideoResolution());
-
-  // if we are using automatic hdmi mode switching
-  if (CSettings::Get().GetInt("videoplayer.adjustrefreshrate") != ADJUST_REFRESHRATE_OFF)
-  {
-    int searchWidth = curr.iScreenWidth;
-    int searchHeight = curr.iScreenHeight;
-
-    // only search the custom resolutions
-    for (unsigned int i = (int)RES_DESKTOP; i < CDisplaySettings::Get().ResolutionInfoSize(); i++)
-    {
-      RESOLUTION_INFO res = CDisplaySettings::Get().GetResolutionInfo(i);
-      if(res.iScreenWidth == searchWidth && res.iScreenHeight == searchHeight && (res.dwFlags & mode))
-        return true;
-    }
-  }
-  // otherwise just consider current mode
-  else
-  {
-     if (curr.dwFlags & mode)
-       return true;
-  }
-
-  return false;
-}
-
 bool CWinSystemEGL::ClampToGUIDisplayLimits(int &width, int &height)
 {
   width = width > m_nWidth ? m_nWidth : width;
diff --git a/xbmc/windowing/egl/WinSystemEGL.h b/xbmc/windowing/egl/WinSystemEGL.h
index 9d4baf6..1ec4225 100644
--- a/xbmc/windowing/egl/WinSystemEGL.h
+++ b/xbmc/windowing/egl/WinSystemEGL.h
@@ -59,7 +59,6 @@ class CWinSystemEGL : public CWinSystemBase, public CRenderSystemGLES
   virtual void  Register(IDispResource *resource);
   virtual void  Unregister(IDispResource *resource);
 
-  virtual bool  Support3D(int width, int height, uint32_t mode)     const;
   virtual bool  ClampToGUIDisplayLimits(int &width, int &height);
 
   EGLConfig     GetEGLConfig();

From b143b7e1557567102546e0024dfabc3c14647544 Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Wed, 16 Apr 2014 21:18:06 +0100
Subject: [PATCH 042/100] [omxplayer] Don't propagate 3d flags based on
 supported 3d modes

---
 xbmc/cores/omxplayer/OMXPlayerVideo.cpp | 29 +++--------------------------
 1 file changed, 3 insertions(+), 26 deletions(-)

diff --git a/xbmc/cores/omxplayer/OMXPlayerVideo.cpp b/xbmc/cores/omxplayer/OMXPlayerVideo.cpp
index 298eaff..3bf7c2e 100644
--- a/xbmc/cores/omxplayer/OMXPlayerVideo.cpp
+++ b/xbmc/cores/omxplayer/OMXPlayerVideo.cpp
@@ -726,40 +726,17 @@ void OMXPlayerVideo::ResolutionUpdateCallBack(uint32_t width, uint32_t height, f
   uint32_t video_width   = CDisplaySettings::Get().GetResolutionInfo(res).iScreenWidth;
   uint32_t video_height  = CDisplaySettings::Get().GetResolutionInfo(res).iScreenHeight;
 
-  unsigned flags = 0;
   ERenderFormat format = RENDER_FMT_BYPASS;
 
+  /* figure out steremode expected based on user settings and hints */
+  unsigned flags = GetStereoModeFlags(GetStereoMode());
+
   if(m_bAllowFullscreen)
   {
     flags |= CONF_FLAGS_FULLSCREEN;
     m_bAllowFullscreen = false; // only allow on first configure
   }
 
-  flags |= GetStereoModeFlags(GetStereoMode());
-
-  if(flags & CONF_FLAGS_STEREO_MODE_SBS)
-  {
-    if(g_Windowing.Support3D(video_width, video_height, D3DPRESENTFLAG_MODE3DSBS))
-      CLog::Log(LOGNOTICE, "3DSBS movie found");
-    else
-    {
-      flags &= ~CONF_FLAGS_STEREO_MODE_MASK(~0);
-      CLog::Log(LOGNOTICE, "3DSBS movie found but not supported");
-    }
-  }
-  else if(flags & CONF_FLAGS_STEREO_MODE_TAB)
-  {
-    if(g_Windowing.Support3D(video_width, video_height, D3DPRESENTFLAG_MODE3DTB))
-      CLog::Log(LOGNOTICE, "3DTB movie found");
-    else
-    {
-      flags &= ~CONF_FLAGS_STEREO_MODE_MASK(~0);
-      CLog::Log(LOGNOTICE, "3DTB movie found but not supported");
-    }
-  }
-  else
-    CLog::Log(LOGNOTICE, "not a 3D movie");
-
   unsigned int iDisplayWidth  = width;
   unsigned int iDisplayHeight = height;
 

From 7dfba284734131f43d27dbd8dd5b5def95ce91f7 Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Sun, 21 Jun 2015 18:52:28 +0100
Subject: [PATCH 043/100] [3d] Avoid switching stereo mode based on current
 display mode

---
 xbmc/guilib/GraphicContext.cpp | 21 ---------------------
 1 file changed, 21 deletions(-)

diff --git a/xbmc/guilib/GraphicContext.cpp b/xbmc/guilib/GraphicContext.cpp
index fc4cc95..e18232e 100644
--- a/xbmc/guilib/GraphicContext.cpp
+++ b/xbmc/guilib/GraphicContext.cpp
@@ -432,27 +432,6 @@ void CGraphicContext::SetVideoResolutionInternal(RESOLUTION res, bool forceUpdat
   Lock();
 
   RESOLUTION_INFO info_org  = CDisplaySettings::Get().GetResolutionInfo(res);
-  RESOLUTION_INFO info_last = CDisplaySettings::Get().GetResolutionInfo(lastRes);
-
-  RENDER_STEREO_MODE stereo_mode = m_stereoMode;
-
-  // if the new mode is an actual stereo mode, switch to that
-  // if the old mode was an actual stereo mode, switch to no 3d mode
-  if (info_org.dwFlags & D3DPRESENTFLAG_MODE3DTB)
-    stereo_mode = RENDER_STEREO_MODE_SPLIT_HORIZONTAL;
-  else if (info_org.dwFlags & D3DPRESENTFLAG_MODE3DSBS)
-    stereo_mode = RENDER_STEREO_MODE_SPLIT_VERTICAL;
-  else if ((info_last.dwFlags & D3DPRESENTFLAG_MODE3DSBS) != 0
-        || (info_last.dwFlags & D3DPRESENTFLAG_MODE3DTB)  != 0)
-    stereo_mode = RENDER_STEREO_MODE_OFF;
-
-  if(stereo_mode != m_stereoMode)
-  {
-    m_stereoView     = RENDER_STEREO_VIEW_OFF;
-    m_stereoMode     = stereo_mode;
-    m_nextStereoMode = stereo_mode;
-    CSettings::Get().SetInt("videoscreen.stereoscopicmode", (int)m_stereoMode);
-  }
 
   RESOLUTION_INFO info_mod = GetResInfo(res);
 

From 44998e6fed4bba5175446b483f86074d6c41fff7 Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Wed, 3 Jun 2015 23:13:51 +0100
Subject: [PATCH 044/100] [rpi] Always add desktop resolution to supported list

There was an assumption that the desktop resolution would be in the probed list, but that is sometimes not the case.
We don't add interlaced resolutions to list, but they can be the preferred resolution read from edid. See:
http://openelec.tv/forum/124-raspberry-pi/77074-forcing-interlaced-output

Also hotplug changes causing an edid reread may cause the supported modes to change (e.g. powering on receiver)
and it is possible the previous preferred mode is no longer there

So ensure that desktop resolution is always added to list. Also handle the case where desktop resolution is invalid on launch
(e.g. hdmi output powered off)
---
 xbmc/windowing/egl/EGLNativeTypeRaspberryPI.cpp | 14 +++++++++-----
 1 file changed, 9 insertions(+), 5 deletions(-)

diff --git a/xbmc/windowing/egl/EGLNativeTypeRaspberryPI.cpp b/xbmc/windowing/egl/EGLNativeTypeRaspberryPI.cpp
index a1f67fd..69ce9b7 100644
--- a/xbmc/windowing/egl/EGLNativeTypeRaspberryPI.cpp
+++ b/xbmc/windowing/egl/EGLNativeTypeRaspberryPI.cpp
@@ -190,7 +190,7 @@ int CEGLNativeTypeRaspberryPI::FindMatchingResolution(const RESOLUTION_INFO &res
   for (int i = 0; i < (int)resolutions.size(); i++)
   {
     if(resolutions[i].iScreenWidth == res.iScreenWidth && resolutions[i].iScreenHeight == res.iScreenHeight && resolutions[i].fRefreshRate == res.fRefreshRate &&
-      (resolutions[i].dwFlags & (D3DPRESENTFLAG_MODE3DSBS|D3DPRESENTFLAG_MODE3DTB)) == (res.dwFlags & (D3DPRESENTFLAG_MODE3DSBS|D3DPRESENTFLAG_MODE3DTB)))
+      (resolutions[i].dwFlags & D3DPRESENTFLAG_MODEMASK) == (res.dwFlags & D3DPRESENTFLAG_MODEMASK))
     {
        return i;
     }
@@ -206,8 +206,7 @@ int CEGLNativeTypeRaspberryPI::AddUniqueResolution(RESOLUTION_INFO &res, std::ve
   int i = FindMatchingResolution(res, resolutions);
   if (i>=0)
   {  // don't replace a progressive resolution with an interlaced one of same resolution
-     if (!(res.dwFlags & D3DPRESENTFLAG_INTERLACED))
-       resolutions[i] = res;
+     resolutions[i] = res;
   }
   else
   {
@@ -569,7 +568,7 @@ bool CEGLNativeTypeRaspberryPI::ProbeResolutions(std::vector<RESOLUTION_INFO> &r
       vc_tv_hdmi_get_property(&property);
       m_desktopRes.fRefreshRate = property.param1 == HDMI_PIXEL_CLOCK_TYPE_NTSC ? tv_state.display.hdmi.frame_rate * (1000.0f/1001.0f) : tv_state.display.hdmi.frame_rate;
     }
-    else // sdtv
+    else if ((tv_state.state & ( VC_SDTV_NTSC | VC_SDTV_PAL )) != 0) // sdtv
     {
       m_desktopRes.iScreen      = 0;
       m_desktopRes.bFullScreen  = true;
@@ -594,7 +593,6 @@ bool CEGLNativeTypeRaspberryPI::ProbeResolutions(std::vector<RESOLUTION_INFO> &r
   GetSupportedModes(HDMI_RES_GROUP_CEA, resolutions);
   GetSupportedModes(HDMI_RES_GROUP_DMT, resolutions);
 
-  if(resolutions.size() == 0)
   {
     AddUniqueResolution(m_desktopRes, resolutions);
     CLog::Log(LOGDEBUG, "EGL probe resolution %s:%x\n", m_desktopRes.strMode.c_str(), m_desktopRes.dwFlags);
@@ -686,6 +684,12 @@ void CEGLNativeTypeRaspberryPI::GetSupportedModes(HDMI_RES_GROUP_T group, std::v
       res.fPixelRatio   = get_display_aspect_ratio((HDMI_ASPECT_T)tv->aspect_ratio) / ((float)res.iScreenWidth / (float)res.iScreenHeight);
       res.iSubtitles    = (int)(0.965 * res.iHeight);
 
+      if (!m_desktopRes.dwFlags && prefer_group == group && prefer_mode == tv->code)
+        m_desktopRes = res;
+
+      if (res.dwFlags & D3DPRESENTFLAG_INTERLACED)
+        continue;
+
       AddUniqueResolution(res, resolutions);
       CLog::Log(LOGDEBUG, "EGL mode %d: %s (%.2f) %s%s:%x\n", i, res.strMode.c_str(), res.fPixelRatio,
           tv->native ? "N" : "", tv->scan_mode ? "I" : "", tv->code);

From 5089c4d05954af59297fd9f0960bf70db707bbfb Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Sun, 21 Jun 2015 18:53:29 +0100
Subject: [PATCH 045/100] [rbp] Drop reporting 3D modes and just use current
 rendering mode to request 3D signalling

---
 xbmc/windowing/egl/EGLNativeTypeRaspberryPI.cpp | 76 +++++--------------------
 1 file changed, 15 insertions(+), 61 deletions(-)

diff --git a/xbmc/windowing/egl/EGLNativeTypeRaspberryPI.cpp b/xbmc/windowing/egl/EGLNativeTypeRaspberryPI.cpp
index 69ce9b7..25a97ad 100644
--- a/xbmc/windowing/egl/EGLNativeTypeRaspberryPI.cpp
+++ b/xbmc/windowing/egl/EGLNativeTypeRaspberryPI.cpp
@@ -28,6 +28,9 @@
 #include "linux/RBP.h"
 #include "utils/StringUtils.h"
 #include "settings/Settings.h"
+#include "guilib/GraphicContext.h"
+#include "guilib/StereoscopicsManager.h"
+#include "rendering/RenderSystem.h"
 #include <cassert>
 
 #ifndef __VIDEOCORE4__
@@ -273,21 +276,22 @@ bool CEGLNativeTypeRaspberryPI::SetNativeResolution(const RESOLUTION_INFO &res)
 
   DestroyDispmaxWindow();
 
+  RENDER_STEREO_MODE stereo_mode = g_graphicsContext.GetStereoMode();
   if(GETFLAGS_GROUP(res.dwFlags) && GETFLAGS_MODE(res.dwFlags))
   {
     sem_init(&m_tv_synced, 0, 0);
     m_DllBcmHost->vc_tv_register_callback(CallbackTvServiceCallback, this);
 
-    if (res.dwFlags & (D3DPRESENTFLAG_MODE3DSBS|D3DPRESENTFLAG_MODE3DTB))
+    if (stereo_mode == RENDER_STEREO_MODE_SPLIT_HORIZONTAL || stereo_mode == RENDER_STEREO_MODE_SPLIT_VERTICAL)
     {
       /* inform TV of any 3D settings. Note this property just applies to next hdmi mode change, so no need to call for 2D modes */
       HDMI_PROPERTY_PARAM_T property;
       property.property = HDMI_PROPERTY_3D_STRUCTURE;
       if (CSettings::Get().GetBool("videoplayer.framepacking") && CSettings::Get().GetBool("videoplayer.supportmvc"))
         property.param1 = HDMI_3D_FORMAT_FRAME_PACKING;
-      else if (res.dwFlags & D3DPRESENTFLAG_MODE3DSBS)
+      else if (stereo_mode == RENDER_STEREO_MODE_SPLIT_VERTICAL)
         property.param1 = HDMI_3D_FORMAT_SBS_HALF;
-      else if (res.dwFlags & D3DPRESENTFLAG_MODE3DTB)
+      else if (stereo_mode == RENDER_STEREO_MODE_SPLIT_HORIZONTAL)
         property.param1 = HDMI_3D_FORMAT_TB_HALF;
       else
         property.param1 = HDMI_3D_FORMAT_NONE;
@@ -310,19 +314,17 @@ bool CEGLNativeTypeRaspberryPI::SetNativeResolution(const RESOLUTION_INFO &res)
 
     if (success == 0)
     {
-      CLog::Log(LOGDEBUG, "EGL set HDMI mode (%d,%d)=%d%s%s\n",
+      CLog::Log(LOGDEBUG, "EGL set HDMI mode (%d,%d)=%d %s\n",
                           GETFLAGS_GROUP(res.dwFlags), GETFLAGS_MODE(res.dwFlags), success,
-                          (res.dwFlags & D3DPRESENTFLAG_MODE3DSBS) ? " SBS":"",
-                          (res.dwFlags & D3DPRESENTFLAG_MODE3DTB) ? " TB":"");
+                          CStereoscopicsManager::Get().ConvertGuiStereoModeToString(stereo_mode));
 
       sem_wait(&m_tv_synced);
     }
     else
     {
-      CLog::Log(LOGERROR, "EGL failed to set HDMI mode (%d,%d)=%d%s%s\n",
+      CLog::Log(LOGERROR, "EGL failed to set HDMI mode (%d,%d)=%d %s\n",
                           GETFLAGS_GROUP(res.dwFlags), GETFLAGS_MODE(res.dwFlags), success,
-                          (res.dwFlags & D3DPRESENTFLAG_MODE3DSBS) ? " SBS":"",
-                          (res.dwFlags & D3DPRESENTFLAG_MODE3DTB) ? " TB":"");
+                          CStereoscopicsManager::Get().ConvertGuiStereoModeToString(stereo_mode));
     }
     m_DllBcmHost->vc_tv_unregister_callback(CallbackTvServiceCallback);
     sem_destroy(&m_tv_synced);
@@ -385,9 +387,9 @@ bool CEGLNativeTypeRaspberryPI::SetNativeResolution(const RESOLUTION_INFO &res)
   DISPMANX_TRANSFORM_T transform = DISPMANX_NO_ROTATE;
   DISPMANX_UPDATE_HANDLE_T dispman_update = m_DllBcmHost->vc_dispmanx_update_start(0);
 
-  if (res.dwFlags & D3DPRESENTFLAG_MODE3DSBS)
+  if (stereo_mode == RENDER_STEREO_MODE_SPLIT_VERTICAL)
     transform = DISPMANX_STEREOSCOPIC_SBS;
-  else if (res.dwFlags & D3DPRESENTFLAG_MODE3DTB)
+  else if (stereo_mode == RENDER_STEREO_MODE_SPLIT_HORIZONTAL)
     transform = DISPMANX_STEREOSCOPIC_TB;
   else
     transform = DISPMANX_STEREOSCOPIC_MONO;
@@ -494,10 +496,8 @@ static void SetResolutionString(RESOLUTION_INFO &res)
   res.iWidth = gui_width;
   res.iHeight = gui_height;
 
-  res.strMode = StringUtils::Format("%dx%d (%dx%d) @ %.2f%s%s%s - Full Screen", res.iScreenWidth, res.iScreenHeight, res.iWidth, res.iHeight, res.fRefreshRate,
-    res.dwFlags & D3DPRESENTFLAG_INTERLACED ? "i" : "",
-    res.dwFlags & D3DPRESENTFLAG_MODE3DTB   ? " 3DTB" : "",
-    res.dwFlags & D3DPRESENTFLAG_MODE3DSBS  ? " 3DSBS" : "");
+  res.strMode = StringUtils::Format("%dx%d (%dx%d) @ %.2f%s - Full Screen", res.iScreenWidth, res.iScreenHeight, res.iWidth, res.iHeight, res.fRefreshRate,
+    res.dwFlags & D3DPRESENTFLAG_INTERLACED ? "i" : "");
 }
 
 static SDTV_ASPECT_T get_sdtv_aspect_from_display_aspect(float display_aspect)
@@ -552,17 +552,6 @@ bool CEGLNativeTypeRaspberryPI::ProbeResolutions(std::vector<RESOLUTION_INFO> &r
       m_desktopRes.iScreenHeight= tv_state.display.hdmi.height;
       m_desktopRes.dwFlags      = MAKEFLAGS(tv_state.display.hdmi.group, tv_state.display.hdmi.mode, tv_state.display.hdmi.scan_mode);
       m_desktopRes.fPixelRatio  = tv_state.display.hdmi.display_options.aspect == 0 ? 1.0f : get_display_aspect_ratio((HDMI_ASPECT_T)tv_state.display.hdmi.display_options.aspect) / ((float)m_desktopRes.iScreenWidth / (float)m_desktopRes.iScreenHeight);
-      // Also add 3D flags
-      if (tv_state.display.hdmi.format_3d == HDMI_3D_FORMAT_SBS_HALF)
-      {
-        m_desktopRes.dwFlags |= D3DPRESENTFLAG_MODE3DSBS;
-        m_desktopRes.fPixelRatio *= 2.0;
-      }
-      else if (tv_state.display.hdmi.format_3d == HDMI_3D_FORMAT_TB_HALF)
-      {
-        m_desktopRes.dwFlags |= D3DPRESENTFLAG_MODE3DTB;
-        m_desktopRes.fPixelRatio *= 0.5;
-      }
       HDMI_PROPERTY_PARAM_T property;
       property.property = HDMI_PROPERTY_PIXEL_CLOCK_TYPE;
       vc_tv_hdmi_get_property(&property);
@@ -700,41 +689,6 @@ void CEGLNativeTypeRaspberryPI::GetSupportedModes(HDMI_RES_GROUP_T group, std::v
         res2.fRefreshRate  = (float)tv->frame_rate * (1000.0f/1001.0f);
         AddUniqueResolution(res2, resolutions);
       }
-
-      // Also add 3D versions of modes
-      if (tv->struct_3d_mask & HDMI_3D_STRUCT_SIDE_BY_SIDE_HALF_HORIZONTAL)
-      {
-        RESOLUTION_INFO res2 = res;
-        res2.dwFlags |= D3DPRESENTFLAG_MODE3DSBS;
-        res2.fPixelRatio    = get_display_aspect_ratio((HDMI_ASPECT_T)tv->aspect_ratio) / ((float)res2.iScreenWidth / (float)res2.iScreenHeight);
-        res2.fPixelRatio   *= 2.0f;
-        res2.iSubtitles    = (int)(0.965 * res2.iHeight);
-
-        AddUniqueResolution(res2, resolutions);
-        CLog::Log(LOGDEBUG, "EGL mode %d: %s (%.2f)\n", i, res2.strMode.c_str(), res2.fPixelRatio);
-        if (tv->frame_rate == 24 || tv->frame_rate == 30 || tv->frame_rate == 60)
-        {
-          res2.fRefreshRate  = (float)tv->frame_rate * (1000.0f/1001.0f);
-          AddUniqueResolution(res2, resolutions);
-        }
-      }
-      if (tv->struct_3d_mask & HDMI_3D_STRUCT_TOP_AND_BOTTOM)
-      {
-        RESOLUTION_INFO res2 = res;
-        res2.dwFlags |= D3DPRESENTFLAG_MODE3DTB;
-        res2.fPixelRatio    = get_display_aspect_ratio((HDMI_ASPECT_T)tv->aspect_ratio) / ((float)res2.iScreenWidth / (float)res2.iScreenHeight);
-        res2.fPixelRatio   *= 0.5f;
-        res2.iSubtitles    = (int)(0.965 * res2.iHeight);
-
-        AddUniqueResolution(res2, resolutions);
-        CLog::Log(LOGDEBUG, "EGL mode %d: %s (%.2f)\n", i, res2.strMode.c_str(), res2.fPixelRatio);
-        if (tv->frame_rate == 24 || tv->frame_rate == 30 || tv->frame_rate == 60)
-        {
-          res2.fRefreshRate  = (float)tv->frame_rate * (1000.0f/1001.0f);
-          AddUniqueResolution(res2, resolutions);
-        }
-
-      }
     }
   }
   if (supported_modes)

From 34d893fa7966aee5713548b781294fefcbb33c49 Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Tue, 30 Jun 2015 14:08:24 +0100
Subject: [PATCH 046/100] [rbp] Ignore video stereo mode when 3D display mode
 is disabled

---
 xbmc/cores/VideoRenderers/MMALRenderer.cpp | 4 ++++
 xbmc/cores/omxplayer/OMXPlayerVideo.cpp    | 4 ++++
 2 files changed, 8 insertions(+)

diff --git a/xbmc/cores/VideoRenderers/MMALRenderer.cpp b/xbmc/cores/VideoRenderers/MMALRenderer.cpp
index 5fc68d2..ce2e98d 100644
--- a/xbmc/cores/VideoRenderers/MMALRenderer.cpp
+++ b/xbmc/cores/VideoRenderers/MMALRenderer.cpp
@@ -589,6 +589,10 @@ void CMMALRenderer::SetVideoRect(const CRect& InSrcRect, const CRect& InDestRect
   bool stereo_invert                   = (m_iFlags & CONF_FLAGS_STEREO_CADANCE_RIGHT_LEFT) ? true : false;
   RENDER_STEREO_MODE display_stereo_mode = g_graphicsContext.GetStereoMode();
 
+  // ignore video stereo mode when 3D display mode is disabled
+  if (display_stereo_mode == RENDER_STEREO_MODE_OFF)
+    video_stereo_mode = RENDER_STEREO_MODE_OFF;
+
   // fix up transposed video
   if (m_renderOrientation == 90 || m_renderOrientation == 270)
   {
diff --git a/xbmc/cores/omxplayer/OMXPlayerVideo.cpp b/xbmc/cores/omxplayer/OMXPlayerVideo.cpp
index 3bf7c2e..5f6b402 100644
--- a/xbmc/cores/omxplayer/OMXPlayerVideo.cpp
+++ b/xbmc/cores/omxplayer/OMXPlayerVideo.cpp
@@ -658,6 +658,10 @@ void OMXPlayerVideo::SetVideoRect(const CRect &InSrcRect, const CRect &InDestRec
   bool stereo_invert                   = (flags & CONF_FLAGS_STEREO_CADANCE_RIGHT_LEFT) ? true : false;
   RENDER_STEREO_MODE display_stereo_mode = g_graphicsContext.GetStereoMode();
 
+  // ignore video stereo mode when 3D display mode is disabled
+  if (display_stereo_mode == RENDER_STEREO_MODE_OFF)
+    video_stereo_mode = RENDER_STEREO_MODE_OFF;
+
   // fix up transposed video
   if (m_hints.orientation == 90 || m_hints.orientation == 270)
   {

From b0df84434abb8b86d32d0e61c365c26b10c510dc Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Mon, 22 Jun 2015 16:27:15 +0100
Subject: [PATCH 047/100] [EGL] Don't skip out when HDMI mode is considered the
 same

It might have different 3D signalling. TODO: keep track of 3D signalling
---
 xbmc/windowing/egl/WinSystemEGL.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/xbmc/windowing/egl/WinSystemEGL.cpp b/xbmc/windowing/egl/WinSystemEGL.cpp
index c43c4d0..13b75b1 100644
--- a/xbmc/windowing/egl/WinSystemEGL.cpp
+++ b/xbmc/windowing/egl/WinSystemEGL.cpp
@@ -287,7 +287,7 @@ bool CWinSystemEGL::CreateNewWindow(const std::string& name, bool fullScreen, RE
     (current_resolution.dwFlags & D3DPRESENTFLAG_MODEMASK) == (res.dwFlags & D3DPRESENTFLAG_MODEMASK))
   {
     CLog::Log(LOGDEBUG, "CWinSystemEGL::CreateNewWindow: No need to create a new window");
-    return true;
+//xxx    return true;
   }
 
   m_bFullScreen   = fullScreen;

From bae1d271fec80a8707b447953e12b08934a0b163 Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Tue, 21 Apr 2015 14:32:07 +0100
Subject: [PATCH 048/100] [mmalrenderer] Add sharpness control

---
 addons/resource.language.en_gb/resources/strings.po |  2 +-
 xbmc/cores/VideoRenderers/MMALRenderer.cpp          | 13 ++++++++++++-
 xbmc/cores/VideoRenderers/MMALRenderer.h            |  1 +
 3 files changed, 14 insertions(+), 2 deletions(-)

diff --git a/addons/resource.language.en_gb/resources/strings.po b/addons/resource.language.en_gb/resources/strings.po
index 26ac2d7..f06ced6 100644
--- a/addons/resource.language.en_gb/resources/strings.po
+++ b/addons/resource.language.en_gb/resources/strings.po
@@ -7503,7 +7503,7 @@ msgstr ""
 
 #: xbmc/video/dialogs/GUIDialogVideoSettings.cpp
 msgctxt "#16313"
-msgid "VDPAU - Sharpness"
+msgid "Sharpness"
 msgstr ""
 
 #: xbmc/video/dialogs/GUIDialogVideoSettings.cpp
diff --git a/xbmc/cores/VideoRenderers/MMALRenderer.cpp b/xbmc/cores/VideoRenderers/MMALRenderer.cpp
index ce2e98d..fb92079 100644
--- a/xbmc/cores/VideoRenderers/MMALRenderer.cpp
+++ b/xbmc/cores/VideoRenderers/MMALRenderer.cpp
@@ -207,6 +207,7 @@ CMMALRenderer::CMMALRenderer()
   m_bConfigured = false;
   m_bMMALConfigured = false;
   m_iYV12RenderBuffer = 0;
+  m_sharpness = -2.0f;
 }
 
 CMMALRenderer::~CMMALRenderer()
@@ -373,6 +374,15 @@ void CMMALRenderer::RenderUpdate(bool clear, DWORD flags, DWORD alpha)
   if (m_RenderUpdateCallBackFn)
     (*m_RenderUpdateCallBackFn)(m_RenderUpdateCallBackCtx, m_sourceRect, m_destRect);
 
+  // if sharpness setting has changed, we should update it
+  if (m_sharpness != CMediaSettings::Get().GetCurrentVideoSettings().m_Sharpness)
+  {
+    m_sharpness = CMediaSettings::Get().GetCurrentVideoSettings().m_Sharpness;
+    char command[80], response[80];
+    sprintf(command, "scaling_sharpness %d", ((int)(50.0f * (m_sharpness + 1.0f) + 0.5f)));
+    vc_gencmd(response, sizeof response, command);
+  }
+
   if (m_format == RENDER_FMT_BYPASS)
     return;
 
@@ -559,7 +569,8 @@ bool CMMALRenderer::Supports(ERENDERFEATURE feature)
       feature == RENDERFEATURE_ZOOM            ||
       feature == RENDERFEATURE_ROTATION        ||
       feature == RENDERFEATURE_VERTICAL_SHIFT  ||
-      feature == RENDERFEATURE_PIXEL_RATIO)
+      feature == RENDERFEATURE_PIXEL_RATIO     ||
+      feature == RENDERFEATURE_SHARPNESS)
     return true;
 
   return false;
diff --git a/xbmc/cores/VideoRenderers/MMALRenderer.h b/xbmc/cores/VideoRenderers/MMALRenderer.h
index 1404fb3..9bced7e 100644
--- a/xbmc/cores/VideoRenderers/MMALRenderer.h
+++ b/xbmc/cores/VideoRenderers/MMALRenderer.h
@@ -105,6 +105,7 @@ class CMMALRenderer : public CBaseRenderer
   RENDER_STEREO_MODE        m_video_stereo_mode;
   RENDER_STEREO_MODE        m_display_stereo_mode;
   bool                      m_StereoInvert;
+  float                     m_sharpness;
 
   CCriticalSection m_sharedSection;
   MMAL_COMPONENT_T *m_vout;

From 33f42e33ae846ff3b3708870835255850080973a Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Fri, 24 Apr 2015 13:49:51 +0100
Subject: [PATCH 049/100] [dvdplayer] Add back required include

---
 xbmc/cores/dvdplayer/DVDPlayerVideo.cpp | 1 +
 1 file changed, 1 insertion(+)

diff --git a/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp b/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp
index 6ad751f..40c0102 100644
--- a/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp
+++ b/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp
@@ -33,6 +33,7 @@
 #include "DVDCodecs/Video/DVDVideoPPFFmpeg.h"
 #include "DVDCodecs/Video/DVDVideoCodecFFmpeg.h"
 #include "DVDDemuxers/DVDDemux.h"
+#include "DVDDemuxers/DVDDemuxUtils.h"
 #include "DVDOverlayRenderer.h"
 #include "guilib/GraphicContext.h"
 #include <sstream>

From 00ba5a7e69d67f0c102ef162fa7c13b3325a7550 Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Tue, 5 May 2015 23:58:06 +0100
Subject: [PATCH 050/100] [screensaver] Leave GUI contents available for
 screensaver

---
 xbmc/guilib/GUIWindowManager.cpp | 11 ++++++++++-
 1 file changed, 10 insertions(+), 1 deletion(-)

diff --git a/xbmc/guilib/GUIWindowManager.cpp b/xbmc/guilib/GUIWindowManager.cpp
index aa6713d..590fcec 100644
--- a/xbmc/guilib/GUIWindowManager.cpp
+++ b/xbmc/guilib/GUIWindowManager.cpp
@@ -800,7 +800,16 @@ void CGUIWindowManager::ActivateWindow_Internal(int iWindowID, const vector<stri
   int currentWindow = GetActiveWindow();
   CGUIWindow *pWindow = GetWindow(currentWindow);
   if (pWindow)
-    CloseWindowSync(pWindow, iWindowID);
+  {
+    if (iWindowID == WINDOW_SCREENSAVER)
+    {
+      pWindow->Close(true, iWindowID);
+    }
+    else
+    {
+      CloseWindowSync(pWindow, iWindowID);
+    }
+  }
   g_infoManager.SetNextWindow(WINDOW_INVALID);
 
   // Add window to the history list (we must do this before we activate it,

From a73c7d93b39be8ba657a7ea9635bc17bcb2ba759 Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Fri, 15 May 2015 14:04:11 +0100
Subject: [PATCH 052/100] [omxplayer] Make unsupported when ac3transcode is
 enabled

---
 xbmc/cores/omxplayer/OMXHelper.cpp | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/xbmc/cores/omxplayer/OMXHelper.cpp b/xbmc/cores/omxplayer/OMXHelper.cpp
index eff47e0..b954276 100644
--- a/xbmc/cores/omxplayer/OMXHelper.cpp
+++ b/xbmc/cores/omxplayer/OMXHelper.cpp
@@ -56,6 +56,12 @@ bool OMXPlayerUnsuitable(bool m_HasVideo, bool m_HasAudio, CDVDDemux* m_pDemuxer
     CLog::Log(LOGNOTICE, "%s OMXPlayer unsuitable due to audio sink", __func__);
     return true;
   }
+  // omxplayer doesn't handle ac3 transcode
+  if (CSettings::Get().GetBool("audiooutput.ac3transcode"))
+  {
+    CLog::Log(LOGNOTICE, "%s OMXPlayer unsuitable due to ac3transcode", __func__);
+    return true;
+  }
   if (m_pDemuxer)
   {
     // find video stream

From 5653b18176534dead919f805f5ca1430c998ab6f Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Mon, 1 Jun 2015 14:14:43 +0100
Subject: [PATCH 053/100] [omximage] Don't report failed decode of progressive
 jpegs as as error

---
 xbmc/cores/omxplayer/OMXImage.cpp | 26 ++++++++++----------------
 1 file changed, 10 insertions(+), 16 deletions(-)

diff --git a/xbmc/cores/omxplayer/OMXImage.cpp b/xbmc/cores/omxplayer/OMXImage.cpp
index a43a446..890ca88 100644
--- a/xbmc/cores/omxplayer/OMXImage.cpp
+++ b/xbmc/cores/omxplayer/OMXImage.cpp
@@ -601,7 +601,10 @@ OMX_IMAGE_CODINGTYPE COMXImageFile::GetCodingType(unsigned int &width, unsigned
   m_orientation   = 0;
 
   if(!m_image_size)
+  {
+    CLog::Log(LOGERROR, "%s::%s %s m_image_size unexpected (%lu)\n", CLASSNAME, __func__, m_filename, m_image_size);
     return OMX_IMAGE_CodingMax;
+  }
 
   uint8_t *p = m_image_buffer;
   uint8_t *q = m_image_buffer + m_image_size;
@@ -848,17 +851,14 @@ OMX_IMAGE_CODINGTYPE COMXImageFile::GetCodingType(unsigned int &width, unsigned
 
     }
   }
+  else
+    CLog::Log(LOGERROR, "%s::%s error unsupported image format\n", CLASSNAME, __func__);
 
   // apply input orientation
   m_orientation = m_orientation ^ orientation;
   if(m_orientation < 0 || m_orientation >= 8)
     m_orientation = 0;
 
-  if(eCompressionFormat == OMX_IMAGE_CodingMax)
-  {
-    CLog::Log(LOGERROR, "%s::%s error unsupported image format\n", CLASSNAME, __func__);
-  }
-
   if(progressive)
   {
     CLog::Log(LOGWARNING, "%s::%s progressive images not supported by decoder\n", CLASSNAME, __func__);
@@ -881,7 +881,7 @@ bool COMXImageFile::ReadFile(const std::string& inputFile, int orientation)
   m_filename = inputFile.c_str();
   if(!m_pFile.Open(inputFile, 0))
   {
-    CLog::Log(LOGERROR, "%s::%s %s not found\n", CLASSNAME, __func__, inputFile.c_str());
+    CLog::Log(LOGERROR, "%s::%s %s not found\n", CLASSNAME, __func__, m_filename);
     return false;
   }
 
@@ -893,13 +893,13 @@ bool COMXImageFile::ReadFile(const std::string& inputFile, int orientation)
 
   if(!m_image_size)
   {
-    CLog::Log(LOGERROR, "%s::%s %s m_image_size zero\n", CLASSNAME, __func__, inputFile.c_str());
+    CLog::Log(LOGERROR, "%s::%s %s m_image_size zero\n", CLASSNAME, __func__, m_filename);
     return false;
   }
   m_image_buffer = (uint8_t *)malloc(m_image_size);
   if(!m_image_buffer)
   {
-    CLog::Log(LOGERROR, "%s::%s %s m_image_buffer null (%lu)\n", CLASSNAME, __func__, inputFile.c_str(), m_image_size);
+    CLog::Log(LOGERROR, "%s::%s %s m_image_buffer null (%lu)\n", CLASSNAME, __func__, m_filename, m_image_size);
     return false;
   }
   
@@ -907,15 +907,9 @@ bool COMXImageFile::ReadFile(const std::string& inputFile, int orientation)
   m_pFile.Close();
 
   OMX_IMAGE_CODINGTYPE eCompressionFormat = GetCodingType(m_width, m_height, orientation);
-  if(eCompressionFormat != OMX_IMAGE_CodingJPEG)
-  {
-    CLog::Log(LOGERROR, "%s::%s %s GetCodingType=0x%x\n", CLASSNAME, __func__, inputFile.c_str(), eCompressionFormat);
-    return false;
-  }
-
-  if(m_width < 1 || m_height < 1)
+  if(eCompressionFormat != OMX_IMAGE_CodingJPEG || m_width < 1 || m_height < 1)
   {
-    CLog::Log(LOGERROR, "%s::%s %s m_width=%d m_height=%d\n", CLASSNAME, __func__, inputFile.c_str(), m_width, m_height);
+    CLog::Log(LOGDEBUG, "%s::%s %s GetCodingType=0x%x (%dx%x)\n", CLASSNAME, __func__, m_filename, eCompressionFormat, m_width, m_height);
     return false;
   }
 

From f7dca5ab0bb6e606f661820f4a5d28172e28d27b Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Mon, 25 May 2015 19:01:00 +0100
Subject: [PATCH 054/100] [rbp] Allow settings option for timestamp preference

We currently have some files that play better with pts timestamps and some that play better with dts timestamps
Provide a gui setting to allow users to adjust this behaviour until we have a better solution
---
 addons/resource.language.en_gb/resources/strings.po | 10 ++++++++++
 system/settings/rbp.xml                             |  7 +++++++
 xbmc/cores/dvdplayer/DVDCodecs/Video/MMALCodec.cpp  |  2 +-
 xbmc/cores/omxplayer/OMXPlayerVideo.cpp             |  2 +-
 4 files changed, 19 insertions(+), 2 deletions(-)

diff --git a/addons/resource.language.en_gb/resources/strings.po b/addons/resource.language.en_gb/resources/strings.po
index eb31d58..a631d80 100644
--- a/addons/resource.language.en_gb/resources/strings.po
+++ b/addons/resource.language.en_gb/resources/strings.po
@@ -16737,3 +16737,13 @@ msgstr ""
 msgctxt "#38121"
 msgid "This option supports 8 channel DTS HD decoding, but may use more CPU. It is only available when DTS and DTS-HD audio passthrough is disabled"
 msgstr ""
+
+#: system/settings/rbp.xml
+msgctxt "#38210"
+msgid "Prefer PTS timestamps"
+msgstr ""
+
+#: system/settings/rbp.xml
+msgctxt "#38211"
+msgid "Try enabling this if you have stutter with video files"
+msgstr ""
diff --git a/system/settings/rbp.xml b/system/settings/rbp.xml
index b27d23f..8c6e69d 100644
--- a/system/settings/rbp.xml
+++ b/system/settings/rbp.xml
@@ -42,6 +42,13 @@
           <control type="toggle" />
         </setting>
       </group>
+      <group id="3">
+        <setting id="videoplayer.preferptstimestamps" type="boolean" label="38210" help="38211">
+          <level>3</level>
+          <default>false</default>
+          <control type="toggle" />
+        </setting>
+      </group>
     </category>
     <category id="myvideos">
       <group id="1">
diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/MMALCodec.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/MMALCodec.cpp
index a583450..4a63820 100644
--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/MMALCodec.cpp
+++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/MMALCodec.cpp
@@ -797,7 +797,7 @@ int CMMALVideo::Decode(uint8_t* pData, int iSize, double dts, double pts)
          pts = 0;
        buffer->pts = pts == DVD_NOPTS_VALUE ? MMAL_TIME_UNKNOWN : pts;
        buffer->dts = dts == DVD_NOPTS_VALUE ? MMAL_TIME_UNKNOWN : dts;
-       if (buffer->dts != MMAL_TIME_UNKNOWN) buffer->pts = MMAL_TIME_UNKNOWN;
+       if (buffer->dts != MMAL_TIME_UNKNOWN && !CSettings::Get().GetBool("videoplayer.preferptstimestamps")) buffer->pts = MMAL_TIME_UNKNOWN;
        buffer->length = demuxer_bytes > buffer->alloc_size ? buffer->alloc_size : demuxer_bytes;
        // set a flag so we can identify primary frames from generated frames (deinterlace)
        buffer->flags = MMAL_BUFFER_HEADER_FLAG_USER0;
diff --git a/xbmc/cores/omxplayer/OMXPlayerVideo.cpp b/xbmc/cores/omxplayer/OMXPlayerVideo.cpp
index 5f6b402..ce23bec 100644
--- a/xbmc/cores/omxplayer/OMXPlayerVideo.cpp
+++ b/xbmc/cores/omxplayer/OMXPlayerVideo.cpp
@@ -495,7 +495,7 @@ void OMXPlayerVideo::Process()
         if (pts != DVD_NOPTS_VALUE)
           pts += m_iVideoDelay;
 
-        m_omxVideo.Decode(pPacket->pData, pPacket->iSize, dts, dts == DVD_NOPTS_VALUE ? pts : DVD_NOPTS_VALUE);
+        m_omxVideo.Decode(pPacket->pData, pPacket->iSize, dts, dts != DVD_NOPTS_VALUE && !CSettings::Get().GetBool("videoplayer.preferptstimestamps") ? DVD_NOPTS_VALUE : pts);
 
         if (pts == DVD_NOPTS_VALUE)
           pts = dts;

From b267cc628998b7221a005fabd07700980ca0dcca Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Sat, 6 Jun 2015 18:44:37 +0100
Subject: [PATCH 055/100] [rbp] Ignore pts value when m_hints.ptsinvalid set

---
 xbmc/cores/dvdplayer/DVDCodecs/Video/MMALCodec.cpp | 2 +-
 xbmc/cores/omxplayer/OMXPlayerVideo.cpp            | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/MMALCodec.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/MMALCodec.cpp
index 4a63820..f7b0b25 100644
--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/MMALCodec.cpp
+++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/MMALCodec.cpp
@@ -797,7 +797,7 @@ int CMMALVideo::Decode(uint8_t* pData, int iSize, double dts, double pts)
          pts = 0;
        buffer->pts = pts == DVD_NOPTS_VALUE ? MMAL_TIME_UNKNOWN : pts;
        buffer->dts = dts == DVD_NOPTS_VALUE ? MMAL_TIME_UNKNOWN : dts;
-       if (buffer->dts != MMAL_TIME_UNKNOWN && !CSettings::Get().GetBool("videoplayer.preferptstimestamps")) buffer->pts = MMAL_TIME_UNKNOWN;
+       if (m_hints.ptsinvalid || (buffer->dts != MMAL_TIME_UNKNOWN && !CSettings::Get().GetBool("videoplayer.preferptstimestamps"))) buffer->pts = MMAL_TIME_UNKNOWN;
        buffer->length = demuxer_bytes > buffer->alloc_size ? buffer->alloc_size : demuxer_bytes;
        // set a flag so we can identify primary frames from generated frames (deinterlace)
        buffer->flags = MMAL_BUFFER_HEADER_FLAG_USER0;
diff --git a/xbmc/cores/omxplayer/OMXPlayerVideo.cpp b/xbmc/cores/omxplayer/OMXPlayerVideo.cpp
index ce23bec..e17fdb8 100644
--- a/xbmc/cores/omxplayer/OMXPlayerVideo.cpp
+++ b/xbmc/cores/omxplayer/OMXPlayerVideo.cpp
@@ -495,7 +495,7 @@ void OMXPlayerVideo::Process()
         if (pts != DVD_NOPTS_VALUE)
           pts += m_iVideoDelay;
 
-        m_omxVideo.Decode(pPacket->pData, pPacket->iSize, dts, dts != DVD_NOPTS_VALUE && !CSettings::Get().GetBool("videoplayer.preferptstimestamps") ? DVD_NOPTS_VALUE : pts);
+        m_omxVideo.Decode(pPacket->pData, pPacket->iSize, dts, m_hints.ptsinvalid || (dts != DVD_NOPTS_VALUE && !CSettings::Get().GetBool("videoplayer.preferptstimestamps")) ? DVD_NOPTS_VALUE : pts);
 
         if (pts == DVD_NOPTS_VALUE)
           pts = dts;

From 4f81908e104cabccf91b87dbafefc7d3916bc637 Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Sat, 6 Jun 2015 18:43:57 +0100
Subject: [PATCH 056/100] ffmpeg: Automatic switch to software decode for GMC
 with more than one warp point

---
 ...Signal-unsupported-GMC-with-more-than-one.patch | 48 ++++++++++++++++++++++
 tools/depends/target/ffmpeg/Makefile               |  4 +-
 xbmc/cores/dvdplayer/DVDCodecs/Video/MMALCodec.cpp |  2 +
 xbmc/cores/dvdplayer/DVDDemuxers/DVDDemux.h        |  2 +
 .../cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.cpp |  2 +-
 xbmc/cores/dvdplayer/DVDStreamInfo.cpp             |  3 ++
 xbmc/cores/dvdplayer/DVDStreamInfo.h               |  1 +
 xbmc/cores/omxplayer/OMXHelper.cpp                 |  4 +-
 8 files changed, 63 insertions(+), 3 deletions(-)
 create mode 100644 tools/depends/target/ffmpeg/0001-mpeg4video-Signal-unsupported-GMC-with-more-than-one.patch

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 <popcornmix@gmail.com>
+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/xbmc/cores/dvdplayer/DVDCodecs/Video/MMALCodec.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/MMALCodec.cpp
index f7b0b25..3e97f1d 100644
--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/MMALCodec.cpp
+++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/MMALCodec.cpp
@@ -516,6 +516,8 @@ bool CMMALVideo::Open(CDVDStreamInfo &hints, CDVDCodecOptions &options)
   // we always qualify even if DVDFactoryCodec does this too.
   if (!CSettings::Get().GetBool("videoplayer.usemmal") || hints.software)
     return false;
+  if (hints.workaround_bugs & FF_BUG_GMC_UNSUPPORTED)
+    return false;
 
   m_hints = hints;
   m_vout_input_pool = (MMAL_POOL_T *)options.m_opaque_pointer;
diff --git a/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemux.h b/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemux.h
index fca164d..d450413 100644
--- a/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemux.h
+++ b/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemux.h
@@ -162,6 +162,7 @@ class CDemuxStreamVideo : public CDemuxStream
     type = STREAM_VIDEO;
     iOrientation = 0;
     iBitsPerPixel = 0;
+    workaround_bugs = 0;
   }
 
   virtual ~CDemuxStreamVideo() {}
@@ -178,6 +179,7 @@ class CDemuxStreamVideo : public CDemuxStream
   int iOrientation; // orientation of the video in degress counter clockwise
   int iBitsPerPixel;
   std::string stereo_mode; // expected stereo mode
+  int workaround_bugs; // info for decoder
 };
 
 class CDemuxStreamAudio : public CDemuxStream
diff --git a/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.cpp b/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.cpp
index 5feac29..f7d6dc8 100644
--- a/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.cpp
+++ b/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.cpp
@@ -1199,7 +1199,7 @@ CDemuxStream* CDVDDemuxFFmpeg::AddStream(int iId)
         if (!stereoMode.empty())
           st->stereo_mode = stereoMode;
 
-        
+        st->workaround_bugs = pStream->codec->workaround_bugs;
         if ( m_pInput->IsStreamType(DVDSTREAM_TYPE_DVD) )
         {
           if (pStream->codec->codec_id == AV_CODEC_ID_PROBE)
diff --git a/xbmc/cores/dvdplayer/DVDStreamInfo.cpp b/xbmc/cores/dvdplayer/DVDStreamInfo.cpp
index fa0defa..37c2d16 100644
--- a/xbmc/cores/dvdplayer/DVDStreamInfo.cpp
+++ b/xbmc/cores/dvdplayer/DVDStreamInfo.cpp
@@ -73,6 +73,7 @@ void CDVDStreamInfo::Clear()
   bitspersample = 0;
 
   orientation = 0;
+  workaround_bugs = 0;
 }
 
 bool CDVDStreamInfo::Equal(const CDVDStreamInfo& right, bool withextradata)
@@ -174,6 +175,7 @@ void CDVDStreamInfo::Assign(const CDVDStreamInfo& right, bool withextradata)
   vfr = right.vfr;
   software = right.software;
   stereo_mode = right.stereo_mode;
+  workaround_bugs = right.workaround_bugs;
 
   // AUDIO
   channels      = right.channels;
@@ -231,6 +233,7 @@ void CDVDStreamInfo::Assign(const CDemuxStream& right, bool withextradata)
     bitsperpixel = stream->iBitsPerPixel;
     pid = stream->iPhysicalId;
     stereo_mode = stream->stereo_mode;
+    workaround_bugs = stream->workaround_bugs;
   }
   else if(  right.type == STREAM_SUBTITLE )
   {
diff --git a/xbmc/cores/dvdplayer/DVDStreamInfo.h b/xbmc/cores/dvdplayer/DVDStreamInfo.h
index c0e22a2..3849993 100644
--- a/xbmc/cores/dvdplayer/DVDStreamInfo.h
+++ b/xbmc/cores/dvdplayer/DVDStreamInfo.h
@@ -73,6 +73,7 @@ class CDVDStreamInfo
   int bitsperpixel;
   int pid;
   std::string stereo_mode; // stereoscopic 3d mode
+  int workaround_bugs; // info for decoder
 
   // AUDIO
   int channels;
diff --git a/xbmc/cores/omxplayer/OMXHelper.cpp b/xbmc/cores/omxplayer/OMXHelper.cpp
index b954276..b5ee4b6 100644
--- a/xbmc/cores/omxplayer/OMXHelper.cpp
+++ b/xbmc/cores/omxplayer/OMXHelper.cpp
@@ -77,7 +77,9 @@ bool OMXPlayerUnsuitable(bool m_HasVideo, bool m_HasAudio, CDVDDemux* m_pDemuxer
       CDVDStreamInfo hint(*stream, true);
 
       bool supported = false;
-      if ((hint.codec == AV_CODEC_ID_MPEG1VIDEO || hint.codec == AV_CODEC_ID_MPEG2VIDEO) && g_RBP.GetCodecMpg2())
+      if (hint.workaround_bugs & FF_BUG_GMC_UNSUPPORTED)
+        ;
+      else if ((hint.codec == AV_CODEC_ID_MPEG1VIDEO || hint.codec == AV_CODEC_ID_MPEG2VIDEO) && g_RBP.GetCodecMpg2())
         supported = true;
       else if ((hint.codec == AV_CODEC_ID_VC1 || hint.codec == AV_CODEC_ID_WMV3) && g_RBP.GetCodecWvc1())
         supported = true;

From cbf63035726a23c0d4c0e56a073c5cf39d721643 Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Mon, 22 Jun 2015 21:46:57 +0100
Subject: [PATCH 057/100] [rbp] Use default resampling setting on Pi2

---
 system/settings/rbp2.xml | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/system/settings/rbp2.xml b/system/settings/rbp2.xml
index b29a428..1c8b116 100644
--- a/system/settings/rbp2.xml
+++ b/system/settings/rbp2.xml
@@ -28,6 +28,11 @@
         <setting id="audiooutput.ac3transcode" help="36429">
         </setting>
       </group>
+      <group id="1">
+        <setting id="audiooutput.processquality">
+          <default>30</default> <!-- AE_QUALITY_MID -->
+        </setting>
+      </group>
     </category>
   </section>
 </settings>

From 289515a7f96751f323490ca7ec30e97eeb5865e0 Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Thu, 25 Jun 2015 19:43:10 +0100
Subject: [PATCH 058/100] [rbp] HW mouse pointer

Updating the mouse point provokes a complete screen update which can make it feel laggy
and results in high cpu.

Render the mouse with an overlay to avoid redrawing the normal gui.

Requires recent firmware.
---
 xbmc/guilib/GUIWindowManager.cpp  |   2 +
 xbmc/linux/RBP.cpp                | 254 +++++++++++++++++++++
 xbmc/linux/RBP.h                  |  10 +
 xbmc/linux/rpi_user_vcsm.h        | 460 ++++++++++++++++++++++++++++++++++++++
 xbmc/windowing/WinEventsLinux.cpp | 147 ++++++++++++
 xbmc/windowing/WinEventsLinux.h   |  11 +
 6 files changed, 884 insertions(+)
 create mode 100644 xbmc/linux/rpi_user_vcsm.h

diff --git a/xbmc/guilib/GUIWindowManager.cpp b/xbmc/guilib/GUIWindowManager.cpp
index 590fcec..0494bc2 100644
--- a/xbmc/guilib/GUIWindowManager.cpp
+++ b/xbmc/guilib/GUIWindowManager.cpp
@@ -195,7 +195,9 @@ void CGUIWindowManager::CreateWindows()
   Add(new CGUIWindowAddonBrowser);
   Add(new CGUIWindowScreensaverDim);
   Add(new CGUIWindowDebugInfo);
+#ifndef TARGET_RASPBERRY_PI
   Add(new CGUIWindowPointer);
+#endif
   Add(new CGUIDialogYesNo);
   Add(new CGUIDialogProgress);
   Add(new CGUIDialogExtendedProgressBar);
diff --git a/xbmc/linux/RBP.cpp b/xbmc/linux/RBP.cpp
index 096ea18..2c8d09b 100644
--- a/xbmc/linux/RBP.cpp
+++ b/xbmc/linux/RBP.cpp
@@ -28,6 +28,31 @@
 
 #include "cores/omxplayer/OMXImage.h"
 
+#include "guilib/GraphicContext.h"
+#include "settings/DisplaySettings.h"
+
+#include <sys/ioctl.h>
+#include <linux/ioctl.h>
+#include "rpi_user_vcsm.h"
+
+#define MAJOR_NUM 100
+#define IOCTL_MBOX_PROPERTY _IOWR(MAJOR_NUM, 0, char *)
+#define DEVICE_FILE_NAME "/dev/vcio"
+
+typedef struct gpu_mem_ptr_s {
+  void *arm; // Pointer to memory mapped on ARM side
+  int vc_handle;   // Videocore handle of relocatable memory
+  int vcsm_handle; // Handle for use by VCSM
+  int vc;       // Address for use in GPU code
+  int numbytes; // Size of memory block
+  int suballoc;
+} GPU_MEM_PTR_T;
+
+static int mbox_open();
+static void mbox_close(int file_desc);
+static void gpu_free_internal(GPU_MEM_PTR_T *p, int mb);
+static int gpu_malloc_uncached_internal(int numbytes, GPU_MEM_PTR_T *p, int mb);
+
 CRBP::CRBP()
 {
   m_initialized     = false;
@@ -35,6 +60,9 @@ CRBP::CRBP()
   m_DllBcmHost      = new DllBcmHost();
   m_OMX             = new COMXCore();
   m_display = DISPMANX_NO_HANDLE;
+  m_p = NULL;
+  m_mb = mbox_open();
+  vcsm_init();
 }
 
 CRBP::~CRBP()
@@ -115,7 +143,10 @@ void CRBP::LogFirmwareVerison()
 DISPMANX_DISPLAY_HANDLE_T CRBP::OpenDisplay(uint32_t device)
 {
   if (m_display == DISPMANX_NO_HANDLE)
+  {
     m_display = vc_dispmanx_display_open( 0 /*screen*/ );
+    init_cursor();
+  }
   return m_display;
 }
 
@@ -124,6 +155,7 @@ void CRBP::CloseDisplay(DISPMANX_DISPLAY_HANDLE_T display)
   assert(display == m_display);
   vc_dispmanx_display_close(m_display);
   m_display = DISPMANX_NO_HANDLE;
+  uninit_cursor();
 }
 
 void CRBP::GetDisplaySize(int &width, int &height)
@@ -224,6 +256,15 @@ void CRBP::Deinitialize()
   m_omx_image_init  = false;
   m_initialized     = false;
   m_omx_initialized = false;
+  uninit_cursor();
+  if (m_mb && m_p)
+    gpu_free_internal(m_p, m_mb);
+  delete m_p;
+  m_p = NULL;
+  if (m_mb)
+    mbox_close(m_mb);
+  m_mb = 0;
+  vcsm_exit();
 }
 
 double CRBP::AdjustHDMIClock(double adjust)
@@ -239,4 +280,217 @@ double CRBP::AdjustHDMIClock(double adjust)
 }
 
 
+static int mbox_property(int file_desc, void *buf)
+{
+   int ret_val = ioctl(file_desc, IOCTL_MBOX_PROPERTY, buf);
+
+   if (ret_val < 0) {
+      printf("ioctl_set_msg failed:%d\n", ret_val);
+   }
+   return ret_val;
+}
+
+static int mbox_open()
+{
+   int file_desc;
+
+   // open a char device file used for communicating with kernel mbox driver
+   file_desc = open(DEVICE_FILE_NAME, 0);
+   if (file_desc < 0) {
+      printf("Can't open device file: %s (%d)\n", DEVICE_FILE_NAME, file_desc);
+      printf("Try creating a device file with: sudo mknod %s c %d 0\n", DEVICE_FILE_NAME, MAJOR_NUM);
+   }
+   return file_desc;
+}
+
+static void mbox_close(int file_desc)
+{
+  close(file_desc);
+}
+
+static unsigned mem_lock(int file_desc, unsigned handle)
+{
+   int i=0;
+   unsigned p[32];
+   p[i++] = 0; // size
+   p[i++] = 0x00000000; // process request
+
+   p[i++] = 0x3000d; // (the tag id)
+   p[i++] = 4; // (size of the buffer)
+   p[i++] = 4; // (size of the data)
+   p[i++] = handle;
+
+   p[i++] = 0x00000000; // end tag
+   p[0] = i*sizeof *p; // actual size
+
+   mbox_property(file_desc, p);
+   return p[5];
+}
+
+unsigned mem_unlock(int file_desc, unsigned handle)
+{
+   int i=0;
+   unsigned p[32];
+   p[i++] = 0; // size
+   p[i++] = 0x00000000; // process request
+
+   p[i++] = 0x3000e; // (the tag id)
+   p[i++] = 4; // (size of the buffer)
+   p[i++] = 4; // (size of the data)
+   p[i++] = handle;
+
+   p[i++] = 0x00000000; // end tag
+   p[0] = i*sizeof *p; // actual size
+
+   mbox_property(file_desc, p);
+   return p[5];
+}
+
+unsigned int mailbox_set_cursor_info(int file_desc, int width, int height, int format, uint32_t buffer, int hotspotx, int hotspoty)
+{
+   int i=0;
+   unsigned int p[32];
+   p[i++] = 0; // size
+   p[i++] = 0x00000000; // process request
+   p[i++] = 0x00008010; // set cursor state
+   p[i++] = 24; // buffer size
+   p[i++] = 24; // data size
+
+   p[i++] = width;
+   p[i++] = height;
+   p[i++] = format;
+   p[i++] = buffer;           // ptr to VC memory buffer. Doesn't work in 64bit....
+   p[i++] = hotspotx;
+   p[i++] = hotspoty;
+
+   p[i++] = 0x00000000; // end tag
+   p[0] = i*sizeof(*p); // actual size
+
+   mbox_property(file_desc, p);
+   return p[5];
+
+}
+
+unsigned int mailbox_set_cursor_position(int file_desc, int enabled, int x, int y)
+{
+   int i=0;
+   unsigned p[32];
+   p[i++] = 0; // size
+   p[i++] = 0x00000000; // process request
+   p[i++] = 0x00008011; // set cursor state
+   p[i++] = 12; // buffer size
+   p[i++] = 12; // data size
+
+   p[i++] = enabled;
+   p[i++] = x;
+   p[i++] = y;
+
+   p[i++] = 0x00000000; // end tag
+   p[0] = i*sizeof *p; // actual size
+
+   mbox_property(file_desc, p);
+   return p[5];
+}
+
+static int gpu_malloc_uncached_internal(int numbytes, GPU_MEM_PTR_T *p, int mb)
+{
+  //printf("%s %d\n", __func__, numbytes);
+
+  p->numbytes = numbytes;
+  p->suballoc = 0;
+  p->vcsm_handle = vcsm_malloc_cache(numbytes, VCSM_CACHE_TYPE_NONE, (char *)"Mouse pointer");
+  assert(p->vcsm_handle);
+  p->vc_handle = vcsm_vc_hdl_from_hdl(p->vcsm_handle);
+  assert(p->vc_handle);
+  p->arm = vcsm_lock(p->vcsm_handle);
+  assert(p->arm);
+  p->vc = mem_lock(mb, p->vc_handle);
+  assert(p->vc);
+  return 0;
+}
+
+static void gpu_free_internal(GPU_MEM_PTR_T *p, int mb)
+{
+  mem_unlock(mb,p->vc_handle);
+  vcsm_unlock_ptr(p->arm);
+  vcsm_free(p->vcsm_handle);
+}
+
+#define T 0
+#define W 0xffffffff
+#define B 0xff000000
+
+const static uint32_t default_cursor_pixels[] =
+{
+   B,B,B,B,B,B,B,B,B,T,T,T,T,T,T,T,
+   B,W,W,W,W,W,W,B,T,T,T,T,T,T,T,T,
+   B,W,W,W,W,W,B,T,T,T,T,T,T,T,T,T,
+   B,W,W,W,W,B,T,T,T,T,T,T,T,T,T,T,
+   B,W,W,W,W,W,B,T,T,T,T,T,T,T,T,T,
+   B,W,W,B,W,W,W,B,T,T,T,T,T,T,T,T,
+   B,W,B,T,B,W,W,W,B,T,T,T,T,T,T,T,
+   B,B,T,T,T,B,W,W,W,B,T,T,T,T,T,T,
+   B,T,T,T,T,T,B,W,W,W,B,T,T,T,T,T,
+   T,T,T,T,T,T,T,B,W,W,W,B,T,T,T,T,
+   T,T,T,T,T,T,T,T,B,W,W,W,B,T,T,T,
+   T,T,T,T,T,T,T,T,T,B,W,W,W,B,T,T,
+   T,T,T,T,T,T,T,T,T,T,B,W,W,W,B,T,
+   T,T,T,T,T,T,T,T,T,T,T,B,W,W,W,B,
+   T,T,T,T,T,T,T,T,T,T,T,T,B,W,B,T,
+   T,T,T,T,T,T,T,T,T,T,T,T,T,B,T,T
+};
+
+#undef T
+#undef W
+#undef B
+
+void CRBP::init_cursor()
+{
+  //printf("%s\n", __func__);
+  if (!m_mb)
+    return;
+  if (!m_p)
+  {
+    m_p = new GPU_MEM_PTR_T;
+    if (m_p)
+      gpu_malloc_uncached_internal(64 * 64 * 4, m_p, m_mb);
+  }
+  if (m_mb && m_p && m_p->arm && m_p->vc)
+    set_cursor(default_cursor_pixels, 16, 16, 0, 0);
+}
+
+void CRBP::set_cursor(const void *pixels, int width, int height, int hotspot_x, int hotspot_y)
+{
+  if (!m_mb || !m_p || !m_p->arm || !m_p->vc || !pixels || width * height > 64 * 64)
+    return;
+  //printf("%s %dx%d %p\n", __func__, width, height, pixels);
+  memcpy(m_p->arm, pixels, width * height * 4);
+  unsigned int s = mailbox_set_cursor_info(m_mb, width, height, 0, m_p->vc, hotspot_x, hotspot_y);
+  assert(s == 0);
+}
+
+void CRBP::update_cursor(int x, int y, bool enabled)
+{
+  if (!m_mb || !m_p || !m_p->arm || !m_p->vc)
+    return;
+
+  RESOLUTION res = g_graphicsContext.GetVideoResolution();
+  CRect gui(0, 0, CDisplaySettings::Get().GetResolutionInfo(res).iWidth, CDisplaySettings::Get().GetResolutionInfo(res).iHeight);
+  CRect display(0, 0, CDisplaySettings::Get().GetResolutionInfo(res).iScreenWidth, CDisplaySettings::Get().GetResolutionInfo(res).iScreenHeight);
+
+  int x2 = x * display.Width()  / gui.Width();
+  int y2 = y * display.Height() / gui.Height();
+
+  //printf("%s %d,%d (%d)\n", __func__, x, y, enabled);
+  mailbox_set_cursor_position(m_mb, enabled, x2, y2);
+}
+
+void CRBP::uninit_cursor()
+{
+  if (!m_mb || !m_p || !m_p->arm || !m_p->vc)
+    return;
+  //printf("%s\n", __func__);
+  mailbox_set_cursor_position(m_mb, 0, 0, 0);
+}
+
 #endif
diff --git a/xbmc/linux/RBP.h b/xbmc/linux/RBP.h
index b422c89..f233a5e 100644
--- a/xbmc/linux/RBP.h
+++ b/xbmc/linux/RBP.h
@@ -41,6 +41,8 @@
 #include "threads/CriticalSection.h"
 #include "threads/Event.h"
 
+struct gpu_mem_ptr_s;
+
 class CRBP
 {
 public:
@@ -81,6 +83,14 @@ class CRBP
   CEvent     m_vsync;
   class DllLibOMXCore;
   CCriticalSection m_critSection;
+
+  struct gpu_mem_ptr_s *m_p;
+  int m_mb;
+public:
+  void init_cursor();
+  void set_cursor(const void *pixels, int width, int height, int hotspot_x, int hotspot_y);
+  void update_cursor(int x, int y, bool enabled);
+  void uninit_cursor();
 };
 
 extern CRBP g_RBP;
diff --git a/xbmc/linux/rpi_user_vcsm.h b/xbmc/linux/rpi_user_vcsm.h
new file mode 100644
index 0000000..94e6e79
--- /dev/null
+++ b/xbmc/linux/rpi_user_vcsm.h
@@ -0,0 +1,460 @@
+/*****************************************************************************
+* Copyright 2001 - 2011 Broadcom Corporation.  All rights reserved.
+*
+* This program is the proprietary software of Broadcom Corporation and/or
+* its licensors, and may only be used, duplicated, modified or distributed
+* pursuant to the terms and conditions of a separate, written license
+* agreement executed between you and Broadcom (an "Authorized License").
+* Except as set forth in an Authorized License, Broadcom grants no license
+* (express or implied), right to use, or waiver of any kind with respect to
+* the Software, and Broadcom expressly reserves all rights in and to the
+* Software and all intellectual property rights therein.  IF YOU HAVE NO
+* AUTHORIZED LICENSE, THEN YOU HAVE NO RIGHT TO USE THIS SOFTWARE IN ANY
+* WAY, AND SHOULD IMMEDIATELY NOTIFY BROADCOM AND DISCONTINUE ALL USE OF
+* THE SOFTWARE.
+*
+* Except as expressly set forth in the Authorized License,
+* 1. This program, including its structure, sequence and organization,
+*    constitutes the valuable trade secrets of Broadcom, and you shall use
+*    all reasonable efforts to protect the confidentiality thereof, and to
+*    use this information only in connection with your use of Broadcom
+*    integrated circuit products.
+* 2. TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED "AS IS"
+*    AND WITH ALL FAULTS AND BROADCOM MAKES NO PROMISES, REPRESENTATIONS OR
+*    WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY, OR OTHERWISE, WITH
+*    RESPECT TO THE SOFTWARE.  BROADCOM SPECIFICALLY DISCLAIMS ANY AND ALL
+*    IMPLIED WARRANTIES OF TITLE, MERCHANTABILITY, NONINFRINGEMENT, FITNESS
+*    FOR A PARTICULAR PURPOSE, LACK OF VIRUSES, ACCURACY OR COMPLETENESS,
+*    QUIET ENJOYMENT, QUIET POSSESSION OR CORRESPONDENCE TO DESCRIPTION. YOU
+*    ASSUME THE ENTIRE RISK ARISING OUT OF USE OR PERFORMANCE OF THE SOFTWARE.
+* 3. TO THE MAXIMUM EXTENT PERMITTED BY LAW, IN NO EVENT SHALL BROADCOM OR ITS
+*    LICENSORS BE LIABLE FOR (i) CONSEQUENTIAL, INCIDENTAL, SPECIAL, INDIRECT,
+*    OR EXEMPLARY DAMAGES WHATSOEVER ARISING OUT OF OR IN ANY WAY RELATING TO
+*    YOUR USE OF OR INABILITY TO USE THE SOFTWARE EVEN IF BROADCOM HAS BEEN
+*    ADVISED OF THE POSSIBILITY OF SUCH DAMAGES; OR (ii) ANY AMOUNT IN EXCESS
+*    OF THE AMOUNT ACTUALLY PAID FOR THE SOFTWARE ITSELF OR U.S. $1, WHICHEVER
+*    IS GREATER. THESE LIMITATIONS SHALL APPLY NOTWITHSTANDING ANY FAILURE OF
+*    ESSENTIAL PURPOSE OF ANY LIMITED REMEDY.
+*****************************************************************************/
+
+#ifndef __USER_VCSM__H__INCLUDED__
+#define __USER_VCSM__H__INCLUDED__
+
+/* VideoCore Shared Memory - user interface library.
+**
+** This library provides all the necessary abstraction for any application to
+** make use of the shared memory service which is distributed accross a kernel
+** driver and a videocore service.
+**
+** It is an application design decision to choose or not to use this service.
+**
+** The logical flow of operations that a user application needs to follow when
+** using this service is:
+**
+**       1) Initialize the service.
+**       2) Allocate shared memory blocks.
+**       3) Start using the allocated blocks.
+**          - In order to gain ownership on a block, lock the allocated block,
+**            locking a block returns a valid address that the user application
+**            can access.
+**          - When finished with using the block for the current execution cycle
+**            or function, and so when giving up the ownership, unlock the block.
+**       4) A block can be locked/unlocked as many times required - within or outside
+**          of - a specific execution context.
+**       5) To completely release an allocated block, free it.
+**       6) If the service is no longer required, terminate it.
+**
+**
+** Some generic considerations:
+
+** Allocating memory blocks.
+**
+**   Memory blocks can be allocated in different manners depending on the cache
+**   behavior desired.  A given block can either be:
+
+**       - Allocated in a non cached fashion all the way through host and videocore.
+**       - Allocated in a cached fashion on host OR videocore.
+**       - Allocated in a cached fashion on host AND videocore.
+**
+**   It is an application decision to determine how to allocate a block.  Evidently
+**   if the application will be doing substantial read/write accesses to a given block,
+**   it is recommended to allocate the block at least in a 'host cached' fashion for
+**   better results.
+**
+**
+** Locking memory blocks.
+**
+**   When the memory block has been allocated in a host cached fashion, locking the
+**   memory block (and so taking ownership of it) will trigger a cache invalidation.
+**
+**   For the above reason and when using host cached allocation, it is important that
+**   an application properly implements the lock/unlock mechanism to ensure cache will
+**   stay coherent, otherwise there is no guarantee it will at all be.
+**
+**   It is possible to dynamically change the host cache behavior (ie cached or non
+**   cached) of a given allocation without needing to free and re-allocate the block.
+**   This feature can be useful for such application which requires access to the block
+**   only at certain times and not otherwise.  By changing the cache behavior dynamically
+**   the application can optimize performances for a given duration of use.
+**   Such dynamic cache behavior remapping only applies to host cache and not videocore
+**   cache.  If one requires to change the videocore cache behavior, then a new block
+**   must be created to replace the old one.
+**
+**   On successful locking, a valid pointer is returned that the application can use
+**   to access to data inside the block.  There is no guarantee that the pointer will
+**   stay valid following the unlock action corresponding to this lock.
+**
+**
+** Unocking memory blocks.
+**
+**   When the memory block has been allocated in a host cached fashion, unlocking the
+**   memory block (and so forgiving its ownership) will trigger a cache flush unless
+**   explicitely asked not to flush the cache for performances reasons.
+**
+**   For the above reason and when using host cached allocation, it is important that
+**   an application properly implements the lock/unlock mechanism to ensure cache will
+**   stay coherent, otherwise there is no guarantee it will at all be.
+**
+**
+** A complete API is defined below.
+*/
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/* Different status that can be dumped.
+*/
+typedef enum
+{
+   VCSM_STATUS_VC_WALK_ALLOC = 0,   // Walks *all* the allocation on videocore.
+                                    // Result of the walk is seen in the videocore
+                                    // log.
+   VCSM_STATUS_HOST_WALK_MAP,       // Walks the *full* mapping allocation on host
+                                    // driver (ie for all processes).  Result of
+                                    // the walk is seen in the kernel log.
+   VCSM_STATUS_HOST_WALK_PID_MAP,   // Walks the per process mapping allocation on host
+                                    // driver (for current process).  Result of
+                                    // the walk is seen in the kernel log.
+   VCSM_STATUS_HOST_WALK_PID_ALLOC, // Walks the per process host allocation on host
+                                    // driver (for current process).  Result of
+                                    // the walk is seen in the kernel log.
+   VCSM_STATUS_VC_MAP_ALL,          // Equivalent to both VCSM_STATUS_VC_WALK_ALLOC and
+                                    // VCSM_STATUS_HOST_WALK_MAP.
+                                    //
+   VCSM_STATUS_NONE,                // Must be last - invalid.
+
+} VCSM_STATUS_T;
+
+/* Different kind of cache behavior.
+*/
+typedef enum
+{
+   VCSM_CACHE_TYPE_NONE = 0,        // No caching applies.
+   VCSM_CACHE_TYPE_HOST,            // Allocation is cached on host (user space).
+   VCSM_CACHE_TYPE_VC,              // Allocation is cached on videocore.
+   VCSM_CACHE_TYPE_HOST_AND_VC,     // Allocation is cached on both host and videocore.
+
+} VCSM_CACHE_TYPE_T;
+
+/* Initialize the vcsm processing.
+**
+** Must be called once before attempting to do anything else.
+**
+** Returns 0 on success, -1 on error.
+*/
+int vcsm_init( void );
+
+
+/* Terminates the vcsm processing.
+**
+** Must be called vcsm services are no longer needed, it will
+** take care of removing any allocation under the current process
+** control if deemed necessary.
+*/
+void vcsm_exit( void );
+
+
+/* Queries the status of the the vcsm.
+**
+** Triggers dump of various kind of information, see the
+** different variants specified in VCSM_STATUS_T.
+**
+** Pid is optional.
+*/
+void vcsm_status( VCSM_STATUS_T status, int pid );
+
+
+/* Allocates a non-cached block of memory of size 'size' via the vcsm memory
+** allocator.
+**
+** Returns:        0 on error
+**                 a non-zero opaque handle on success.
+**
+** On success, the user must invoke vcsm_lock with the returned opaque
+** handle to gain access to the memory associated with the opaque handle.
+** When finished using the memory, the user calls vcsm_unlock_xx (see those
+** function definition for more details on the one that can be used).
+** 
+** A well behaved application should make every attempt to lock/unlock
+** only for the duration it needs to access the memory data associated with
+** the opaque handle.
+*/
+unsigned int vcsm_malloc( unsigned int size, char *name );
+
+
+/* Allocates a cached block of memory of size 'size' via the vcsm memory
+** allocator, the type of caching requested is passed as argument of the
+** function call.
+**
+** Returns:        0 on error
+**                 a non-zero opaque handle on success.
+**
+** On success, the user must invoke vcsm_lock with the returned opaque
+** handle to gain access to the memory associated with the opaque handle.
+** When finished using the memory, the user calls vcsm_unlock_xx (see those
+** function definition for more details on the one that can be used).
+** 
+** A well behaved application should make every attempt to lock/unlock
+** only for the duration it needs to access the memory data associated with
+** the opaque handle.
+*/
+unsigned int vcsm_malloc_cache( unsigned int size, VCSM_CACHE_TYPE_T cache, char *name );
+
+
+/* Shares an allocated block of memory via the vcsm memory allocator.
+**
+** Returns:        0 on error
+**                 a non-zero opaque handle on success.
+**
+** On success, the user must invoke vcsm_lock with the returned opaque
+** handle to gain access to the memory associated with the opaque handle.
+** When finished using the memory, the user calls vcsm_unlock_xx (see those
+** function definition for more details on the one that can be used).
+**
+** A well behaved application should make every attempt to lock/unlock
+** only for the duration it needs to access the memory data associated with
+** the opaque handle.
+*/
+unsigned int vcsm_malloc_share( unsigned int handle );
+
+
+/* Resizes a block of memory allocated previously by vcsm_alloc.
+**
+** Returns:        0 on success
+**                 -errno on error.
+**
+** The handle must be unlocked by user prior to attempting any
+** resize action.
+**
+** On error, the original size allocated against the handle
+** remains available the same way it would be following a
+** successful vcsm_malloc.
+*/
+int vcsm_resize( unsigned int handle, unsigned int new_size );
+
+
+/* Frees a block of memory that was successfully allocated by
+** a prior call the vcms_alloc.
+**
+** The handle should be considered invalid upon return from this
+** call.
+**
+** Whether any memory is actually freed up or not as the result of
+** this call will depends on many factors, if all goes well it will
+** be freed.  If something goes wrong, the memory will likely end up
+** being freed up as part of the vcsm_exit process.  In the end the
+** memory is guaranteed to be freed one way or another.
+*/
+void vcsm_free( unsigned int handle );
+
+
+/* Retrieves a videocore opaque handle from a mapped user address
+** pointer.  The videocore handle will correspond to the actual
+** memory mapped in videocore.
+**
+** Returns:        0 on error
+**                 a non-zero opaque handle on success.
+**
+** Note: the videocore opaque handle is distinct from the user
+**       opaque handle (allocated via vcsm_malloc) and it is only
+**       significant for such application which knows what to do
+**       with it, for the others it is just a number with little
+**       use since nothing can be done with it (in particular
+**       for safety reason it cannot be used to map anything).
+*/
+unsigned int vcsm_vc_hdl_from_ptr( void *usr_ptr );
+
+
+/* Retrieves a videocore opaque handle from a opaque handle
+** pointer.  The videocore handle will correspond to the actual
+** memory mapped in videocore.
+**
+** Returns:        0 on error
+**                 a non-zero opaque handle on success.
+**
+** Note: the videocore opaque handle is distinct from the user
+**       opaque handle (allocated via vcsm_malloc) and it is only
+**       significant for such application which knows what to do
+**       with it, for the others it is just a number with little
+**       use since nothing can be done with it (in particular
+**       for safety reason it cannot be used to map anything).
+*/
+unsigned int vcsm_vc_hdl_from_hdl( unsigned int handle );
+
+
+/* Retrieves a user opaque handle from a mapped user address
+** pointer.
+**
+** Returns:        0 on error
+**                 a non-zero opaque handle on success.
+*/
+unsigned int vcsm_usr_handle( void *usr_ptr );
+
+
+/* Retrieves a mapped user address from an opaque user
+** handle.
+**
+** Returns:        0 on error
+**                 a non-zero address on success.
+**
+** On success, the address corresponds to the pointer
+** which can access the data allocated via the vcsm_malloc
+** call.
+*/
+void *vcsm_usr_address( unsigned int handle );
+
+
+/* Locks the memory associated with this opaque handle.
+**
+** Returns:        NULL on error
+**                 a valid pointer on success.
+**
+** A user MUST lock the handle received from vcsm_malloc
+** in order to be able to use the memory associated with it.
+**
+** On success, the pointer returned is only valid within
+** the lock content (ie until a corresponding vcsm_unlock_xx
+** is invoked).
+*/
+void *vcsm_lock( unsigned int handle );
+
+
+/* Locks the memory associated with this opaque handle.  The lock
+** also gives a chance to update the *host* cache behavior of the
+** allocated buffer if so desired.  The *videocore* cache behavior
+** of the allocated buffer cannot be changed by this call and such
+** attempt will be ignored.
+**
+** The system will attempt to honour the cache_update mode request,
+** the cache_result mode will provide the final answer on which cache
+** mode is really in use.  Failing to change the cache mode will not
+** result in a failure to lock the buffer as it is an application
+** decision to choose what to do if (cache_result != cache_update)
+**
+** The value returned in cache_result can only be considered valid if
+** the returned pointer is non NULL.  The cache_result pointer may be
+** NULL if the application does not care about the actual outcome of
+** its action with regards to the cache behavior change.
+**
+** Returns:        NULL on error
+**                 a valid pointer on success.
+**
+** A user MUST lock the handle received from vcsm_malloc
+** in order to be able to use the memory associated with it.
+**
+** On success, the pointer returned is only valid within
+** the lock content (ie until a corresponding vcsm_unlock_xx
+** is invoked).
+*/
+void *vcsm_lock_cache( unsigned int handle,
+                       VCSM_CACHE_TYPE_T cache_update,
+                       VCSM_CACHE_TYPE_T *cache_result );
+
+
+/* Unlocks the memory associated with this user mapped address.
+**
+** Returns:        0 on success
+**                 -errno on error.
+**
+** After unlocking a mapped address, the user should no longer
+** attempt to reference it.
+*/
+int vcsm_unlock_ptr( void *usr_ptr );
+
+
+/* Unlocks the memory associated with this user mapped address.
+** Apply special processing that would override the otherwise
+** default behavior.
+**
+** If 'cache_no_flush' is specified:
+**    Do not flush cache as the result of the unlock (if cache
+**    flush was otherwise applicable in this case).
+**
+** Returns:        0 on success
+**                 -errno on error.
+**
+** After unlocking a mapped address, the user should no longer
+** attempt to reference it.
+*/
+int vcsm_unlock_ptr_sp( void *usr_ptr, int cache_no_flush );
+
+
+/* Unlocks the memory associated with this user opaque handle.
+**
+** Returns:        0 on success
+**                 -errno on error.
+**
+** After unlocking an opaque handle, the user should no longer
+** attempt to reference the mapped addressed once associated
+** with it.
+*/
+int vcsm_unlock_hdl( unsigned int handle );
+
+
+/* Unlocks the memory associated with this user opaque handle.
+** Apply special processing that would override the otherwise
+** default behavior.
+**
+** If 'cache_no_flush' is specified:
+**    Do not flush cache as the result of the unlock (if cache
+**    flush was otherwise applicable in this case).
+**
+** Returns:        0 on success
+**                 -errno on error.
+**
+** After unlocking an opaque handle, the user should no longer
+** attempt to reference the mapped addressed once associated
+** with it.
+*/
+int vcsm_unlock_hdl_sp( unsigned int handle, int cache_no_flush );
+
+/* Clean and/or invalidate the memory associated with this user opaque handle
+**
+** Returns:        non-zero on error
+**
+** structure contains a list of flush/invalidate commands. Commands are:
+** 0: nop
+** 1: invalidate       given virtual range in L1/L2
+** 2: clean            given virtual range in L1/L2
+** 3: clean+invalidate given virtual range in L1/L2
+** 4: flush all L1/L2
+*/
+struct vcsm_user_clean_invalid_s {
+   struct {
+      unsigned int cmd;
+      unsigned int handle;
+      unsigned int addr;
+      unsigned int size;
+   } s[8];
+};
+
+int vcsm_clean_invalid( struct vcsm_user_clean_invalid_s *s );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __USER_VCSM__H__INCLUDED__ */
+
diff --git a/xbmc/windowing/WinEventsLinux.cpp b/xbmc/windowing/WinEventsLinux.cpp
index 6f97e9e..bde7649 100644
--- a/xbmc/windowing/WinEventsLinux.cpp
+++ b/xbmc/windowing/WinEventsLinux.cpp
@@ -30,11 +30,31 @@
 #include "utils/log.h"
 #include "powermanagement/PowerManager.h"
 
+#ifdef TARGET_RASPBERRY_PI
+#include "utils/TimeUtils.h"
+#include "guilib/Resolution.h"
+#include "addons/Skin.h"
+#include "utils/XMLUtils.h"
+#include "utils/StringUtils.h"
+#include "filesystem/File.h"
+#include "guilib/iimage.h"
+#include "guilib/XBTF.h"
+#include "guilib/imagefactory.h"
+#include "guilib/TextureManager.h"
+#include "linux/RBP.h"
+#include "input/InputManager.h"
+#endif
+
 bool CWinEventsLinux::m_initialized = false;
 CLinuxInputDevices CWinEventsLinux::m_devices;
 
 CWinEventsLinux::CWinEventsLinux()
 {
+#ifdef TARGET_RASPBERRY_PI
+  m_last_mouse_move_time = 0;
+  m_mouse_state = -1;
+  memset(m_cursors, 0, sizeof m_cursors);
+#endif
 }
 
 void CWinEventsLinux::RefreshDevices()
@@ -48,19 +68,142 @@ bool CWinEventsLinux::IsRemoteLowBattery()
   return false;
 }
 
+#ifdef TARGET_RASPBERRY_PI
+void *CWinEventsLinux::LoadImage(const std::string texturePath, int &width, int &height)
+{
+  void *pixels = NULL;
+  // Read image into memory to use our vfs
+  XFILE::CFile file;
+  XFILE::auto_buffer buf;
+
+  if (file.LoadFile(texturePath, buf) <= 0)
+    return NULL;
+
+  IImage *pImage = ImageFactory::CreateLoader(texturePath);
+  if (pImage != NULL && pImage->LoadImageFromMemory((unsigned char *)buf.get(), buf.size(), width, height))
+  {
+    width = pImage->Width();
+    height = pImage->Height();
+    if (width > 0 && height > 0)
+    {
+      pixels = malloc(width * height * 4);
+      if (!pixels)
+        return NULL;
+      if (!pImage->Decode((unsigned char *)pixels, width * 4, XB_FMT_A8R8G8B8))
+      {
+        free(pixels);
+        return NULL;
+      }
+    }
+  }
+  return pixels;
+}
+
+bool CWinEventsLinux::LoadXML(const std::string strFileName)
+{
+  RESOLUTION_INFO m_coordsRes; // resolution that the window coordinates are in.
+  // Find appropriate skin folder + resolution to load from
+  std::string strFileNameLower = strFileName;
+  StringUtils::ToLower(strFileNameLower);
+  std::string strLowerPath = g_SkinInfo->GetSkinPath(strFileNameLower, &m_coordsRes);
+  std::string strPath = g_SkinInfo->GetSkinPath(strFileName, &m_coordsRes);
+
+  TiXmlElement* pRootElement = NULL;
+  CXBMCTinyXML xmlDoc;
+  std::string strPathLower = strPath;
+  StringUtils::ToLower(strPathLower);
+  if (!xmlDoc.LoadFile(strPath) && !xmlDoc.LoadFile(strPathLower) && !xmlDoc.LoadFile(strLowerPath))
+  {
+    CLog::Log(LOGERROR, "unable to load:%s, Line %d\n%s", strPath.c_str(), xmlDoc.ErrorRow(), xmlDoc.ErrorDesc());
+    return false;
+  }
+  pRootElement = (TiXmlElement*)xmlDoc.RootElement()->Clone();
+  //printf("%s: load:%s,%s,%s\n", __func__, strPath.c_str(), strPathLower.c_str(), strLowerPath.c_str());
+
+  if (!pRootElement)
+    return false;
+
+  if (strcmpi(pRootElement->Value(), "window"))
+  {
+    CLog::Log(LOGERROR, "file : XML file doesnt contain <window>");
+    return false;
+  }
+
+  TiXmlElement *pChild = pRootElement->FirstChildElement();
+  while (pChild)
+  {
+    if (strcmpi(pChild->Value(), "controls") == 0)
+    {
+      TiXmlElement *pControl = pChild->FirstChildElement();
+      while (pControl)
+      {
+        //printf("%s:2 %s\n", __func__, pControl->Value());
+        if (strcmpi(pControl->Value(), "control") == 0)
+        {
+          std::string strStringValue;
+          if (XMLUtils::GetString(pControl, "texture", strStringValue))
+          {
+            const char* idAttr = pControl->Attribute("id");
+            int index = idAttr ? atoi(idAttr)-1 : -1;
+            if (index >= 0 && index < (int)(sizeof m_cursors/sizeof *m_cursors))
+            {
+              if (m_cursors[index].pixels)
+                free(m_cursors[index].pixels);
+              std::string path = g_TextureManager.GetTexturePath(strStringValue);
+              m_cursors[index].width = m_cursors[index].height = 64; // max
+              m_cursors[index].pixels = LoadImage(path, m_cursors[index].width, m_cursors[index].height);
+              //printf("%s: texture: %d %s %dx%d %p\n", __func__, index, path.c_str(), m_cursors[index].width, m_cursors[index].height, m_cursors[index].pixels);
+            }
+          }
+        }
+        pControl = pControl->NextSiblingElement();
+      }
+    }
+    pChild = pChild->NextSiblingElement();
+  }
+  delete pRootElement;
+  return true;
+}
+#endif
+
 bool CWinEventsLinux::MessagePump()
 {
   if (!m_initialized)
   {
     m_devices.InitAvailable();
     m_initialized = true;
+#ifdef TARGET_RASPBERRY_PI
+    LoadXML("Pointer.xml");
+#endif
   }
 
   bool ret = false;
   XBMC_Event event = {0};
+#ifdef TARGET_RASPBERRY_PI
+  int64_t Now = CurrentHostCounter();
+  int state = CInputManager::Get().GetMouseState() - 1;
+  if (m_mouse_state != state)
+  {
+    //printf("%s: %d->%d\n", __func__, m_mouse_state, state);
+    if (state >= 0 && state < (int)(sizeof m_cursors/sizeof *m_cursors) && m_cursors[state].pixels)
+    {
+      g_RBP.set_cursor(m_cursors[state].pixels, m_cursors[state].width, m_cursors[state].height, 0, 0);
+    }
+    m_mouse_state = state;
+  }
+#endif
   while (1)
   {
     event = m_devices.ReadEvent();
+#ifdef TARGET_RASPBERRY_PI
+    if (event.type == XBMC_MOUSEMOTION || event.type == XBMC_MOUSEBUTTONDOWN || event.type == XBMC_MOUSEBUTTONUP)
+    {
+      if (event.type == XBMC_MOUSEMOTION)
+        g_RBP.update_cursor(event.motion.x, event.motion.y, 1);
+      m_last_mouse_move_time = Now;
+      //printf("%s: %d,%d %d %d,%d (%d,%d)\n", __func__, event.motion.type, event.motion.which, event.motion.state, event.motion.x, event.motion.y, event.motion.xrel, event.motion.yrel);
+    }
+#endif
     if (event.type != XBMC_NOEVENT)
     {
       ret |= g_application.OnEvent(event);
@@ -71,6 +214,10 @@ bool CWinEventsLinux::MessagePump()
     }
   }
 
+#ifdef TARGET_RASPBERRY_PI
+  if (Now - m_last_mouse_move_time > 5 * 1000000000LL)
+    g_RBP.update_cursor(0, 0, 0);
+#endif
   return ret;
 }
 
diff --git a/xbmc/windowing/WinEventsLinux.h b/xbmc/windowing/WinEventsLinux.h
index f6c8df0..5c2b583 100644
--- a/xbmc/windowing/WinEventsLinux.h
+++ b/xbmc/windowing/WinEventsLinux.h
@@ -42,6 +42,17 @@ class CWinEventsLinux : public IWinEvents
 private:
   static bool m_initialized;
   static CLinuxInputDevices m_devices;
+#ifdef TARGET_RASPBERRY_PI
+  bool LoadXML(const std::string strFileName);
+  void *LoadImage(const std::string texturePath, int &width, int &height);
+  int64_t m_last_mouse_move_time;
+  struct
+  {
+    void *pixels;
+    int width, height;
+  } m_cursors[4];
+  int m_mouse_state;
+#endif
 };
 
 #endif

From 73f943c955674662396b11be531b060e48e4c47f Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Mon, 22 Jun 2015 22:06:53 +0100
Subject: [PATCH 060/100] [rbp] Flip default of prefer pts timestamps

---
 system/settings/rbp.xml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/system/settings/rbp.xml b/system/settings/rbp.xml
index 8c6e69d..f9528bc 100644
--- a/system/settings/rbp.xml
+++ b/system/settings/rbp.xml
@@ -45,7 +45,7 @@
       <group id="3">
         <setting id="videoplayer.preferptstimestamps" type="boolean" label="38210" help="38211">
           <level>3</level>
-          <default>false</default>
+          <default>true</default>
           <control type="toggle" />
         </setting>
       </group>

From 5a6394c526f55c6799e3962f8a6348994a92bcdd Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Thu, 7 May 2015 14:28:37 +0100
Subject: [PATCH 061/100] build: Add vcsm lib

---
 configure.ac | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/configure.ac b/configure.ac
index cb11ffb..60ff2e5 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1059,7 +1059,7 @@ 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"
+      LIBS="$LIBS -lEGL -lGLESv2 -lbcm_host -lvcos -lvchiq_arm -lmmal -lmmal_core -lmmal_util -lvcsm"
     else
       AC_CHECK_LIB([EGL],   [main],, AC_MSG_ERROR($missing_library))
       AC_CHECK_LIB([GLESv2],[main],, AC_MSG_ERROR($missing_library))

From a3d34d75e32b7b1eb140a1d2e00b9c96bd8ec37f Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Mon, 20 Jul 2015 16:11:37 +0100
Subject: [PATCH 062/100] [mmalcodec] Populate the framerate of video decoder

When timestamps are unknown, they may be interpolated based on the framerate. Without setting this,
a default of 30fps is used which may be incorrect and cause stutters
---
 xbmc/cores/dvdplayer/DVDCodecs/Video/MMALCodec.cpp | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/MMALCodec.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/MMALCodec.cpp
index 3e97f1d..5b064d2 100644
--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/MMALCodec.cpp
+++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/MMALCodec.cpp
@@ -629,6 +629,11 @@ bool CMMALVideo::Open(CDVDStreamInfo &hints, CDVDCodecOptions &options)
     m_dec_input->format->es->video.width = ALIGN_UP(m_hints.width, 32);
     m_dec_input->format->es->video.height = ALIGN_UP(m_hints.height, 16);
   }
+  if (hints.fpsrate > 0 && hints.fpsscale > 0)
+  {
+    m_dec_input->format->es->video.frame_rate.num = hints.fpsrate;
+    m_dec_input->format->es->video.frame_rate.den = hints.fpsscale;
+  }
   m_dec_input->format->flags |= MMAL_ES_FORMAT_FLAG_FRAMED;
 
   error_concealment.hdr.id = MMAL_PARAMETER_VIDEO_DECODE_ERROR_CONCEALMENT;

From fa3d1cdb0220a227b7fc6f2161eb9b04d9ef75b4 Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Wed, 22 Jul 2015 22:52:46 +0100
Subject: [PATCH 063/100] [mmalcodec] Enable interpolate timestamps

---
 xbmc/cores/dvdplayer/DVDCodecs/Video/MMALCodec.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/MMALCodec.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/MMALCodec.cpp
index 5b064d2..a202421 100644
--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/MMALCodec.cpp
+++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/MMALCodec.cpp
@@ -647,7 +647,7 @@ bool CMMALVideo::Open(CDVDStreamInfo &hints, CDVDCodecOptions &options)
   if (status != MMAL_SUCCESS)
     CLog::Log(LOGERROR, "%s::%s Failed to enable extra buffers on %s (status=%x %s)", CLASSNAME, __func__, m_dec_input->name, status, mmal_status_to_string(status));
 
-  status = mmal_port_parameter_set_uint32(m_dec_input, MMAL_PARAMETER_VIDEO_INTERPOLATE_TIMESTAMPS, 0);
+  status = mmal_port_parameter_set_uint32(m_dec_input, MMAL_PARAMETER_VIDEO_INTERPOLATE_TIMESTAMPS, 1);
   if (status != MMAL_SUCCESS)
     CLog::Log(LOGERROR, "%s::%s Failed to disable interpolate timestamps mode on %s (status=%x %s)", CLASSNAME, __func__, m_dec_input->name, status, mmal_status_to_string(status));
 

From 1fa31ca6a89e3afc8d73ddc220e3af872b931fa8 Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Thu, 23 Jul 2015 00:55:47 +0100
Subject: [PATCH 064/100] Revert "[rbp] Flip default of prefer pts timestamps"

This reverts commit 34100dcdf830a0e957df585108066c48d6c5c38d.
---
 system/settings/rbp.xml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/system/settings/rbp.xml b/system/settings/rbp.xml
index f9528bc..8c6e69d 100644
--- a/system/settings/rbp.xml
+++ b/system/settings/rbp.xml
@@ -45,7 +45,7 @@
       <group id="3">
         <setting id="videoplayer.preferptstimestamps" type="boolean" label="38210" help="38211">
           <level>3</level>
-          <default>true</default>
+          <default>false</default>
           <control type="toggle" />
         </setting>
       </group>

From 634188b43f2fef26de9d7f0818aa4fe679762bb8 Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Thu, 23 Jul 2015 00:56:56 +0100
Subject: [PATCH 065/100] Revert "[rbp] Allow settings option for timestamp
 preference"

This reverts commit c0eef926dd376cbf8a7857b2848e118ea3689b98.
---
 addons/resource.language.en_gb/resources/strings.po | 10 ----------
 system/settings/rbp.xml                             |  7 -------
 xbmc/cores/dvdplayer/DVDCodecs/Video/MMALCodec.cpp  |  2 +-
 xbmc/cores/omxplayer/OMXPlayerVideo.cpp             |  2 +-
 4 files changed, 2 insertions(+), 19 deletions(-)

diff --git a/addons/resource.language.en_gb/resources/strings.po b/addons/resource.language.en_gb/resources/strings.po
index a631d80..eb31d58 100644
--- a/addons/resource.language.en_gb/resources/strings.po
+++ b/addons/resource.language.en_gb/resources/strings.po
@@ -16737,13 +16737,3 @@ msgstr ""
 msgctxt "#38121"
 msgid "This option supports 8 channel DTS HD decoding, but may use more CPU. It is only available when DTS and DTS-HD audio passthrough is disabled"
 msgstr ""
-
-#: system/settings/rbp.xml
-msgctxt "#38210"
-msgid "Prefer PTS timestamps"
-msgstr ""
-
-#: system/settings/rbp.xml
-msgctxt "#38211"
-msgid "Try enabling this if you have stutter with video files"
-msgstr ""
diff --git a/system/settings/rbp.xml b/system/settings/rbp.xml
index 8c6e69d..b27d23f 100644
--- a/system/settings/rbp.xml
+++ b/system/settings/rbp.xml
@@ -42,13 +42,6 @@
           <control type="toggle" />
         </setting>
       </group>
-      <group id="3">
-        <setting id="videoplayer.preferptstimestamps" type="boolean" label="38210" help="38211">
-          <level>3</level>
-          <default>false</default>
-          <control type="toggle" />
-        </setting>
-      </group>
     </category>
     <category id="myvideos">
       <group id="1">
diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/MMALCodec.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/MMALCodec.cpp
index a202421..5d054bb 100644
--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/MMALCodec.cpp
+++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/MMALCodec.cpp
@@ -804,7 +804,7 @@ int CMMALVideo::Decode(uint8_t* pData, int iSize, double dts, double pts)
          pts = 0;
        buffer->pts = pts == DVD_NOPTS_VALUE ? MMAL_TIME_UNKNOWN : pts;
        buffer->dts = dts == DVD_NOPTS_VALUE ? MMAL_TIME_UNKNOWN : dts;
-       if (m_hints.ptsinvalid || (buffer->dts != MMAL_TIME_UNKNOWN && !CSettings::Get().GetBool("videoplayer.preferptstimestamps"))) buffer->pts = MMAL_TIME_UNKNOWN;
+       if (m_hints.ptsinvalid) buffer->pts = MMAL_TIME_UNKNOWN;
        buffer->length = demuxer_bytes > buffer->alloc_size ? buffer->alloc_size : demuxer_bytes;
        // set a flag so we can identify primary frames from generated frames (deinterlace)
        buffer->flags = MMAL_BUFFER_HEADER_FLAG_USER0;
diff --git a/xbmc/cores/omxplayer/OMXPlayerVideo.cpp b/xbmc/cores/omxplayer/OMXPlayerVideo.cpp
index e17fdb8..f06ee9c 100644
--- a/xbmc/cores/omxplayer/OMXPlayerVideo.cpp
+++ b/xbmc/cores/omxplayer/OMXPlayerVideo.cpp
@@ -495,7 +495,7 @@ void OMXPlayerVideo::Process()
         if (pts != DVD_NOPTS_VALUE)
           pts += m_iVideoDelay;
 
-        m_omxVideo.Decode(pPacket->pData, pPacket->iSize, dts, m_hints.ptsinvalid || (dts != DVD_NOPTS_VALUE && !CSettings::Get().GetBool("videoplayer.preferptstimestamps")) ? DVD_NOPTS_VALUE : pts);
+        m_omxVideo.Decode(pPacket->pData, pPacket->iSize, dts, m_hints.ptsinvalid ? DVD_NOPTS_VALUE : pts);
 
         if (pts == DVD_NOPTS_VALUE)
           pts = dts;

From 4cc3d3fa17f8ffd4206f44a56b82316deba1b32f Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Thu, 23 Jul 2015 15:52:39 +0100
Subject: [PATCH 066/100] [omxhelper] Ignore embedded coverart image when
 looking for supported video streams

---
 xbmc/cores/omxplayer/OMXHelper.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/xbmc/cores/omxplayer/OMXHelper.cpp b/xbmc/cores/omxplayer/OMXHelper.cpp
index b5ee4b6..59479fe 100644
--- a/xbmc/cores/omxplayer/OMXHelper.cpp
+++ b/xbmc/cores/omxplayer/OMXHelper.cpp
@@ -72,7 +72,7 @@ bool OMXPlayerUnsuitable(bool m_HasVideo, bool m_HasAudio, CDVDDemux* m_pDemuxer
     {
       int iStream = it->id;
       CDemuxStream *stream = m_pDemuxer->GetStream(iStream);
-      if(!stream || stream->disabled)
+      if(!stream || stream->disabled || stream->flags & AV_DISPOSITION_ATTACHED_PIC)
         continue;
       CDVDStreamInfo hint(*stream, true);
 

From a293e4faa8345a022982bc40ce87beaca3ec551c Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Fri, 24 Jul 2015 18:39:25 +0100
Subject: [PATCH 068/100] [mmalcodec] Don't set initial unknown timestamps to
 zero

This used to be done to keep the firmware happy, but is no longer required and messes with timestamp statistics
---
 xbmc/cores/dvdplayer/DVDCodecs/Video/MMALCodec.cpp | 8 --------
 xbmc/cores/dvdplayer/DVDCodecs/Video/MMALCodec.h   | 1 -
 2 files changed, 9 deletions(-)

diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/MMALCodec.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/MMALCodec.cpp
index 5d054bb..b2ac68f 100644
--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/MMALCodec.cpp
+++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/MMALCodec.cpp
@@ -106,7 +106,6 @@ CMMALVideo::CMMALVideo()
 
   m_interlace_mode = MMAL_InterlaceProgressive;
   m_interlace_method = VS_INTERLACEMETHOD_NONE;
-  m_startframe = false;
   m_decoderPts = DVD_NOPTS_VALUE;
 
   m_dec = NULL;
@@ -713,7 +712,6 @@ bool CMMALVideo::Open(CDVDStreamInfo &hints, CDVDCodecOptions &options)
     return false;
 
   Prime();
-  m_startframe = false;
   m_preroll = !m_hints.stills;
   m_speed = DVD_PLAYSPEED_NORMAL;
 
@@ -800,8 +798,6 @@ int CMMALVideo::Decode(uint8_t* pData, int iSize, double dts, double pts)
 
        mmal_buffer_header_reset(buffer);
        buffer->cmd = 0;
-       if (!m_startframe && pts == DVD_NOPTS_VALUE)
-         pts = 0;
        buffer->pts = pts == DVD_NOPTS_VALUE ? MMAL_TIME_UNKNOWN : pts;
        buffer->dts = dts == DVD_NOPTS_VALUE ? MMAL_TIME_UNKNOWN : dts;
        if (m_hints.ptsinvalid) buffer->pts = MMAL_TIME_UNKNOWN;
@@ -829,9 +825,6 @@ int CMMALVideo::Decode(uint8_t* pData, int iSize, double dts, double pts)
 
        if (demuxer_bytes == 0)
        {
-         pthread_mutex_lock(&m_output_mutex);
-         m_startframe = true;
-         pthread_mutex_unlock(&m_output_mutex);
          EDEINTERLACEMODE deinterlace_request = CMediaSettings::Get().GetCurrentVideoSettings().m_DeinterlaceMode;
          EINTERLACEMETHOD interlace_method = g_renderManager.AutoInterlaceMethod(CMediaSettings::Get().GetCurrentVideoSettings().m_InterlaceMethod);
 
@@ -956,7 +949,6 @@ void CMMALVideo::Reset(void)
     SendCodecConfigData();
     Prime();
   }
-  m_startframe = false;
   m_decoderPts = DVD_NOPTS_VALUE;
   m_preroll = !m_hints.stills && (m_speed == DVD_PLAYSPEED_NORMAL || m_speed == DVD_PLAYSPEED_PAUSE);
   m_codecControlFlags = 0;
diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/MMALCodec.h b/xbmc/cores/dvdplayer/DVDCodecs/Video/MMALCodec.h
index bde8c06..42d6a7b 100644
--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/MMALCodec.h
+++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/MMALCodec.h
@@ -127,7 +127,6 @@ class CMMALVideo : public CDVDVideoCodec
   // Components
   MMAL_INTERLACETYPE_T m_interlace_mode;
   EINTERLACEMETHOD  m_interlace_method;
-  bool              m_startframe;
   double            m_decoderPts;
   int               m_speed;
   bool              m_preroll;

From b34316efe7018bac17f95ed4afb7d850832c9ae4 Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Fri, 24 Jul 2015 22:53:21 +0100
Subject: [PATCH 069/100] [mmalcodec] Tidy up setting of timestamp flags

---
 xbmc/cores/omxplayer/OMXVideo.cpp | 27 ++++++++++++++-------------
 1 file changed, 14 insertions(+), 13 deletions(-)

diff --git a/xbmc/cores/omxplayer/OMXVideo.cpp b/xbmc/cores/omxplayer/OMXVideo.cpp
index 832a9c9..1a08aa9 100644
--- a/xbmc/cores/omxplayer/OMXVideo.cpp
+++ b/xbmc/cores/omxplayer/OMXVideo.cpp
@@ -754,6 +754,19 @@ int COMXVideo::Decode(uint8_t *pData, int iSize, double dts, double pts)
 
   if (demuxer_content && demuxer_bytes > 0)
   {
+    OMX_U32 nFlags = 0;
+
+    if(m_setStartTime)
+    {
+      nFlags |= OMX_BUFFERFLAG_STARTTIME;
+      CLog::Log(LOGDEBUG, "OMXVideo::Decode VDec : setStartTime %f\n", (pts == DVD_NOPTS_VALUE ? 0.0 : pts) / DVD_TIME_BASE);
+      m_setStartTime = false;
+    }
+    if (pts == DVD_NOPTS_VALUE && dts == DVD_NOPTS_VALUE)
+      nFlags |= OMX_BUFFERFLAG_TIME_UNKNOWN;
+    else if (pts == DVD_NOPTS_VALUE)
+      nFlags |= OMX_BUFFERFLAG_TIME_IS_DTS;
+
     while(demuxer_bytes)
     {
       // 500ms timeout
@@ -764,21 +777,9 @@ int COMXVideo::Decode(uint8_t *pData, int iSize, double dts, double pts)
         return false;
       }
 
-      omx_buffer->nFlags = 0;
+      omx_buffer->nFlags = nFlags;
       omx_buffer->nOffset = 0;
       omx_buffer->nTimeStamp = ToOMXTime((uint64_t)(pts != DVD_NOPTS_VALUE ? pts : dts != DVD_NOPTS_VALUE ? dts : 0));
-
-      if(m_setStartTime)
-      {
-        omx_buffer->nFlags |= OMX_BUFFERFLAG_STARTTIME;
-        CLog::Log(LOGDEBUG, "OMXVideo::Decode VDec : setStartTime %f\n", (pts == DVD_NOPTS_VALUE ? 0.0 : pts) / DVD_TIME_BASE);
-        m_setStartTime = false;
-      }
-      else if (pts == DVD_NOPTS_VALUE && dts == DVD_NOPTS_VALUE)
-        omx_buffer->nFlags |= OMX_BUFFERFLAG_TIME_UNKNOWN;
-      else if (pts == DVD_NOPTS_VALUE)
-        omx_buffer->nFlags |= OMX_BUFFERFLAG_TIME_IS_DTS;
-
       omx_buffer->nFilledLen = std::min((OMX_U32)demuxer_bytes, omx_buffer->nAllocLen);
       memcpy(omx_buffer->pBuffer, demuxer_content, omx_buffer->nFilledLen);
 

From ab872c49995e776214c6a5fd6d02c3a00b5cfcf4 Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Sat, 25 Jul 2015 15:32:35 +0100
Subject: [PATCH 070/100] [rbp] Only send changes in hw cursor state

---
 xbmc/linux/RBP.cpp | 9 ++++++++-
 xbmc/linux/RBP.h   | 5 ++++-
 2 files changed, 12 insertions(+), 2 deletions(-)

diff --git a/xbmc/linux/RBP.cpp b/xbmc/linux/RBP.cpp
index 2c8d09b..3953740 100644
--- a/xbmc/linux/RBP.cpp
+++ b/xbmc/linux/RBP.cpp
@@ -61,6 +61,9 @@ CRBP::CRBP()
   m_OMX             = new COMXCore();
   m_display = DISPMANX_NO_HANDLE;
   m_p = NULL;
+  m_x = 0;
+  m_y = 0;
+  m_enabled = 0;
   m_mb = mbox_open();
   vcsm_init();
 }
@@ -482,7 +485,11 @@ void CRBP::update_cursor(int x, int y, bool enabled)
   int y2 = y * display.Height() / gui.Height();
 
   //printf("%s %d,%d (%d)\n", __func__, x, y, enabled);
-  mailbox_set_cursor_position(m_mb, enabled, x2, y2);
+  if (m_x != x2 || m_y != y2 || m_enabled != enabled)
+    mailbox_set_cursor_position(m_mb, enabled, x2, y2);
+  m_x = x2;
+  m_y = y2;
+  m_enabled = enabled;
 }
 
 void CRBP::uninit_cursor()
diff --git a/xbmc/linux/RBP.h b/xbmc/linux/RBP.h
index f233a5e..be0cafc 100644
--- a/xbmc/linux/RBP.h
+++ b/xbmc/linux/RBP.h
@@ -86,7 +86,10 @@ class CRBP
 
   struct gpu_mem_ptr_s *m_p;
   int m_mb;
-public:
+  int m_x;
+  int m_y;
+  bool m_enabled;
+  public:
   void init_cursor();
   void set_cursor(const void *pixels, int width, int height, int hotspot_x, int hotspot_y);
   void update_cursor(int x, int y, bool enabled);

From bc665147a5b77c980e58a73ae9fcebecddf033f9 Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Tue, 28 Jul 2015 00:08:58 +0100
Subject: [PATCH 071/100] [mmalcodec] Use both dts and pts for determining
 amount of queued data

---
 xbmc/cores/dvdplayer/DVDCodecs/Video/MMALCodec.cpp | 10 ++++++++--
 xbmc/cores/dvdplayer/DVDCodecs/Video/MMALCodec.h   |  1 +
 2 files changed, 9 insertions(+), 2 deletions(-)

diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/MMALCodec.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/MMALCodec.cpp
index b2ac68f..6cf4023 100644
--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/MMALCodec.cpp
+++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/MMALCodec.cpp
@@ -107,6 +107,7 @@ CMMALVideo::CMMALVideo()
   m_interlace_mode = MMAL_InterlaceProgressive;
   m_interlace_method = VS_INTERLACEMETHOD_NONE;
   m_decoderPts = DVD_NOPTS_VALUE;
+  m_demuxerPts = DVD_NOPTS_VALUE;
 
   m_dec = NULL;
   m_dec_input = NULL;
@@ -853,7 +854,11 @@ int CMMALVideo::Decode(uint8_t* pData, int iSize, double dts, double pts)
       break;
   }
   int ret = 0;
-  double queued = m_decoderPts != DVD_NOPTS_VALUE && pts != DVD_NOPTS_VALUE ? pts - m_decoderPts : 0.0;
+  if (pts != DVD_NOPTS_VALUE)
+    m_demuxerPts = pts;
+  else if (dts != DVD_NOPTS_VALUE)
+    m_demuxerPts = dts;
+  double queued = m_decoderPts != DVD_NOPTS_VALUE && m_demuxerPts != DVD_NOPTS_VALUE ? m_demuxerPts - m_decoderPts : 0.0;
   if (mmal_queue_length(m_dec_input_pool->queue) > 0 && !m_demux_queue_length && queued <= DVD_MSEC_TO_TIME(500))
   {
     if (g_advancedSettings.CanLogComponent(LOGVIDEO))
@@ -950,6 +955,7 @@ void CMMALVideo::Reset(void)
     Prime();
   }
   m_decoderPts = DVD_NOPTS_VALUE;
+  m_demuxerPts = DVD_NOPTS_VALUE;
   m_preroll = !m_hints.stills && (m_speed == DVD_PLAYSPEED_NORMAL || m_speed == DVD_PLAYSPEED_PAUSE);
   m_codecControlFlags = 0;
 }
@@ -1043,7 +1049,7 @@ bool CMMALVideo::GetPicture(DVDVideoPicture* pDvdVideoPicture)
   if (pDvdVideoPicture->pts != DVD_NOPTS_VALUE)
     m_decoderPts = pDvdVideoPicture->pts;
   else
-    m_decoderPts = pDvdVideoPicture->dts; // xxx is DVD_NOPTS_VALUE better?
+    m_decoderPts = pDvdVideoPicture->dts;
 
   return true;
 }
diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/MMALCodec.h b/xbmc/cores/dvdplayer/DVDCodecs/Video/MMALCodec.h
index 42d6a7b..f8f5209 100644
--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/MMALCodec.h
+++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/MMALCodec.h
@@ -127,6 +127,7 @@ class CMMALVideo : public CDVDVideoCodec
   // Components
   MMAL_INTERLACETYPE_T m_interlace_mode;
   EINTERLACEMETHOD  m_interlace_method;
+  double            m_demuxerPts;
   double            m_decoderPts;
   int               m_speed;
   bool              m_preroll;

From ac6ae272ef8ff57ed1a999bcfd4fabc49ee15765 Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Tue, 28 Jul 2015 17:47:33 +0100
Subject: [PATCH 072/100] [rbp] Refactor the vsync handle to support multiple
 callers

---
 xbmc/linux/RBP.cpp | 68 ++++++++++++++++++++++++++++++------------------------
 xbmc/linux/RBP.h   |  7 ++++--
 2 files changed, 43 insertions(+), 32 deletions(-)

diff --git a/xbmc/linux/RBP.cpp b/xbmc/linux/RBP.cpp
index 3953740..901250e 100644
--- a/xbmc/linux/RBP.cpp
+++ b/xbmc/linux/RBP.cpp
@@ -66,6 +66,7 @@ CRBP::CRBP()
   m_enabled = 0;
   m_mb = mbox_open();
   vcsm_init();
+  m_vsync_count = 0;
 }
 
 CRBP::~CRBP()
@@ -143,11 +144,45 @@ void CRBP::LogFirmwareVerison()
   CLog::Log(LOGNOTICE, "Config:\n%s", response);
 }
 
+static void vsync_callback_static(DISPMANX_UPDATE_HANDLE_T u, void *arg)
+{
+  CRBP *rbp = reinterpret_cast<CRBP*>(arg);
+  rbp->VSyncCallback();
+}
+
+void CRBP::VSyncCallback()
+{
+  CSingleLock lock(m_vsync_lock);
+  m_vsync_count++;
+  m_vsync_cond.notifyAll();
+}
+
+unsigned int CRBP::WaitVsync(unsigned int target)
+{
+  CSingleLock lock(m_vsync_lock);
+  if (target == ~0U)
+    target = m_vsync_count+1;
+
+  if (m_display == DISPMANX_NO_HANDLE)
+  {
+    CLog::Log(LOGDEBUG, "CRBP::%s skipping while display closed", __func__);
+    return m_vsync_count;
+  }
+
+  while (m_vsync_count < target)
+    if (!m_vsync_cond.wait(lock, 100))
+      break;
+
+  return m_vsync_count;
+}
+
 DISPMANX_DISPLAY_HANDLE_T CRBP::OpenDisplay(uint32_t device)
 {
   if (m_display == DISPMANX_NO_HANDLE)
   {
     m_display = vc_dispmanx_display_open( 0 /*screen*/ );
+    int s = vc_dispmanx_vsync_callback(m_display, vsync_callback_static, (void *)this);
+    assert(s == 0);
     init_cursor();
   }
   return m_display;
@@ -156,9 +191,11 @@ DISPMANX_DISPLAY_HANDLE_T CRBP::OpenDisplay(uint32_t device)
 void CRBP::CloseDisplay(DISPMANX_DISPLAY_HANDLE_T display)
 {
   assert(display == m_display);
+  int s = vc_dispmanx_vsync_callback(m_display, NULL, NULL);
+  assert(s == 0);
+  uninit_cursor();
   vc_dispmanx_display_close(m_display);
   m_display = DISPMANX_NO_HANDLE;
-  uninit_cursor();
 }
 
 void CRBP::GetDisplaySize(int &width, int &height)
@@ -211,35 +248,6 @@ unsigned char *CRBP::CaptureDisplay(int width, int height, int *pstride, bool sw
   return image;
 }
 
-
-static void vsync_callback(DISPMANX_UPDATE_HANDLE_T u, void *arg)
-{
-  CEvent *sync = (CEvent *)arg;
-  sync->Set();
-}
-
-void CRBP::WaitVsync()
-{
-  int s;
-  DISPMANX_DISPLAY_HANDLE_T m_display = vc_dispmanx_display_open( 0 /*screen*/ );
-  if (m_display == DISPMANX_NO_HANDLE)
-  {
-    CLog::Log(LOGDEBUG, "CRBP::%s skipping while display closed", __func__);
-    return;
-  }
-  m_vsync.Reset();
-  s = vc_dispmanx_vsync_callback(m_display, vsync_callback, (void *)&m_vsync);
-  if (s == 0)
-  {
-    m_vsync.WaitMSec(1000);
-  }
-  else assert(0);
-  s = vc_dispmanx_vsync_callback(m_display, NULL, NULL);
-  assert(s == 0);
-  vc_dispmanx_display_close( m_display );
-}
-
-
 void CRBP::Deinitialize()
 {
   if (m_omx_image_init)
diff --git a/xbmc/linux/RBP.h b/xbmc/linux/RBP.h
index be0cafc..0572b47 100644
--- a/xbmc/linux/RBP.h
+++ b/xbmc/linux/RBP.h
@@ -65,7 +65,8 @@ class CRBP
   // stride can be null for packed output
   unsigned char *CaptureDisplay(int width, int height, int *stride, bool swap_red_blue, bool video_only = true);
   DllOMX *GetDllOMX() { return m_OMX ? m_OMX->GetDll() : NULL; }
-  void WaitVsync();
+  unsigned int WaitVsync(unsigned int target = ~0U);
+  void VSyncCallback();
   double AdjustHDMIClock(double adjust);
 
 private:
@@ -80,7 +81,9 @@ class CRBP
   bool       m_codec_wvc1_enabled;
   COMXCore   *m_OMX;
   DISPMANX_DISPLAY_HANDLE_T m_display;
-  CEvent     m_vsync;
+  CCriticalSection m_vsync_lock;
+  XbmcThreads::ConditionVariable m_vsync_cond;
+  unsigned int m_vsync_count;
   class DllLibOMXCore;
   CCriticalSection m_critSection;
 

From 8325bffa3c7dfcc02076b176975c11f7b03571ad Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Wed, 29 Jul 2015 14:06:17 +0100
Subject: [PATCH 073/100] [mmalrenderer] Wait for vsync before submitting to
 mmal when display sync is disabled

This avoids an issue where video occasionally goes stuttery after a seek, until the next pause/play or seek.
The issue is when display sync is disabled, and framerate of video matches display, and render times are coincident with vsync
you find that depending on timestamp/scheduling jitter, you may or may not get an update each vsync resulting in stuttery video.

Some scheme to force render times to be dependent on vsync is required. We do this by blocking in RenderUpdate unto next vsync.
---
 xbmc/cores/VideoRenderers/MMALRenderer.cpp | 23 +++++++++++++++++++++--
 xbmc/cores/VideoRenderers/MMALRenderer.h   |  2 ++
 2 files changed, 23 insertions(+), 2 deletions(-)

diff --git a/xbmc/cores/VideoRenderers/MMALRenderer.cpp b/xbmc/cores/VideoRenderers/MMALRenderer.cpp
index fb92079..2e2bc83 100644
--- a/xbmc/cores/VideoRenderers/MMALRenderer.cpp
+++ b/xbmc/cores/VideoRenderers/MMALRenderer.cpp
@@ -208,6 +208,7 @@ CMMALRenderer::CMMALRenderer()
   m_bMMALConfigured = false;
   m_iYV12RenderBuffer = 0;
   m_sharpness = -2.0f;
+  m_vsyncCount = ~0;
 }
 
 CMMALRenderer::~CMMALRenderer()
@@ -357,6 +358,24 @@ void CMMALRenderer::Update()
   ManageDisplay();
 }
 
+void CMMALRenderer::SubmitFrame(MMAL_BUFFER_HEADER_T *buffer)
+{
+  if (!CSettings::Get().GetBool("videoplayer.usedisplayasclock"))
+  {
+    if (fabs(m_fps - g_graphicsContext.GetFPS()) < 1e-2)
+    {
+      #if defined(MMAL_DEBUG_VERBOSE)
+      CLog::Log(LOGDEBUG, "%s::%s - buffer:%p vfps:%.3f dfps:%.3f vsync:%d dsync:%d", CLASSNAME, __func__, buffer, m_fps, g_graphicsContext.GetFPS(), m_vsyncCount, CSettings::Get().GetBool("videoplayer.usedisplayasclock"));
+      #endif
+      m_vsyncCount = g_RBP.WaitVsync(m_vsyncCount) + 1;
+      #if defined(MMAL_DEBUG_VERBOSE)
+      CLog::Log(LOGDEBUG, "%s::%s - done vsync:%d", CLASSNAME, __func__, m_vsyncCount);
+      #endif
+    }
+  }
+  mmal_port_send_buffer(m_vout_input, buffer);
+}
+
 void CMMALRenderer::RenderUpdate(bool clear, DWORD flags, DWORD alpha)
 {
   CSingleLock lock(m_sharedSection);
@@ -402,7 +421,7 @@ void CMMALRenderer::RenderUpdate(bool clear, DWORD flags, DWORD alpha)
         return;
       omvb->Acquire();
       omvb->mmal_buffer->flags |= MMAL_BUFFER_HEADER_FLAG_USER1 | MMAL_BUFFER_HEADER_FLAG_USER2;
-      mmal_port_send_buffer(m_vout_input, omvb->mmal_buffer);
+      SubmitFrame(omvb->mmal_buffer);
     }
     else
       CLog::Log(LOGDEBUG, "%s::%s - No buffer to update", CLASSNAME, __func__);
@@ -417,7 +436,7 @@ void CMMALRenderer::RenderUpdate(bool clear, DWORD flags, DWORD alpha)
         return;
       // sanity check it is not on display
       buffer->mmal_buffer->flags |= MMAL_BUFFER_HEADER_FLAG_USER1 | MMAL_BUFFER_HEADER_FLAG_USER2;
-      mmal_port_send_buffer(m_vout_input, buffer->mmal_buffer);
+      SubmitFrame(buffer->mmal_buffer);
     }
     else
       CLog::Log(LOGDEBUG, "%s::%s - No buffer to update", CLASSNAME, __func__);
diff --git a/xbmc/cores/VideoRenderers/MMALRenderer.h b/xbmc/cores/VideoRenderers/MMALRenderer.h
index 9bced7e..ec279ed 100644
--- a/xbmc/cores/VideoRenderers/MMALRenderer.h
+++ b/xbmc/cores/VideoRenderers/MMALRenderer.h
@@ -99,6 +99,7 @@ class CMMALRenderer : public CBaseRenderer
   unsigned int         m_destWidth;
   unsigned int         m_destHeight;
   int                  m_neededBuffers;
+  int                  m_vsyncCount;
 
   CRect                     m_src_rect;
   CRect                     m_dst_rect;
@@ -115,4 +116,5 @@ class CMMALRenderer : public CBaseRenderer
   bool init_vout(ERenderFormat format);
   void ReleaseBuffers();
   void UnInitMMAL();
+  void SubmitFrame(MMAL_BUFFER_HEADER_T *buffer);
 };

From 1d65392cfdb65de6263948ee61212b8673d21be7 Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Wed, 29 Jul 2015 15:07:22 +0100
Subject: [PATCH 074/100] [omxplayer] Support per refresh rate display latency
 settings

---
 xbmc/cores/omxplayer/OMXPlayerVideo.cpp | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/xbmc/cores/omxplayer/OMXPlayerVideo.cpp b/xbmc/cores/omxplayer/OMXPlayerVideo.cpp
index f06ee9c..4ad66a8 100644
--- a/xbmc/cores/omxplayer/OMXPlayerVideo.cpp
+++ b/xbmc/cores/omxplayer/OMXPlayerVideo.cpp
@@ -490,10 +490,10 @@ void OMXPlayerVideo::Process()
         double pts = pPacket->pts;
 
         if (dts != DVD_NOPTS_VALUE)
-          dts += m_iVideoDelay;
+          dts += m_iVideoDelay - DVD_SEC_TO_TIME(g_renderManager.GetDisplayLatency());
 
         if (pts != DVD_NOPTS_VALUE)
-          pts += m_iVideoDelay;
+          pts += m_iVideoDelay - DVD_SEC_TO_TIME(g_renderManager.GetDisplayLatency());
 
         m_omxVideo.Decode(pPacket->pData, pPacket->iSize, dts, m_hints.ptsinvalid ? DVD_NOPTS_VALUE : pts);
 

From 70d0a1afa22b87eb9bb6968c7e3cc65fee6de2be Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Wed, 29 Jul 2015 15:46:18 +0100
Subject: [PATCH 075/100] squash: release gfx lock when blocking

---
 xbmc/cores/VideoRenderers/MMALRenderer.cpp | 1 +
 1 file changed, 1 insertion(+)

diff --git a/xbmc/cores/VideoRenderers/MMALRenderer.cpp b/xbmc/cores/VideoRenderers/MMALRenderer.cpp
index 2e2bc83..c80a8a6 100644
--- a/xbmc/cores/VideoRenderers/MMALRenderer.cpp
+++ b/xbmc/cores/VideoRenderers/MMALRenderer.cpp
@@ -367,6 +367,7 @@ void CMMALRenderer::SubmitFrame(MMAL_BUFFER_HEADER_T *buffer)
       #if defined(MMAL_DEBUG_VERBOSE)
       CLog::Log(LOGDEBUG, "%s::%s - buffer:%p vfps:%.3f dfps:%.3f vsync:%d dsync:%d", CLASSNAME, __func__, buffer, m_fps, g_graphicsContext.GetFPS(), m_vsyncCount, CSettings::Get().GetBool("videoplayer.usedisplayasclock"));
       #endif
+      CSingleExit lock(g_graphicsContext);
       m_vsyncCount = g_RBP.WaitVsync(m_vsyncCount) + 1;
       #if defined(MMAL_DEBUG_VERBOSE)
       CLog::Log(LOGDEBUG, "%s::%s - done vsync:%d", CLASSNAME, __func__, m_vsyncCount);

From 80b95491d82075ff13ac45fa8fc7184a660258da Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Wed, 29 Jul 2015 17:34:11 +0100
Subject: [PATCH 076/100] [rbp] Leave 3D framepacking output disabled by
 default

---
 system/settings/rbp.xml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/system/settings/rbp.xml b/system/settings/rbp.xml
index b27d23f..bf3b05f 100644
--- a/system/settings/rbp.xml
+++ b/system/settings/rbp.xml
@@ -38,7 +38,7 @@
             <dependency type="enable" setting="videoplayer.supportmvc">true</dependency>
           </dependencies>
           <level>2</level>
-          <default>true</default>
+          <default>false</default>
           <control type="toggle" />
         </setting>
       </group>

From 016a4c59339bd8e7205475013737fae416886f17 Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Wed, 29 Jul 2015 17:26:30 +0100
Subject: [PATCH 077/100] [omxplayer] Allow automatic switching back to
 omxplayer after it has been disabled

Omxplayer gets disabled when it is unsuitable (e.g. software decoder required, or ALSA audio or AC3 transcode).
However if you play another file without quitting dvdplayer, it doesn't reconsider.

E.g. play divx3 file and omxplayer is disabled. If you then launch a h.264 file while first file is still playing it doesn't switch
back to omxplayer as you might expect.

This patch allows a switch back to omxplayer mode
---
 xbmc/cores/dvdplayer/DVDPlayer.cpp | 5 +++--
 xbmc/cores/omxplayer/OMXHelper.cpp | 3 +++
 2 files changed, 6 insertions(+), 2 deletions(-)

diff --git a/xbmc/cores/dvdplayer/DVDPlayer.cpp b/xbmc/cores/dvdplayer/DVDPlayer.cpp
index 3118be2..a572bc2 100644
--- a/xbmc/cores/dvdplayer/DVDPlayer.cpp
+++ b/xbmc/cores/dvdplayer/DVDPlayer.cpp
@@ -519,10 +519,11 @@ void CDVDPlayer::CreatePlayers()
 {
   CSingleLock lock(m_players_lock);
 #ifdef HAS_OMXPLAYER
-  if (m_omxplayer_mode && OMXPlayerUnsuitable(m_HasVideo, m_HasAudio, m_pDemuxer, m_pInputStream, m_SelectionStreams))
+  bool omx_suitable = !OMXPlayerUnsuitable(m_HasVideo, m_HasAudio, m_pDemuxer, m_pInputStream, m_SelectionStreams);
+  if (m_omxplayer_mode != omx_suitable)
   {
     DestroyPlayers();
-    m_omxplayer_mode = false;
+    m_omxplayer_mode = omx_suitable;
   }
 #endif
   if (m_players_created)
diff --git a/xbmc/cores/omxplayer/OMXHelper.cpp b/xbmc/cores/omxplayer/OMXHelper.cpp
index 59479fe..014eaf1 100644
--- a/xbmc/cores/omxplayer/OMXHelper.cpp
+++ b/xbmc/cores/omxplayer/OMXHelper.cpp
@@ -44,6 +44,9 @@ static bool PredicateVideoPriority(const SelectionStream& lh, const SelectionStr
 
 bool OMXPlayerUnsuitable(bool m_HasVideo, bool m_HasAudio, CDVDDemux* m_pDemuxer, CDVDInputStream* m_pInputStream, CSelectionStreams &m_SelectionStreams)
 {
+  // if no OMXPlayer acceleration then it is not suitable
+  if (!CSettings::Get().GetBool("videoplayer.useomxplayer"))
+    return true;
   // if no MMAL acceleration stick with omxplayer regardless
   if (!CSettings::Get().GetBool("videoplayer.usemmal"))
     return false;

From 202bf4a032763605d21ba42a29c9df41a71360a1 Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Wed, 29 Jul 2015 21:05:41 +0100
Subject: [PATCH 078/100] [omxplayer] Set audio properties for passthrough

We weren't setting the stream_channels property for passthrough for omxplayer (we do with Pi Sink)
That means we were using 2 in number of channels of the AudioInfoFrame packet, rather then 0
which is 'refer to stream header' which is correct for passthrough
---
 xbmc/cores/omxplayer/OMXAudio.cpp | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/xbmc/cores/omxplayer/OMXAudio.cpp b/xbmc/cores/omxplayer/OMXAudio.cpp
index 1911189..4072f7d 100644
--- a/xbmc/cores/omxplayer/OMXAudio.cpp
+++ b/xbmc/cores/omxplayer/OMXAudio.cpp
@@ -731,6 +731,8 @@ bool COMXAudio::Initialize(AEAudioFormat format, OMXClock *clock, CDVDStreamInfo
 
     m_wave_header.dwChannelMask = m_src_chan_layout;
   }
+  else
+    SetAudioProps(m_Passthrough, 0);
 
   m_SampleRate    = m_format.m_sampleRate;
   m_BitsPerSample = CAEUtil::DataFormatToBits(m_format.m_dataFormat);

From 1eee018bcf8e8a1a1fc4f64d2f8e5ebbae20038c Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Fri, 31 Jul 2015 16:38:06 +0100
Subject: [PATCH 079/100] squash: mmal: increase queue limit to 1 second to
 avoid stalls

---
 xbmc/cores/dvdplayer/DVDCodecs/Video/MMALCodec.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/MMALCodec.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/MMALCodec.cpp
index 6cf4023..7fea172 100644
--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/MMALCodec.cpp
+++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/MMALCodec.cpp
@@ -859,7 +859,7 @@ int CMMALVideo::Decode(uint8_t* pData, int iSize, double dts, double pts)
   else if (dts != DVD_NOPTS_VALUE)
     m_demuxerPts = dts;
   double queued = m_decoderPts != DVD_NOPTS_VALUE && m_demuxerPts != DVD_NOPTS_VALUE ? m_demuxerPts - m_decoderPts : 0.0;
-  if (mmal_queue_length(m_dec_input_pool->queue) > 0 && !m_demux_queue_length && queued <= DVD_MSEC_TO_TIME(500))
+  if (mmal_queue_length(m_dec_input_pool->queue) > 0 && !m_demux_queue_length && queued <= DVD_MSEC_TO_TIME(1000))
   {
     if (g_advancedSettings.CanLogComponent(LOGVIDEO))
       CLog::Log(LOGDEBUG, "%s::%s - got space for output: demux_queue(%d) space(%d) queued(%.2f)", CLASSNAME, __func__, m_demux_queue_length, mmal_queue_length(m_dec_input_pool->queue) * m_dec_input->buffer_size, queued*1e-6);

From ae9a3e037128369a843ae66d4f1e2a2d7baa29f1 Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Thu, 6 Aug 2015 11:25:08 +0100
Subject: [PATCH 080/100] Revert "squash: release gfx lock when blocking"

This reverts commit f10f0af15d0b57d148f5b3556fd9f94bb2f44509.
---
 xbmc/cores/VideoRenderers/MMALRenderer.cpp | 1 -
 1 file changed, 1 deletion(-)

diff --git a/xbmc/cores/VideoRenderers/MMALRenderer.cpp b/xbmc/cores/VideoRenderers/MMALRenderer.cpp
index c80a8a6..2e2bc83 100644
--- a/xbmc/cores/VideoRenderers/MMALRenderer.cpp
+++ b/xbmc/cores/VideoRenderers/MMALRenderer.cpp
@@ -367,7 +367,6 @@ void CMMALRenderer::SubmitFrame(MMAL_BUFFER_HEADER_T *buffer)
       #if defined(MMAL_DEBUG_VERBOSE)
       CLog::Log(LOGDEBUG, "%s::%s - buffer:%p vfps:%.3f dfps:%.3f vsync:%d dsync:%d", CLASSNAME, __func__, buffer, m_fps, g_graphicsContext.GetFPS(), m_vsyncCount, CSettings::Get().GetBool("videoplayer.usedisplayasclock"));
       #endif
-      CSingleExit lock(g_graphicsContext);
       m_vsyncCount = g_RBP.WaitVsync(m_vsyncCount) + 1;
       #if defined(MMAL_DEBUG_VERBOSE)
       CLog::Log(LOGDEBUG, "%s::%s - done vsync:%d", CLASSNAME, __func__, m_vsyncCount);

From 07f5b95bf68feda10424410f25ce158692bd1eeb Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Thu, 6 Aug 2015 11:25:21 +0100
Subject: [PATCH 081/100] Revert "[mmalrenderer] Wait for vsync before
 submitting to mmal when display sync is disabled"

This reverts commit f1a4416194f75f75e2145ec3fe64aee1177d3ccc.
---
 xbmc/cores/VideoRenderers/MMALRenderer.cpp | 23 ++---------------------
 xbmc/cores/VideoRenderers/MMALRenderer.h   |  2 --
 2 files changed, 2 insertions(+), 23 deletions(-)

diff --git a/xbmc/cores/VideoRenderers/MMALRenderer.cpp b/xbmc/cores/VideoRenderers/MMALRenderer.cpp
index 2e2bc83..fb92079 100644
--- a/xbmc/cores/VideoRenderers/MMALRenderer.cpp
+++ b/xbmc/cores/VideoRenderers/MMALRenderer.cpp
@@ -208,7 +208,6 @@ CMMALRenderer::CMMALRenderer()
   m_bMMALConfigured = false;
   m_iYV12RenderBuffer = 0;
   m_sharpness = -2.0f;
-  m_vsyncCount = ~0;
 }
 
 CMMALRenderer::~CMMALRenderer()
@@ -358,24 +357,6 @@ void CMMALRenderer::Update()
   ManageDisplay();
 }
 
-void CMMALRenderer::SubmitFrame(MMAL_BUFFER_HEADER_T *buffer)
-{
-  if (!CSettings::Get().GetBool("videoplayer.usedisplayasclock"))
-  {
-    if (fabs(m_fps - g_graphicsContext.GetFPS()) < 1e-2)
-    {
-      #if defined(MMAL_DEBUG_VERBOSE)
-      CLog::Log(LOGDEBUG, "%s::%s - buffer:%p vfps:%.3f dfps:%.3f vsync:%d dsync:%d", CLASSNAME, __func__, buffer, m_fps, g_graphicsContext.GetFPS(), m_vsyncCount, CSettings::Get().GetBool("videoplayer.usedisplayasclock"));
-      #endif
-      m_vsyncCount = g_RBP.WaitVsync(m_vsyncCount) + 1;
-      #if defined(MMAL_DEBUG_VERBOSE)
-      CLog::Log(LOGDEBUG, "%s::%s - done vsync:%d", CLASSNAME, __func__, m_vsyncCount);
-      #endif
-    }
-  }
-  mmal_port_send_buffer(m_vout_input, buffer);
-}
-
 void CMMALRenderer::RenderUpdate(bool clear, DWORD flags, DWORD alpha)
 {
   CSingleLock lock(m_sharedSection);
@@ -421,7 +402,7 @@ void CMMALRenderer::RenderUpdate(bool clear, DWORD flags, DWORD alpha)
         return;
       omvb->Acquire();
       omvb->mmal_buffer->flags |= MMAL_BUFFER_HEADER_FLAG_USER1 | MMAL_BUFFER_HEADER_FLAG_USER2;
-      SubmitFrame(omvb->mmal_buffer);
+      mmal_port_send_buffer(m_vout_input, omvb->mmal_buffer);
     }
     else
       CLog::Log(LOGDEBUG, "%s::%s - No buffer to update", CLASSNAME, __func__);
@@ -436,7 +417,7 @@ void CMMALRenderer::RenderUpdate(bool clear, DWORD flags, DWORD alpha)
         return;
       // sanity check it is not on display
       buffer->mmal_buffer->flags |= MMAL_BUFFER_HEADER_FLAG_USER1 | MMAL_BUFFER_HEADER_FLAG_USER2;
-      SubmitFrame(buffer->mmal_buffer);
+      mmal_port_send_buffer(m_vout_input, buffer->mmal_buffer);
     }
     else
       CLog::Log(LOGDEBUG, "%s::%s - No buffer to update", CLASSNAME, __func__);
diff --git a/xbmc/cores/VideoRenderers/MMALRenderer.h b/xbmc/cores/VideoRenderers/MMALRenderer.h
index ec279ed..9bced7e 100644
--- a/xbmc/cores/VideoRenderers/MMALRenderer.h
+++ b/xbmc/cores/VideoRenderers/MMALRenderer.h
@@ -99,7 +99,6 @@ class CMMALRenderer : public CBaseRenderer
   unsigned int         m_destWidth;
   unsigned int         m_destHeight;
   int                  m_neededBuffers;
-  int                  m_vsyncCount;
 
   CRect                     m_src_rect;
   CRect                     m_dst_rect;
@@ -116,5 +115,4 @@ class CMMALRenderer : public CBaseRenderer
   bool init_vout(ERenderFormat format);
   void ReleaseBuffers();
   void UnInitMMAL();
-  void SubmitFrame(MMAL_BUFFER_HEADER_T *buffer);
 };

From 7a7663d4157750849712e41d7bb5ba701b4e2c71 Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Thu, 6 Aug 2015 11:25:30 +0100
Subject: [PATCH 082/100] Revert "[rbp] Refactor the vsync handle to support
 multiple callers"

This reverts commit 68bd91282359a9da4645af4eeead7b2842f835eb.
---
 xbmc/linux/RBP.cpp | 68 ++++++++++++++++++++++++------------------------------
 xbmc/linux/RBP.h   |  7 ++----
 2 files changed, 32 insertions(+), 43 deletions(-)

diff --git a/xbmc/linux/RBP.cpp b/xbmc/linux/RBP.cpp
index 901250e..3953740 100644
--- a/xbmc/linux/RBP.cpp
+++ b/xbmc/linux/RBP.cpp
@@ -66,7 +66,6 @@ CRBP::CRBP()
   m_enabled = 0;
   m_mb = mbox_open();
   vcsm_init();
-  m_vsync_count = 0;
 }
 
 CRBP::~CRBP()
@@ -144,45 +143,11 @@ void CRBP::LogFirmwareVerison()
   CLog::Log(LOGNOTICE, "Config:\n%s", response);
 }
 
-static void vsync_callback_static(DISPMANX_UPDATE_HANDLE_T u, void *arg)
-{
-  CRBP *rbp = reinterpret_cast<CRBP*>(arg);
-  rbp->VSyncCallback();
-}
-
-void CRBP::VSyncCallback()
-{
-  CSingleLock lock(m_vsync_lock);
-  m_vsync_count++;
-  m_vsync_cond.notifyAll();
-}
-
-unsigned int CRBP::WaitVsync(unsigned int target)
-{
-  CSingleLock lock(m_vsync_lock);
-  if (target == ~0U)
-    target = m_vsync_count+1;
-
-  if (m_display == DISPMANX_NO_HANDLE)
-  {
-    CLog::Log(LOGDEBUG, "CRBP::%s skipping while display closed", __func__);
-    return m_vsync_count;
-  }
-
-  while (m_vsync_count < target)
-    if (!m_vsync_cond.wait(lock, 100))
-      break;
-
-  return m_vsync_count;
-}
-
 DISPMANX_DISPLAY_HANDLE_T CRBP::OpenDisplay(uint32_t device)
 {
   if (m_display == DISPMANX_NO_HANDLE)
   {
     m_display = vc_dispmanx_display_open( 0 /*screen*/ );
-    int s = vc_dispmanx_vsync_callback(m_display, vsync_callback_static, (void *)this);
-    assert(s == 0);
     init_cursor();
   }
   return m_display;
@@ -191,11 +156,9 @@ DISPMANX_DISPLAY_HANDLE_T CRBP::OpenDisplay(uint32_t device)
 void CRBP::CloseDisplay(DISPMANX_DISPLAY_HANDLE_T display)
 {
   assert(display == m_display);
-  int s = vc_dispmanx_vsync_callback(m_display, NULL, NULL);
-  assert(s == 0);
-  uninit_cursor();
   vc_dispmanx_display_close(m_display);
   m_display = DISPMANX_NO_HANDLE;
+  uninit_cursor();
 }
 
 void CRBP::GetDisplaySize(int &width, int &height)
@@ -248,6 +211,35 @@ unsigned char *CRBP::CaptureDisplay(int width, int height, int *pstride, bool sw
   return image;
 }
 
+
+static void vsync_callback(DISPMANX_UPDATE_HANDLE_T u, void *arg)
+{
+  CEvent *sync = (CEvent *)arg;
+  sync->Set();
+}
+
+void CRBP::WaitVsync()
+{
+  int s;
+  DISPMANX_DISPLAY_HANDLE_T m_display = vc_dispmanx_display_open( 0 /*screen*/ );
+  if (m_display == DISPMANX_NO_HANDLE)
+  {
+    CLog::Log(LOGDEBUG, "CRBP::%s skipping while display closed", __func__);
+    return;
+  }
+  m_vsync.Reset();
+  s = vc_dispmanx_vsync_callback(m_display, vsync_callback, (void *)&m_vsync);
+  if (s == 0)
+  {
+    m_vsync.WaitMSec(1000);
+  }
+  else assert(0);
+  s = vc_dispmanx_vsync_callback(m_display, NULL, NULL);
+  assert(s == 0);
+  vc_dispmanx_display_close( m_display );
+}
+
+
 void CRBP::Deinitialize()
 {
   if (m_omx_image_init)
diff --git a/xbmc/linux/RBP.h b/xbmc/linux/RBP.h
index 0572b47..be0cafc 100644
--- a/xbmc/linux/RBP.h
+++ b/xbmc/linux/RBP.h
@@ -65,8 +65,7 @@ class CRBP
   // stride can be null for packed output
   unsigned char *CaptureDisplay(int width, int height, int *stride, bool swap_red_blue, bool video_only = true);
   DllOMX *GetDllOMX() { return m_OMX ? m_OMX->GetDll() : NULL; }
-  unsigned int WaitVsync(unsigned int target = ~0U);
-  void VSyncCallback();
+  void WaitVsync();
   double AdjustHDMIClock(double adjust);
 
 private:
@@ -81,9 +80,7 @@ class CRBP
   bool       m_codec_wvc1_enabled;
   COMXCore   *m_OMX;
   DISPMANX_DISPLAY_HANDLE_T m_display;
-  CCriticalSection m_vsync_lock;
-  XbmcThreads::ConditionVariable m_vsync_cond;
-  unsigned int m_vsync_count;
+  CEvent     m_vsync;
   class DllLibOMXCore;
   CCriticalSection m_critSection;
 

From 08c932d103afc098ad828aa4baf5038a5ba10588 Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Thu, 6 Aug 2015 11:23:05 +0100
Subject: [PATCH 083/100] [rbp] Make sync playback to display the default
 option

---
 system/settings/rbp.xml | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/system/settings/rbp.xml b/system/settings/rbp.xml
index bf3b05f..0743176 100644
--- a/system/settings/rbp.xml
+++ b/system/settings/rbp.xml
@@ -1,6 +1,13 @@
 <?xml version="1.0" encoding="utf-8" ?>
 <settings>
   <section id="videos">
+    <category id="videoplayer">
+      <group id="3">
+        <setting id="videoplayer.usedisplayasclock">
+          <default>true</default>
+        </setting>
+      </group>
+    </category>
     <category id="videoacceleration">
       <group id="1">
         <visible>false</visible>

From bed5c73dd318408b8c1e7762b87be28214a42958 Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Fri, 31 Jul 2015 18:39:31 +0100
Subject: [PATCH 084/100] [mmalcodec] Tidy up debug logging for decode

---
 xbmc/cores/dvdplayer/DVDCodecs/Video/MMALCodec.cpp | 16 ++++------------
 1 file changed, 4 insertions(+), 12 deletions(-)

diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/MMALCodec.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/MMALCodec.cpp
index 7fea172..756b845 100644
--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/MMALCodec.cpp
+++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/MMALCodec.cpp
@@ -860,11 +860,7 @@ int CMMALVideo::Decode(uint8_t* pData, int iSize, double dts, double pts)
     m_demuxerPts = dts;
   double queued = m_decoderPts != DVD_NOPTS_VALUE && m_demuxerPts != DVD_NOPTS_VALUE ? m_demuxerPts - m_decoderPts : 0.0;
   if (mmal_queue_length(m_dec_input_pool->queue) > 0 && !m_demux_queue_length && queued <= DVD_MSEC_TO_TIME(1000))
-  {
-    if (g_advancedSettings.CanLogComponent(LOGVIDEO))
-      CLog::Log(LOGDEBUG, "%s::%s - got space for output: demux_queue(%d) space(%d) queued(%.2f)", CLASSNAME, __func__, m_demux_queue_length, mmal_queue_length(m_dec_input_pool->queue) * m_dec_input->buffer_size, queued*1e-6);
     ret |= VC_BUFFER;
-  }
   else
     m_preroll = false;
 
@@ -873,21 +869,17 @@ int CMMALVideo::Decode(uint8_t* pData, int iSize, double dts, double pts)
 
   if (!m_output_ready.empty() && !m_preroll)
   {
-    if (g_advancedSettings.CanLogComponent(LOGVIDEO))
-      CLog::Log(LOGDEBUG, "%s::%s -  got output picture:%d", CLASSNAME, __func__, m_output_ready.size());
     ret |= VC_PICTURE;
     // renderer is low - give priority to returning pictures
     if (0 && m_codecControlFlags & DVD_CODEC_CTRL_DRAIN)
       ret &= ~VC_BUFFER;
   }
   if (!ret)
-  {
-    if (g_advancedSettings.CanLogComponent(LOGVIDEO))
-      CLog::Log(LOGDEBUG, "%s::%s - Nothing to do: ready_queue(%d) demux_queue(%d) space(%d) preroll(%d)",
-        CLASSNAME, __func__, m_output_ready.size(), m_demux_queue_length, mmal_queue_length(m_dec_input_pool->queue) * m_dec_input->buffer_size, m_preroll);
-    lock.Leave();
     Sleep(10); // otherwise we busy spin
-  }
+
+  if (g_advancedSettings.CanLogComponent(LOGVIDEO))
+    CLog::Log(LOGDEBUG, "%s::%s - ret(%x) pics(%d) demux_queue(%d) space(%d) queued(%.2f) preroll(%d) flags(%x)", CLASSNAME, __func__, ret, m_output_ready.size(), m_demux_queue_length, mmal_queue_length(m_dec_input_pool->queue) * m_dec_input->buffer_size, queued*1e-6, m_preroll, m_codecControlFlags);
+
   return ret;
 }
 

From 15fa59d3608dbf28dc49384f220d9412176f364b Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Thu, 6 Aug 2015 13:25:32 +0100
Subject: [PATCH 085/100] [rbp] Don't enable DTS-HD by default on Pi2

Reports of no audio with omxplayer and this enabled
that are not yet understood
---
 system/settings/rbp2.xml | 5 -----
 1 file changed, 5 deletions(-)

diff --git a/system/settings/rbp2.xml b/system/settings/rbp2.xml
index 1c8b116..52778ecd 100644
--- a/system/settings/rbp2.xml
+++ b/system/settings/rbp2.xml
@@ -19,11 +19,6 @@
       </group>
     </category>
     <category id="audiooutput">
-      <group id="1">
-        <setting id="audiooutput.supportdtshdcpudecoding">
-          <default>true</default>
-        </setting>
-      </group>
       <group id="3">
         <setting id="audiooutput.ac3transcode" help="36429">
         </setting>

From 97bff94a5c6341728b3c11ab16c9fa65e95fc869 Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Fri, 7 Aug 2015 18:09:09 +0100
Subject: [PATCH 086/100] Revert "[rbp] Don't enable DTS-HD by default on Pi2"

This reverts commit 8166e8990b8cf599cc4eb1641c58fad1f1f0821f.
---
 system/settings/rbp2.xml | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/system/settings/rbp2.xml b/system/settings/rbp2.xml
index 52778ecd..1c8b116 100644
--- a/system/settings/rbp2.xml
+++ b/system/settings/rbp2.xml
@@ -19,6 +19,11 @@
       </group>
     </category>
     <category id="audiooutput">
+      <group id="1">
+        <setting id="audiooutput.supportdtshdcpudecoding">
+          <default>true</default>
+        </setting>
+      </group>
       <group id="3">
         <setting id="audiooutput.ac3transcode" help="36429">
         </setting>

From 50d9de5e2d3182fbc19c806ba18f77bbf43decda Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Fri, 14 Aug 2015 17:46:11 +0100
Subject: [PATCH 088/100] [mmalrenderer] Add reference counting to sw decode
 buffer and improve logging messages

---
 xbmc/cores/VideoRenderers/MMALRenderer.cpp | 162 +++++++++++++++++++++++------
 xbmc/cores/VideoRenderers/MMALRenderer.h   |  16 ++-
 2 files changed, 145 insertions(+), 33 deletions(-)

diff --git a/xbmc/cores/VideoRenderers/MMALRenderer.cpp b/xbmc/cores/VideoRenderers/MMALRenderer.cpp
index fb92079..6e97c1c 100644
--- a/xbmc/cores/VideoRenderers/MMALRenderer.cpp
+++ b/xbmc/cores/VideoRenderers/MMALRenderer.cpp
@@ -19,6 +19,7 @@
  */
 
 #include "Util.h"
+#include "threads/Atomics.h"
 #include "MMALRenderer.h"
 #include "cores/dvdplayer/DVDCodecs/Video/DVDVideoCodec.h"
 #include "filesystem/File.h"
@@ -39,6 +40,44 @@
 #define MMAL_DEBUG_VERBOSE
 #endif
 
+
+CYUVVideoBuffer::CYUVVideoBuffer()
+{
+  m_refs = 0;
+  mmal_buffer = 0;
+}
+
+CYUVVideoBuffer::~CYUVVideoBuffer()
+{
+  m_refs = 0;
+  mmal_buffer = 0;
+}
+
+CYUVVideoBuffer *CYUVVideoBuffer::Acquire()
+{
+  long count = AtomicIncrement(&m_refs);
+#ifdef MMAL_DEBUG_VERBOSE
+  CLog::Log(LOGDEBUG, "%s::%s omvb:%p mmal:%p ref:%ld", CLASSNAME, __func__, this, mmal_buffer, count);
+#endif
+  (void)count;
+  return this;
+}
+
+long CYUVVideoBuffer::Release()
+{
+  long count = AtomicDecrement(&m_refs);
+#ifdef MMAL_DEBUG_VERBOSE
+  CLog::Log(LOGDEBUG, "%s::%s omvb:%p mmal:%p ref:%ld", CLASSNAME, __func__, this, mmal_buffer, count);
+#endif
+  if (count == 0)
+  {
+    mmal_buffer_header_release(mmal_buffer);
+    delete this;
+  }
+  else assert(count > 0);
+  return count;
+}
+
 CRenderInfo CMMALRenderer::GetRenderInfo()
 {
   CSingleLock lock(m_sharedSection);
@@ -67,21 +106,26 @@ static void vout_control_port_cb(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer
 
 void CMMALRenderer::vout_input_port_cb(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer)
 {
-  #if defined(MMAL_DEBUG_VERBOSE)
-  CMMALVideoBuffer *omvb = (CMMALVideoBuffer *)buffer->user_data;
-  CLog::Log(LOGDEBUG, "%s::%s port:%p buffer %p (%p), len %d cmd:%x f:%x", CLASSNAME, __func__, port, buffer, omvb, buffer->length, buffer->cmd, buffer->flags);
-  #endif
-
   assert(!(buffer->flags & MMAL_BUFFER_HEADER_FLAG_TRANSMISSION_FAILED));
   buffer->flags &= ~MMAL_BUFFER_HEADER_FLAG_USER2;
   if (m_format == RENDER_FMT_MMAL)
   {
     CMMALVideoBuffer *omvb = (CMMALVideoBuffer *)buffer->user_data;
+    assert(buffer == omvb->mmal_buffer);
+#if defined(MMAL_DEBUG_VERBOSE)
+    CLog::Log(LOGDEBUG, "%s::%s port:%p omvb:%p mmal:%p len:%d cmd:%x flags:%x flight:%d", CLASSNAME, __func__, port, omvb, omvb->mmal_buffer, buffer->length, buffer->cmd, buffer->flags, m_inflight);
+#endif
     omvb->Release();
   }
   else if (m_format == RENDER_FMT_YUV420P)
   {
-    mmal_buffer_header_release(buffer);
+    CYUVVideoBuffer *omvb = (CYUVVideoBuffer *)buffer->user_data;
+    assert(buffer == omvb->mmal_buffer);
+#if defined(MMAL_DEBUG_VERBOSE)
+    CLog::Log(LOGDEBUG, "%s::%s port:%p omvb:%p mmal:%p len:%d cmd:%x flags:%x flight:%d", CLASSNAME, __func__, port, omvb, omvb->mmal_buffer, buffer->length, buffer->cmd, buffer->flags, m_inflight);
+#endif
+    m_inflight--;
+    omvb->Release();
   }
   else assert(0);
 }
@@ -208,6 +252,7 @@ CMMALRenderer::CMMALRenderer()
   m_bMMALConfigured = false;
   m_iYV12RenderBuffer = 0;
   m_sharpness = -2.0f;
+  m_inflight = 0;
 }
 
 CMMALRenderer::~CMMALRenderer()
@@ -262,16 +307,19 @@ bool CMMALRenderer::Configure(unsigned int width, unsigned int height, unsigned
 
 int CMMALRenderer::GetImage(YV12Image *image, int source, bool readonly)
 {
+  if (!image || source < 0)
+  {
 #if defined(MMAL_DEBUG_VERBOSE)
-  CLog::Log(LOGDEBUG, "%s::%s - %p %d %d", CLASSNAME, __func__, image, source, readonly);
+    CLog::Log(LOGDEBUG, "%s::%s - invalid: image:%p source:%d ro:%d flight:%d", CLASSNAME, __func__, image, source, readonly, m_inflight);
 #endif
-  if (!image) return -1;
-
-  if( source < 0)
     return -1;
+  }
 
   if (m_format == RENDER_FMT_MMAL)
   {
+#if defined(MMAL_DEBUG_VERBOSE)
+    CLog::Log(LOGDEBUG, "%s::%s - MMAL: image:%p source:%d ro:%d flight:%d", CLASSNAME, __func__, image, source, readonly, m_inflight);
+#endif
   }
   else if (m_format == RENDER_FMT_YUV420P)
   {
@@ -285,6 +333,7 @@ int CMMALRenderer::GetImage(YV12Image *image, int source, bool readonly)
       return -1;
     }
 
+    m_inflight++;
     mmal_buffer_header_reset(buffer);
 
     buffer->length = 3 * pitch * aligned_height >> 1;
@@ -307,10 +356,16 @@ int CMMALRenderer::GetImage(YV12Image *image, int source, bool readonly)
     image->plane[1] = image->plane[0] + image->planesize[0];
     image->plane[2] = image->plane[1] + image->planesize[1];
 
-    CLog::Log(LOGDEBUG, "%s::%s - %p %d", CLASSNAME, __func__, buffer, source);
     YUVBUFFER &buf = m_buffers[source];
     memset(&buf, 0, sizeof buf);
-    buf.mmal_buffer = buffer;
+    buf.YUVBuffer = new CYUVVideoBuffer;
+    if (!buf.YUVBuffer)
+      return -1;
+    buf.YUVBuffer->mmal_buffer = buffer;
+#if defined(MMAL_DEBUG_VERBOSE)
+    CLog::Log(LOGDEBUG, "%s::%s - YUV: image:%p source:%d ro:%d omvb:%p mmal:%p flight:%d", CLASSNAME, __func__, image, source, readonly, buf.YUVBuffer, buffer, m_inflight);
+#endif
+    buf.YUVBuffer->Acquire();
   }
   else assert(0);
 
@@ -320,21 +375,44 @@ int CMMALRenderer::GetImage(YV12Image *image, int source, bool readonly)
 void CMMALRenderer::ReleaseBuffer(int idx)
 {
   CSingleLock lock(m_sharedSection);
-  if (!m_bMMALConfigured || m_format == RENDER_FMT_BYPASS)
+  if (!m_bMMALConfigured)
+  {
+#if defined(MMAL_DEBUG_VERBOSE)
+    CLog::Log(LOGDEBUG, "%s::%s - not configured: source:%d", CLASSNAME, __func__, idx);
+#endif
+    return;
+  }
+  if (m_format == RENDER_FMT_BYPASS)
+  {
+#if defined(MMAL_DEBUG_VERBOSE)
+    CLog::Log(LOGDEBUG, "%s::%s - bypass: source:%d", CLASSNAME, __func__, idx);
+#endif
     return;
+  }
 
+  YUVBUFFER *buffer = &m_buffers[idx];
+  if (m_format == RENDER_FMT_MMAL)
+  {
+    CMMALVideoBuffer *omvb = buffer->MMALBuffer;
+#if defined(MMAL_DEBUG_VERBOSE)
+    CLog::Log(LOGDEBUG, "%s::%s - MMAL: source:%d omvb:%p mmal:%p", CLASSNAME, __func__, idx, omvb, omvb ? omvb->mmal_buffer:NULL);
+#endif
+    SAFE_RELEASE(buffer->MMALBuffer);
+  }
+  else if (m_format == RENDER_FMT_YUV420P)
+  {
+    CYUVVideoBuffer *omvb = buffer->YUVBuffer;
 #if defined(MMAL_DEBUG_VERBOSE)
-  CLog::Log(LOGDEBUG, "%s::%s - %d (%p)", CLASSNAME, __func__, idx, m_buffers[idx].MMALBuffer);
+    CLog::Log(LOGDEBUG, "%s::%s - YUV: source:%d omvb:%p mmal:%p flight:%d", CLASSNAME, __func__, idx, omvb, omvb ? omvb->mmal_buffer:NULL, m_inflight);
 #endif
-  YUVBUFFER &buf = m_buffers[idx];
-  SAFE_RELEASE(buf.MMALBuffer);
+    if (omvb && omvb->mmal_buffer)
+      SAFE_RELEASE(buffer->YUVBuffer);
+  }
+  else assert(0);
 }
 
 void CMMALRenderer::ReleaseImage(int source, bool preserve)
 {
-#if defined(MMAL_DEBUG_VERBOSE)
-  CLog::Log(LOGDEBUG, "%s::%s - %d %d (%p)", CLASSNAME, __func__, source, preserve, m_buffers[source].MMALBuffer);
-#endif
 }
 
 void CMMALRenderer::Reset()
@@ -361,11 +439,14 @@ void CMMALRenderer::RenderUpdate(bool clear, DWORD flags, DWORD alpha)
 {
   CSingleLock lock(m_sharedSection);
   int source = m_iYV12RenderBuffer;
+
+  if (!m_bConfigured)
+  {
 #if defined(MMAL_DEBUG_VERBOSE)
-  CLog::Log(LOGDEBUG, "%s::%s - %d %x %d %d", CLASSNAME, __func__, clear, flags, alpha, source);
+    CLog::Log(LOGDEBUG, "%s::%s - not configured: clear:%d flags:%x alpha:%d source:%d", CLASSNAME, __func__, clear, flags, alpha, source);
 #endif
-
-  if (!m_bConfigured) return;
+    return;
+  }
 
   ManageDisplay();
 
@@ -384,18 +465,22 @@ void CMMALRenderer::RenderUpdate(bool clear, DWORD flags, DWORD alpha)
   }
 
   if (m_format == RENDER_FMT_BYPASS)
+  {
+#if defined(MMAL_DEBUG_VERBOSE)
+    CLog::Log(LOGDEBUG, "%s::%s - bypass: clear:%d flags:%x alpha:%d source:%d", CLASSNAME, __func__, clear, flags, alpha, source);
+#endif
     return;
-
+  }
   SetVideoRect(m_sourceRect, m_destRect);
 
   YUVBUFFER *buffer = &m_buffers[source];
   if (m_format == RENDER_FMT_MMAL)
   {
     CMMALVideoBuffer *omvb = buffer->MMALBuffer;
-    if (omvb)
+    if (omvb && omvb->mmal_buffer)
     {
 #if defined(MMAL_DEBUG_VERBOSE)
-      CLog::Log(LOGDEBUG, "%s::%s %p (%p) f:%x", CLASSNAME, __func__, omvb, omvb->mmal_buffer, omvb->mmal_buffer->flags);
+      CLog::Log(LOGDEBUG, "%s::%s - MMAL: clear:%d flags:%x alpha:%d source:%d omvb:%p mmal:%p mflags:%x", CLASSNAME, __func__, clear, flags, alpha, source, omvb, omvb->mmal_buffer, omvb->mmal_buffer->flags);
 #endif
       // we only want to upload frames once
       if (omvb->mmal_buffer->flags & MMAL_BUFFER_HEADER_FLAG_USER1)
@@ -409,18 +494,23 @@ void CMMALRenderer::RenderUpdate(bool clear, DWORD flags, DWORD alpha)
   }
   else if (m_format == RENDER_FMT_YUV420P)
   {
-    if (buffer->mmal_buffer)
+    CYUVVideoBuffer *omvb = buffer->YUVBuffer;
+    if (omvb && omvb->mmal_buffer)
     {
-      CLog::Log(LOGDEBUG, "%s::%s - %p %d f:%x", CLASSNAME, __func__, buffer->mmal_buffer, source, buffer->mmal_buffer->flags);
+#if defined(MMAL_DEBUG_VERBOSE)
+      CLog::Log(LOGDEBUG, "%s::%s - YUV: clear:%d flags:%x alpha:%d source:%d omvb:%p mmal:%p mflags:%x", CLASSNAME, __func__, clear, flags, alpha, source, omvb, omvb->mmal_buffer, omvb->mmal_buffer->flags);
+#endif
       // we only want to upload frames once
-      if (buffer->mmal_buffer->flags & MMAL_BUFFER_HEADER_FLAG_USER1)
+      if (omvb->mmal_buffer->flags & MMAL_BUFFER_HEADER_FLAG_USER1)
         return;
       // sanity check it is not on display
-      buffer->mmal_buffer->flags |= MMAL_BUFFER_HEADER_FLAG_USER1 | MMAL_BUFFER_HEADER_FLAG_USER2;
-      mmal_port_send_buffer(m_vout_input, buffer->mmal_buffer);
+      omvb->Acquire();
+      omvb->mmal_buffer->flags |= MMAL_BUFFER_HEADER_FLAG_USER1 | MMAL_BUFFER_HEADER_FLAG_USER2;
+      omvb->mmal_buffer->user_data = omvb;
+      mmal_port_send_buffer(m_vout_input, omvb->mmal_buffer);
     }
     else
-      CLog::Log(LOGDEBUG, "%s::%s - No buffer to update", CLASSNAME, __func__);
+      CLog::Log(LOGDEBUG, "%s::%s - No buffer to update: clear:%d flags:%x alpha:%d source:%d", CLASSNAME, __func__, clear, flags, alpha, source);
   }
   else assert(0);
 }
@@ -429,10 +519,15 @@ void CMMALRenderer::FlipPage(int source)
 {
   CSingleLock lock(m_sharedSection);
   if (!m_bConfigured || m_format == RENDER_FMT_BYPASS)
+  {
+#if defined(MMAL_DEBUG_VERBOSE)
+    CLog::Log(LOGDEBUG, "%s::%s - not configured: source:%d", CLASSNAME, __func__, source);
+#endif
     return;
+  }
 
 #if defined(MMAL_DEBUG_VERBOSE)
-  CLog::Log(LOGDEBUG, "%s::%s - %d", CLASSNAME, __func__, source);
+  CLog::Log(LOGDEBUG, "%s::%s - source:%d", CLASSNAME, __func__, source);
 #endif
 
   m_iYV12RenderBuffer = source;
@@ -466,6 +561,9 @@ unsigned int CMMALRenderer::PreInit()
 
 void CMMALRenderer::ReleaseBuffers()
 {
+#if defined(MMAL_DEBUG_VERBOSE)
+  CLog::Log(LOGDEBUG, "%s::%s", CLASSNAME, __func__);
+#endif
   for (int i=0; i<NUM_BUFFERS; i++)
     ReleaseBuffer(i);
 }
diff --git a/xbmc/cores/VideoRenderers/MMALRenderer.h b/xbmc/cores/VideoRenderers/MMALRenderer.h
index 9bced7e..5fbcb03 100644
--- a/xbmc/cores/VideoRenderers/MMALRenderer.h
+++ b/xbmc/cores/VideoRenderers/MMALRenderer.h
@@ -42,12 +42,25 @@ class CMMALVideoBuffer;
 
 struct DVDVideoPicture;
 
+class CYUVVideoBuffer
+{
+public:
+  CYUVVideoBuffer();
+  ~CYUVVideoBuffer();
+  // reference counting
+  CYUVVideoBuffer *Acquire();
+  long Release();
+  MMAL_BUFFER_HEADER_T *mmal_buffer;
+protected:
+  long m_refs;
+};
+
 class CMMALRenderer : public CBaseRenderer
 {
   struct YUVBUFFER
   {
     CMMALVideoBuffer *MMALBuffer; // used for hw decoded buffers
-    MMAL_BUFFER_HEADER_T *mmal_buffer;  // used for sw decoded buffers
+    CYUVVideoBuffer  *YUVBuffer;  // used for sw decoded buffers
   };
 public:
   CMMALRenderer();
@@ -106,6 +119,7 @@ class CMMALRenderer : public CBaseRenderer
   RENDER_STEREO_MODE        m_display_stereo_mode;
   bool                      m_StereoInvert;
   float                     m_sharpness;
+  int                       m_inflight;
 
   CCriticalSection m_sharedSection;
   MMAL_COMPONENT_T *m_vout;

From 1847f250fc140b51e781de4293f4bdc72a6ed117 Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Sat, 15 Aug 2015 14:27:10 +0100
Subject: [PATCH 089/100] [mmalrenderer] Use half rate deinterlace when playing
 video in background

---
 xbmc/cores/dvdplayer/DVDCodecs/Video/MMALCodec.cpp | 10 +++++++++-
 1 file changed, 9 insertions(+), 1 deletion(-)

diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/MMALCodec.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/MMALCodec.cpp
index 756b845..56a9121 100644
--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/MMALCodec.cpp
+++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/MMALCodec.cpp
@@ -828,9 +828,17 @@ int CMMALVideo::Decode(uint8_t* pData, int iSize, double dts, double pts)
        {
          EDEINTERLACEMODE deinterlace_request = CMediaSettings::Get().GetCurrentVideoSettings().m_DeinterlaceMode;
          EINTERLACEMETHOD interlace_method = g_renderManager.AutoInterlaceMethod(CMediaSettings::Get().GetCurrentVideoSettings().m_InterlaceMethod);
-
          bool deinterlace = m_interlace_mode != MMAL_InterlaceProgressive;
 
+         // we don't keep up when running at 60fps in the background so switch to half rate
+         if (!g_graphicsContext.IsFullScreenVideo())
+         {
+           if (interlace_method == VS_INTERLACEMETHOD_MMAL_ADVANCED)
+             interlace_method = VS_INTERLACEMETHOD_MMAL_ADVANCED_HALF;
+           if (interlace_method == VS_INTERLACEMETHOD_MMAL_BOB)
+             interlace_method = VS_INTERLACEMETHOD_MMAL_BOB_HALF;
+         }
+
          if (m_hints.stills || deinterlace_request == VS_DEINTERLACEMODE_OFF || interlace_method == VS_INTERLACEMETHOD_NONE)
            deinterlace = false;
          else if (deinterlace_request == VS_DEINTERLACEMODE_FORCE)

From 2cf9bdbb7433388370653d0b9b97cf2eadccfbdd Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Thu, 13 Aug 2015 16:30:31 +0100
Subject: [PATCH 090/100] squash: rbp: Remove HW mouse pointer when mouse is
 disabled in GUI

---
 xbmc/windowing/WinEventsLinux.cpp | 33 ++++++++++++++++++++++++---------
 1 file changed, 24 insertions(+), 9 deletions(-)

diff --git a/xbmc/windowing/WinEventsLinux.cpp b/xbmc/windowing/WinEventsLinux.cpp
index bde7649..89aca2b 100644
--- a/xbmc/windowing/WinEventsLinux.cpp
+++ b/xbmc/windowing/WinEventsLinux.cpp
@@ -180,28 +180,40 @@ bool CWinEventsLinux::MessagePump()
   bool ret = false;
   XBMC_Event event = {0};
 #ifdef TARGET_RASPBERRY_PI
+  bool active = CInputManager::Get().IsMouseActive();
   int64_t Now = CurrentHostCounter();
-  int state = CInputManager::Get().GetMouseState() - 1;
-  if (m_mouse_state != state)
+  if (!active)
   {
-    //printf("%s: %d->%d\n", __func__, m_mouse_state, state);
-    if (state >= 0 && state < (int)(sizeof m_cursors/sizeof *m_cursors) && m_cursors[state].pixels)
+    if (m_mouse_state != -1)
     {
-      g_RBP.set_cursor(m_cursors[state].pixels, m_cursors[state].width, m_cursors[state].height, 0, 0);
+      g_RBP.update_cursor(0, 0, 0);
+      m_mouse_state = -1;
+    }
+  }
+  else
+  {
+    int state = CInputManager::Get().GetMouseState() - 1;
+    if (m_mouse_state != state)
+    {
+      //printf("%s: %d->%d\n", __func__, m_mouse_state, state);
+      if (state >= 0 && state < (int)(sizeof m_cursors/sizeof *m_cursors) && m_cursors[state].pixels)
+      {
+        g_RBP.set_cursor(m_cursors[state].pixels, m_cursors[state].width, m_cursors[state].height, 0, 0);
+      }
+      m_mouse_state = state;
     }
-    m_mouse_state = state;
   }
 #endif
   while (1)
   {
     event = m_devices.ReadEvent();
 #ifdef TARGET_RASPBERRY_PI
-    if (event.type == XBMC_MOUSEMOTION || event.type == XBMC_MOUSEBUTTONDOWN || event.type == XBMC_MOUSEBUTTONUP)
+    if (active && (event.type == XBMC_MOUSEMOTION || event.type == XBMC_MOUSEBUTTONDOWN || event.type == XBMC_MOUSEBUTTONUP))
     {
       if (event.type == XBMC_MOUSEMOTION)
         g_RBP.update_cursor(event.motion.x, event.motion.y, 1);
       m_last_mouse_move_time = Now;
-      //printf("%s: %d,%d %d %d,%d (%d,%d)\n", __func__, event.motion.type, event.motion.which, event.motion.state, event.motion.x, event.motion.y, event.motion.xrel, event.motion.yrel);
+      //printf("%s: %d,%d %d %d,%d (%d,%d) act:%d\n", __func__, event.motion.type, event.motion.which, event.motion.state, event.motion.x, event.motion.y, event.motion.xrel, event.motion.yrel, CInputManager::Get().IsMouseActive());
     }
 #endif
     if (event.type != XBMC_NOEVENT)
@@ -215,8 +227,11 @@ bool CWinEventsLinux::MessagePump()
   }
 
 #ifdef TARGET_RASPBERRY_PI
-  if (Now - m_last_mouse_move_time > 5 * 1000000000LL)
+  if (active && Now - m_last_mouse_move_time > 5 * 1000000000LL)
+  {
     g_RBP.update_cursor(0, 0, 0);
+    m_mouse_state = -1;
+  }
 #endif
   return ret;
 }

From 9e7033c49cd99640325abaf6b9534ccf2ced97fe Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Sun, 9 Aug 2015 18:01:34 +0100
Subject: [PATCH 091/100] [rbp] Add ntsc version of 48Hz mode

---
 xbmc/windowing/egl/EGLNativeTypeRaspberryPI.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/xbmc/windowing/egl/EGLNativeTypeRaspberryPI.cpp b/xbmc/windowing/egl/EGLNativeTypeRaspberryPI.cpp
index 25a97ad..25475bf 100644
--- a/xbmc/windowing/egl/EGLNativeTypeRaspberryPI.cpp
+++ b/xbmc/windowing/egl/EGLNativeTypeRaspberryPI.cpp
@@ -683,7 +683,7 @@ void CEGLNativeTypeRaspberryPI::GetSupportedModes(HDMI_RES_GROUP_T group, std::v
       CLog::Log(LOGDEBUG, "EGL mode %d: %s (%.2f) %s%s:%x\n", i, res.strMode.c_str(), res.fPixelRatio,
           tv->native ? "N" : "", tv->scan_mode ? "I" : "", tv->code);
 
-      if (tv->frame_rate == 24 || tv->frame_rate == 30 || tv->frame_rate == 60)
+      if (tv->frame_rate == 24 || tv->frame_rate == 30 || tv->frame_rate == 48 || tv->frame_rate == 60 || tv->frame_rate == 72)
       {
         RESOLUTION_INFO res2 = res;
         res2.fRefreshRate  = (float)tv->frame_rate * (1000.0f/1001.0f);

From 6563dca0bd3006aa71fe98bbdce30c4b58cb1848 Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Sat, 22 Aug 2015 23:06:56 +0100
Subject: [PATCH 092/100] [dvdmessage] Increase timeout on
 CDVDMsgGeneralSynchronize

---
 xbmc/cores/dvdplayer/DVDMessage.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/xbmc/cores/dvdplayer/DVDMessage.cpp b/xbmc/cores/dvdplayer/DVDMessage.cpp
index ae745c6..73fff98 100644
--- a/xbmc/cores/dvdplayer/DVDMessage.cpp
+++ b/xbmc/cores/dvdplayer/DVDMessage.cpp
@@ -91,7 +91,7 @@ bool CDVDMsgGeneralSynchronize::Wait(unsigned int milliseconds, unsigned int sou
 
 void CDVDMsgGeneralSynchronize::Wait(volatile bool *abort, unsigned int source)
 {
-  while(!Wait(100, source))
+  while(!Wait(200, source))
   {
     if(abort && *abort)
       return;

From e0097ee5ac47accbdef83e24b229eecc633014fd Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Sat, 22 Aug 2015 23:19:15 +0100
Subject: [PATCH 093/100] [mmalcodec] refector the decoder flags logic to avoid
 stalls on seek

---
 xbmc/cores/dvdplayer/DVDCodecs/Video/MMALCodec.cpp | 47 +++++++++++++---------
 1 file changed, 28 insertions(+), 19 deletions(-)

diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/MMALCodec.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/MMALCodec.cpp
index 56a9121..557faa2 100644
--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/MMALCodec.cpp
+++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/MMALCodec.cpp
@@ -253,12 +253,20 @@ void CMMALVideo::dec_output_port_cb(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buf
   {
     if (buffer->length > 0)
     {
+      if (buffer->pts != MMAL_TIME_UNKNOWN)
+        m_decoderPts = buffer->pts;
+      else if (buffer->dts != MMAL_TIME_UNKNOWN)
+        m_decoderPts = buffer->dts;
+
       assert(!(buffer->flags & MMAL_BUFFER_HEADER_FLAG_DECODEONLY));
+      CMMALVideoBuffer *omvb = NULL;
+      if (!(buffer->flags & MMAL_BUFFER_HEADER_FLAG_CORRUPTED));
+        omvb = new CMMALVideoBuffer(this);
+      if (g_advancedSettings.CanLogComponent(LOGVIDEO))
+        CLog::Log(LOGDEBUG, "%s::%s - %p (%p) buffer_size(%u) dts:%.3f pts:%.3f flags:%x:%x",
+          CLASSNAME, __func__, buffer, omvb, buffer->length, buffer->dts*1e-6, buffer->pts*1e-6, buffer->flags, buffer->type->video.flags);
+      if (omvb)
       {
-        CMMALVideoBuffer *omvb = new CMMALVideoBuffer(this);
-        if (g_advancedSettings.CanLogComponent(LOGVIDEO))
-          CLog::Log(LOGDEBUG, "%s::%s - %p (%p) buffer_size(%u) dts:%.3f pts:%.3f flags:%x:%x",
-            CLASSNAME, __func__, buffer, omvb, buffer->length, buffer->dts*1e-6, buffer->pts*1e-6, buffer->flags, buffer->type->video.flags);
         omvb->mmal_buffer = buffer;
         buffer->user_data = (void *)omvb;
         omvb->width = m_decoded_width;
@@ -861,33 +869,39 @@ int CMMALVideo::Decode(uint8_t* pData, int iSize, double dts, double pts)
     if (!demuxer_bytes)
       break;
   }
-  int ret = 0;
   if (pts != DVD_NOPTS_VALUE)
     m_demuxerPts = pts;
   else if (dts != DVD_NOPTS_VALUE)
     m_demuxerPts = dts;
+
+  if (m_demuxerPts != DVD_NOPTS_VALUE && m_decoderPts == DVD_NOPTS_VALUE)
+    m_decoderPts = m_demuxerPts;
+
+  // we've built up quite a lot of data in decoder - try to throttle it
   double queued = m_decoderPts != DVD_NOPTS_VALUE && m_demuxerPts != DVD_NOPTS_VALUE ? m_demuxerPts - m_decoderPts : 0.0;
-  if (mmal_queue_length(m_dec_input_pool->queue) > 0 && !m_demux_queue_length && queued <= DVD_MSEC_TO_TIME(1000))
-    ret |= VC_BUFFER;
-  else
-    m_preroll = false;
+  bool full = queued > DVD_MSEC_TO_TIME(1000);
+  bool want_buffer = mmal_queue_length(m_dec_input_pool->queue) > 0 && !m_demux_queue_length && !full;
+  int ret = VC_BUFFER;
 
-  if (m_preroll && m_output_ready.size() >= GetAllowedReferences())
+  if (m_preroll && (!want_buffer || m_output_ready.size() >= GetAllowedReferences()))
     m_preroll = false;
 
   if (!m_output_ready.empty() && !m_preroll)
   {
     ret |= VC_PICTURE;
     // renderer is low - give priority to returning pictures
-    if (0 && m_codecControlFlags & DVD_CODEC_CTRL_DRAIN)
+    if (m_codecControlFlags & DVD_CODEC_CTRL_DRAIN || !want_buffer || full)
       ret &= ~VC_BUFFER;
   }
-  if (!ret)
-    Sleep(10); // otherwise we busy spin
 
   if (g_advancedSettings.CanLogComponent(LOGVIDEO))
-    CLog::Log(LOGDEBUG, "%s::%s - ret(%x) pics(%d) demux_queue(%d) space(%d) queued(%.2f) preroll(%d) flags(%x)", CLASSNAME, __func__, ret, m_output_ready.size(), m_demux_queue_length, mmal_queue_length(m_dec_input_pool->queue) * m_dec_input->buffer_size, queued*1e-6, m_preroll, m_codecControlFlags);
+    CLog::Log(LOGDEBUG, "%s::%s - ret(%x) pics(%d) demux_queue(%d) space(%d) queued(%.2f) (%.2f:%.2f) preroll(%d) flags(%x) full(%d)", CLASSNAME, __func__, ret, m_output_ready.size(), m_demux_queue_length, mmal_queue_length(m_dec_input_pool->queue) * m_dec_input->buffer_size, queued*1e-6, m_demuxerPts*1e-6, m_decoderPts*1e-6, m_preroll, m_codecControlFlags, full);
 
+  if (full)
+  {
+    lock.Leave();
+    Sleep(queued * 1e-6 * 10.0);
+  }
   return ret;
 }
 
@@ -1046,11 +1060,6 @@ bool CMMALVideo::GetPicture(DVDVideoPicture* pDvdVideoPicture)
     return false;
   }
 
-  if (pDvdVideoPicture->pts != DVD_NOPTS_VALUE)
-    m_decoderPts = pDvdVideoPicture->pts;
-  else
-    m_decoderPts = pDvdVideoPicture->dts;
-
   return true;
 }
 

From d733cf94e2a98db3a44f8035e466ed67d5bc0d3c Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Sun, 23 Aug 2015 18:57:34 +0100
Subject: [PATCH 094/100] [omxplayer] Flush EOS message from queue to avoid it
 turning up after a seek

A GENERAL_EOS is queued when demuxer reaches EOF but playback may continue for several seconds.
It should be possible to seek backwards during this playback time, but the GENERAL_EOS may still be queued after flushing
and it unwantedly causes stream to stall after the seek. So flush these obsolete messages when flushing data packets
---
 xbmc/cores/omxplayer/OMXPlayerAudio.cpp | 1 +
 xbmc/cores/omxplayer/OMXPlayerVideo.cpp | 1 +
 2 files changed, 2 insertions(+)

diff --git a/xbmc/cores/omxplayer/OMXPlayerAudio.cpp b/xbmc/cores/omxplayer/OMXPlayerAudio.cpp
index c2da2d2..1c3b904 100644
--- a/xbmc/cores/omxplayer/OMXPlayerAudio.cpp
+++ b/xbmc/cores/omxplayer/OMXPlayerAudio.cpp
@@ -495,6 +495,7 @@ void OMXPlayerAudio::Flush()
 {
   m_flush = true;
   m_messageQueue.Flush();
+  m_messageQueue.Flush(CDVDMsg::GENERAL_EOF);
   m_messageQueue.Put( new CDVDMsg(CDVDMsg::GENERAL_FLUSH), 1);
 }
 
diff --git a/xbmc/cores/omxplayer/OMXPlayerVideo.cpp b/xbmc/cores/omxplayer/OMXPlayerVideo.cpp
index 4ad66a8..276857f 100644
--- a/xbmc/cores/omxplayer/OMXPlayerVideo.cpp
+++ b/xbmc/cores/omxplayer/OMXPlayerVideo.cpp
@@ -535,6 +535,7 @@ void OMXPlayerVideo::Flush()
 {
   m_flush = true;
   m_messageQueue.Flush();
+  m_messageQueue.Flush(CDVDMsg::GENERAL_EOF);
   m_messageQueue.Put(new CDVDMsg(CDVDMsg::GENERAL_FLUSH), 1);
 }
 

From e4971e53c16f1e11907764c580b35a5507dce7b7 Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Mon, 13 Jul 2015 19:27:25 +0100
Subject: [PATCH 095/100] [rbp] Enable QPU based deinterlace and remove
 resolution limit

---
 xbmc/cores/VideoRenderers/MMALRenderer.cpp         | 2 +-
 xbmc/cores/dvdplayer/DVDCodecs/Video/MMALCodec.cpp | 5 ++---
 xbmc/cores/omxplayer/OMXVideo.cpp                  | 6 +++---
 3 files changed, 6 insertions(+), 7 deletions(-)

diff --git a/xbmc/cores/VideoRenderers/MMALRenderer.cpp b/xbmc/cores/VideoRenderers/MMALRenderer.cpp
index 6e97c1c..e278184 100644
--- a/xbmc/cores/VideoRenderers/MMALRenderer.cpp
+++ b/xbmc/cores/VideoRenderers/MMALRenderer.cpp
@@ -681,7 +681,7 @@ bool CMMALRenderer::Supports(ESCALINGMETHOD method)
 
 EINTERLACEMETHOD CMMALRenderer::AutoInterlaceMethod()
 {
-  return VS_INTERLACEMETHOD_MMAL_ADVANCED;
+  return m_sourceWidth * m_sourceHeight <= 576 * 720 ? VS_INTERLACEMETHOD_MMAL_ADVANCED : VS_INTERLACEMETHOD_MMAL_BOB;
 }
 
 void CMMALRenderer::SetVideoRect(const CRect& InSrcRect, const CRect& InDestRect)
diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/MMALCodec.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/MMALCodec.cpp
index 557faa2..a28a5e3 100644
--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/MMALCodec.cpp
+++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/MMALCodec.cpp
@@ -355,12 +355,11 @@ bool CMMALVideo::CreateDeinterlace(EINTERLACEMETHOD interlace_method)
     CLog::Log(LOGERROR, "%s::%s Failed to create deinterlace component (status=%x %s)", CLASSNAME, __func__, status, mmal_status_to_string(status));
     return false;
   }
-  bool advanced_deinterlace = (interlace_method == VS_INTERLACEMETHOD_MMAL_ADVANCED || interlace_method == VS_INTERLACEMETHOD_MMAL_ADVANCED_HALF) &&
-      m_decoded_width * m_decoded_height <= 576 * 720;
+  bool advanced_deinterlace = interlace_method == VS_INTERLACEMETHOD_MMAL_ADVANCED || interlace_method == VS_INTERLACEMETHOD_MMAL_ADVANCED_HALF;
   bool half_framerate = interlace_method == VS_INTERLACEMETHOD_MMAL_ADVANCED_HALF || interlace_method == VS_INTERLACEMETHOD_MMAL_BOB_HALF;
 
   MMAL_PARAMETER_IMAGEFX_PARAMETERS_T imfx_param = {{MMAL_PARAMETER_IMAGE_EFFECT_PARAMETERS, sizeof(imfx_param)},
-        advanced_deinterlace ? MMAL_PARAM_IMAGEFX_DEINTERLACE_ADV : MMAL_PARAM_IMAGEFX_DEINTERLACE_FAST, 3, {3, 0, half_framerate }};
+        advanced_deinterlace ? MMAL_PARAM_IMAGEFX_DEINTERLACE_ADV : MMAL_PARAM_IMAGEFX_DEINTERLACE_FAST, 4, {3, 0, half_framerate, 1 }};
 
   status = mmal_port_parameter_set(m_deint->output[0], &imfx_param.hdr);
   if (status != MMAL_SUCCESS)
diff --git a/xbmc/cores/omxplayer/OMXVideo.cpp b/xbmc/cores/omxplayer/OMXVideo.cpp
index 1a08aa9..fbb395d 100644
--- a/xbmc/cores/omxplayer/OMXVideo.cpp
+++ b/xbmc/cores/omxplayer/OMXVideo.cpp
@@ -244,8 +244,7 @@ bool COMXVideo::PortSettingsChanged()
   if(m_deinterlace)
   {
     EINTERLACEMETHOD interlace_method = g_renderManager.AutoInterlaceMethod(CMediaSettings::Get().GetCurrentVideoSettings().m_InterlaceMethod);
-    bool advanced_deinterlace = (interlace_method == VS_INTERLACEMETHOD_MMAL_ADVANCED || interlace_method == VS_INTERLACEMETHOD_MMAL_ADVANCED_HALF) &&
-        port_image.format.video.nFrameWidth * port_image.format.video.nFrameHeight <= 576 * 720;
+    bool advanced_deinterlace = interlace_method == VS_INTERLACEMETHOD_MMAL_ADVANCED || interlace_method == VS_INTERLACEMETHOD_MMAL_ADVANCED_HALF;
     bool half_framerate = interlace_method == VS_INTERLACEMETHOD_MMAL_ADVANCED_HALF || interlace_method == VS_INTERLACEMETHOD_MMAL_BOB_HALF;
     if (!advanced_deinterlace)
     {
@@ -266,10 +265,11 @@ bool COMXVideo::PortSettingsChanged()
     OMX_INIT_STRUCTURE(image_filter);
 
     image_filter.nPortIndex = m_omx_image_fx.GetOutputPort();
-    image_filter.nNumParams = 3;
+    image_filter.nNumParams = 4;
     image_filter.nParams[0] = 3;
     image_filter.nParams[1] = 0;
     image_filter.nParams[2] = half_framerate;
+    image_filter.nParams[3] = 1; // qpu
     if (!advanced_deinterlace)
       image_filter.eImageFilter = OMX_ImageFilterDeInterlaceFast;
     else

From 45675407456e03348c7f7774f1d80d2fbca4a006 Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Sun, 16 Aug 2015 15:46:33 +0100
Subject: [PATCH 096/100] [mmalrenderer] Allow deinterlace with software decode

---
 xbmc/cores/VideoRenderers/MMALRenderer.cpp | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/xbmc/cores/VideoRenderers/MMALRenderer.cpp b/xbmc/cores/VideoRenderers/MMALRenderer.cpp
index e278184..1eb8936 100644
--- a/xbmc/cores/VideoRenderers/MMALRenderer.cpp
+++ b/xbmc/cores/VideoRenderers/MMALRenderer.cpp
@@ -647,6 +647,13 @@ bool CMMALRenderer::Supports(EDEINTERLACEMODE mode)
 
 bool CMMALRenderer::Supports(EINTERLACEMETHOD method)
 {
+  if (m_format == RENDER_FMT_YUV420P)
+  {
+    if (method == VS_INTERLACEMETHOD_DEINTERLACE_HALF)
+      return true;
+    else
+      return false;
+  }
   if (method == VS_INTERLACEMETHOD_AUTO)
     return true;
   if (method == VS_INTERLACEMETHOD_MMAL_ADVANCED)
@@ -681,6 +688,8 @@ bool CMMALRenderer::Supports(ESCALINGMETHOD method)
 
 EINTERLACEMETHOD CMMALRenderer::AutoInterlaceMethod()
 {
+  if (m_format == RENDER_FMT_YUV420P)
+    return VS_INTERLACEMETHOD_DEINTERLACE_HALF;
   return m_sourceWidth * m_sourceHeight <= 576 * 720 ? VS_INTERLACEMETHOD_MMAL_ADVANCED : VS_INTERLACEMETHOD_MMAL_BOB;
 }
 

From a5a13a9ee012234f9089b3f2e0cc62bcffaf01af Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Wed, 9 Sep 2015 23:34:41 +0100
Subject: [PATCH 098/100] [rbp] Extract the correct resolution with Pi LCD

---
 xbmc/windowing/egl/EGLNativeTypeRaspberryPI.cpp | 20 +++++++++++++++++---
 1 file changed, 17 insertions(+), 3 deletions(-)

diff --git a/xbmc/windowing/egl/EGLNativeTypeRaspberryPI.cpp b/xbmc/windowing/egl/EGLNativeTypeRaspberryPI.cpp
index 25475bf..bccb774 100644
--- a/xbmc/windowing/egl/EGLNativeTypeRaspberryPI.cpp
+++ b/xbmc/windowing/egl/EGLNativeTypeRaspberryPI.cpp
@@ -569,6 +569,18 @@ bool CEGLNativeTypeRaspberryPI::ProbeResolutions(std::vector<RESOLUTION_INFO> &r
       m_desktopRes.fRefreshRate = (float)tv_state.display.sdtv.frame_rate;
       m_desktopRes.fPixelRatio  = tv_state.display.hdmi.display_options.aspect == 0 ? 1.0f : get_display_aspect_ratio((SDTV_ASPECT_T)tv_state.display.sdtv.display_options.aspect) / ((float)m_desktopRes.iScreenWidth / (float)m_desktopRes.iScreenHeight);
     }
+    else if ((tv_state.state & VC_LCD_ATTACHED_DEFAULT) != 0) // lcd
+    {
+      m_desktopRes.iScreen      = 0;
+      m_desktopRes.bFullScreen  = true;
+      m_desktopRes.iWidth       = tv_state.display.sdtv.width;
+      m_desktopRes.iHeight      = tv_state.display.sdtv.height;
+      m_desktopRes.iScreenWidth = tv_state.display.sdtv.width;
+      m_desktopRes.iScreenHeight= tv_state.display.sdtv.height;
+      m_desktopRes.dwFlags      = MAKEFLAGS(HDMI_RES_GROUP_INVALID, 0, 0);
+      m_desktopRes.fRefreshRate = (float)tv_state.display.sdtv.frame_rate;
+      m_desktopRes.fPixelRatio  = tv_state.display.hdmi.display_options.aspect == 0 ? 1.0f : get_display_aspect_ratio((SDTV_ASPECT_T)tv_state.display.sdtv.display_options.aspect) / ((float)m_desktopRes.iScreenWidth / (float)m_desktopRes.iScreenHeight);
+    }
 
     SetResolutionString(m_desktopRes);
 
@@ -579,9 +591,11 @@ bool CEGLNativeTypeRaspberryPI::ProbeResolutions(std::vector<RESOLUTION_INFO> &r
     CLog::Log(LOGDEBUG, "EGL initial desktop resolution %s (%.2f)\n", m_desktopRes.strMode.c_str(), m_desktopRes.fPixelRatio);
   }
 
-  GetSupportedModes(HDMI_RES_GROUP_CEA, resolutions);
-  GetSupportedModes(HDMI_RES_GROUP_DMT, resolutions);
-
+  if(GETFLAGS_GROUP(m_desktopRes.dwFlags) && GETFLAGS_MODE(m_desktopRes.dwFlags))
+  {
+    GetSupportedModes(HDMI_RES_GROUP_CEA, resolutions);
+    GetSupportedModes(HDMI_RES_GROUP_DMT, resolutions);
+  }
   {
     AddUniqueResolution(m_desktopRes, resolutions);
     CLog::Log(LOGDEBUG, "EGL probe resolution %s:%x\n", m_desktopRes.strMode.c_str(), m_desktopRes.dwFlags);

From 19c583a5b7612092ad8973cb9a817f418b0d1597 Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Tue, 15 Sep 2015 22:26:26 +0100
Subject: [PATCH 099/100] squash: omxplayer: Don't use AutoInterlaceMethod it
 changes at start of file

---
 xbmc/cores/omxplayer/OMXHelper.cpp | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/xbmc/cores/omxplayer/OMXHelper.cpp b/xbmc/cores/omxplayer/OMXHelper.cpp
index 014eaf1..72ed3ab 100644
--- a/xbmc/cores/omxplayer/OMXHelper.cpp
+++ b/xbmc/cores/omxplayer/OMXHelper.cpp
@@ -132,19 +132,19 @@ bool OMXDoProcessing(struct SOmxPlayerState &m_OmxPlayerState, int m_playSpeed,
     bool audio_fifo_low = false, video_fifo_low = false, audio_fifo_high = false, video_fifo_high = false;
 
     if (m_OmxPlayerState.interlace_method == VS_INTERLACEMETHOD_MAX)
-      m_OmxPlayerState.interlace_method = g_renderManager.AutoInterlaceMethod(CMediaSettings::Get().GetCurrentVideoSettings().m_InterlaceMethod);
+      m_OmxPlayerState.interlace_method = CMediaSettings::Get().GetCurrentVideoSettings().m_InterlaceMethod;
 
     // if deinterlace setting has changed, we should close and open video
     if (m_OmxPlayerState.current_deinterlace != CMediaSettings::Get().GetCurrentVideoSettings().m_DeinterlaceMode ||
        (m_OmxPlayerState.current_deinterlace != VS_DEINTERLACEMODE_OFF &&
-        m_OmxPlayerState.interlace_method != g_renderManager.AutoInterlaceMethod(CMediaSettings::Get().GetCurrentVideoSettings().m_InterlaceMethod)))
+        m_OmxPlayerState.interlace_method != CMediaSettings::Get().GetCurrentVideoSettings().m_InterlaceMethod))
     {
       CLog::Log(LOGNOTICE, "%s - Reopen stream due to interlace change (%d,%d,%d,%d)", __FUNCTION__,
         m_OmxPlayerState.current_deinterlace, CMediaSettings::Get().GetCurrentVideoSettings().m_DeinterlaceMode,
-        m_OmxPlayerState.interlace_method, g_renderManager.AutoInterlaceMethod(CMediaSettings::Get().GetCurrentVideoSettings().m_InterlaceMethod));
+        m_OmxPlayerState.interlace_method, CMediaSettings::Get().GetCurrentVideoSettings().m_InterlaceMethod);
 
       m_OmxPlayerState.current_deinterlace = CMediaSettings::Get().GetCurrentVideoSettings().m_DeinterlaceMode;
-      m_OmxPlayerState.interlace_method    = g_renderManager.AutoInterlaceMethod(CMediaSettings::Get().GetCurrentVideoSettings().m_InterlaceMethod);
+      m_OmxPlayerState.interlace_method    = CMediaSettings::Get().GetCurrentVideoSettings().m_InterlaceMethod;
       reopen_stream = true;
     }
 

From 18bca1ea11093bef939a375a8b845a0c1c3dc0d5 Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Wed, 16 Sep 2015 15:05:37 +0100
Subject: [PATCH 100/100] [omxplayer] Avoid calling render callback with the
 lock held to avoid a deadlock

---
 xbmc/cores/omxplayer/OMXVideo.cpp | 27 ++++++++++++++-------------
 xbmc/cores/omxplayer/OMXVideo.h   | 10 +++++++++-
 2 files changed, 23 insertions(+), 14 deletions(-)

diff --git a/xbmc/cores/omxplayer/OMXVideo.cpp b/xbmc/cores/omxplayer/OMXVideo.cpp
index fbb395d..aaea687 100644
--- a/xbmc/cores/omxplayer/OMXVideo.cpp
+++ b/xbmc/cores/omxplayer/OMXVideo.cpp
@@ -141,9 +141,8 @@ bool COMXVideo::NaluFormatStartCodes(enum AVCodecID codec, uint8_t *in_extradata
   return false;    
 }
 
-bool COMXVideo::PortSettingsChanged()
+bool COMXVideo::PortSettingsChanged(ResolutionUpdateInfo &resinfo)
 {
-  CSingleLock lock (m_critSection);
   OMX_ERRORTYPE omx_err   = OMX_ErrorNone;
 
   if (m_settings_changed)
@@ -186,15 +185,13 @@ bool COMXVideo::PortSettingsChanged()
       port_image.format.video.xFramerate / (float)(1<<16), interlace.eMode, m_deinterlace);
 
   // let OMXPlayerVideo know about resolution so it can inform RenderManager
-  if (m_res_callback)
-  {
-    float display_aspect = 0.0f;
-    if (pixel_aspect.nX && pixel_aspect.nY)
-      display_aspect = (float)pixel_aspect.nX * port_image.format.video.nFrameWidth /
-        ((float)pixel_aspect.nY * port_image.format.video.nFrameHeight);
-    m_res_callback(m_res_ctx, port_image.format.video.nFrameWidth, port_image.format.video.nFrameHeight,
-        port_image.format.video.xFramerate / (float)(1<<16), display_aspect);
-  }
+  resinfo.width = port_image.format.video.nFrameWidth;
+  resinfo.height = port_image.format.video.nFrameHeight;
+  resinfo.framerate = port_image.format.video.xFramerate / (float)(1<<16);
+  resinfo.display_aspect = 0.0f;
+  resinfo.changed = true;
+  if (pixel_aspect.nX && pixel_aspect.nY)
+    resinfo.display_aspect = (float)pixel_aspect.nX * port_image.format.video.nFrameWidth / ((float)pixel_aspect.nY * port_image.format.video.nFrameHeight);
 
   if (m_settings_changed)
   {
@@ -798,10 +795,11 @@ int COMXVideo::Decode(uint8_t *pData, int iSize, double dts, double pts)
       }
       //CLog::Log(LOGINFO, "VideD: dts:%.0f pts:%.0f size:%d)\n", dts, pts, iSize);
 
+      ResolutionUpdateInfo resinfo = {};
       omx_err = m_omx_decoder.WaitForEvent(OMX_EventPortSettingsChanged, 0);
       if (omx_err == OMX_ErrorNone)
       {
-        if(!PortSettingsChanged())
+        if(!PortSettingsChanged(resinfo))
         {
           CLog::Log(LOGERROR, "%s::%s - error PortSettingsChanged omx_err(0x%08x)\n", CLASSNAME, __func__, omx_err);
           return false;
@@ -810,11 +808,14 @@ int COMXVideo::Decode(uint8_t *pData, int iSize, double dts, double pts)
       omx_err = m_omx_decoder.WaitForEvent(OMX_EventParamOrConfigChanged, 0);
       if (omx_err == OMX_ErrorNone)
       {
-        if(!PortSettingsChanged())
+        if(!PortSettingsChanged(resinfo))
         {
           CLog::Log(LOGERROR, "%s::%s - error PortSettingsChanged (EventParamOrConfigChanged) omx_err(0x%08x)\n", CLASSNAME, __func__, omx_err);
         }
       }
+      lock.Leave();
+      if (resinfo.changed && m_res_callback)
+        m_res_callback(m_res_ctx, resinfo.width, resinfo.height, resinfo.framerate, resinfo.display_aspect);
     }
     return true;
 
diff --git a/xbmc/cores/omxplayer/OMXVideo.h b/xbmc/cores/omxplayer/OMXVideo.h
index 86e94ce..31982b4 100644
--- a/xbmc/cores/omxplayer/OMXVideo.h
+++ b/xbmc/cores/omxplayer/OMXVideo.h
@@ -41,6 +41,14 @@
 
 typedef void (*ResolutionUpdateCallBackFn)(void *ctx, uint32_t width, uint32_t height, float framerate, float display_aspect);
 
+struct ResolutionUpdateInfo {
+  uint32_t width;
+  uint32_t height;
+  float framerate;
+  float display_aspect;
+  bool changed;
+};
+
 class COMXVideo
 {
 public:
@@ -50,7 +58,7 @@ class COMXVideo
   // Required overrides
   bool SendDecoderConfig();
   bool Open(CDVDStreamInfo &hints, OMXClock *clock, EDEINTERLACEMODE deinterlace = VS_DEINTERLACEMODE_OFF, bool hdmi_clock_sync = false);
-  bool PortSettingsChanged();
+  bool PortSettingsChanged(ResolutionUpdateInfo &resinfo);
   void RegisterResolutionUpdateCallBack(void *ctx, ResolutionUpdateCallBackFn callback) { m_res_ctx = ctx; m_res_callback = callback; }
   void Close(void);
   unsigned int GetFreeSpace();
