[mythtv] Update to lastest fixes/0.28 from git.

Richard Shaw hobbes1069 at rpmfusion.org
Wed Oct 19 17:18:55 CEST 2016


commit 3a4db0f6a8c709320e6ebc59253be4cd1a0d10a4
Author: Richard Shaw <hobbes1069 at gmail.com>
Date:   Wed Oct 19 10:18:48 2016 -0500

    Update to lastest fixes/0.28 from git.

 ChangeLog               |  204 ++++
 mythtv-0.28-fixes.patch | 2469 +++++++++++++++++++++++++++++++++++++++++++++--
 mythtv.spec             |    7 +-
 3 files changed, 2607 insertions(+), 73 deletions(-)
---
diff --git a/ChangeLog b/ChangeLog
index 6e50117..53be816 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,207 @@
+commit 228b05bd7a8103192957a9abfc0a5baa551e8ba6
+Author: Stuart Auchterlonie <stuarta at mythtv.org>
+Date:   Wed Oct 12 16:02:04 2016 +0100
+
+    Some http -> https changes
+    
+    (cherry picked from commit 98b5662598807e819111e4a7423818a961a3d24e)
+
+commit 7c91ab6bc635c0299c029e6a0c148b290396b695
+Author: Bill Meek <bmeek at mythtv.org>
+Date:   Fri Aug 12 21:34:39 2016 -0500
+
+    Serialization Implementation for XML: gcc6/Qt5.{6,7} SEGVs
+    
+    Missed one (actually, there are at least 2 more.) The author
+    is trying to carve out some time to look for the actual fix.
+    
+    Thanks to PlanetEater for catching this.
+    
+    Refs #12782
+    
+    (cherry picked from commit eaf81bc3438e71f9623b59199b9ad1e7683db780)
+
+commit 8eb43db5ba274c6105f61a5fe91f94ea62ac10fe
+Author: Bill Meek <bmeek at mythtv.org>
+Date:   Thu Aug 4 09:49:18 2016 -0500
+
+    Serialization Implementation for XML: gcc6/Qt5.{6,7} SEGVs
+    
+    This isn't a MythTV bug, rather an issue with Qt5.{6,7,??}
+    and gcc version 6. This will get Arch users with the above
+    combinations working until a proper solution is developed.
+    
+    In XmlSerializer::GetContentName when pMetaObject is NULL,
+    a SEGV fires rather that getting a -1 return from
+    pMetaObject->indexOfClassInfo().
+    
+    Examples: <be>:6544/Myth/version and <be>:6544/Myth/GetHostName.
+    Both fail on Arch linux with the above combinations.
+    
+    Thanks for the research on: bbs.archlinux.org/viewtopic.php?pid=1631996,
+    testing on the ticket, and the reference to:
+    http://lists.qt-project.org/pipermail/development/2016-March/025153.html
+    
+    Refs #12782
+    
+    (cherry picked from commit 38de43efa92603e2ac524b9a72951c15caf2af4e)
+
+commit 8580a41b71ca24f1900103cc696d246cbac8a769
+Author: Peter Bennett <pbennett at mythtv.org>
+Date:   Tue Oct 4 16:43:44 2016 -0400
+
+    Fix scrolling at and of grid style button list.
+    
+    Fixes #12892
+    
+    (cherry picked from commit 9a5b4116ae506d4c7f77e88d3b67c368262694ef)
+
+commit 07a52a0b421b20b32716d5cb10a22c7a2bef4116
+Author: Peter Bennett <pbennett at mythtv.org>
+Date:   Fri Sep 30 13:42:18 2016 -0400
+
+    Fix time stretch on Raspberry Pi.
+    
+    Fixes #12819
+    
+    (cherry picked from commit 8b49d6cb407f827a1a19dff5c96773556f25dcd3)
+
+commit 7a1f690e2f156a946cd308b893cb7f98476ca8d5
+Author: MIke Bibbings <mike.bibbings at gmail.com>
+Date:   Fri Sep 30 10:17:26 2016 -0500
+
+    Fix multiplex restriction determination in Live TV.
+    
+    Signed-off-by: David Engel <dengel at mythtv.org>
+    
+    Refs #12891
+    
+    (cherry picked from commit 17e2f7344368a24ab4bca73bbf799224e15b1a71)
+
+commit b36ab879cf7c69e649eecfe7dbed9a92854f510c
+Author: Peter Bennett <pbennett at mythtv.org>
+Date:   Tue Sep 27 09:44:19 2016 -0400
+
+    Fix for frontend control socket not working on openmax playback.
+    
+    Fixes #12863
+    
+    (cherry picked from commit 61b0a26fb2fbaf1503488afc4bc560498160702b)
+
+commit 45f608999904c4f97dc1ef5c0e92f8db2b5e4b5b
+Author: Peter Bennett <pbennett at mythtv.org>
+Date:   Sun Sep 25 16:04:15 2016 -0400
+
+    Fix: OSD notification flash on again after fading due to negative "time left" calculation.
+    
+    (cherry picked from commit a6300a778d1a76123c09ef22875c3149d1c8a77b)
+
+commit 0c63edefcc93f07f7742aa31f8e49e4a39d7f90d
+Author: Peter Bennett <pbennett at mythtv.org>
+Date:   Sun Sep 25 15:53:50 2016 -0400
+
+    Fix: OSD notifications remain on screen forever with OpenMAX and OpenGL.
+    
+    (cherry picked from commit e94e5a1c4790e246326181a54b2b92cf26b6cf6f)
+
+commit 3adc5555602524ba9aa0d697675a6740c7375518
+Author: Jonatan Lindblad <jlindblad at mythtv.org>
+Date:   Mon Sep 26 21:07:13 2016 +0200
+
+    MythFrontend: Allow playback of streamed https:// files
+    
+    (cherry picked from commit 45b8725a8d262d7b69515e30f3e01538a51349fe)
+
+commit 0f005f4be5487e3b4859723e64e9313534cd40ca
+Author: John Poet <jpoet at mythtv.org>
+Date:   Thu Sep 22 13:40:33 2016 -0600
+
+    ServicesAPI: Add ability to Stop/Reactivate a recording.
+    
+    (cherry picked from commit 38d9ba259110e6495759897d4a3f25d961347eb0)
+
+commit 0fa7674c3815dd025f9dcfdfb4324ca79a881926
+Author: John Poet <jpoet at mythtv.org>
+Date:   Thu Sep 22 16:46:41 2016 -0600
+
+    TVRec::TuningNewRecorder: On failure, make sure scheduler knows about it.
+    
+    (cherry picked from commit fe296d93b34360c26301abeb3108a5b5513ba21f)
+
+commit 6a9d7b5131f36f257fb7b622ff1b1568b213f39a
+Author: John Poet <jpoet at mythtv.org>
+Date:   Thu Sep 22 19:36:39 2016 -0600
+
+    Scheduler::FillRecordingDir: Fix a race condition trying to start a
+    recording before being fulling initialized.
+    
+    If a recording is 'in progress' when mythbackend starts up, it could fail to
+    record because the scheduler tries to start it up before it knows what
+    directory to store it in.
+    
+    (cherry picked from commit 96415b4c7ce110e59080f3cf4fa8461308117fad)
+
+commit 75587f08e7da9c86a3f781ccefb3860786018686
+Author: John Poet <jpoet at mythtv.org>
+Date:   Thu Sep 22 13:30:42 2016 -0600
+
+    ServicesAPI: Add RecodIdForFilename()
+    
+    (cherry picked from commit 359a20a5ec7310715ffa79754c45554744e01b63)
+
+commit b575f9e1fd6149590ba2b78235a7b7b31f022fff
+Author: John Poet <jpoet at mythtv.org>
+Date:   Thu Sep 22 13:30:42 2016 -0600
+
+    Add a Service API method for returning seektable information.
+    
+    (cherry picked from commit 98f7b5dd5ea5c9781600ef1389f95639c6b20be9)
+
+commit 44cf853213184e6ce75d7f40e590b70058395343
+Author: John Poet <jpoet at mythtv.org>
+Date:   Thu Sep 22 13:30:41 2016 -0600
+
+    Cleanup whitespace in some of the Services API files.
+    
+    (cherry picked from commit 1c32299486693355c18ecd14901e522d3dbe341f)
+
+commit 5c18d3f91b3d30ca70f8b98de6117429c4cb9c8e
+Author: Peter Bennett <pbennett at mythtv.org>
+Date:   Tue Sep 20 12:51:37 2016 -0400
+
+    Fix mythfilldatabase incorrectly populating airdate for TV series.
+    
+    Fixes #12882
+    
+    (cherry picked from commit 1b0f7fb9f42561d20241d56c2dd575afbd10be30)
+
+commit 2faf5fe2b70080500088c88b9d3af8ce95e2fd5b
+Author: Peter Bennett <pbennett at mythtv.org>
+Date:   Fri Sep 16 15:07:41 2016 -0400
+
+    Fix OpenMAX hdmi audio 5.1 channel PCM crackling noise.
+    Caused by misalignment of samples due to incorrect audio fragment size.
+    
+    (cherry picked from commit 14177228e1493c8faf66aa8fcc2a342225647680)
+
+commit 851a33ec36efa53fe13fa9825f5c2dc815455ea2
+Author: Peter Bennett <pbennett at mythtv.org>
+Date:   Wed Aug 17 10:19:29 2016 -0400
+
+    Fix Raspberry Pi digital audio AC-3 passthrough.
+    
+    Fixes #12827
+    
+    (cherry picked from commit 5ddf67e34abeac606fb9bcaf5c4550894d201226)
+
+commit 5861a1da48dc970b02e475f4ebd7eee41bb7f4a0
+Author: Peter Bennett <pbennett at mythtv.org>
+Date:   Sat Aug 6 10:28:07 2016 -0400
+
+    Delete unused and untested class AudioDecoderOMX from OMX Audio output code.
+    
+    (cherry picked from commit a115dfb0226b98d85b9c82b305494fb38f52f77e)
+
 commit e6a60f7d11ce05b7c7c56e0f889d11f213d8c495
 Author: John Poet <jpoet at mythtv.org>
 Date:   Fri Sep 9 18:48:27 2016 -0600
diff --git a/mythtv-0.28-fixes.patch b/mythtv-0.28-fixes.patch
index 5c9d72a..2ccdbd7 100644
--- a/mythtv-0.28-fixes.patch
+++ b/mythtv-0.28-fixes.patch
@@ -1,3 +1,4 @@
+ README.rst                                         |     4 +-
  mythplugins/mythgallery/mythgallery/main.cpp       |    21 +-
  mythplugins/mythmusic/mythmusic/main.cpp           |    14 +-
  mythplugins/mythnews/mythnews/mythnews.cpp         |    22 +-
@@ -12,29 +13,45 @@
  mythtv/i18n/mythfrontend_cs.ts                     | 48373 ++++++++++++-------
  mythtv/i18n/mythfrontend_de.qm                     |   Bin 734286 -> 734286 bytes
  mythtv/i18n/mythfrontend_de.ts                     |     2 +-
+ mythtv/libs/libmyth/audio/audiooutput_omx.cpp      |   906 +-
+ mythtv/libs/libmyth/audio/audiooutput_omx.h        |     8 -
+ mythtv/libs/libmyth/audio/audiooutputbase.cpp      |    52 +-
+ mythtv/libs/libmyth/audio/audiooutputbase.h        |     4 +-
  mythtv/libs/libmyth/mythmediamonitor.cpp           |    29 +-
- mythtv/libs/libmyth/programinfo.cpp                |   178 +-
- mythtv/libs/libmyth/programinfo.h                  |    18 +-
+ mythtv/libs/libmyth/programinfo.cpp                |   200 +-
+ mythtv/libs/libmyth/programinfo.h                  |    22 +-
  mythtv/libs/libmythbase/mythmedia.cpp              |     2 +-
  mythtv/libs/libmythbase/mythstorage.cpp            |     4 +-
  mythtv/libs/libmythmetadata/imagemanager.cpp       |     2 +-
- .../libmythservicecontracts/services/dvrServices.h |    14 +-
- mythtv/libs/libmythtv/avformatdecoder.cpp          |     6 +
+ .../services/captureServices.h                     |     1 -
+ .../services/channelServices.h                     |     1 -
+ .../services/contentServices.h                     |     9 +-
+ .../libmythservicecontracts/services/dvrServices.h |    32 +-
+ .../services/guideServices.h                       |     5 +-
+ .../services/mythServices.h                        |     5 +-
+ .../services/rttiServices.h                        |     5 +-
+ .../services/videoServices.h                       |     1 -
+ mythtv/libs/libmythtv/avformatdecoder.cpp          |    11 +
  .../libmythtv/channelscan/vboxchannelfetcher.cpp   |    30 +-
  .../libmythtv/channelscan/vboxchannelfetcher.h     |     1 +
  mythtv/libs/libmythtv/eitfixup.cpp                 |    33 +-
  mythtv/libs/libmythtv/eitfixup.h                   |     4 +-
  mythtv/libs/libmythtv/eithelper.cpp                |     5 +
- mythtv/libs/libmythtv/mythplayer.cpp               |   109 +-
+ mythtv/libs/libmythtv/mythplayer.cpp               |   162 +-
+ mythtv/libs/libmythtv/mythplayer.h                 |     5 +
+ mythtv/libs/libmythtv/osd.cpp                      |     9 +-
+ mythtv/libs/libmythtv/osd.h                        |     1 +
  mythtv/libs/libmythtv/privatedecoder_omx.cpp       |     4 +-
  mythtv/libs/libmythtv/recorders/asichannel.cpp     |     6 +-
+ mythtv/libs/libmythtv/recorders/channelbase.cpp    |     7 +-
  mythtv/libs/libmythtv/recorders/vboxutils.cpp      |    10 +-
  mythtv/libs/libmythtv/recorders/vboxutils.h        |     2 +-
  .../test/test_eitfixups/test_eitfixups.cpp         |    28 +
  mythtv/libs/libmythtv/tv_play.cpp                  |     4 +-
+ mythtv/libs/libmythtv/tv_rec.cpp                   |    20 +-
  mythtv/libs/libmythtv/videodisplayprofile.cpp      |    33 +-
  mythtv/libs/libmythtv/videodisplayprofile.h        |     2 +-
- mythtv/libs/libmythtv/videoout_omx.cpp             |   251 +-
+ mythtv/libs/libmythtv/videoout_omx.cpp             |   254 +-
  mythtv/libs/libmythtv/videoout_omx.h               |    11 +-
  .../visualisations/videovisualcircles.cpp          |     2 +-
  mythtv/libs/libmythui/cecadapter.cpp               |    41 +-
@@ -44,16 +61,31 @@
  mythtv/libs/libmythui/mythpainter_ogl.h            |     2 +-
  mythtv/libs/libmythui/mythrender_opengl.cpp        |     4 +-
  mythtv/libs/libmythui/mythrender_opengl.h          |     4 +
+ mythtv/libs/libmythui/mythuibuttonlist.cpp         |     5 +-
  mythtv/libs/libmythui/screensaver-dbus.cpp         |     2 +-
  mythtv/libs/libmythupnp/httprequest.cpp            |   172 +-
  mythtv/libs/libmythupnp/httprequest.h              |    55 +-
+ mythtv/libs/libmythupnp/serializers/serializer.cpp |     5 +-
+ .../libs/libmythupnp/serializers/xmlSerializer.cpp |    12 +-
+ .../libmythupnp/serializers/xmlplistSerializer.cpp |     6 +-
+ mythtv/libs/libmythupnp/wsdl.cpp                   |     5 +-
+ mythtv/libs/libmythupnp/xsd.cpp                    |     5 +-
  mythtv/programs/mythbackend/autoexpire.cpp         |    75 +-
  mythtv/programs/mythbackend/autoexpire.h           |    20 +-
  mythtv/programs/mythbackend/backendhousekeeper.cpp |     2 +-
- mythtv/programs/mythbackend/scheduler.cpp          |    26 +-
- mythtv/programs/mythbackend/services/dvr.cpp       |    71 +
- mythtv/programs/mythbackend/services/dvr.h         |    12 +
+ mythtv/programs/mythbackend/mainserver.cpp         |    44 +-
+ mythtv/programs/mythbackend/scheduler.cpp          |    34 +-
+ mythtv/programs/mythbackend/services/capture.cpp   |     3 +-
+ mythtv/programs/mythbackend/services/content.cpp   |     4 +-
+ mythtv/programs/mythbackend/services/content.h     |     2 -
+ mythtv/programs/mythbackend/services/dvr.cpp       |   170 +-
+ mythtv/programs/mythbackend/services/dvr.h         |    23 +
+ mythtv/programs/mythbackend/services/guide.cpp     |    13 +-
+ mythtv/programs/mythbackend/services/guide.h       |    10 +-
+ .../programs/mythbackend/services/serviceUtil.cpp  |    22 +
+ mythtv/programs/mythbackend/services/serviceUtil.h |     3 +
  mythtv/programs/mythbackend/services/video.cpp     |     3 +-
+ mythtv/programs/mythfilldatabase/xmltvparser.cpp   |     3 +-
  mythtv/programs/mythfrontend/galleryconfig.cpp     |    13 +-
  mythtv/programs/mythfrontend/galleryconfig.h       |    10 +-
  mythtv/programs/mythfrontend/galleryslideview.cpp  |    93 +-
@@ -62,14 +94,36 @@
  mythtv/programs/mythfrontend/galleryviews.cpp      |    80 +-
  mythtv/programs/mythfrontend/galleryviews.h        |     8 +-
  mythtv/programs/mythfrontend/globalsettings.cpp    |    12 +-
- mythtv/programs/mythfrontend/main.cpp              |    11 +-
+ mythtv/programs/mythfrontend/main.cpp              |    14 +-
  mythtv/programs/mythfrontend/mythfrontend.pro      |    24 +
  mythtv/programs/mythfrontend/themechooser.cpp      |     2 +-
  mythtv/programs/mythtv-setup/importicons.cpp       |     6 +-
  mythtv/programs/mythtv-setup/mythtv-setup.pro      |    12 +
  mythtv/programs/mythwelcome/mythwelcome.pro        |    11 +
- 70 files changed, 31433 insertions(+), 18694 deletions(-)
+ 102 files changed, 31832 insertions(+), 19706 deletions(-)
 
+diff --git a/README.rst b/README.rst
+index 8b8014d..ec3fa1f 100644
+--- a/README.rst
++++ b/README.rst
+@@ -5,7 +5,7 @@ MythTV Project Info
+ Useful project links
+ -----
+ 
+- - `Trac bug tracker <http://code.mythtv.org/trac>`_
++ - `Trac bug tracker <https://code.mythtv.org/trac>`_
+ 
+    - Please note: If you create a pull request, we expect a corresponding
+      ticket to be created in Trac with a link to the pull request in it.  
+@@ -17,7 +17,7 @@ Useful project links
+      reports to the owners of the fork where the code was committed.
+ 
+  - `Forums <https://forum.mythtv.org>`_
+- - `Documentation wiki <http://www.mythtv.org/wiki>`_
++ - `Documentation wiki <https://www.mythtv.org/wiki>`_
+  - `Mailing lists <http://lists.mythtv.org/mailman/listinfo>`_
+  - `IRC <irc://freenode.net/mythtv-users>`_ at Freenode.net, #mythtv-users
+ 
 diff --git a/mythplugins/mythgallery/mythgallery/main.cpp b/mythplugins/mythgallery/mythgallery/main.cpp
 index 3237dfe..3aab56b 100644
 --- a/mythplugins/mythgallery/mythgallery/main.cpp
@@ -60817,6 +60871,1170 @@ index 4abd787..fec2c27 100644
      </message>
      <message>
          <location filename="../programs/mythfrontend/customedit.cpp" line="507"/>
+diff --git a/mythtv/libs/libmyth/audio/audiooutput_omx.cpp b/mythtv/libs/libmyth/audio/audiooutput_omx.cpp
+index c738580..53344db 100644
+--- a/mythtv/libs/libmyth/audio/audiooutput_omx.cpp
++++ b/mythtv/libs/libmyth/audio/audiooutput_omx.cpp
+@@ -42,50 +42,6 @@ using namespace omxcontext;
+ /*
+  * Types
+  */
+-class AudioDecoderOMX : public OMXComponentCtx
+-{
+-    // No copying
+-    AudioDecoderOMX(const AudioDecoderOMX&);
+-    AudioDecoderOMX & operator =(const AudioDecoderOMX&);
+-
+-  public:
+-    explicit AudioDecoderOMX(OMXComponent&);
+-    virtual ~AudioDecoderOMX();
+-
+-    // OMXComponentCtx overrides
+-    virtual OMX_ERRORTYPE EmptyBufferDone(OMXComponent&, OMX_BUFFERHEADERTYPE*);
+-    virtual OMX_ERRORTYPE FillBufferDone(OMXComponent&, OMX_BUFFERHEADERTYPE*);
+-    virtual void ReleaseBuffers(OMXComponent&);
+-
+-    // Implementation
+-    void Stop() { m_audiodecoder.Shutdown(); m_bIsStarted = false; }
+-    bool Start(AVCodecID, AudioFormat, int chnls, int sps);
+-    bool IsStarted() { return m_bIsStarted; }
+-    int DecodeAudio(AVCodecContext*, uint8_t*, int&, const AVPacket*);
+-
+-  protected:
+-    int GetBufferedFrame(uint8_t *buffer);
+-    int ProcessPacket(const AVPacket *pkt);
+-
+-  private:
+-    OMX_ERRORTYPE FillOutputBuffers();
+-
+-    // OMXComponentCB actions
+-    typedef OMX_ERRORTYPE ComponentCB();
+-    ComponentCB FreeBuffersCB, AllocBuffersCB;
+-    ComponentCB AllocInputBuffers, AllocOutputBuffers;
+-
+-  private:
+-    OMXComponent &m_audiorender;
+-    OMXComponent m_audiodecoder;
+-    bool m_bIsStarted;
+-
+-    QSemaphore m_ibufs_sema;    // EmptyBufferDone signal
+-    QSemaphore m_obufs_sema;    // FillBufferDone signal
+-    QMutex mutable m_lock;      // Protects data following
+-    QList<OMX_BUFFERHEADERTYPE*> m_ibufs;
+-    QList<OMX_BUFFERHEADERTYPE*> m_obufs;
+-};
+ 
+ 
+ /*
+@@ -94,7 +50,6 @@ class AudioDecoderOMX : public OMXComponentCtx
+ AudioOutputOMX::AudioOutputOMX(const AudioSettings &settings) :
+     AudioOutputBase(settings),
+     m_audiorender(gCoreContext->GetSetting("OMXAudioRender", AUDIO_RENDER), *this),
+-    m_audiodecoder(0),
+     m_lock(QMutex::Recursive)
+ {
+     if (m_audiorender.GetState() != OMX_StateLoaded)
+@@ -125,9 +80,6 @@ AudioOutputOMX::AudioOutputOMX(const AudioSettings &settings) :
+         if (0) m_audiorender.ShowFormats(port, LOG_DEBUG, VB_AUDIO);
+     }
+ 
+-    // Create the OMX audio decoder
+-    m_audiodecoder = new AudioDecoderOMX(m_audiorender);
+-
+     InitSettings(settings);
+     if (settings.init)
+         Reconfigure(settings);
+@@ -140,7 +92,6 @@ AudioOutputOMX::~AudioOutputOMX()
+ 
+     // Must shutdown the OMX components now before our state becomes invalid.
+     // When the component's dtor is called our state has already been destroyed.
+-    delete m_audiodecoder, m_audiodecoder = 0;
+     m_audiorender.Shutdown();
+ }
+ 
+@@ -239,7 +190,6 @@ bool AudioOutputOMX::OpenDevice(void)
+     }
+ 
+     m_audiorender.Shutdown();
+-    if (m_audiodecoder) m_audiodecoder->Stop();
+ 
+     OMX_ERRORTYPE e;
+     unsigned nBitPerSample = 0;
+@@ -416,9 +366,8 @@ bool AudioOutputOMX::OpenDevice(void)
+     // NB the OpenMAX spec requires PCM buffer size >= 5mS data
+     m_audiorender.GetPortDef();
+     OMX_PARAM_PORTDEFINITIONTYPE &def = m_audiorender.PortDef();
+-#define OUT_CHANNELS(n) (((n) > 4) ? 8U: ((n) > 2) ? 4U: unsigned(n))
+     def.nBufferSize = std::max(
+-        OMX_U32((1024 * nBitPerSample * OUT_CHANNELS(channels)) / 8),
++        OMX_U32((1024 * nBitPerSample * channels) / 8),
+         def.nBufferSize);
+     def.nBufferCountActual = std::max(OMX_U32(10), def.nBufferCountActual);
+     //def.bBuffersContiguous = OMX_FALSE;
+@@ -460,10 +409,6 @@ bool AudioOutputOMX::OpenDevice(void)
+     }
+ #endif
+ 
+-    // Setup the audio decoder
+-    if (!passthru && m_audiodecoder)
+-        m_audiodecoder->Start(AVCodecID(codec), output_format, channels, samplerate);
+-
+     // Goto OMX_StateIdle & allocate buffers
+     OMXComponentCB<AudioOutputOMX> cb(this, &AudioOutputOMX::AllocBuffersCB);
+     e = m_audiorender.SetState(OMX_StateIdle, 500, &cb);
+@@ -587,7 +532,6 @@ AudioOutputSettings* AudioOutputOMX::GetOutputSettings(bool passthrough)
+     }
+ 
+     m_audiorender.Shutdown();
+-    if (m_audiodecoder) m_audiodecoder->Stop();
+ 
+     OMX_ERRORTYPE e;
+     OMX_AUDIO_PARAM_PORTFORMATTYPE fmt;
+@@ -751,28 +695,6 @@ bool AudioOutputOMX::OpenMixer()
+ }
+ 
+ // virtual
+-int AudioOutputOMX::DecodeAudio(AVCodecContext *ctx, uint8_t *buffer,
+-    int &data_size, const AVPacket *pkt)
+-{
+-    if (m_audiodecoder && m_audiodecoder->IsStarted())
+-    {
+-        static int s_bShown;
+-        if (!s_bShown)
+-        {
+-            s_bShown = 1;
+-            LOG(VB_GENERAL, LOG_CRIT, LOC +
+-                "AudioDecoderOMX::DecodeAudio is available but untested.");
+-        }
+-
+-        static int s_enable = gCoreContext->GetNumSetting("OMXAudioDecoderEnable", 0);
+-        if (s_enable)
+-            return m_audiodecoder->DecodeAudio(ctx, buffer, data_size, pkt);
+-    }
+-
+-    return AudioOutputBase::DecodeAudio(ctx, buffer, data_size, pkt);
+-}
+-
+-// virtual
+ OMX_ERRORTYPE AudioOutputOMX::EmptyBufferDone(
+     OMXComponent&, OMX_BUFFERHEADERTYPE *hdr)
+ {
+@@ -870,830 +792,4 @@ OMX_ERRORTYPE AudioOutputOMX::AllocBuffersCB()
+     return OMX_ErrorNone;
+ }
+ 
+-/*******************************************************************************
+- * AudioDecoder
+- ******************************************************************************/
+-#undef LOC
+-#define LOC QString("ADOMX:%1 ").arg(m_audiodecoder.Id())
+-
+-AudioDecoderOMX::AudioDecoderOMX(OMXComponent &render) :
+-    m_audiorender(render),
+-    m_audiodecoder(gCoreContext->GetSetting("OMXAudioDecode", AUDIO_DECODE), *this),
+-    m_bIsStarted(false), m_lock(QMutex::Recursive)
+-{
+-    if (m_audiodecoder.GetState() != OMX_StateLoaded)
+-        return;
+-
+-    if (OMX_ErrorNone != m_audiodecoder.Init(OMX_IndexParamAudioInit))
+-        return;
+-
+-    if (!m_audiodecoder.IsValid())
+-        return;
+-
+-    // Show default port definitions and audio formats supported
+-    for (unsigned port = 0; port < m_audiodecoder.Ports(); ++port)
+-    {
+-        m_audiodecoder.ShowPortDef(port, LOG_DEBUG, VB_AUDIO);
+-        if (0) m_audiodecoder.ShowFormats(port, LOG_DEBUG, VB_AUDIO);
+-    }
+-}
+-
+-// virtual
+-AudioDecoderOMX::~AudioDecoderOMX()
+-{
+-    // Must shutdown the OMX components now before our state becomes invalid.
+-    // When the component's dtor is called our state has already been destroyed.
+-    m_audiodecoder.Shutdown();
+-}
+-
+-static const char *toString(OMX_AUDIO_CHANNELMODETYPE mode)
+-{
+-    switch (mode)
+-    {
+-        CASE2STR(OMX_AUDIO_ChannelModeStereo);
+-        CASE2STR(OMX_AUDIO_ChannelModeJointStereo);
+-        CASE2STR(OMX_AUDIO_ChannelModeDual);
+-        CASE2STR(OMX_AUDIO_ChannelModeMono);
+-    }
+-    static char buf[32];
+-    return strcpy(buf, qPrintable(QString("ChannelMode 0x%1").arg(mode,0,16)));
+-}
+-
+-static const char *toString(OMX_AUDIO_MP3STREAMFORMATTYPE type)
+-{
+-    switch (type)
+-    {
+-        CASE2STR(OMX_AUDIO_MP3StreamFormatMP1Layer3);
+-        CASE2STR(OMX_AUDIO_MP3StreamFormatMP2Layer3);
+-        CASE2STR(OMX_AUDIO_MP3StreamFormatMP2_5Layer3);
+-    }
+-    static char buf[32];
+-    return strcpy(buf, qPrintable(QString("StreamFormat 0x%1").arg(type,0,16)));
+-}
+-
+-bool AudioDecoderOMX::Start(AVCodecID codec, AudioFormat format, int chnls, int sps)
+-{
+-    if (!m_audiodecoder.IsValid())
+-        return false;
+-
+-    Stop();
+-
+-    if (m_audiodecoder.Ports() < 2)
+-    {
+-        LOG(VB_AUDIO, LOG_ERR, LOC + __func__ + ": missing output port");
+-        return false;
+-    }
+-
+-    OMX_ERRORTYPE e;
+-    OMX_AUDIO_PARAM_PORTFORMATTYPE fmt;
+-    OMX_DATA_INIT(fmt);
+-
+-    // Map Ffmpeg audio codec ID to OMX coding
+-    switch (codec)
+-    {
+-      case AV_CODEC_ID_NONE:
+-        return false;
+-      case AV_CODEC_ID_PCM_S16LE:
+-      case AV_CODEC_ID_PCM_S16BE:
+-      case AV_CODEC_ID_PCM_U16LE:
+-      case AV_CODEC_ID_PCM_U16BE:
+-      case AV_CODEC_ID_PCM_S8:
+-      case AV_CODEC_ID_PCM_U8:
+-      case AV_CODEC_ID_PCM_S32LE:
+-      case AV_CODEC_ID_PCM_S32BE:
+-      case AV_CODEC_ID_PCM_U32LE:
+-      case AV_CODEC_ID_PCM_U32BE:
+-      case AV_CODEC_ID_PCM_S24LE:
+-      case AV_CODEC_ID_PCM_S24BE:
+-      case AV_CODEC_ID_PCM_U24LE:
+-      case AV_CODEC_ID_PCM_U24BE:
+-        fmt.eEncoding = OMX_AUDIO_CodingPCM;
+-        break;
+-      case AV_CODEC_ID_MP1:
+-      case AV_CODEC_ID_MP2:
+-      case AV_CODEC_ID_MP3:
+-        fmt.eEncoding = OMX_AUDIO_CodingMP3;
+-        break;
+-      case AV_CODEC_ID_AAC:
+-        fmt.eEncoding = OMX_AUDIO_CodingAAC;
+-        break;
+-#ifdef OMX_AUDIO_CodingDDP_Supported
+-      case AV_CODEC_ID_AC3:
+-      case AV_CODEC_ID_EAC3:
+-        fmt.eEncoding = OMX_AUDIO_CodingDDP;
+-        break;
+-#endif
+-#ifdef OMX_AUDIO_CodingDTS_Supported
+-      case AV_CODEC_ID_DTS:
+-        fmt.eEncoding = OMX_AUDIO_CodingDTS;
+-        break;
+-#endif
+-      case AV_CODEC_ID_VORBIS:
+-      case AV_CODEC_ID_FLAC:
+-        fmt.eEncoding = OMX_AUDIO_CodingVORBIS;
+-        break;
+-      case AV_CODEC_ID_WMAV1:
+-      case AV_CODEC_ID_WMAV2:
+-        fmt.eEncoding = OMX_AUDIO_CodingWMA;
+-        break;
+-#ifdef OMX_AUDIO_CodingATRAC3_Supported
+-      case AV_CODEC_ID_ATRAC3:
+-      case AV_CODEC_ID_ATRAC3P:
+-        fmt.eEncoding = OMX_AUDIO_CodingATRAC3;
+-        break;
+-#endif
+-      default:
+-        LOG(VB_AUDIO, LOG_NOTICE, LOC + __func__ +
+-            QString(" codec %1 not supported").arg(ff_codec_id_string(codec)));
+-        return false;
+-    }
+-
+-    // Set input encoding
+-    fmt.nPortIndex = m_audiodecoder.Base();
+-    e = m_audiodecoder.SetParameter(OMX_IndexParamAudioPortFormat, &fmt);
+-    if (e != OMX_ErrorNone)
+-    {
+-        LOG(VB_AUDIO, LOG_ERR, LOC + QString(
+-                "SetParameter input AudioPortFormat error %1")
+-            .arg(Error2String(e)));
+-        return false;
+-    }
+-
+-    // Set input parameters
+-    switch (fmt.eEncoding)
+-    {
+-      case OMX_AUDIO_CodingPCM:
+-        OMX_AUDIO_PARAM_PCMMODETYPE pcm;
+-        OMX_DATA_INIT(pcm);
+-        pcm.nPortIndex = m_audiodecoder.Base();
+-
+-        e = m_audiodecoder.GetParameter(OMX_IndexParamAudioPcm, &pcm);
+-        if (e != OMX_ErrorNone)
+-        {
+-            LOG(VB_AUDIO, LOG_ERR, LOC + QString(
+-                    "GetParameter input AudioPcm error %1")
+-                .arg(Error2String(e)));
+-            return false;
+-        }
+-
+-        // TODO: Anything other than zeroes here causes bad parameter
+-        pcm.nChannels = chnls;
+-        pcm.nSamplingRate = sps;
+-        if (!::Format2Pcm(pcm, format))
+-        {
+-            LOG(VB_AUDIO, LOG_ERR, LOC + __func__ + QString(
+-                    " Unsupported PCM input format %1")
+-                .arg(AudioOutputSettings::FormatToString(format)));
+-            return false;
+-        }
+-
+-        ::SetupChannels(pcm);
+-
+-        LOG(VB_AUDIO, LOG_INFO, LOC + QString(
+-                "Input PCM %1 chnls @ %2 sps %3 %4 bits")
+-            .arg(pcm.nChannels).arg(pcm.nSamplingRate).arg(pcm.nBitPerSample)
+-            .arg(pcm.eNumData == OMX_NumericalDataSigned ? "signed" : "unsigned") );
+-
+-        e = m_audiodecoder.SetParameter(OMX_IndexParamAudioPcm, &pcm);
+-        if (e != OMX_ErrorNone)
+-        {
+-            LOG(VB_AUDIO, LOG_ERR, LOC + QString(
+-                    "SetParameter input AudioPcm error %1")
+-                .arg(Error2String(e)));
+-            return false;
+-        }
+-        break;
+-
+-      case OMX_AUDIO_CodingMP3:
+-        OMX_AUDIO_PARAM_MP3TYPE mp3type;
+-        OMX_DATA_INIT(mp3type);
+-        mp3type.nPortIndex = m_audiodecoder.Base();
+-
+-        e = m_audiodecoder.GetParameter(OMX_IndexParamAudioMp3, &mp3type);
+-        if (e != OMX_ErrorNone)
+-        {
+-            LOG(VB_AUDIO, LOG_ERR, LOC + QString(
+-                    "GetParameter input AudioMp3 error %1")
+-                .arg(Error2String(e)));
+-            return false;
+-        }
+-
+-        mp3type.nChannels = chnls;
+-        mp3type.nBitRate = 0;
+-        mp3type.nSampleRate = sps;
+-        mp3type.nAudioBandWidth = 0;
+-        mp3type.eChannelMode = (chnls == 1) ? OMX_AUDIO_ChannelModeMono :
+-                                OMX_AUDIO_ChannelModeStereo;
+-        mp3type.eFormat = (codec == AV_CODEC_ID_MP1) ?
+-                            OMX_AUDIO_MP3StreamFormatMP1Layer3 :
+-                            OMX_AUDIO_MP3StreamFormatMP2Layer3;
+-                            // or OMX_AUDIO_MP3StreamFormatMP2_5Layer3
+-
+-        LOG(VB_AUDIO, LOG_INFO, LOC + QString("Input %1 %2 chnls @ %3 sps %4")
+-            .arg(toString(mp3type.eFormat)).arg(mp3type.nChannels)
+-            .arg(mp3type.nSampleRate).arg(toString(mp3type.eChannelMode)) );
+-
+-        e = m_audiodecoder.SetParameter(OMX_IndexParamAudioMp3, &mp3type);
+-        if (e != OMX_ErrorNone)
+-        {
+-            LOG(VB_AUDIO, LOG_ERR, LOC + QString(
+-                    "SetParameter output AudioMp3 error %1")
+-                .arg(Error2String(e)));
+-            return false;
+-        }
+-        break;
+-
+-#ifdef OMX_AUDIO_CodingDDP_Supported
+-      case OMX_AUDIO_CodingDDP:
+-        OMX_AUDIO_PARAM_DDPTYPE ddp;
+-        OMX_DATA_INIT(ddp);
+-        ddp.nPortIndex = m_audiodecoder.Base();
+-        e = m_audiodecoder.GetParameter(OMX_IndexParamAudioDdp, &ddp);
+-        if (e != OMX_ErrorNone)
+-        {
+-            LOG(VB_AUDIO, LOG_ERR, LOC + QString(
+-                    "GetParameter AudioDdp error %1")
+-                .arg(Error2String(e)));
+-            return false;
+-        }
+-
+-        ddp.nChannels = chnls;
+-        ddp.nBitRate = 0;
+-        ddp.nSampleRate = sps;
+-        ddp.eBitStreamId = (AV_CODEC_ID_AC3 == codec) ?
+-                           OMX_AUDIO_DDPBitStreamIdAC3 :
+-                           OMX_AUDIO_DDPBitStreamIdEAC3;
+-        ddp.eBitStreamMode = OMX_AUDIO_DDPBitStreamModeCM;
+-        ddp.eDolbySurroundMode = OMX_AUDIO_DDPDolbySurroundModeNotIndicated;
+-        ::SetupChannels(ddp);
+-
+-        LOG(VB_AUDIO, LOG_INFO, LOC + QString("Input %1 %2 chnls @ %3 sps")
+-            .arg(toString(ddp.eBitStreamId)).arg(ddp.nChannels)
+-            .arg(ddp.nSampleRate) );
+-
+-        e = m_audiodecoder.SetParameter(OMX_IndexParamAudioDdp, &ddp);
+-        if (e != OMX_ErrorNone)
+-        {
+-            LOG(VB_AUDIO, LOG_ERR, LOC + QString(
+-                    "SetParameter AudioDdp error %1")
+-                .arg(Error2String(e)));
+-            return false;
+-        }
+-        break;
+-#endif //def OMX_AUDIO_CodingDDP_Supported
+-
+-      case OMX_AUDIO_CodingVORBIS:
+-        OMX_AUDIO_PARAM_VORBISTYPE vorbis;
+-        OMX_DATA_INIT(vorbis);
+-        vorbis.nPortIndex = m_audiodecoder.Base();
+-        e = m_audiodecoder.GetParameter(OMX_IndexParamAudioVorbis, &vorbis);
+-        if (e != OMX_ErrorNone)
+-        {
+-            LOG(VB_AUDIO, LOG_ERR, LOC + QString(
+-                    "GetParameter AudioVorbis error %1")
+-                .arg(Error2String(e)));
+-            return false;
+-        }
+-
+-        vorbis.nChannels = chnls;
+-        vorbis.nBitRate = 0;
+-        vorbis.nMinBitRate = 0;
+-        vorbis.nMaxBitRate = 0;
+-        vorbis.nSampleRate = sps;
+-        vorbis.nAudioBandWidth = 0;
+-        vorbis.nQuality = 0;
+-        vorbis.bManaged = OMX_FALSE;
+-        vorbis.bDownmix = OMX_FALSE;
+-
+-        LOG(VB_AUDIO, LOG_INFO, LOC + QString("Input Vorbis %1 chnls @ %2 sps")
+-            .arg(vorbis.nChannels).arg(vorbis.nSampleRate) );
+-
+-        e = m_audiodecoder.SetParameter(OMX_IndexParamAudioVorbis, &vorbis);
+-        if (e != OMX_ErrorNone)
+-        {
+-            LOG(VB_AUDIO, LOG_ERR, LOC + QString(
+-                    "SetParameter AudioVorbis error %1")
+-                .arg(Error2String(e)));
+-            return false;
+-        }
+-        break;
+-
+-#ifdef OMX_AUDIO_CodingDTS_Supported
+-      case OMX_AUDIO_CodingDTS:
+-        OMX_AUDIO_PARAM_DTSTYPE dts;
+-        OMX_DATA_INIT(dts);
+-        dts.nPortIndex = m_audiodecoder.Base();
+-        e = m_audiorender.GetParameter(OMX_IndexParamAudioDts, &dts);
+-        if (e != OMX_ErrorNone)
+-        {
+-            LOG(VB_AUDIO, LOG_ERR, LOC + QString(
+-                    "GetParameter AudioDts error %1")
+-                .arg(Error2String(e)));
+-            return false;
+-        }
+-
+-        dts.nChannels = chnls;
+-        dts.nBitRate = 0;
+-        dts.nSampleRate = sps;
+-        // TODO
+-        //dts.nDtsType;           // OMX_U32 DTS type 1, 2, or 3
+-        //dts.nFormat;            // OMX_U32 DTS stream is either big/little endian and 16/14 bit packing
+-        //dts.nDtsFrameSizeBytes; // OMX_U32 DTS frame size in bytes
+-        ::SetupChannels(dts);
+-
+-        LOG(VB_AUDIO, LOG_INFO, LOC + QString("Input DTS %1 chnls @ %2 sps")
+-            .arg(dts.nChannels).arg(dts.nSampleRate) );
+-
+-        e = m_audiorender.SetParameter(OMX_IndexParamAudioDts, &dts);
+-        if (e != OMX_ErrorNone)
+-        {
+-            LOG(VB_AUDIO, LOG_ERR, LOC + QString(
+-                    "SetParameter AudioDts error %1")
+-                .arg(Error2String(e)));
+-            return false;
+-        }
+-        break;
+-#endif //def OMX_AUDIO_CodingDTS_Supported
+-
+-      case OMX_AUDIO_CodingAAC: // TODO
+-      case OMX_AUDIO_CodingWMA: // TODO
+-      //case OMX_AUDIO_CodingATRAC3: // TODO
+-      default:
+-        LOG(VB_GENERAL, LOG_WARNING, LOC + QString("Unhandled codec %1")
+-            .arg(Coding2String(fmt.eEncoding)));
+-        return false;
+-    }
+-
+-    // Setup input buffer size & count
+-    m_audiodecoder.GetPortDef();
+-    OMX_PARAM_PORTDEFINITIONTYPE &def = m_audiodecoder.PortDef();
+-    //def.nBufferSize = 1024;
+-    def.nBufferCountActual = std::max(OMX_U32(2), def.nBufferCountMin);
+-    assert(def.eDomain == OMX_PortDomainAudio);
+-    assert(def.format.audio.eEncoding == fmt.eEncoding);
+-    e = m_audiodecoder.SetParameter(OMX_IndexParamPortDefinition, &def);
+-    if (e != OMX_ErrorNone)
+-    {
+-        LOG(VB_AUDIO, LOG_ERR, LOC + QString(
+-                "SetParameter PortDefinition error %1")
+-            .arg(Error2String(e)));
+-        return false;
+-    }
+-
+-#if 0
+-    // Setup pass through
+-    OMX_CONFIG_BOOLEANTYPE boolType;
+-    OMX_DATA_INIT(boolType);
+-    boolType.bEnabled = OMX_FALSE;
+-    e = m_audiodecoder.SetParameter(OMX_IndexParamBrcmDecoderPassThrough, &boolType);
+-    if (e != OMX_ErrorNone)
+-    {
+-        LOG(VB_AUDIO, LOG_ERR, LOC + QString(
+-                "SetParameter BrcmDecoderPassThrough error %1")
+-            .arg(Error2String(e)));
+-    }
+-#endif
+-
+-    // Setup output encoding
+-    m_audiodecoder.GetPortDef(1);
+-    OMX_PARAM_PORTDEFINITIONTYPE &odef = m_audiodecoder.PortDef(1);
+-    assert(odef.eDomain == OMX_PortDomainAudio);
+-    if (odef.format.audio.eEncoding != OMX_AUDIO_CodingPCM)
+-    {
+-        // Set output encoding
+-        OMX_AUDIO_PARAM_PORTFORMATTYPE ofmt;
+-        OMX_DATA_INIT(ofmt);
+-        ofmt.nPortIndex = odef.nPortIndex;
+-        ofmt.eEncoding = OMX_AUDIO_CodingPCM;
+-        e = m_audiodecoder.SetParameter(OMX_IndexParamAudioPortFormat, &ofmt);
+-        if (e != OMX_ErrorNone)
+-        {
+-            LOG(VB_AUDIO, LOG_ERR, LOC + QString(
+-                    "SetParameter output AudioPortFormat error %1")
+-                .arg(Error2String(e)));
+-            return false;
+-        }
+-    }
+-
+-    // Setup output PCM format
+-    OMX_AUDIO_PARAM_PCMMODETYPE pcm;
+-    OMX_DATA_INIT(pcm);
+-    pcm.nPortIndex = odef.nPortIndex;
+-    pcm.nChannels = chnls;
+-    pcm.nSamplingRate = sps;
+-    if (!::Format2Pcm(pcm, format))
+-    {
+-        LOG(VB_AUDIO, LOG_ERR, LOC + QString("Unsupported PCM output format %1")
+-            .arg(AudioOutputSettings::FormatToString(format)));
+-        return false;
+-    }
+-    ::SetupChannels(pcm);
+-
+-    LOG(VB_AUDIO, LOG_INFO, LOC + QString("Output PCM %1 chnls @ %2 sps %3 %4 bits")
+-        .arg(pcm.nChannels).arg(pcm.nSamplingRate).arg(pcm.nBitPerSample)
+-        .arg(pcm.eNumData == OMX_NumericalDataSigned ? "signed" : "unsigned") );
+-
+-    e = m_audiodecoder.SetParameter(OMX_IndexParamAudioPcm, &pcm);
+-    if (e != OMX_ErrorNone)
+-    {
+-        LOG(VB_AUDIO, LOG_ERR, LOC + QString(
+-                "SetParameter output AudioPcm error %1")
+-            .arg(Error2String(e)));
+-        return false;
+-    }
+-
+-    m_audiodecoder.GetPortDef(1);
+-    assert(odef.format.audio.eEncoding == OMX_AUDIO_CodingPCM);
+-
+-    // Setup output buffer size & count
+-    // NB the OpenMAX spec requires PCM buffer size >= 5mS data
+-    //odef.nBufferSize = 16384;
+-    odef.nBufferCountActual = std::max(OMX_U32(4), odef.nBufferCountMin);
+-    e = m_audiodecoder.SetParameter(OMX_IndexParamPortDefinition, &odef);
+-    if (e != OMX_ErrorNone)
+-    {
+-        LOG(VB_AUDIO, LOG_ERR, LOC + QString(
+-                "SetParameter output PortDefinition error %1")
+-            .arg(Error2String(e)));
+-        return false;
+-    }
+-
+-#if 0
+-    // Goto OMX_StateIdle & allocate buffers
+-    OMXComponentCB<AudioDecoderOMX> cb(this, &AudioDecoderOMX::AllocBuffersCB);
+-    e = m_audiodecoder.SetState(OMX_StateIdle, 500, &cb);
+-    switch (e)
+-    {
+-      case OMX_ErrorNone:
+-        break;
+-      case OMX_ErrorUnsupportedSetting:
+-        // lvr: only OMX_AUDIO_CodingPCM is currently (17-Dec-2015) supported
+-        LOG(VB_AUDIO, LOG_WARNING, LOC + QString("%1 is not supported")
+-            .arg(Coding2String(fmt.eEncoding)));
+-        return false;
+-      default:
+-        LOG(VB_AUDIO, LOG_ERR, LOC + QString("SetState idle error %1")
+-            .arg(Error2String(e)));
+-        return false;
+-    }
+-#else
+-    // A disabled port is not populated with buffers on a transition to IDLE
+-    if (m_audiodecoder.PortDisable(0, 500) != OMX_ErrorNone)
+-        return false;
+-    if (m_audiodecoder.PortDisable(1, 500) != OMX_ErrorNone)
+-        return false;
+-
+-    // Goto OMX_StateIdle
+-    e = m_audiodecoder.SetState(OMX_StateIdle, 500);
+-    if (e != OMX_ErrorNone)
+-        return false;
+-
+-    // Enable input port
+-    OMXComponentCB<AudioDecoderOMX> cb(this, &AudioDecoderOMX::AllocInputBuffers);
+-    e = m_audiodecoder.PortEnable(0, 500, &cb);
+-    switch (e)
+-    {
+-      case OMX_ErrorNone:
+-        break;
+-      case OMX_ErrorUnsupportedSetting:
+-        // lvr: only OMX_AUDIO_CodingPCM is currently (17-Dec-2015) supported
+-        LOG(VB_AUDIO, LOG_WARNING, LOC + QString("%1 is not supported")
+-            .arg(Coding2String(fmt.eEncoding)));
+-        return false;
+-      default:
+-        LOG(VB_AUDIO, LOG_ERR, LOC + QString("SetState idle error %1")
+-            .arg(Error2String(e)));
+-        return false;
+-    }
+-
+-    OMXComponentCB<AudioDecoderOMX> cb2(this, &AudioDecoderOMX::AllocOutputBuffers);
+-    e = m_audiodecoder.PortEnable(1, 500, &cb2);
+-    if (e != OMX_ErrorNone)
+-        return false;
+-#endif
+-
+-    // Goto OMX_StateExecuting
+-    e = m_audiodecoder.SetState(OMX_StateExecuting, 500);
+-    if (e != OMX_ErrorNone)
+-        return false;
+-
+-    e = FillOutputBuffers();
+-    if (e != OMX_ErrorNone)
+-        return false;
+-
+-    m_bIsStarted = true;
+-    return true;
+-}
+-
+-/**
+- * Decode an audio packet, and compact it if data is planar
+- * Return negative error code if an error occurred during decoding
+- * or the number of bytes consumed from the input AVPacket
+- * data_size contains the size of decoded data copied into buffer
+- * data decoded will be S16 samples if class instance can't handle HD audio
+- * or S16 and above otherwise. No U8 PCM format can be returned
+- */
+-int AudioDecoderOMX::DecodeAudio(AVCodecContext *ctx, uint8_t *buffer,
+-    int &data_size, const AVPacket *pkt)
+-{
+-    if (!m_audiodecoder.IsValid())
+-        return -1;
+-
+-    // Check for decoded data
+-    int ret = GetBufferedFrame(buffer);
+-    if (ret < 0)
+-        return ret;
+-    if (ret > 0)
+-        data_size = ret;
+-
+-    // Submit a packet for decoding
+-    return (pkt && pkt->size) ? ProcessPacket(pkt) : 0;
+-}
+-
+-int AudioDecoderOMX::GetBufferedFrame(uint8_t *buffer)
+-{
+-    if (!buffer)
+-        return 0;
+-
+-    if (!m_obufs_sema.tryAcquire())
+-        return 0;
+-
+-    m_lock.lock();
+-    assert(!m_obufs.isEmpty());
+-    OMX_BUFFERHEADERTYPE *hdr = m_obufs.takeFirst();
+-    m_lock.unlock();
+-
+-    int ret = hdr->nFilledLen;
+-    memcpy(buffer, &hdr->pBuffer[hdr->nOffset], hdr->nFilledLen);
+-
+-    hdr->nFlags = 0;
+-    hdr->nFilledLen = 0;
+-    OMX_ERRORTYPE e = OMX_FillThisBuffer(m_audiodecoder.Handle(), hdr);
+-    if (e != OMX_ErrorNone)
+-        LOG(VB_PLAYBACK, LOG_ERR, LOC + QString(
+-            "OMX_FillThisBuffer reQ error %1").arg(Error2String(e)) );
+-
+-    return ret;
+-}
+-
+-int AudioDecoderOMX::ProcessPacket(const AVPacket *pkt)
+-{
+-    uint8_t *buf = pkt->data;
+-    int size = pkt->size;
+-    int ret = pkt->size;
+-
+-    while (size > 0)
+-    {
+-        if (!m_ibufs_sema.tryAcquire(1, 5))
+-        {
+-            LOG(VB_AUDIO, LOG_DEBUG, LOC + __func__ + " - no input buffers");
+-            ret = 0;
+-            break;
+-        }
+-        m_lock.lock();
+-        assert(!m_ibufs.isEmpty());
+-        OMX_BUFFERHEADERTYPE *hdr = m_ibufs.takeFirst();
+-        m_lock.unlock();
+-
+-        int free = int(hdr->nAllocLen) - int(hdr->nFilledLen + hdr->nOffset);
+-        int cnt = (free > size) ? size : free;
+-        memcpy(&hdr->pBuffer[hdr->nOffset + hdr->nFilledLen], buf, cnt);
+-        hdr->nFilledLen += cnt;
+-        buf += cnt;
+-        size -= cnt;
+-        free -= cnt;
+-
+-        hdr->nFlags = 0;
+-        OMX_ERRORTYPE e = OMX_EmptyThisBuffer(m_audiodecoder.Handle(), hdr);
+-        if (e != OMX_ErrorNone)
+-        {
+-            LOG(VB_PLAYBACK, LOG_ERR, LOC + QString(
+-                "OMX_EmptyThisBuffer error %1").arg(Error2String(e)) );
+-            m_lock.lock();
+-            m_ibufs.append(hdr);
+-            m_lock.unlock();
+-            m_ibufs_sema.release();
+-            ret = -1;
+-            break;
+-        }
+-    }
+-
+-    return ret;
+-}
+-
+-// OMX_StateIdle callback
+-OMX_ERRORTYPE AudioDecoderOMX::AllocBuffersCB()
+-{
+-    OMX_ERRORTYPE e = AllocInputBuffers();
+-    return (e == OMX_ErrorNone) ? AllocOutputBuffers() : e;
+-}
+-
+-// Allocate decoder input buffers
+-OMX_ERRORTYPE AudioDecoderOMX::AllocInputBuffers()
+-{
+-    assert(m_audiodecoder.IsValid());
+-    assert(m_ibufs_sema.available() == 0);
+-    assert(m_ibufs.isEmpty());
+-
+-    const OMX_PARAM_PORTDEFINITIONTYPE &def = m_audiodecoder.PortDef();
+-    OMX_U32 uBufs = def.nBufferCountActual;
+-    LOG(VB_AUDIO, LOG_DEBUG, LOC + __func__ + QString(" %1 x %2 bytes")
+-            .arg(uBufs).arg(def.nBufferSize));
+-    while (uBufs--)
+-    {
+-        OMX_BUFFERHEADERTYPE *hdr;
+-        OMX_ERRORTYPE e = OMX_AllocateBuffer(m_audiodecoder.Handle(), &hdr,
+-            def.nPortIndex, 0, def.nBufferSize);
+-        if (e != OMX_ErrorNone)
+-        {
+-            LOG(VB_AUDIO, LOG_ERR, LOC + QString(
+-                "OMX_AllocateBuffer error %1").arg(Error2String(e)) );
+-            return e;
+-        }
+-        if (hdr->nSize != sizeof(OMX_BUFFERHEADERTYPE))
+-        {
+-            LOG(VB_AUDIO, LOG_ERR, LOC + "OMX_AllocateBuffer header mismatch");
+-            OMX_FreeBuffer(m_audiodecoder.Handle(), def.nPortIndex, hdr);
+-            return OMX_ErrorVersionMismatch;
+-        }
+-        if (hdr->nVersion.nVersion != OMX_VERSION)
+-        {
+-            LOG(VB_AUDIO, LOG_ERR, LOC + "OMX_AllocateBuffer version mismatch");
+-            OMX_FreeBuffer(m_audiodecoder.Handle(), def.nPortIndex, hdr);
+-            return OMX_ErrorVersionMismatch;
+-        }
+-        hdr->nFilledLen = 0;
+-        hdr->nOffset = 0;
+-        m_lock.lock();
+-        m_ibufs.append(hdr);
+-        m_lock.unlock();
+-        m_ibufs_sema.release();
+-    }
+-    return OMX_ErrorNone;
+-}
+-
+-// Allocate decoder output buffers
+-OMX_ERRORTYPE AudioDecoderOMX::AllocOutputBuffers()
+-{
+-    assert(m_audiodecoder.IsValid());
+-    assert(m_obufs_sema.available() == 0);
+-    assert(m_obufs.isEmpty());
+-
+-    const OMX_PARAM_PORTDEFINITIONTYPE &def = m_audiodecoder.PortDef(1);
+-    OMX_U32 uBufs = def.nBufferCountActual;
+-    LOG(VB_AUDIO, LOG_DEBUG, LOC + __func__ + QString(" %1 x %2 bytes")
+-            .arg(uBufs).arg(def.nBufferSize));
+-    while (uBufs--)
+-    {
+-        OMX_BUFFERHEADERTYPE *hdr;
+-        OMX_ERRORTYPE e = OMX_AllocateBuffer(m_audiodecoder.Handle(), &hdr,
+-            def.nPortIndex, 0, def.nBufferSize);
+-        if (e != OMX_ErrorNone)
+-        {
+-            LOG(VB_AUDIO, LOG_ERR, LOC + QString(
+-                "OMX_AllocateBuffer error %1").arg(Error2String(e)) );
+-            return e;
+-        }
+-        if (hdr->nSize != sizeof(OMX_BUFFERHEADERTYPE))
+-        {
+-            LOG(VB_AUDIO, LOG_ERR, LOC + "OMX_AllocateBuffer header mismatch");
+-            OMX_FreeBuffer(m_audiodecoder.Handle(), def.nPortIndex, hdr);
+-            return OMX_ErrorVersionMismatch;
+-        }
+-        if (hdr->nVersion.nVersion != OMX_VERSION)
+-        {
+-            LOG(VB_AUDIO, LOG_ERR, LOC + "OMX_AllocateBuffer version mismatch");
+-            OMX_FreeBuffer(m_audiodecoder.Handle(), def.nPortIndex, hdr);
+-            return OMX_ErrorVersionMismatch;
+-        }
+-        hdr->nFilledLen = 0;
+-        hdr->nOffset = 0;
+-        m_lock.lock();
+-        m_obufs.append(hdr);
+-        m_lock.unlock();
+-        m_obufs_sema.release();
+-    }
+-    return OMX_ErrorNone;
+-}
+-
+-// Shutdown OMX_StateIdle -> OMX_StateLoaded callback
+-// virtual
+-void AudioDecoderOMX::ReleaseBuffers(OMXComponent &cmpnt)
+-{
+-    FreeBuffersCB();
+-}
+-
+-// Free all OMX buffers
+-// OMX_CommandPortDisable callback
+-OMX_ERRORTYPE AudioDecoderOMX::FreeBuffersCB()
+-{
+-    assert(m_audiodecoder.IsValid());
+-
+-    // Free all input buffers
+-    while (m_ibufs_sema.tryAcquire())
+-    {
+-        m_lock.lock();
+-        assert(!m_ibufs.isEmpty());
+-        OMX_BUFFERHEADERTYPE *hdr = m_ibufs.takeFirst();
+-        m_lock.unlock();
+-
+-        assert(hdr->nSize == sizeof(OMX_BUFFERHEADERTYPE));
+-        assert(hdr->nVersion.nVersion == OMX_VERSION);
+-
+-        OMX_ERRORTYPE e;
+-        e = OMX_FreeBuffer(m_audiodecoder.Handle(), m_audiodecoder.Base(), hdr);
+-        if (e != OMX_ErrorNone)
+-            LOG(VB_AUDIO, LOG_ERR, LOC + QString(
+-                    "OMX_FreeBuffer 0x%1 error %2")
+-                .arg(quintptr(hdr),0,16).arg(Error2String(e)));
+-    }
+-
+-    // Free all output buffers
+-    while (m_obufs_sema.tryAcquire())
+-    {
+-        m_lock.lock();
+-        assert(!m_obufs.isEmpty());
+-        OMX_BUFFERHEADERTYPE *hdr = m_obufs.takeFirst();
+-        m_lock.unlock();
+-
+-        assert(hdr->nSize == sizeof(OMX_BUFFERHEADERTYPE));
+-        assert(hdr->nVersion.nVersion == OMX_VERSION);
+-
+-        OMX_ERRORTYPE e;
+-        e = OMX_FreeBuffer(m_audiodecoder.Handle(), m_audiodecoder.Base() + 1, hdr);
+-        if (e != OMX_ErrorNone)
+-            LOG(VB_AUDIO, LOG_ERR, LOC + QString(
+-                    "OMX_FreeBuffer 0x%1 error %2")
+-                .arg(quintptr(hdr),0,16).arg(Error2String(e)));
+-    }
+-
+-    return OMX_ErrorNone;
+-}
+-
+-// virtual
+-OMX_ERRORTYPE AudioDecoderOMX::EmptyBufferDone(
+-    OMXComponent&, OMX_BUFFERHEADERTYPE *hdr)
+-{
+-    assert(hdr->nSize == sizeof(OMX_BUFFERHEADERTYPE));
+-    assert(hdr->nVersion.nVersion == OMX_VERSION);
+-    hdr->nFilledLen = 0;
+-    hdr->nFlags = 0;
+-    if (m_lock.tryLock(1000))
+-    {
+-        m_ibufs.append(hdr);
+-        m_lock.unlock();
+-        m_ibufs_sema.release();
+-    }
+-    else
+-        LOG(VB_GENERAL, LOG_CRIT, LOC + "EmptyBufferDone deadlock");
+-    return OMX_ErrorNone;
+-}
+-
+-// virtual
+-OMX_ERRORTYPE AudioDecoderOMX::FillBufferDone(
+-    OMXComponent&, OMX_BUFFERHEADERTYPE *hdr)
+-{
+-    assert(hdr->nSize == sizeof(OMX_BUFFERHEADERTYPE));
+-    assert(hdr->nVersion.nVersion == OMX_VERSION);
+-    if (m_lock.tryLock(1000))
+-    {
+-        m_obufs.append(hdr);
+-        m_lock.unlock();
+-        m_obufs_sema.release();
+-    }
+-    else
+-        LOG(VB_GENERAL, LOG_CRIT, LOC + "FillBufferDone deadlock");
+-    return OMX_ErrorNone;
+-}
+-
+-// Start filling the output buffers
+-OMX_ERRORTYPE AudioDecoderOMX::FillOutputBuffers()
+-{
+-    while (m_obufs_sema.tryAcquire())
+-    {
+-        m_lock.lock();
+-        assert(!m_obufs.isEmpty());
+-        OMX_BUFFERHEADERTYPE *hdr = m_obufs.takeFirst();
+-        m_lock.unlock();
+-
+-        assert(hdr->nSize == sizeof(OMX_BUFFERHEADERTYPE));
+-        assert(hdr->nVersion.nVersion == OMX_VERSION);
+-
+-        hdr->nFlags = 0;
+-        hdr->nFilledLen = 0;
+-        OMX_ERRORTYPE e = OMX_FillThisBuffer(m_audiodecoder.Handle(), hdr);
+-        if (e != OMX_ErrorNone)
+-        {
+-            LOG(VB_AUDIO, LOG_ERR, LOC + QString(
+-                "OMX_FillThisBuffer error %1").arg(Error2String(e)) );
+-            m_lock.lock();
+-            m_obufs.append(hdr);
+-            m_lock.unlock();
+-            m_obufs_sema.release();
+-            return e;
+-        }
+-    }
+-
+-    return OMX_ErrorNone;
+-}
+ // EOF
+diff --git a/mythtv/libs/libmyth/audio/audiooutput_omx.h b/mythtv/libs/libmyth/audio/audiooutput_omx.h
+index 94966b6..1903d37 100644
+--- a/mythtv/libs/libmyth/audio/audiooutput_omx.h
++++ b/mythtv/libs/libmyth/audio/audiooutput_omx.h
+@@ -12,12 +12,8 @@
+ #include "audiooutputbase.h"
+ #include "omxcontext.h"
+ 
+-class AudioDecoderOMX;
+-
+ class AudioOutputOMX : public AudioOutputBase, private OMXComponentCtx
+ {
+-    friend class AudioDecoderOMX;
+-
+     // No copying
+     AudioOutputOMX(const AudioOutputOMX&);
+     AudioOutputOMX & operator =(const AudioOutputOMX&);
+@@ -30,9 +26,6 @@ class AudioOutputOMX : public AudioOutputBase, private OMXComponentCtx
+     virtual int GetVolumeChannel(int channel) const; // Returns 0-100
+     virtual void SetVolumeChannel(int channel, int volume); // range 0-100 for vol
+ 
+-    // AudioOutput overrides
+-    virtual int DecodeAudio(AVCodecContext*, uint8_t*, int&, const AVPacket*);
+-
+   protected:
+     // AudioOutputBase implementation
+     virtual bool OpenDevice(void);
+@@ -58,7 +51,6 @@ class AudioOutputOMX : public AudioOutputBase, private OMXComponentCtx
+ 
+   private:
+     OMXComponent m_audiorender;
+-    AudioDecoderOMX *m_audiodecoder;
+ 
+     QSemaphore m_ibufs_sema;    // EmptyBufferDone signal
+     QMutex mutable m_lock;      // Protects data following
+diff --git a/mythtv/libs/libmyth/audio/audiooutputbase.cpp b/mythtv/libs/libmyth/audio/audiooutputbase.cpp
+index 833dff6..4dcc49b 100644
+--- a/mythtv/libs/libmyth/audio/audiooutputbase.cpp
++++ b/mythtv/libs/libmyth/audio/audiooutputbase.cpp
+@@ -24,6 +24,7 @@ using namespace std;
+ #include "freesurround.h"
+ #include "spdifencoder.h"
+ #include "mythlogging.h"
++#include "mythconfig.h"
+ 
+ #define LOC QString("AOBase: ")
+ 
+@@ -76,6 +77,8 @@ AudioOutputBase::AudioOutputBase(const AudioSettings &settings) :
+     configured_channels(0),
+     max_channels(0),
+     src_quality(QUALITY_MEDIUM),
++    source_bitrate(-1),
++    source_samplerate(0),
+ 
+     // private
+     output_settingsraw(NULL),   output_settings(NULL),
+@@ -84,7 +87,7 @@ AudioOutputBase::AudioOutputBase(const AudioSettings &settings) :
+ 
+     pSoundStretch(NULL),
+     encoder(NULL),              upmixer(NULL),
+-    source_channels(-1),        source_samplerate(0),
++    source_channels(-1),
+     source_bytes_per_frame(0),  upmix_default(false),
+     needs_upmix(false),         needs_downmix(false),
+     surround_mode(QUALITY_LOW), old_stretchfactor(1.0f),
+@@ -101,7 +104,7 @@ AudioOutputBase::AudioOutputBase(const AudioSettings &settings) :
+     audbuf_timecode(0),
+ 
+     killAudioLock(QMutex::NonRecursive),
+-    current_seconds(-1),        source_bitrate(-1),
++    current_seconds(-1),
+ 
+     memory_corruption_test0(0xdeadbeef),
+     memory_corruption_test1(0xdeadbeef),
+@@ -361,7 +364,14 @@ void AudioOutputBase::SetStretchFactorLocked(float lstretchfactor)
+         pSoundStretch->setSampleRate(samplerate);
+         pSoundStretch->setChannels(channels);
+         pSoundStretch->setTempo(stretchfactor);
++#if ARCH_ARM
++        // use less demanding settings for Raspberry pi
++        pSoundStretch->setSetting(SETTING_SEQUENCE_MS, 82);
++        pSoundStretch->setSetting(SETTING_USE_AA_FILTER, 0);
++        pSoundStretch->setSetting(SETTING_USE_QUICKSEEK, 1);
++#else
+         pSoundStretch->setSetting(SETTING_SEQUENCE_MS, 35);
++#endif
+         /* If we weren't already processing we need to turn on float conversion
+            adjust sample and frame sizes accordingly and dump the contents of
+            the audiobuffer */
+@@ -459,8 +469,12 @@ bool AudioOutputBase::SetupPassthrough(int codec, int codec_profile,
+         delete m_spdifenc;
+     }
+ 
+-    m_spdifenc = new SPDIFEncoder("spdif", codec);
+-    if (m_spdifenc->Succeeded() && codec == AV_CODEC_ID_DTS)
++    // No spdif encoder if using openmax audio
++    if (main_device.startsWith("OpenMAX:"))
++        m_spdifenc = 0;
++    else
++        m_spdifenc = new SPDIFEncoder("spdif", codec);
++    if (m_spdifenc && m_spdifenc->Succeeded() && codec == AV_CODEC_ID_DTS)
+     {
+         switch(codec_profile)
+         {
+@@ -476,7 +490,7 @@ bool AudioOutputBase::SetupPassthrough(int codec, int codec_profile,
+         }
+     }
+ 
+-    if (!m_spdifenc->Succeeded())
++    if (m_spdifenc && !m_spdifenc->Succeeded())
+     {
+         delete m_spdifenc;
+         m_spdifenc = NULL;
+@@ -1058,10 +1072,12 @@ int64_t AudioOutputBase::GetAudiotime(void)
+ 
+        We use these variables:
+ 
+-       'effdsp' is frames/sec
++       'effdsp' is 100 * frames/sec
++
++       'audbuf_timecode' is the timecode in milliseconds of the
++       audio that has just been written into the buffer.
+ 
+-       'audbuf_timecode' is the timecode of the audio that has just been
+-       written into the buffer.
++       'eff_stretchfactor' is stretch factor * 100,000
+ 
+        'totalbuffer' is the total # of bytes in our audio buffer, and the
+        sound card's buffer. */
+@@ -1091,16 +1107,16 @@ int64_t AudioOutputBase::GetAudiotime(void)
+     if (audiotime < oldaudiotime)
+         audiotime = oldaudiotime;
+ 
+-    VBAUDIOTS(QString("GetAudiotime audt=%1 atc=%2 mb=%3 sb=%4 tb=%5 "
+-                      "sr=%6 obpf=%7 bpf=%8 sf=%9 %10 %11")
+-              .arg(audiotime).arg(audbuf_timecode)
+-              .arg(main_buffer)
+-              .arg(soundcard_buffer)
+-              .arg(main_buffer+soundcard_buffer)
+-              .arg(samplerate).arg(obpf).arg(bytes_per_frame).arg(stretchfactor)
+-              .arg((main_buffer + soundcard_buffer) * eff_stretchfactor)
+-              .arg((effdsp && obpf) ? ((main_buffer + soundcard_buffer) *
+-                   eff_stretchfactor ) / (effdsp * obpf) : 0)
++    VBAUDIOTS(QString("GetAudiotime audt=%1 abtc=%2 mb=%3 sb=%4 tb=%5 "
++                      "sr=%6 obpf=%7 bpf=%8 esf=%9 edsp=%10 sbr=%11")
++              .arg(audiotime).arg(audbuf_timecode)  // 1, 2
++              .arg(main_buffer)                     // 3
++              .arg(soundcard_buffer)                // 4
++              .arg(main_buffer+soundcard_buffer)    // 5
++              .arg(samplerate).arg(obpf)            // 6, 7
++              .arg(bytes_per_frame)                 // 8
++              .arg(eff_stretchfactor)               // 9
++              .arg(effdsp).arg(source_bitrate)      // 10, 11
+               );
+ 
+     return audiotime;
+diff --git a/mythtv/libs/libmyth/audio/audiooutputbase.h b/mythtv/libs/libmyth/audio/audiooutputbase.h
+index 6ed5b60..634823e 100644
+--- a/mythtv/libs/libmyth/audio/audiooutputbase.h
++++ b/mythtv/libs/libmyth/audio/audiooutputbase.h
+@@ -201,6 +201,8 @@ class AudioOutputBase : public AudioOutput, public MThread
+         QUALITY_HIGH     =  2,
+     };
+     int src_quality;
++    long source_bitrate;
++    int source_samplerate;
+ 
+  private:
+     bool SetupPassthrough(int codec, int codec_profile,
+@@ -219,7 +221,6 @@ class AudioOutputBase : public AudioOutput, public MThread
+     FreeSurround              *upmixer;
+ 
+     int source_channels;
+-    int source_samplerate;
+     int source_bytes_per_frame;
+     bool upmix_default;
+     bool needs_upmix;
+@@ -265,7 +266,6 @@ class AudioOutputBase : public AudioOutput, public MThread
+     QMutex killAudioLock;
+ 
+     long current_seconds;
+-    long source_bitrate;
+ 
+     float *src_in;
+ 
 diff --git a/mythtv/libs/libmyth/mythmediamonitor.cpp b/mythtv/libs/libmyth/mythmediamonitor.cpp
 index 1eee655..f459dfe 100644
 --- a/mythtv/libs/libmyth/mythmediamonitor.cpp
@@ -60859,10 +62077,39 @@ index 1eee655..f459dfe 100644
      handlers.at(selected).callback(pMedia);
  }
 diff --git a/mythtv/libs/libmyth/programinfo.cpp b/mythtv/libs/libmyth/programinfo.cpp
-index cbc1e2d..d845a28 100644
+index cbc1e2d..56a1a3b 100644
 --- a/mythtv/libs/libmyth/programinfo.cpp
 +++ b/mythtv/libs/libmyth/programinfo.cpp
-@@ -3971,169 +3971,169 @@ static const char *from_filemarkup_offset_asc =
+@@ -1338,6 +1338,28 @@ bool ProgramInfo::QueryKeyFromPathname(
+     return ExtractKeyFromPathname(pathname, chanid, recstartts);
+ }
+ 
++bool ProgramInfo::QueryRecordedIdFromPathname(const QString &pathname,
++                                              uint &recordedid)
++{
++    QString basename = pathname.section('/', -1);
++    if (basename.isEmpty())
++        return false;
++
++    MSqlQuery query(MSqlQuery::InitCon());
++    query.prepare(
++        "SELECT recordedid "
++        "FROM recorded "
++        "WHERE basename = :BASENAME");
++    query.bindValue(":BASENAME", basename);
++    if (query.exec() && query.next())
++    {
++        recordedid = query.value(0).toUInt();
++        return true;
++    }
++
++    return false;
++}
++
+ #define INT_TO_LIST(x)       do { list << QString::number(x); } while (0)
+ 
+ #define DATETIME_TO_LIST(x)  INT_TO_LIST((x).toTime_t())
+@@ -3971,169 +3993,169 @@ static const char *from_filemarkup_offset_asc =
      "SELECT mark, offset FROM filemarkup"
      " WHERE filename = :PATH"
      " AND type = :TYPE"
@@ -60903,7 +62150,7 @@ index cbc1e2d..d845a28 100644
 +    " WHERE filename = :PATH"
 +    " AND type = :TYPE"
 +    " AND offset <= :QUERY_ARG"
-+    " ORDER BY filename DESC, type DESC, mark DESC LIMIT 1;";    
++    " ORDER BY filename DESC, type DESC, mark DESC LIMIT 1;";
 +static const char *from_recordedseek_mark_asc =
 +    "SELECT offset,mark FROM recordedseek"
 +    " WHERE chanid = :CHANID"
@@ -61122,9 +62369,18 @@ index cbc1e2d..d845a28 100644
  
  /// \brief Store aspect ratio of a frame in the recordedmark table
 diff --git a/mythtv/libs/libmyth/programinfo.h b/mythtv/libs/libmyth/programinfo.h
-index b692bca..dbaed33 100644
+index b692bca..d56c4f7 100644
 --- a/mythtv/libs/libmyth/programinfo.h
 +++ b/mythtv/libs/libmyth/programinfo.h
+@@ -68,7 +68,7 @@ class MPUBLIC ProgramInfo
+   public:
+     enum CategoryType { kCategoryNone, kCategoryMovie, kCategorySeries,
+                         kCategorySports, kCategoryTVShow };
+-                        
++
+     /// Null constructor
+     ProgramInfo(void);
+     /// Copy constructor
 @@ -626,9 +626,21 @@ class MPUBLIC ProgramInfo
                           int64_t min_frm = -1, int64_t max_frm = -1) const;
      void SavePositionMapDelta(frm_pos_map_t &, MarkTypes type) const;
@@ -61150,6 +62406,15 @@ index b692bca..dbaed33 100644
  
      // Get/set all markup
      struct MarkupEntry
+@@ -664,6 +676,8 @@ class MPUBLIC ProgramInfo
+         const QString &pathname, uint &chanid, QDateTime &recstartts);
+     static bool QueryKeyFromPathname(
+         const QString &pathname, uint &chanid, QDateTime &recstartts);
++    static bool QueryRecordedIdFromPathname(const QString &pathname,
++        uint &recordedid);
+ 
+     static QString  QueryRecordingGroupPassword(const QString &group);
+     static uint64_t QueryBookmark(uint chanid, const QDateTime &recstartts);
 diff --git a/mythtv/libs/libmythbase/mythmedia.cpp b/mythtv/libs/libmythbase/mythmedia.cpp
 index 527c7af..9f5da10 100644
 --- a/mythtv/libs/libmythbase/mythmedia.cpp
@@ -61191,16 +62456,80 @@ index a9c802f..e0e72d9 100644
  }
  
  
+diff --git a/mythtv/libs/libmythservicecontracts/services/captureServices.h b/mythtv/libs/libmythservicecontracts/services/captureServices.h
+index e68ed2e..6779278 100644
+--- a/mythtv/libs/libmythservicecontracts/services/captureServices.h
++++ b/mythtv/libs/libmythservicecontracts/services/captureServices.h
+@@ -123,4 +123,3 @@ class SERVICE_PUBLIC CaptureServices : public Service
+ };
+ 
+ #endif
+-
+diff --git a/mythtv/libs/libmythservicecontracts/services/channelServices.h b/mythtv/libs/libmythservicecontracts/services/channelServices.h
+index 42a7e96..e725ee0 100644
+--- a/mythtv/libs/libmythservicecontracts/services/channelServices.h
++++ b/mythtv/libs/libmythservicecontracts/services/channelServices.h
+@@ -162,4 +162,3 @@ class SERVICE_PUBLIC ChannelServices : public Service
+ };
+ 
+ #endif
+-
+diff --git a/mythtv/libs/libmythservicecontracts/services/contentServices.h b/mythtv/libs/libmythservicecontracts/services/contentServices.h
+index 0942172..f060d77 100644
+--- a/mythtv/libs/libmythservicecontracts/services/contentServices.h
++++ b/mythtv/libs/libmythservicecontracts/services/contentServices.h
+@@ -2,10 +2,10 @@
+ // Program Name: contentServices.h
+ // Created     : Mar. 7, 2011
+ //
+-// Purpose - Content Services API Interface definition 
++// Purpose - Content Services API Interface definition
+ //
+ // Copyright (c) 2010 David Blain <dblain at mythtv.org>
+-//                                          
++//
+ // Licensed under the GPL v2 or later, see COPYING for details
+ //
+ //////////////////////////////////////////////////////////////////////////////
+@@ -90,8 +90,8 @@ class SERVICE_PUBLIC ContentServices : public Service  //, public QScriptable ??
+         virtual QFileInfo           GetPreviewImage     ( int              RecordedId,
+                                                           int              ChanId,
+                                                           const QDateTime &StartTime,
+-                                                          int              Width,    
+-                                                          int              Height,   
++                                                          int              Width,
++                                                          int              Height,
+                                                           int              SecsIn,
+                                                           const QString   &Format) = 0;
+ 
+@@ -144,4 +144,3 @@ class SERVICE_PUBLIC ContentServices : public Service  //, public QScriptable ??
+ };
+ 
+ #endif
+-
 diff --git a/mythtv/libs/libmythservicecontracts/services/dvrServices.h b/mythtv/libs/libmythservicecontracts/services/dvrServices.h
-index 3fde9d0..44fd2f3 100644
+index 3fde9d0..522b788 100644
 --- a/mythtv/libs/libmythservicecontracts/services/dvrServices.h
 +++ b/mythtv/libs/libmythservicecontracts/services/dvrServices.h
+@@ -2,10 +2,10 @@
+ // Program Name: dvrServices.h
+ // Created     : Mar. 7, 2011
+ //
+-// Purpose - DVR Services API Interface definition 
++// Purpose - DVR Services API Interface definition
+ //
+ // Copyright (c) 2010 David Blain <dblain at mythtv.org>
+-//                                          
++//
+ // Licensed under the GPL v2 or later, see COPYING for details
+ //
+ //////////////////////////////////////////////////////////////////////////////
 @@ -45,11 +45,12 @@
  class SERVICE_PUBLIC DvrServices : public Service  //, public QScriptable ???
  {
      Q_OBJECT
 -    Q_CLASSINFO( "version"    , "6.1" );
-+    Q_CLASSINFO( "version"    , "6.2" );
++    Q_CLASSINFO( "version"    , "6.3" );
      Q_CLASSINFO( "RemoveRecorded_Method",                       "POST" )
      Q_CLASSINFO( "DeleteRecording_Method",                      "POST" )
      Q_CLASSINFO( "UnDeleteRecording",                           "POST" )
@@ -61209,7 +62538,27 @@ index 3fde9d0..44fd2f3 100644
      Q_CLASSINFO( "AddRecordSchedule_Method",                    "POST" )
      Q_CLASSINFO( "UpdateRecordSchedule_Method",                 "POST" )
      Q_CLASSINFO( "RemoveRecordSchedule_Method",                 "POST" )
-@@ -111,6 +112,17 @@ class SERVICE_PUBLIC DvrServices : public Service  //, public QScriptable ???
+@@ -76,7 +77,7 @@ class SERVICE_PUBLIC DvrServices : public Service  //, public QScriptable ???
+ 
+     public slots:
+ 
+-        virtual DTC::ProgramList*  GetExpiringList       ( int              StartIndex, 
++        virtual DTC::ProgramList*  GetExpiringList       ( int              StartIndex,
+                                                            int              Count      ) = 0;
+ 
+         virtual DTC::ProgramList*  GetRecordedList       ( bool             Descending,
+@@ -106,11 +107,28 @@ class SERVICE_PUBLIC DvrServices : public Service  //, public QScriptable ???
+                                                            int              ChanId,
+                                                            const QDateTime &StartTime ) = 0;
+ 
++        virtual bool               StopRecording         ( int              RecordedId ) = 0;
++
++        virtual bool               ReactivateRecording   ( int              RecordedId ) = 0;
++
++        virtual bool               RescheduleRecordings  ( void ) = 0;
++
+         virtual bool               UpdateRecordedWatchedStatus ( int              RecordedId,
+                                                                  int   ChanId,
                                                                   const QDateTime &StartTime,
                                                                   bool  Watched) = 0;
  
@@ -61227,11 +62576,119 @@ index 3fde9d0..44fd2f3 100644
          virtual DTC::CutList*      GetRecordedCutList    ( int              RecordedId,
                                                             int              ChanId,
                                                             const QDateTime &StartTime,
+@@ -121,6 +139,9 @@ class SERVICE_PUBLIC DvrServices : public Service  //, public QScriptable ???
+                                                            const QDateTime &StartTime,
+                                                            const QString   &OffsetType ) = 0;
+ 
++        virtual DTC::CutList*      GetRecordedSeek       ( int              RecordedId,
++                                                           const QString   &OffsetType ) = 0;
++
+         virtual DTC::ProgramList*  GetConflictList       ( int              StartIndex,
+                                                            int              Count,
+                                                            int              RecordId ) = 0;
+@@ -255,6 +276,8 @@ class SERVICE_PUBLIC DvrServices : public Service  //, public QScriptable ???
+ 
+         virtual bool               DisableRecordSchedule ( uint             RecordId   ) = 0;
+ 
++        virtual int                RecordedIdForPathname ( const QString   &Pathname   ) = 0;
++
+         // The following are all temporary, pending implementation of a
+         // 'enum metadata' endpoint
+         virtual QString            RecStatusToString     ( int              RecStatus  ) = 0;
+@@ -277,4 +300,3 @@ class SERVICE_PUBLIC DvrServices : public Service  //, public QScriptable ???
+ };
+ 
+ #endif
+-
+diff --git a/mythtv/libs/libmythservicecontracts/services/guideServices.h b/mythtv/libs/libmythservicecontracts/services/guideServices.h
+index 0b4929b..0fce0ab 100644
+--- a/mythtv/libs/libmythservicecontracts/services/guideServices.h
++++ b/mythtv/libs/libmythservicecontracts/services/guideServices.h
+@@ -2,10 +2,10 @@
+ // Program Name: guideservices.h
+ // Created     : Mar. 7, 2011
+ //
+-// Purpose - Program Guide Services API Interface definition 
++// Purpose - Program Guide Services API Interface definition
+ //
+ // Copyright (c) 2010 David Blain <dblain at mythtv.org>
+-//                                          
++//
+ // Licensed under the GPL v2 or later, see COPYING for details
+ //
+ //////////////////////////////////////////////////////////////////////////////
+@@ -94,4 +94,3 @@ class SERVICE_PUBLIC GuideServices : public Service  //, public QScriptable ???
+ };
+ 
+ #endif
+-
+diff --git a/mythtv/libs/libmythservicecontracts/services/mythServices.h b/mythtv/libs/libmythservicecontracts/services/mythServices.h
+index 3bd7495..12a0db0 100644
+--- a/mythtv/libs/libmythservicecontracts/services/mythServices.h
++++ b/mythtv/libs/libmythservicecontracts/services/mythServices.h
+@@ -2,10 +2,10 @@
+ // Program Name: mythservices.h
+ // Created     : Jan. 19, 2010
+ //
+-// Purpose - Myth Services API Interface definition 
++// Purpose - Myth Services API Interface definition
+ //
+ // Copyright (c) 2010 David Blain <dblain at mythtv.org>
+-//                                          
++//
+ // Licensed under the GPL v2 or later, see COPYING for details
+ //
+ //////////////////////////////////////////////////////////////////////////////
+@@ -176,4 +176,3 @@ class SERVICE_PUBLIC MythServices : public Service  //, public QScriptable ???
+ };
+ 
+ #endif
+-
+diff --git a/mythtv/libs/libmythservicecontracts/services/rttiServices.h b/mythtv/libs/libmythservicecontracts/services/rttiServices.h
+index 2aa6f55..d8def19 100644
+--- a/mythtv/libs/libmythservicecontracts/services/rttiServices.h
++++ b/mythtv/libs/libmythservicecontracts/services/rttiServices.h
+@@ -2,10 +2,10 @@
+ // Program Name: rttiServices.h
+ // Created     : July 25, 2014
+ //
+-// Purpose - Myth Services API Interface definition 
++// Purpose - Myth Services API Interface definition
+ //
+ // Copyright (c) 2014 David Blain <dblain at mythtv.org>
+-//                                          
++//
+ // Licensed under the GPL v2 or later, see COPYING for details
+ //
+ //////////////////////////////////////////////////////////////////////////////
+@@ -53,4 +53,3 @@ class SERVICE_PUBLIC RttiServices : public Service  //, public QScriptable ???
+ };
+ 
+ #endif
+-
+diff --git a/mythtv/libs/libmythservicecontracts/services/videoServices.h b/mythtv/libs/libmythservicecontracts/services/videoServices.h
+index f2b5bd9..511b6ee 100644
+--- a/mythtv/libs/libmythservicecontracts/services/videoServices.h
++++ b/mythtv/libs/libmythservicecontracts/services/videoServices.h
+@@ -93,4 +93,3 @@ class SERVICE_PUBLIC VideoServices : public Service  //, public QScriptable ???
+ };
+ 
+ #endif
+-
 diff --git a/mythtv/libs/libmythtv/avformatdecoder.cpp b/mythtv/libs/libmythtv/avformatdecoder.cpp
-index fb7d793..f02af21 100644
+index fb7d793..218f68a 100644
 --- a/mythtv/libs/libmythtv/avformatdecoder.cpp
 +++ b/mythtv/libs/libmythtv/avformatdecoder.cpp
-@@ -1021,6 +1021,12 @@ int AvFormatDecoder::FindStreamInfo(void)
+@@ -42,6 +42,8 @@ using namespace std;
+ 
+ #include "lcddevice.h"
+ 
++#include "audiooutput.h"
++
+ #ifdef USING_VDPAU
+ #include "videoout_vdpau.h"
+ extern "C" {
+@@ -1021,6 +1023,12 @@ int AvFormatDecoder::FindStreamInfo(void)
          silence_ffmpeg_logging = true;
      int retval = avformat_find_stream_info(ic, NULL);
      silence_ffmpeg_logging = false;
@@ -61244,6 +62701,16 @@ index fb7d793..f02af21 100644
      return retval;
  }
  
+@@ -5325,6 +5333,9 @@ bool AvFormatDecoder::SetupAudioStream(void)
+                             audioOut.codec_id, audioOut.sample_rate,
+                             audioOut.do_passthru, audioOut.codec_profile);
+     m_audio->ReinitAudio();
++    AudioOutput *audioOutput = m_audio->GetAudioOutput();
++    if (audioOutput)
++        audioOutput->SetSourceBitrate(ctx->bit_rate);
+ 
+     if (LCD *lcd = LCD::Get())
+     {
 diff --git a/mythtv/libs/libmythtv/channelscan/vboxchannelfetcher.cpp b/mythtv/libs/libmythtv/channelscan/vboxchannelfetcher.cpp
 index 1100a1b..b811646 100644
 --- a/mythtv/libs/libmythtv/channelscan/vboxchannelfetcher.cpp
@@ -61411,10 +62878,32 @@ index b0e493c..5b66988 100644
      fix[ 2302LL << 32 | 2U << 16] = EITFixUp::kFixUK;
      fix[ 2303LL << 32 | 2U << 16] = EITFixUp::kFixUK;
 diff --git a/mythtv/libs/libmythtv/mythplayer.cpp b/mythtv/libs/libmythtv/mythplayer.cpp
-index f953e11..4ddde4d 100644
+index f953e11..23f70b4 100644
 --- a/mythtv/libs/libmythtv/mythplayer.cpp
 +++ b/mythtv/libs/libmythtv/mythplayer.cpp
-@@ -383,7 +383,7 @@ bool MythPlayer::Pause(void)
+@@ -211,6 +211,10 @@ MythPlayer::MythPlayer(PlayerFlags flags)
+       refreshrate(0),
+       lastsync(false),              repeat_delay(0),
+       disp_timecode(0),             avsync_audiopaused(false),
++      // AVSync for Raspberry Pi digital streams
++      avsync_averaging(4),  // Number of frames to average
++      avsync_interval(0),   // Number of frames skip between sync checks
++      avsync_next(0),      // Frames till next sync check
+       // Time Code stuff
+       prevtc(0),                    prevrp(0),
+       savedAudioTimecodeOffset(0),
+@@ -222,6 +226,10 @@ MythPlayer::MythPlayer(PlayerFlags flags)
+ {
+     memset(&tc_lastval, 0, sizeof(tc_lastval));
+     memset(&tc_wrap,    0, sizeof(tc_wrap));
++    max_diverge = float(gCoreContext->GetFloatSetting
++        ("PlayerMaxDiverge", 3.0));
++    if (max_diverge < 1.0f)
++        max_diverge = 1.0f;
+ 
+     playerThread = QThread::currentThread();
+ #ifdef Q_OS_ANDROID
+@@ -383,7 +391,7 @@ bool MythPlayer::Pause(void)
  
  bool MythPlayer::Play(float speed, bool normal, bool unpauseaudio)
  {
@@ -61423,7 +62912,7 @@ index f953e11..4ddde4d 100644
      LOG(VB_PLAYBACK, LOG_INFO, LOC +
          QString("Play(%1, normal %2, unpause audio %3)")
              .arg(speed,5,'f',1).arg(normal).arg(unpauseaudio));
-@@ -391,6 +391,7 @@ bool MythPlayer::Play(float speed, bool normal, bool unpauseaudio)
+@@ -391,6 +399,7 @@ bool MythPlayer::Play(float speed, bool normal, bool unpauseaudio)
      if (deleteMap.IsEditing())
      {
          LOG(VB_GENERAL, LOG_ERR, LOC + "Ignoring Play(), in edit mode.");
@@ -61431,7 +62920,7 @@ index f953e11..4ddde4d 100644
          return false;
      }
  
-@@ -403,6 +404,7 @@ bool MythPlayer::Play(float speed, bool normal, bool unpauseaudio)
+@@ -403,6 +412,7 @@ bool MythPlayer::Play(float speed, bool normal, bool unpauseaudio)
      allpaused = false;
      next_play_speed   = speed;
      next_normal_speed = normal;
@@ -61439,7 +62928,7 @@ index f953e11..4ddde4d 100644
      return true;
  }
  
-@@ -949,7 +951,7 @@ int MythPlayer::OpenFile(uint retries)
+@@ -949,7 +959,7 @@ int MythPlayer::OpenFile(uint retries)
                  return -1;
              }
              LOG(VB_GENERAL, LOG_WARNING, LOC + "OpenFile() waiting on data");
@@ -61448,7 +62937,7 @@ index f953e11..4ddde4d 100644
          }
  
          player_ctx->LockPlayingInfo(__FILE__, __LINE__);
-@@ -1385,7 +1387,10 @@ void MythPlayer::DisableCaptions(uint mode, bool osd_msg)
+@@ -1385,7 +1395,10 @@ void MythPlayer::DisableCaptions(uint mode, bool osd_msg)
  
      QMutexLocker locker(&osdLock);
  
@@ -61460,7 +62949,7 @@ index f953e11..4ddde4d 100644
      QString msg = "";
      if (kDisplayNUVTeletextCaptions & mode)
          msg += tr("TXT CAP");
-@@ -1422,7 +1427,10 @@ void MythPlayer::DisableCaptions(uint mode, bool osd_msg)
+@@ -1422,7 +1435,10 @@ void MythPlayer::DisableCaptions(uint mode, bool osd_msg)
  void MythPlayer::EnableCaptions(uint mode, bool osd_msg)
  {
      QMutexLocker locker(&osdLock);
@@ -61472,7 +62961,7 @@ index f953e11..4ddde4d 100644
      QString msg = "";
      if ((kDisplayCC608 & mode) || (kDisplayCC708 & mode) ||
          (kDisplayAVSubtitle & mode) || kDisplayRawTextSubtitle & mode)
-@@ -1492,7 +1500,9 @@ void MythPlayer::SetCaptionsEnabled(bool enable, bool osd_msg)
+@@ -1492,7 +1508,9 @@ void MythPlayer::SetCaptionsEnabled(bool enable, bool osd_msg)
      enableCaptions = disableCaptions = false;
      uint origMode = textDisplayMode;
  
@@ -61483,7 +62972,115 @@ index f953e11..4ddde4d 100644
  
      if (!enable)
      {
-@@ -2240,10 +2250,7 @@ void MythPlayer::DisplayNormalFrame(bool check_prebuffer)
+@@ -1772,6 +1790,7 @@ void MythPlayer::ResetAVSync(void)
+     if (!avsync_predictor_enabled || avsync_predictor >= refreshrate)
+         avsync_predictor = 0;
+     prevtc = 0;
++    avsync_next = avsync_interval;      // Frames till next sync check
+     LOG(VB_PLAYBACK | VB_TIMESTAMP, LOG_INFO, LOC + "A/V sync reset");
+ }
+ 
+@@ -1785,6 +1804,24 @@ void MythPlayer::InitAVSync(void)
+ 
+     refreshrate = MythDisplay::GetDisplayInfo(frame_interval).Rate();
+ 
++    // Number of frames over which to average time divergence
++    avsync_averaging=4;
++
++    // Special averaging default of 60 for OpenMAX passthru
++    QString device = gCoreContext->GetSetting("AudioOutputDevice","");
++    int ac3pass = gCoreContext->GetNumSetting("AC3PassThru",-1);
++    if (device == "OpenMAX:hdmi" && ac3pass == 1)
++        avsync_averaging=60;
++
++    // Allow override of averaging value
++    avsync_averaging = gCoreContext->GetNumSetting("AVSyncAveraging", avsync_averaging);  // Number of frames to average
++    if (avsync_averaging < 4)
++        avsync_averaging = 4;
++    avsync_interval = avsync_averaging / max_diverge - 1;   // Number of frames skip between sync checks
++    if (avsync_interval < 0)
++        avsync_interval = 0;
++    avsync_next = avsync_interval;      // Frames till next sync check
++
+     if (!FlagIsSet(kVideoIsNull))
+     {
+         QString timing_type = videosync->getName();
+@@ -1813,8 +1850,6 @@ int64_t MythPlayer::AVSyncGetAudiotime(void)
+     return currentaudiotime;
+ }
+ 
+-#define MAXDIVERGE  3.0f
+-#define DIVERGELIMIT 30.0f
+ void MythPlayer::AVSync(VideoFrame *buffer, bool limit_delay)
+ {
+     int repeat_pict  = 0;
+@@ -1840,18 +1875,25 @@ void MythPlayer::AVSync(VideoFrame *buffer, bool limit_delay)
+         return;
+     }
+ 
+-    if (normal_speed)
++    if (normal_speed && avsync_next==0)
+     {
+         diverge = (float)avsync_avg / (float)frame_interval;
+-        diverge = max(diverge, -DIVERGELIMIT);
+-        diverge = min(diverge, +DIVERGELIMIT);
++    }
++
++    if (avsync_next > 0)
++        avsync_next--;
++    else {
++        int divisor = int(abs(diverge) - max_diverge - 1.0f);
++        if (divisor < 1)
++            divisor=1;
++        avsync_next = avsync_interval/divisor;
+     }
+ 
+     FrameScanType ps = m_scan;
+     if (kScan_Detect == m_scan || kScan_Ignore == m_scan)
+         ps = kScan_Progressive;
+ 
+-    bool max_video_behind = diverge < -MAXDIVERGE;
++    bool max_video_behind = diverge < -max_diverge;
+     bool dropframe = false;
+     QString dbg;
+ 
+@@ -1988,7 +2030,7 @@ void MythPlayer::AVSync(VideoFrame *buffer, bool limit_delay)
+ 
+     avsync_adjustment = 0;
+ 
+-    if (diverge > MAXDIVERGE)
++    if (diverge > max_diverge)
+     {
+         // If audio is way behind of video, adjust for it...
+         // by cutting the frame rate in half for the length of this frame
+@@ -2006,7 +2048,8 @@ void MythPlayer::AVSync(VideoFrame *buffer, bool limit_delay)
+         int64_t currentaudiotime = audio.GetAudioTime();
+         LOG(VB_PLAYBACK | VB_TIMESTAMP, LOG_INFO, LOC +
+             QString("A/V timecodes audio %1 video %2 frameinterval %3 "
+-                    "avdel %4 avg %5 tcoffset %6 avp %7 avpen %8 avdc %9")
++                    "avdel %4 avg %5 tcoffset %6 avp %7 avpen %8 avdc %9 "
++                    "diverge %10")
+                 .arg(currentaudiotime)
+                 .arg(timecode)
+                 .arg(frame_interval)
+@@ -2017,6 +2060,7 @@ void MythPlayer::AVSync(VideoFrame *buffer, bool limit_delay)
+                 .arg(avsync_predictor)
+                 .arg(avsync_predictor_enabled)
+                 .arg(vsync_delay_clock)
++                .arg(diverge)
+                  );
+         if (currentaudiotime != 0 && timecode != 0)
+         { // currentaudiotime == 0 after a seek
+@@ -2054,7 +2098,7 @@ void MythPlayer::AVSync(VideoFrame *buffer, bool limit_delay)
+             // prevents major jitter when pts resets during dvd title
+             if (avsync_delay > 2000000 && limit_delay)
+                 avsync_delay = 90000;
+-            avsync_avg = (avsync_delay + (avsync_avg * 3)) / 4;
++            avsync_avg = (avsync_delay + (avsync_avg * (avsync_averaging-1))) / avsync_averaging;
+ 
+             int avsync_used = avsync_avg;
+             if (labs(avsync_used) > labs(avsync_delay))
+@@ -2240,10 +2284,7 @@ void MythPlayer::DisplayNormalFrame(bool check_prebuffer)
          videoOutput->DoneDisplayingFrame(videoOutput->GetLastShownFrame());
  
      // retrieve the next frame
@@ -61495,7 +63092,7 @@ index f953e11..4ddde4d 100644
      VideoFrame *frame = videoOutput->GetLastShownFrame();
  
      // Check aspect ratio
-@@ -2252,12 +2259,9 @@ void MythPlayer::DisplayNormalFrame(bool check_prebuffer)
+@@ -2252,12 +2293,9 @@ void MythPlayer::DisplayNormalFrame(bool check_prebuffer)
      // Player specific processing (dvd, bd, mheg etc)
      PreProcessNormalFrame();
  
@@ -61511,7 +63108,7 @@ index f953e11..4ddde4d 100644
  
      FrameScanType ps = m_scan;
      if (kScan_Detect == m_scan || kScan_Ignore == m_scan)
-@@ -2265,9 +2269,7 @@ void MythPlayer::DisplayNormalFrame(bool check_prebuffer)
+@@ -2265,9 +2303,7 @@ void MythPlayer::DisplayNormalFrame(bool check_prebuffer)
  
      AVSync(frame, 0);
      // If PiP then keep this frame for MythPlayer::GetCurrentFrame
@@ -61522,7 +63119,7 @@ index f953e11..4ddde4d 100644
          videoOutput->DoneDisplayingFrame(frame);
  }
  
-@@ -2277,12 +2279,10 @@ void MythPlayer::PreProcessNormalFrame(void)
+@@ -2277,12 +2313,10 @@ void MythPlayer::PreProcessNormalFrame(void)
      // handle Interactive TV
      if (GetInteractiveTV())
      {
@@ -61537,7 +63134,7 @@ index f953e11..4ddde4d 100644
              InteractiveScreen *window =
                  (InteractiveScreen*)osd->GetWindow(OSD_WIN_INTERACT);
              if ((interactiveTV->ImageHasChanged() || !itvVisible) && window)
-@@ -2291,6 +2291,8 @@ void MythPlayer::PreProcessNormalFrame(void)
+@@ -2291,6 +2325,8 @@ void MythPlayer::PreProcessNormalFrame(void)
                  itvVisible = true;
              }
          }
@@ -61546,7 +63143,15 @@ index f953e11..4ddde4d 100644
      }
  #endif // USING_MHEG
  }
-@@ -2467,7 +2469,7 @@ bool MythPlayer::VideoLoop(void)
+@@ -2388,6 +2424,7 @@ void MythPlayer::VideoStart(void)
+ 
+     avsync_delay = 0;
+     avsync_avg = 0;
++    avsync_next = avsync_interval;      // Frames till next sync check
+     refreshrate = 0;
+     lastsync = false;
+ 
+@@ -2467,7 +2504,7 @@ bool MythPlayer::VideoLoop(void)
          DisplayPauseFrame();
      }
      else
@@ -61555,7 +63160,7 @@ index f953e11..4ddde4d 100644
  
      if (FlagIsSet(kVideoIsNull) && decoder)
          decoder->UpdateFramesPlayed();
-@@ -2597,10 +2599,7 @@ void MythPlayer::SwitchToProgram(void)
+@@ -2597,10 +2634,7 @@ void MythPlayer::SwitchToProgram(void)
      ProgramInfo *pginfo = player_ctx->tvchain->GetSwitchProgram(
          discontinuity, newtype, newid);
      if (!pginfo)
@@ -61566,7 +63171,7 @@ index f953e11..4ddde4d 100644
  
      bool newIsDummy = player_ctx->tvchain->GetInputType(newid) == "DUMMY";
  
-@@ -2735,10 +2734,7 @@ void MythPlayer::JumpToProgram(void)
+@@ -2735,10 +2769,7 @@ void MythPlayer::JumpToProgram(void)
      ProgramInfo *pginfo = player_ctx->tvchain->GetSwitchProgram(
          discontinuity, newtype, newid);
      if (!pginfo)
@@ -61577,7 +63182,7 @@ index f953e11..4ddde4d 100644
  
      inJumpToProgramPause = true;
  
-@@ -2746,6 +2742,7 @@ void MythPlayer::JumpToProgram(void)
+@@ -2746,6 +2777,7 @@ void MythPlayer::JumpToProgram(void)
      SetPlayingInfo(*pginfo);
  
      Pause();
@@ -61585,7 +63190,7 @@ index f953e11..4ddde4d 100644
      ResetCaptions();
      player_ctx->tvchain->SetProgram(*pginfo);
      player_ctx->buffer->Reset(true);
-@@ -2996,11 +2993,12 @@ void MythPlayer::EventLoop(void)
+@@ -2996,11 +3028,12 @@ void MythPlayer::EventLoop(void)
          JumpToProgram();
      }
      else if ((!allpaused || GetEof() != kEofStateNone) &&
@@ -61601,7 +63206,7 @@ index f953e11..4ddde4d 100644
      }
  
      // Jump to the next program in livetv
-@@ -3201,35 +3199,36 @@ void MythPlayer::AudioEnd(void)
+@@ -3201,35 +3234,36 @@ void MythPlayer::AudioEnd(void)
  
  bool MythPlayer::PauseDecoder(void)
  {
@@ -61647,7 +63252,7 @@ index f953e11..4ddde4d 100644
          return;
      }
  
-@@ -3237,14 +3236,15 @@ void MythPlayer::UnpauseDecoder(void)
+@@ -3237,14 +3271,15 @@ void MythPlayer::UnpauseDecoder(void)
      {
          int tries = 0;
          unpauseDecoder = true;
@@ -61665,7 +63270,7 @@ index f953e11..4ddde4d 100644
  }
  
  void MythPlayer::DecoderStart(bool start_paused)
-@@ -3271,7 +3271,7 @@ void MythPlayer::DecoderEnd(void)
+@@ -3271,7 +3306,7 @@ void MythPlayer::DecoderEnd(void)
      SetPlaying(false);
      killdecoder = true;
      int tries = 0;
@@ -61674,7 +63279,7 @@ index f953e11..4ddde4d 100644
          LOG(VB_PLAYBACK, LOG_INFO, LOC +
              "Waited 100ms for decoder loop to stop");
  
-@@ -3284,23 +3284,12 @@ void MythPlayer::DecoderEnd(void)
+@@ -3284,23 +3319,12 @@ void MythPlayer::DecoderEnd(void)
  
  void MythPlayer::DecoderPauseCheck(void)
  {
@@ -61703,6 +63308,68 @@ index f953e11..4ddde4d 100644
      }
  }
  
+diff --git a/mythtv/libs/libmythtv/mythplayer.h b/mythtv/libs/libmythtv/mythplayer.h
+index bfdac87..140c6a0 100644
+--- a/mythtv/libs/libmythtv/mythplayer.h
++++ b/mythtv/libs/libmythtv/mythplayer.h
+@@ -826,6 +826,11 @@ class MTV_PUBLIC MythPlayer
+     int        repeat_delay;
+     int64_t    disp_timecode;
+     bool       avsync_audiopaused;
++    float      max_diverge;  // from setting PlayerMaxDiverge default 2
++    // AVSync for Raspberry Pi digital streams
++    int        avsync_averaging; // Number of frames to average
++    int        avsync_interval;  // Number of frames skip between sync checks
++    int        avsync_next;      // Frames till next sync check
+ 
+     // Time Code stuff
+     int        prevtc;        ///< 32 bit timecode if last VideoFrame shown
+diff --git a/mythtv/libs/libmythtv/osd.cpp b/mythtv/libs/libmythtv/osd.cpp
+index df59b70..098cc00 100644
+--- a/mythtv/libs/libmythtv/osd.cpp
++++ b/mythtv/libs/libmythtv/osd.cpp
+@@ -152,7 +152,7 @@ OSD::OSD(MythPlayer *player, QObject *parent, MythPainter *painter)
+   : m_parent(player), m_ParentObject(parent), m_CurrentPainter(painter),
+     m_Rect(QRect()), m_Effects(true), m_FadeTime(kOSDFadeTime), m_Dialog(NULL),
+     m_PulsedDialogText(QString()), m_NextPulseUpdate(QDateTime()),
+-    m_Refresh(false),   m_UIScaleOverride(false),
++    m_Refresh(false), m_Visible(false), m_UIScaleOverride(false),
+     m_SavedWMult(1.0f), m_SavedHMult(1.0f),   m_SavedUIRect(QRect()),
+     m_fontStretch(100), m_savedFontStretch(100),
+     m_FunctionalType(kOSDFunctionalType_Default), m_FunctionalWindow(QString())
+@@ -704,6 +704,8 @@ bool OSD::DrawDirect(MythPainter* painter, QSize size, bool repaint)
+             {
+                 QTime expires = nc->ScreenExpiryTime(*it2).time();
+                 int left = now.msecsTo(expires);
++                if (left < 0)
++                    left = 0;
+                 if (expires.isValid() && left < m_FadeTime)
+                     (*it2)->SetAlpha((255 * left) / m_FadeTime);
+             }
+@@ -741,6 +743,11 @@ bool OSD::DrawDirect(MythPainter* painter, QSize size, bool repaint)
+         painter->End();
+     }
+ 
++    // Force a redraw if it just became invisible
++    if (m_Visible && !visible)
++        redraw=true;
++    m_Visible = visible;
++
+     return redraw;
+ }
+ 
+diff --git a/mythtv/libs/libmythtv/osd.h b/mythtv/libs/libmythtv/osd.h
+index 7b3c9c5..85b3447 100644
+--- a/mythtv/libs/libmythtv/osd.h
++++ b/mythtv/libs/libmythtv/osd.h
+@@ -220,6 +220,7 @@ class OSD
+     QString         m_PulsedDialogText;
+     QDateTime       m_NextPulseUpdate;
+     bool            m_Refresh;
++    bool            m_Visible;
+     int             m_Timeouts[4];
+ 
+     bool            m_UIScaleOverride;
 diff --git a/mythtv/libs/libmythtv/privatedecoder_omx.cpp b/mythtv/libs/libmythtv/privatedecoder_omx.cpp
 index a7ce174..b2999ad 100644
 --- a/mythtv/libs/libmythtv/privatedecoder_omx.cpp
@@ -61745,6 +63412,31 @@ index 6956b20..94cba8d 100644
          return false;
  
      m_isopen = true;
+diff --git a/mythtv/libs/libmythtv/recorders/channelbase.cpp b/mythtv/libs/libmythtv/recorders/channelbase.cpp
+index c629ec5..f10ae6a 100644
+--- a/mythtv/libs/libmythtv/recorders/channelbase.cpp
++++ b/mythtv/libs/libmythtv/recorders/channelbase.cpp
+@@ -148,8 +148,8 @@ bool ChannelBase::IsTunable(const QString &channum) const
+         return false;
+     }
+ 
+-    uint mplexid_restriction;
+-    uint chanid_restriction;
++    uint mplexid_restriction = 0;
++    uint chanid_restriction = 0;
+     if (!IsInputAvailable(mplexid_restriction, chanid_restriction))
+     {
+         LOG(VB_GENERAL, LOG_ERR, loc + " " +
+@@ -182,7 +182,8 @@ bool ChannelBase::IsTunable(const QString &channum) const
+     }
+ 
+     if ((mplexid_restriction && (mplexid != mplexid_restriction)) ||
+-        (chanid_restriction && (chanid != chanid_restriction)))
++        (!mplexid_restriction &&
++         chanid_restriction && (chanid != chanid_restriction)))
+     {
+         LOG(VB_GENERAL, LOG_ERR, loc + " " +
+             QString("Channel is valid, but tuner is busy "
 diff --git a/mythtv/libs/libmythtv/recorders/vboxutils.cpp b/mythtv/libs/libmythtv/recorders/vboxutils.cpp
 index f1fc301..629e276 100644
 --- a/mythtv/libs/libmythtv/recorders/vboxutils.cpp
@@ -61865,6 +63557,44 @@ index 9b9511b..f397506 100644
  
      if (oldinputname != ctx->recorder->GetInput())
          UpdateOSDInput(ctx);
+diff --git a/mythtv/libs/libmythtv/tv_rec.cpp b/mythtv/libs/libmythtv/tv_rec.cpp
+index a5fd330..41b88d2 100644
+--- a/mythtv/libs/libmythtv/tv_rec.cpp
++++ b/mythtv/libs/libmythtv/tv_rec.cpp
+@@ -429,7 +429,8 @@ RecStatus::Type TVRec::StartRecording(ProgramInfo *pginfo)
+ 
+     // We need to do this check early so we don't cancel an overrecord
+     // that we're trying to extend.
+-    if (internalState != kState_WatchingLiveTV && m_recStatus != RecStatus::Failing &&
++    if (internalState != kState_WatchingLiveTV &&
++        m_recStatus != RecStatus::Failing &&
+         curRecording && curRecording->IsSameProgramWeakCheck(*rcinfo))
+     {
+         int post_roll_seconds  = curRecording->GetRecordingEndTime()
+@@ -4324,6 +4325,23 @@ void TVRec::TuningNewRecorder(MPEGStreamData *streamData)
+   err_ret:
+     SetRecordingStatus(RecStatus::Failed, __LINE__, true);
+     ChangeState(kState_None);
++
++    if (rec)
++    {
++        // Make sure the scheduler knows...
++        rec->SetRecordingStatus(RecStatus::Failed);
++        LOG(VB_RECORD, LOG_INFO, LOC +
++            QString("TuningNewRecorder -- UPDATE_RECORDING_STATUS: %1")
++            .arg(RecStatus::toString(RecStatus::Failed, kSingleRecord)));
++        MythEvent me(QString("UPDATE_RECORDING_STATUS %1 %2 %3 %4 %5")
++                     .arg(rec->GetInputID())
++                     .arg(rec->GetChanID())
++                     .arg(rec->GetScheduledStartTime(MythDate::ISODate))
++                     .arg(RecStatus::Failed)
++                     .arg(rec->GetRecordingEndTime(MythDate::ISODate)));
++        gCoreContext->dispatch(me);
++    }
++
+     if (tvchain)
+         delete rec;
+ }
 diff --git a/mythtv/libs/libmythtv/videodisplayprofile.cpp b/mythtv/libs/libmythtv/videodisplayprofile.cpp
 index 4d10fe3..083ea98 100644
 --- a/mythtv/libs/libmythtv/videodisplayprofile.cpp
@@ -61941,7 +63671,7 @@ index 61119bb..c148861 100644
      static QStringList GetVideoRenderers(const QString &decoder);
      static QString     GetVideoRendererHelp(const QString &renderer);
 diff --git a/mythtv/libs/libmythtv/videoout_omx.cpp b/mythtv/libs/libmythtv/videoout_omx.cpp
-index 1b90ceb..2af88f9 100644
+index 1b90ceb..3c5c448 100644
 --- a/mythtv/libs/libmythtv/videoout_omx.cpp
 +++ b/mythtv/libs/libmythtv/videoout_omx.cpp
 @@ -4,6 +4,7 @@
@@ -61952,7 +63682,15 @@ index 1b90ceb..2af88f9 100644
  #endif //def OSD_EGL
  
  /* must go before X11/X.h due to #define None 0L */
-@@ -57,7 +58,7 @@ using namespace omxcontext;
+@@ -44,6 +45,7 @@
+ #endif //def OSD_EGL
+ 
+ #include "mythmainwindow.h"
++#include "mythuihelper.h"
+ #include "mythcorecontext.h"
+ 
+ #include "filtermanager.h"
+@@ -57,7 +59,7 @@ using namespace omxcontext;
  /*
   * Macros
   */
@@ -61961,7 +63699,7 @@ index 1b90ceb..2af88f9 100644
  
  // Roundup a value: y = ROUNDUP(x,4)
  #define ROUNDUP( _x,_z) ((_x) + ((-(int)(_x)) & ((_z) -1)) )
-@@ -118,8 +119,110 @@ private:
+@@ -118,8 +120,110 @@ private:
      DISPMANX_DISPLAY_HANDLE_T m_dispman_display;
  #endif
  };
@@ -62073,7 +63811,7 @@ index 1b90ceb..2af88f9 100644
  
  /*
   * Constants
-@@ -150,7 +253,8 @@ void VideoOutputOMX::GetRenderOptions(render_opts &opts,
+@@ -150,7 +254,8 @@ void VideoOutputOMX::GetRenderOptions(render_opts &opts,
      (*opts.deints)[kName].append(kName + "linedouble");
  #endif
  #ifdef OSD_EGL
@@ -62083,7 +63821,7 @@ index 1b90ceb..2af88f9 100644
  #endif
      (*opts.osds)[kName].append("softblend");
  
-@@ -180,8 +284,13 @@ QStringList VideoOutputOMX::GetAllowedRenderers(
+@@ -180,8 +285,13 @@ QStringList VideoOutputOMX::GetAllowedRenderers(
  VideoOutputOMX::VideoOutputOMX() :
      m_render(gCoreContext->GetSetting("OMXVideoRender", VIDEO_RENDER), *this),
      m_imagefx(gCoreContext->GetSetting("OMXVideoFilter", IMAGE_FX), *this),
@@ -62098,7 +63836,7 @@ index 1b90ceb..2af88f9 100644
      init(&av_pause_frame, FMT_YV12, NULL, 0, 0, 0);
  
      if (gCoreContext->GetNumSetting("UseVideoModes", 0))
-@@ -225,9 +334,18 @@ VideoOutputOMX::~VideoOutputOMX()
+@@ -225,15 +335,25 @@ VideoOutputOMX::~VideoOutputOMX()
      DeleteBuffers();
  
  #ifdef OSD_EGL
@@ -62118,7 +63856,14 @@ index 1b90ceb..2af88f9 100644
  #endif
  
      if (m_backgroundscreen)
-@@ -309,8 +427,9 @@ bool VideoOutputOMX::Init(          // Return true if successful
+     {
+         m_backgroundscreen->Close();
+         m_backgroundscreen = 0;
++        GetMythUI()->RemoveCurrentLocation();
+     }
+ }
+ 
+@@ -309,8 +429,9 @@ bool VideoOutputOMX::Init(          // Return true if successful
      if (!CreateBuffers(video_dim_buf, video_dim_disp, winid))
          return false;
  
@@ -62129,7 +63874,7 @@ index 1b90ceb..2af88f9 100644
      {
          MythRenderEGL *render = new MythRenderEGL();
          if (render->create())
-@@ -320,16 +439,35 @@ bool VideoOutputOMX::Init(          // Return true if successful
+@@ -320,16 +441,35 @@ bool VideoOutputOMX::Init(          // Return true if successful
              MythOpenGLPainter *p = new MythOpenGLPainter(m_context);
              p->SetSwapControl(false);
              m_osdpainter = p;
@@ -62166,7 +63911,15 @@ index 1b90ceb..2af88f9 100644
      MoveResize();
  
      m_disp_rect = m_vid_rect = QRect();
-@@ -756,7 +894,11 @@ void VideoOutputOMX::MoveResizeWindow(QRect)
+@@ -687,6 +827,7 @@ void VideoOutputOMX::PrepareFrame(VideoFrame *buffer, FrameScanType scan, OSD *o
+                                           m_backgroundscreen))
+         {
+             mainStack->AddScreen(m_backgroundscreen, false);
++            GetMythUI()->AddCurrentLocation("Playback");
+             if (mainWindow->GetPaintWindow())
+                 mainWindow->GetPaintWindow()->update();
+             qApp->processEvents();
+@@ -756,7 +897,11 @@ void VideoOutputOMX::MoveResizeWindow(QRect)
  bool VideoOutputOMX::hasFullScreenOSD(void) const
  {
  #ifdef OSD_EGL
@@ -62179,7 +63932,7 @@ index 1b90ceb..2af88f9 100644
          return true;
  #endif
      return VideoOutput::hasFullScreenOSD();
-@@ -765,17 +907,23 @@ bool VideoOutputOMX::hasFullScreenOSD(void) const
+@@ -765,17 +910,23 @@ bool VideoOutputOMX::hasFullScreenOSD(void) const
  // virtual
  MythPainter *VideoOutputOMX::GetOSDPainter(void)
  {
@@ -62206,7 +63959,7 @@ index 1b90ceb..2af88f9 100644
          m_context->BindFramebuffer(0);
  
          QRect bounds = GetTotalOSDBounds();
-@@ -799,6 +947,61 @@ bool VideoOutputOMX::DisplayOSD(VideoFrame *frame, OSD *osd)
+@@ -799,6 +950,61 @@ bool VideoOutputOMX::DisplayOSD(VideoFrame *frame, OSD *osd)
          m_context->doneCurrent();
          return true;
      }
@@ -62268,7 +64021,7 @@ index 1b90ceb..2af88f9 100644
  #endif
      return VideoOutput::DisplayOSD(frame, osd);
  }
-@@ -1072,8 +1275,27 @@ bool VideoOutputOMX::SetVideoRect(const QRect &d_rect, const QRect &vid_rect)
+@@ -1072,8 +1278,27 @@ bool VideoOutputOMX::SetVideoRect(const QRect &d_rect, const QRect &vid_rect)
  #endif // USING_BROADCOM
  
  #ifdef OSD_EGL
@@ -62298,7 +64051,7 @@ index 1b90ceb..2af88f9 100644
  #endif
  
      m_disp_rect = disp_rect;
-@@ -1193,6 +1415,8 @@ MythRenderEGL::MythRenderEGL() :
+@@ -1193,6 +1418,8 @@ MythRenderEGL::MythRenderEGL() :
      m_window(0),
      m_surface(EGL_NO_SURFACE)
  {
@@ -62307,7 +64060,7 @@ index 1b90ceb..2af88f9 100644
      // get an EGL display connection
      m_display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
      if (m_display == EGL_NO_DISPLAY)
-@@ -1320,6 +1544,7 @@ MythRenderEGL::~MythRenderEGL()
+@@ -1320,6 +1547,7 @@ MythRenderEGL::~MythRenderEGL()
      assert(b == EGL_TRUE);
  #endif
      m_display = EGL_NO_DISPLAY;
@@ -62591,6 +64344,25 @@ index 3543fa9..adaf302 100644
      // 1D Textures (not available on GL ES 2.0)
      MYTH_GLTEXIMAGE1DPROC                m_glTexImage1D;
  
+diff --git a/mythtv/libs/libmythui/mythuibuttonlist.cpp b/mythtv/libs/libmythui/mythuibuttonlist.cpp
+index 9c25ff4..d87f419 100644
+--- a/mythtv/libs/libmythui/mythuibuttonlist.cpp
++++ b/mythtv/libs/libmythui/mythuibuttonlist.cpp
+@@ -1335,11 +1335,12 @@ void MythUIButtonList::CalculateButtonPositions(void)
+                                     m_columns * m_columns;
+             }
+ 
+-
++            // Adjusted if last item is deleted
+             if (((m_itemList.count() - m_topPosition)
+                  < static_cast<int>(m_itemsVisible)) &&
+                 (m_selPosition - (static_cast<int>(m_itemsVisible) - 1)
+-                 < m_topPosition))
++                 < m_topPosition) &&
++                 m_columns == 1)
+                 m_topPosition = m_selPosition -
+                                 (static_cast<int>(m_itemsVisible) - 1);
+ 
 diff --git a/mythtv/libs/libmythui/screensaver-dbus.cpp b/mythtv/libs/libmythui/screensaver-dbus.cpp
 index b099c46..af41c91 100644
 --- a/mythtv/libs/libmythui/screensaver-dbus.cpp
@@ -63032,6 +64804,102 @@ index c52ae07..c3a9eb7 100644
          {}
  
  };
+diff --git a/mythtv/libs/libmythupnp/serializers/serializer.cpp b/mythtv/libs/libmythupnp/serializers/serializer.cpp
+index 9e6a4fe..6c367ca 100644
+--- a/mythtv/libs/libmythupnp/serializers/serializer.cpp
++++ b/mythtv/libs/libmythupnp/serializers/serializer.cpp
+@@ -152,7 +152,10 @@ QString Serializer::ReadPropertyMetadata( const QObject *pObject,
+ {
+     const QMetaObject *pMeta = pObject->metaObject();
+ 
+-    int nIdx = pMeta->indexOfClassInfo( sPropName.toUtf8() );
++    int nIdx = -1;
++
++    if (pMeta)
++        nIdx = pMeta->indexOfClassInfo( sPropName.toUtf8());
+ 
+     if (nIdx >=0)
+     {
+diff --git a/mythtv/libs/libmythupnp/serializers/xmlSerializer.cpp b/mythtv/libs/libmythupnp/serializers/xmlSerializer.cpp
+index 9851e61..41ad4fd 100644
+--- a/mythtv/libs/libmythupnp/serializers/xmlSerializer.cpp
++++ b/mythtv/libs/libmythupnp/serializers/xmlSerializer.cpp
+@@ -91,7 +91,10 @@ void XmlSerializer::BeginObject( const QString &sName, const QObject  *pObject )
+ 
+     const QMetaObject *pMeta = pObject->metaObject();
+ 
+-    int nIdx = pMeta->indexOfClassInfo( "version" );
++    int nIdx = -1;
++
++    if (pMeta)
++        nIdx = pMeta->indexOfClassInfo( "version" );
+ 
+     if (nIdx >=0)
+         m_pXmlWriter->writeAttribute( "version", pMeta->classInfo( nIdx ).value() );
+@@ -324,9 +327,12 @@ QString XmlSerializer::GetContentName( const QString        &sName,
+ {
+     // Try to read Name or TypeName from classinfo metadata.
+ 
+-    int nClassIdx = pMetaObject->indexOfClassInfo( sName.toLatin1() );
++    int nClassIdx = -1;
++
++    if ( pMetaObject )
++        nClassIdx = pMetaObject->indexOfClassInfo( sName.toLatin1() );
+ 
+-    if (nClassIdx >=0)
++    if (nClassIdx >=0 )
+     {
+         QString     sOptionData = pMetaObject->classInfo( nClassIdx ).value();
+         QStringList sOptions    = sOptionData.split( ';' );
+diff --git a/mythtv/libs/libmythupnp/serializers/xmlplistSerializer.cpp b/mythtv/libs/libmythupnp/serializers/xmlplistSerializer.cpp
+index 589bde9..3758fbb 100644
+--- a/mythtv/libs/libmythupnp/serializers/xmlplistSerializer.cpp
++++ b/mythtv/libs/libmythupnp/serializers/xmlplistSerializer.cpp
+@@ -216,7 +216,11 @@ void XmlPListSerializer::BeginObject(const QString &sName,
+                                      const QObject *pObject)
+ {
+     const QMetaObject *pMeta = pObject->metaObject();
+-    int nIdx = pMeta->indexOfClassInfo("version");
++
++    int nIdx = -1;
++
++    if (pMeta)
++        nIdx = pMeta->indexOfClassInfo("version");
+ 
+     if (nIdx >=0)
+     {
+diff --git a/mythtv/libs/libmythupnp/wsdl.cpp b/mythtv/libs/libmythupnp/wsdl.cpp
+index 2f7c925..71f9a39 100644
+--- a/mythtv/libs/libmythupnp/wsdl.cpp
++++ b/mythtv/libs/libmythupnp/wsdl.cpp
+@@ -527,7 +527,10 @@ QString Wsdl::AddTypeInfo( QString sType )
+ 
+ QString Wsdl::ReadClassInfo( const QMetaObject *pMeta, const QString &sKey )
+ {
+-    int nIdx = pMeta->indexOfClassInfo( sKey.toUtf8() );
++    int nIdx = -1;
++
++    if (pMeta)
++        nIdx = pMeta->indexOfClassInfo( sKey.toUtf8() );
+ 
+     if (nIdx >=0)
+         return pMeta->classInfo( nIdx ).value();
+diff --git a/mythtv/libs/libmythupnp/xsd.cpp b/mythtv/libs/libmythupnp/xsd.cpp
+index 9fe82d1..fab9a0d 100755
+--- a/mythtv/libs/libmythupnp/xsd.cpp
++++ b/mythtv/libs/libmythupnp/xsd.cpp
+@@ -923,7 +923,10 @@ QString Xsd::ReadPropertyMetadata( QObject *pObject, QString sPropName, QString
+ {
+     const QMetaObject *pMeta = pObject->metaObject();
+ 
+-    int nIdx = pMeta->indexOfClassInfo( sPropName.toUtf8() );
++    int nIdx = -1;
++
++    if (pMeta)
++        nIdx = pMeta->indexOfClassInfo( sPropName.toUtf8() );
+ 
+     if (nIdx >=0)
+     {
 diff --git a/mythtv/programs/mythbackend/autoexpire.cpp b/mythtv/programs/mythbackend/autoexpire.cpp
 index eb63ea4..0c1b9e8 100644
 --- a/mythtv/programs/mythbackend/autoexpire.cpp
@@ -63251,8 +65119,84 @@ index 3d7296e..7c3ed2e 100644
          int pos = subexp.indexIn(MYTH_SOURCE_VERSION);
          if (pos > -1)
          {
+diff --git a/mythtv/programs/mythbackend/mainserver.cpp b/mythtv/programs/mythbackend/mainserver.cpp
+index 98b93cd..3503b6f 100644
+--- a/mythtv/programs/mythbackend/mainserver.cpp
++++ b/mythtv/programs/mythbackend/mainserver.cpp
+@@ -497,6 +497,7 @@ void MainServer::ProcessRequestWork(MythSocket *sock)
+     line = line.simplified();
+     QStringList tokens = line.split(' ', QString::SkipEmptyParts);
+     QString command = tokens[0];
++
+     if (command == "MYTH_PROTO_VERSION")
+     {
+         if (tokens.size() < 2)
+@@ -1271,6 +1272,37 @@ void MainServer::customEvent(QEvent *e)
+             return;
+         }
+ 
++        if (me->Message().startsWith("STOP_RECORDING"))
++        {
++            QStringList tokens = me->Message().split(" ",
++                                                     QString::SkipEmptyParts);
++
++
++            if (tokens.size() < 3 || tokens.size() > 3)
++            {
++                LOG(VB_GENERAL, LOG_ERR, LOC +
++                    QString("Bad STOP_RECORDING message: %1")
++                        .arg(me->Message()));
++                return;
++            }
++
++            QDateTime startts = MythDate::fromString(tokens[2]);
++            RecordingInfo recInfo(tokens[1].toUInt(), startts);
++
++            if (recInfo.GetChanID())
++            {
++                DoHandleStopRecording(recInfo, NULL);
++            }
++            else
++            {
++                LOG(VB_GENERAL, LOG_ERR, LOC +
++                    QString("Cannot find program info for '%1' while "
++                            "attempting to stop recording.").arg(me->Message()));
++            }
++
++            return;
++        }
++
+         if ((me->Message().startsWith("DELETE_RECORDING")) ||
+             (me->Message().startsWith("FORCE_DELETE_RECORDING")))
+         {
+@@ -3103,17 +3135,12 @@ void MainServer::DoHandleUndeleteRecording(
+ void MainServer::HandleRescheduleRecordings(const QStringList &request,
+                                             PlaybackSock *pbs)
+ {
+-    QStringList result;
+-    if (m_sched)
+-    {
+-        m_sched->Reschedule(request);
+-        result = QStringList( QString::number(1) );
+-    }
+-    else
+-        result = QStringList( QString::number(0) );
++     ScheduledRecording::RescheduleMatch(0, 0, 0, QDateTime(),
++                                         "HandleRescheduleRecordings");
+ 
+     if (pbs)
+     {
++        QStringList result  = QStringList( QString::number(1) );
+         MythSocket *pbssock = pbs->getSocket();
+         if (pbssock)
+             SendResponse(pbssock, result);
+@@ -8117,4 +8144,3 @@ void MainServer::SendSlaveDisconnectedEvent(
+ }
+ 
+ /* vim: set expandtab tabstop=4 shiftwidth=4: */
+-
 diff --git a/mythtv/programs/mythbackend/scheduler.cpp b/mythtv/programs/mythbackend/scheduler.cpp
-index 287b41b..9642eb4 100644
+index 287b41b..95ad05b 100644
 --- a/mythtv/programs/mythbackend/scheduler.cpp
 +++ b/mythtv/programs/mythbackend/scheduler.cpp
 @@ -306,12 +306,12 @@ static bool comp_recstart(RecordingInfo *a, RecordingInfo *b)
@@ -63316,11 +65260,132 @@ index 287b41b..9642eb4 100644
          {
              ++affinity;
              continue;
+@@ -4787,6 +4783,14 @@ int Scheduler::FillRecordingDir(
+ {
+     LOG(VB_SCHEDULE, LOG_INFO, LOC + "FillRecordingDir: Starting");
+ 
++    uint cnt = 0;
++    while (!m_mainServer)
++    {
++        if (cnt++ % 20 == 0)
++            LOG(VB_SCHEDULE, LOG_WARNING, "Waiting for main server.");
++        usleep(50000);
++    }
++
+     int fsID = -1;
+     MSqlQuery query(MSqlQuery::InitCon());
+     QMap<QString, FileSystemInfo>::Iterator fsit;
+diff --git a/mythtv/programs/mythbackend/services/capture.cpp b/mythtv/programs/mythbackend/services/capture.cpp
+index 7284e22..63506e5 100644
+--- a/mythtv/programs/mythbackend/services/capture.cpp
++++ b/mythtv/programs/mythbackend/services/capture.cpp
+@@ -295,7 +295,7 @@ int Capture::AddCardInput       ( const uint nCardId,
+     int nResult = CardUtil::CreateCardInput(nCardId, nSourceId, sInputName,
+                       sExternalCommand, sChangerDevice, sChangerModel,
+                       sHostName, sTuneChan, sStartChan, sDisplayName,
+-                      bDishnetEIT, nRecPriority, nQuicktune, nSchedOrder, 
++                      bDishnetEIT, nRecPriority, nQuicktune, nSchedOrder,
+                       nLiveTVOrder);
+ 
+     return nResult;
+@@ -310,4 +310,3 @@ bool Capture::UpdateCardInput    ( int              nCardInputId,
+ 
+     return set_on_input(sSetting, nCardInputId, sValue);
+ }
+-
+diff --git a/mythtv/programs/mythbackend/services/content.cpp b/mythtv/programs/mythbackend/services/content.cpp
+index e25affc..1f5cd1b 100644
+--- a/mythtv/programs/mythbackend/services/content.cpp
++++ b/mythtv/programs/mythbackend/services/content.cpp
+@@ -570,8 +570,8 @@ QFileInfo Content::GetPreviewImage(        int        nRecordedId,
+         if (!pginfo.IsLocal())
+             return QFileInfo();
+ 
+-        PreviewGenerator *previewgen = new PreviewGenerator( &pginfo, 
+-                                                             QString(), 
++        PreviewGenerator *previewgen = new PreviewGenerator( &pginfo,
++                                                             QString(),
+                                                              PreviewGenerator::kLocal);
+         previewgen->SetPreviewTimeAsSeconds( nSecsIn          );
+         previewgen->SetOutputFilename      ( sPreviewFileName );
+diff --git a/mythtv/programs/mythbackend/services/content.h b/mythtv/programs/mythbackend/services/content.h
+index 5321bc9..25a9661 100644
+--- a/mythtv/programs/mythbackend/services/content.h
++++ b/mythtv/programs/mythbackend/services/content.h
+@@ -263,5 +263,3 @@ class ScriptableContent : public QObject
+ Q_SCRIPT_DECLARE_QMETAOBJECT_MYTHTV( ScriptableContent, QObject*);
+ 
+ #endif
+-
+-
 diff --git a/mythtv/programs/mythbackend/services/dvr.cpp b/mythtv/programs/mythbackend/services/dvr.cpp
-index b699f29..3868136 100644
+index b699f29..605dd48 100644
 --- a/mythtv/programs/mythbackend/services/dvr.cpp
 +++ b/mythtv/programs/mythbackend/services/dvr.cpp
-@@ -270,6 +270,77 @@ bool Dvr::UpdateRecordedWatchedStatus ( int RecordedId,
+@@ -241,6 +241,62 @@ bool Dvr::UnDeleteRecording(int RecordedId,
+ //
+ /////////////////////////////////////////////////////////////////////////////
+ 
++bool Dvr::StopRecording(int RecordedId)
++{
++    if (RecordedId <= 0)
++        throw QString("Recorded ID is invalid.");
++
++    RecordingInfo ri = RecordingInfo(RecordedId);
++
++    if (ri.GetChanID())
++    {
++        QString cmd = QString("STOP_RECORDING %1 %2")
++                      .arg(ri.GetChanID())
++                      .arg(ri.GetRecordingStartTime(MythDate::ISODate));
++        MythEvent me(cmd);
++
++        gCoreContext->dispatch(me);
++        return true;
++    }
++    else
++        throw QString("RecordID %1 not found").arg(RecordedId);
++
++    return false;
++}
++
++/////////////////////////////////////////////////////////////////////////////
++//
++/////////////////////////////////////////////////////////////////////////////
++
++bool Dvr::ReactivateRecording(int RecordedId)
++{
++    if (RecordedId <= 0)
++        throw QString("Recorded ID is invalid.");
++
++    RecordingInfo ri = RecordingInfo(RecordedId);
++
++    ri.ReactivateRecording();
++
++    return true;
++}
++
++/////////////////////////////////////////////////////////////////////////////
++//
++/////////////////////////////////////////////////////////////////////////////
++
++bool Dvr::RescheduleRecordings(void)
++{
++    QString cmd = QString("RESCHEDULE_RECORDINGS");
++    MythEvent me(cmd);
++
++    gCoreContext->dispatch(me);
++    return true;
++}
++
++/////////////////////////////////////////////////////////////////////////////
++//
++/////////////////////////////////////////////////////////////////////////////
++
+ bool Dvr::UpdateRecordedWatchedStatus ( int RecordedId,
+                                         int   chanid,
+                                         const QDateTime &recstarttsRaw,
+@@ -270,6 +326,77 @@ bool Dvr::UpdateRecordedWatchedStatus ( int RecordedId,
  //
  /////////////////////////////////////////////////////////////////////////////
  
@@ -63342,9 +65407,9 @@ index b699f29..3868136 100644
 +    bool isend=true;
 +    uint64_t position = ri.QueryBookmark();
 +    if (offsettype.toLower() == "position"){
-+    	ri.QueryKeyFramePosition(&offset, position, isend);
-+    	return offset;
-+    } 
++        ri.QueryKeyFramePosition(&offset, position, isend);
++        return offset;
++    }
 +    else if (offsettype.toLower() == "duration"){
 +        ri.QueryKeyFrameDuration(&offset, position, isend);
 +        return offset;
@@ -63378,12 +65443,12 @@ index b699f29..3868136 100644
 +    uint64_t position;
 +    bool isend=true;
 +    if (offsettype.toLower() == "position"){
-+    	if (!ri.QueryPositionKeyFrame(&position, Offset, isend))
-+    		return false;
-+    } 
++        if (!ri.QueryPositionKeyFrame(&position, Offset, isend))
++                return false;
++    }
 +    else if (offsettype.toLower() == "duration"){
 +        if (!ri.QueryDurationKeyFrame(&position, Offset, isend))
-+        	return false;
++                return false;
 +    }
 +    else
 +        position = Offset;
@@ -63398,11 +65463,100 @@ index b699f29..3868136 100644
  DTC::CutList* Dvr::GetRecordedCutList ( int RecordedId,
                                          int chanid,
                                          const QDateTime &recstarttsRaw,
+@@ -336,6 +463,33 @@ DTC::CutList* Dvr::GetRecordedCommBreak ( int RecordedId,
+ //
+ /////////////////////////////////////////////////////////////////////////////
+ 
++DTC::CutList* Dvr::GetRecordedSeek ( int RecordedId,
++                                     const QString &offsettype )
++{
++    MarkTypes marktype;
++    if (RecordedId <= 0)
++        throw QString("Recorded ID appears invalid.");
++
++    RecordingInfo ri;
++    ri = RecordingInfo(RecordedId);
++
++    DTC::CutList* pCutList = new DTC::CutList();
++    if (offsettype == "BYTES")
++        marktype = MARK_GOP_BYFRAME;
++    else if (offsettype == "DURATION")
++        marktype = MARK_DURATION_MS;
++    else
++        throw QString("Type must be 'BYTES' or 'DURATION'.");
++
++    FillSeek(pCutList, &ri, marktype);
++
++    return pCutList;
++}
++
++/////////////////////////////////////////////////////////////////////////////
++//
++/////////////////////////////////////////////////////////////////////////////
++
+ DTC::ProgramList* Dvr::GetExpiringList( int nStartIndex,
+                                         int nCount      )
+ {
+@@ -399,7 +553,7 @@ DTC::EncoderList* Dvr::GetEncoderList()
+         if (elink != NULL)
+         {
+             DTC::Encoder *pEncoder = pList->AddNewEncoder();
+-            
++
+             pEncoder->setId            ( elink->GetInputID()      );
+             pEncoder->setState         ( elink->GetState()        );
+             pEncoder->setLocal         ( elink->IsLocal()         );
+@@ -691,7 +845,7 @@ DTC::ProgramList* Dvr::GetUpcomingList( int  nStartIndex,
+     pPrograms->setAsOf          ( MythDate::current() );
+     pPrograms->setVersion       ( MYTH_BINARY_VERSION );
+     pPrograms->setProtoVer      ( MYTH_PROTO_VERSION  );
+-    
++
+     return pPrograms;
+ }
+ 
+@@ -1161,7 +1315,7 @@ DTC::RecRuleList* Dvr::GetRecordScheduleList( int nStartIndex,
+         delete recList.back();
+         recList.pop_back();
+     }
+-    
++
+     return pRecRules;
+ }
+ 
+@@ -1258,6 +1412,16 @@ bool Dvr::DisableRecordSchedule( uint nRecordId )
+     return bResult;
+ }
+ 
++int Dvr::RecordedIdForPathname(const QString & pathname)
++{
++    uint recordedid;
++
++    if (!ProgramInfo::QueryRecordedIdFromPathname(pathname, recordedid))
++        return -1;
++
++    return recordedid;
++}
++
+ QString Dvr::RecStatusToString(int RecStatus)
+ {
+     RecStatus::Type type = static_cast<RecStatus::Type>(RecStatus);
 diff --git a/mythtv/programs/mythbackend/services/dvr.h b/mythtv/programs/mythbackend/services/dvr.h
-index 672d3ef..1d60856 100644
+index 672d3ef..ff28e5d 100644
 --- a/mythtv/programs/mythbackend/services/dvr.h
 +++ b/mythtv/programs/mythbackend/services/dvr.h
-@@ -75,6 +75,18 @@ class Dvr : public DvrServices
+@@ -70,11 +70,29 @@ class Dvr : public DvrServices
+                                                 int              ChanId,
+                                                 const QDateTime &StartTime );
+ 
++        bool              StopRecording       ( int              RecordedId );
++
++        bool              ReactivateRecording ( int              RecordedId );
++
++        bool              RescheduleRecordings( void );
++
+         bool              UpdateRecordedWatchedStatus ( int   RecordedId,
+                                                         int   ChanId,
                                                          const QDateTime &StartTime,
                                                          bool  Watched);
  
@@ -63421,6 +65575,155 @@ index 672d3ef..1d60856 100644
          DTC::CutList*     GetRecordedCutList  ( int              RecordedId,
                                                  int              ChanId,
                                                  const QDateTime &StartTime,
+@@ -85,6 +103,9 @@ class Dvr : public DvrServices
+                                                  const QDateTime &StartTime,
+                                                  const QString   &OffsetType );
+ 
++        DTC::CutList*     GetRecordedSeek      ( int              RecordedId,
++                                                 const QString   &OffsetType );
++
+         DTC::ProgramList* GetConflictList     ( int              StartIndex,
+                                                 int              Count,
+                                                 int              RecordId );
+@@ -219,6 +240,8 @@ class Dvr : public DvrServices
+ 
+         bool              DisableRecordSchedule( uint             RecordId   );
+ 
++        int               RecordedIdForPathname( const QString   &Filename );
++
+         QString           RecStatusToString    ( int              RecStatus );
+ 
+         QString           RecStatusToDescription ( int            RecStatus,
+diff --git a/mythtv/programs/mythbackend/services/guide.cpp b/mythtv/programs/mythbackend/services/guide.cpp
+index 1d4ce53..cd2e61e 100644
+--- a/mythtv/programs/mythbackend/services/guide.cpp
++++ b/mythtv/programs/mythbackend/services/guide.cpp
+@@ -51,7 +51,7 @@ DTC::ProgramGuide *Guide::GetProgramGuide( const QDateTime &rawStartTime ,
+                                            int              nChannelGroupId,
+                                            int              nStartIndex,
+                                            int              nCount)
+-{     
++{
+     if (!rawStartTime.isValid())
+         throw( "StartTime is invalid" );
+ 
+@@ -148,18 +148,18 @@ DTC::ProgramGuide *Guide::GetProgramGuide( const QDateTime &rawStartTime ,
+     pGuide->setStartTime    ( dtStartTime   );
+     pGuide->setEndTime      ( dtEndTime     );
+     pGuide->setDetails      ( bDetails      );
+-    
++
+     pGuide->setStartIndex    ( nStartIndex     );
+     pGuide->setCount         ( chanList.size() );
+     pGuide->setTotalAvailable( nTotalAvailable );
+     pGuide->setAsOf          ( MythDate::current() );
+-    
++
+     pGuide->setVersion      ( MYTH_BINARY_VERSION );
+     pGuide->setProtoVer     ( MYTH_PROTO_VERSION  );
+-    
++
+     return pGuide;
+ }
+- 
++
+ /////////////////////////////////////////////////////////////////////////////
+ //
+ /////////////////////////////////////////////////////////////////////////////
+@@ -330,7 +330,7 @@ DTC::ProgramList* Guide::GetProgramList(int              nStartIndex,
+ 
+ DTC::Program* Guide::GetProgramDetails( int              nChanId,
+                                         const QDateTime &rawStartTime )
+-                                          
++
+ {
+     if (!(nChanId > 0))
+         throw( "Channel ID is invalid" );
+@@ -525,4 +525,3 @@ QStringList Guide::GetStoredSearches( const QString& sType )
+ 
+     return keywordList;
+ }
+-
+diff --git a/mythtv/programs/mythbackend/services/guide.h b/mythtv/programs/mythbackend/services/guide.h
+index f2fdc55..d81331b 100644
+--- a/mythtv/programs/mythbackend/services/guide.h
++++ b/mythtv/programs/mythbackend/services/guide.h
+@@ -42,12 +42,12 @@ class Guide : public GuideServices
+     Q_OBJECT
+ 
+     public:
+-    
++
+         Q_INVOKABLE explicit Guide( QObject *parent = 0 ) {}
+ 
+     public:
+ 
+-        
++
+         DTC::ProgramGuide*  GetProgramGuide     ( const QDateTime &StartTime  ,
+                                                   const QDateTime &EndTime    ,
+                                                   bool             Details,
+@@ -89,10 +89,10 @@ class Guide : public GuideServices
+ // QObject actually return QObject* (not the user class *).  If the user class pointer
+ // is returned, the script engine treats it as a QVariant and doesn't create a
+ // javascript prototype wrapper for it.
+-// 
++//
+ // This class allows us to keep the rich return types in the main API class while
+ // offering the script engine a class it can work with.
+-// 
++//
+ // Only API Classes that return custom classes needs to implement these wrappers.
+ //
+ // We should continue to look for a cleaning solution to this problem.
+@@ -189,4 +189,4 @@ class ScriptableGuide : public QObject
+ 
+ Q_SCRIPT_DECLARE_QMETAOBJECT_MYTHTV( ScriptableGuide, QObject*);
+ 
+-#endif 
++#endif
+diff --git a/mythtv/programs/mythbackend/services/serviceUtil.cpp b/mythtv/programs/mythbackend/services/serviceUtil.cpp
+index b58285a..4962ce3 100644
+--- a/mythtv/programs/mythbackend/services/serviceUtil.cpp
++++ b/mythtv/programs/mythbackend/services/serviceUtil.cpp
+@@ -619,3 +619,25 @@ void FillCommBreak(DTC::CutList* pCutList, RecordingInfo* rInfo, int marktype)
+         }
+     }
+ }
++
++/////////////////////////////////////////////////////////////////////////////
++//
++/////////////////////////////////////////////////////////////////////////////
++
++void FillSeek(DTC::CutList* pCutList, RecordingInfo* rInfo, MarkTypes marktype)
++{
++    frm_pos_map_t markMap;
++    frm_pos_map_t::const_iterator it;
++
++    if (rInfo && rInfo->GetChanID())
++    {
++        rInfo->QueryPositionMap(markMap, marktype);
++
++        for (it = markMap.begin(); it != markMap.end(); ++it)
++        {
++            DTC::Cutting *pCutting = pCutList->AddNewCutting();
++            pCutting->setMark(it.key());
++            pCutting->setOffset(it.value());
++        }
++    }
++}
+diff --git a/mythtv/programs/mythbackend/services/serviceUtil.h b/mythtv/programs/mythbackend/services/serviceUtil.h
+index 4f9062f..88f1518 100644
+--- a/mythtv/programs/mythbackend/services/serviceUtil.h
++++ b/mythtv/programs/mythbackend/services/serviceUtil.h
+@@ -80,4 +80,7 @@ void FillCutList( DTC::CutList* pCutList, RecordingInfo* rInfo, int marktype);
+ 
+ void FillCommBreak( DTC::CutList* pCutList, RecordingInfo* rInfo, int marktype);
+ 
++void FillSeek(DTC::CutList* pCutList, RecordingInfo* rInfo, MarkTypes marktype);
++
++
+ #endif
 diff --git a/mythtv/programs/mythbackend/services/video.cpp b/mythtv/programs/mythbackend/services/video.cpp
 index 049c189..7f977c2 100644
 --- a/mythtv/programs/mythbackend/services/video.cpp
@@ -63442,6 +65745,20 @@ index 049c189..7f977c2 100644
      return true;
  }
  
+diff --git a/mythtv/programs/mythfilldatabase/xmltvparser.cpp b/mythtv/programs/mythfilldatabase/xmltvparser.cpp
+index 281da9c..62a3a13 100644
+--- a/mythtv/programs/mythfilldatabase/xmltvparser.cpp
++++ b/mythtv/programs/mythfilldatabase/xmltvparser.cpp
+@@ -545,7 +545,8 @@ ProgInfo *XMLTVParser::parseProgram(QDomElement &element)
+         pginfo->categoryType != ProgramInfo::kCategoryNone)
+         pginfo->category = myth_category_type_to_string(pginfo->categoryType);
+ 
+-    if (!pginfo->airdate)
++    if (!pginfo->airdate
++        && ProgramInfo::kCategorySeries != pginfo->categoryType)
+         pginfo->airdate = current_year;
+ 
+     /* Let's build ourself a programid */
 diff --git a/mythtv/programs/mythfrontend/galleryconfig.cpp b/mythtv/programs/mythfrontend/galleryconfig.cpp
 index 00c451e..45cdd79 100644
 --- a/mythtv/programs/mythfrontend/galleryconfig.cpp
@@ -63988,10 +66305,20 @@ index f07e4fe..b90d080 100644
                       OPENGL2_PAINTER);
      gc->addSelection(QCoreApplication::translate("(Common)", "OpenGL 1"),
 diff --git a/mythtv/programs/mythfrontend/main.cpp b/mythtv/programs/mythfrontend/main.cpp
-index f8d7dd1..62ba4b2 100644
+index f8d7dd1..4e6573b 100644
 --- a/mythtv/programs/mythfrontend/main.cpp
 +++ b/mythtv/programs/mythfrontend/main.cpp
-@@ -1473,6 +1473,8 @@ static void InitKeys(void)
+@@ -1154,7 +1154,8 @@ static int internal_play_media(const QString &mrl, const QString &plot,
+     if ((!checkFile.exists() && !mrl.startsWith("dvd:")
+          && !mrl.startsWith("bd:")
+          && !mrl.startsWith("myth:")
+-         && !mrl.startsWith("http://")))
++         && !mrl.startsWith("http://")
++         && !mrl.startsWith("https://")))
+     {
+         QString errorText = qApp->translate("(MythFrontendMain)",
+             "Failed to open \n '%1' in %2 \n"
+@@ -1473,6 +1474,8 @@ static void InitKeys(void)
           "Scroll image down"), "8");
       REG_KEY("Images", "RECENTER", QT_TRANSLATE_NOOP("MythControls",
           "Recenter image"), "5");
@@ -64000,7 +66327,7 @@ index f8d7dd1..62ba4b2 100644
  }
  
  static void ReloadKeys(void)
-@@ -1529,12 +1531,9 @@ static int internal_media_init()
+@@ -1529,12 +1532,9 @@ static int internal_media_init()
  {
      REG_MEDIAPLAYER("Internal", QT_TRANSLATE_NOOP("MythControls",
          "MythTV's native media player."), internal_play_media);
diff --git a/mythtv.spec b/mythtv.spec
index 3c7d48b..a0ab30b 100644
--- a/mythtv.spec
+++ b/mythtv.spec
@@ -61,7 +61,7 @@
 %define desktop_vendor RPMFusion
 
 # MythTV Version string -- preferably the output from git describe
-%define vers_string v0.28-52-ge6a60f7
+%define vers_string v28.0-72-g228b05b
 %define branch fixes/0.28
 
 # Git revision and branch ID
@@ -82,7 +82,7 @@ Version:        0.28
 %if "%{branch}" == "master"
 Release:        0.5.git.%{_gitrev}%{?dist}
 %else
-Release:        7%{?dist}
+Release:        8%{?dist}
 %endif
 
 # The primary license is GPLv2+, but bits are borrowed from a number of
@@ -1397,6 +1397,9 @@ fi
 
 
 %changelog
+* Wed Oct 19 2016 Richard Shaw <hobbes1069 at gmail.com> - 0.28-8
+- Update to lastest fixes/0.28 from git.
+ 
 * Sun Sep 11 2016 Sérgio Basto <sergio at serjux.com> - 0.28-7
 - Update to latest fixes/0.28, rfbz#4241
 


More information about the rpmfusion-commits mailing list