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

Richard Shaw hobbes1069 at rpmfusion.org
Sun Nov 27 18:51:30 CET 2016


commit b93bbd87f66154f5c725c9039a43c6479342c667
Author: Richard Shaw <hobbes1069 at gmail.com>
Date:   Sun Nov 27 11:51:22 2016 -0600

    Update to latest fixes/0.28 from git.
    
    - Add patch for libcec 4, fixes RFBZ#4345.

 ChangeLog               |  302 ++++++++++
 mythtv-0.28-fixes.patch | 1473 +++++++++++++++++++++++++++++++++++++++++++++--
 mythtv.spec             |    6 +-
 3 files changed, 1721 insertions(+), 60 deletions(-)
---
diff --git a/ChangeLog b/ChangeLog
index 53be816..dba2569 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,305 @@
+commit e9d0543d64fc21072fb1a0199ac2e24334169461
+Author: Karl Dietz <dekarl at mythtv.org>
+Date:   Wed Oct 19 12:50:26 2016 +0200
+
+    unbreak JW Player menu item (and three other) in the web frontend
+    
+    (cherry picked from commit d790d9a935a3b161f469272e4d8f898a84c9a302)
+
+commit 0a6ffc71a468048f89266ae1cd49620ddba5f256
+Author: Karl Dietz <dekarl at mythtv.org>
+Date:   Sat Sep 17 22:25:23 2016 +0200
+
+    let IPTV recorder recognize HTTPS urls
+    
+    Fixes #12820
+    
+    (cherry picked from commit 0a3945326e77f53f8091783be3e607d8c3b15a10)
+
+commit bf571d2b07a286df5419c857517dd8789c49fe27
+Author: Peter Bennett <pbennett at mythtv.org>
+Date:   Mon Nov 21 15:32:00 2016 -0500
+
+    Fix small memory leak caused by commit 89bc8e7
+    
+    Refs #12917
+    
+    (cherry picked from commit 169fc9b39c2b7ad94dcb02702796e6a9c9bbf012)
+
+commit a56e4ee5cf7f18598c76c644dec2d87d21c78702
+Author: Jean-Yves Avenard <jyavenard at mozilla.com>
+Date:   Tue Nov 22 21:50:08 2016 +1100
+
+    Bump ABI version.
+
+commit b75130d5181089e70dacad95b20a8d5723665e5b
+Author: Stuart Auchterlonie <stuarta at mythtv.org>
+Date:   Mon Nov 21 09:52:58 2016 +0000
+
+    Install mythframe.h, should fix build failures for plugins
+    
+    (cherry picked from commit ccd8131e8d24ba3d8e8dc7e883e8d12451cc9742)
+
+commit 55169b72b08b58e7c145f1556a55a77d785ace3b
+Author: Jean-Yves Avenard <jyavenard at mozilla.com>
+Date:   Mon Nov 21 16:12:01 2016 +1100
+
+    Make --delete act as an override and ignore global settings.
+    
+    Fixes #12845
+    
+    (cherry picked from commit d610830807cb0a05e170aa01ef67a273e08a2247)
+
+commit 5bf021a477e998267ee1ebd2f09c39b96962ebb2
+Author: Jean-Yves Avenard <jyavenard at mozilla.com>
+Date:   Mon Nov 21 14:50:25 2016 +1100
+
+    Fix RTjpeg transcoding.
+    
+    Fixes #12479
+    
+    (cherry picked from commit 86962abc626add3d7f2fbac8646c7d0194e4a8cb)
+
+commit f4dcd3aab0317dbd875eca8370419c7873d16f78
+Author: Jean-Yves Avenard <jyavenard at mozilla.com>
+Date:   Mon Nov 21 14:29:26 2016 +1100
+
+    Prevent out of bound access when invalid parameters are provided
+    
+    (cherry picked from commit 9232f657ca75dd6604e6b225ebdec21654bddfb3)
+
+commit 49ef81ea4c31dea3140fc3c0f69423660b2e5900
+Author: Jean-Yves Avenard <jyavenard at mozilla.com>
+Date:   Mon Nov 21 13:12:40 2016 +1100
+
+    Fixes transcoding when decoder doesn't ouput YUV420 frame.
+    
+    Fix #12479
+    
+    (cherry picked from commit cea674d6b6198f61d1bfed1c59ddf34ce99262e0)
+
+commit 825d528a6ec42103c600b8991613f4f6b3d19775
+Author: Jean-Yves Avenard <jyavenard at mozilla.com>
+Date:   Mon Nov 21 11:43:46 2016 +1100
+
+    Fix FIFO transcoding.
+    
+    There were two issues at play.
+    One that was a regression over 0.27, in that it was assumed the stride was identical to the width which is no longer true from 0.28
+    Second, if the file being transcoded changed resolution, the video output would have been corrupted.
+    
+    TODO: Handle codecs not returning a YUV420 frame.
+    
+    Fixes #12479
+    
+    (cherry picked from commit 97054767dd3f838ceb02998a69703c574cdb1eb3)
+
+commit f513db7548ba14ed52fda13fa1108b478dbf0c23
+Author: Jean-Yves Avenard <jyavenard at mozilla.com>
+Date:   Mon Nov 21 03:37:54 2016 +1100
+
+    Properly handle stride size when transcoding in fifo mode.
+    
+    Fixes #12479
+    
+    (cherry picked from commit 1d9033084562f24b7e0a4003dc05da6cea4c19f8)
+
+commit 261858dc9db063c84e0e462e5111c98c4a18a38e
+Author: Jean-Yves Avenard <jyavenard at mozilla.com>
+Date:   Mon Nov 21 00:36:16 2016 +1100
+
+    Properly handle stride size when transcoding.
+    
+    Fixes #12479
+    
+    (cherry picked from commit 5e3a9bf2ce9ffa3e46b5691340e0feaae8ffb5f7)
+
+commit 9028a7763b73872cfcc2d39288fb533fd0d554a7
+Author: Jean-Yves Avenard <jyavenard at mozilla.com>
+Date:   Sun Nov 20 23:21:13 2016 +1100
+
+    Only delete original recording if explictly set.
+    This is done by adding --delete (or -d) as argument.
+    Auto transcoding will continue to replace the original.
+    
+    Fixes #12845
+    
+    (cherry picked from commit b1d1d5aa7c348cf0a49b6efd4981e726960e4f03)
+
+commit efbedfb142ede80ee9d1e6e7ba6bce61e9998d31
+Author: Richard Hulme <peper03 at mythtv.org>
+Date:   Sat Nov 19 19:21:48 2016 +0100
+
+    Fix getting stuck in an infinite loop when undeleting a recording.
+    
+    Fixes #12518
+    (cherry picked from commit 86bd8a84e47a3ca183437d053a28764be26e5376)
+
+commit a55db54b9d938937adffbe2b09d7d68f0c1b063e
+Author: Jean-Yves Avenard <jyavenard at mozilla.com>
+Date:   Sat Nov 19 13:09:06 2016 +1100
+
+    Prevent potential out of bound memory access.
+    
+    (cherry picked from commit 4880fe2427c1c83b861c3158fe7899865093cba0)
+
+commit 1224d760d9901289836ae2c3fe18f4210ae2a6a7
+Author: Jean-Yves Avenard <jyavenard at mozilla.com>
+Date:   Sat Nov 19 14:53:10 2016 +1100
+
+    Prevent out of bound access when table is empty.
+    
+    Fixes #12928
+    
+    (cherry picked from commit faf254ffd5ff2ca170b9995966940c6ccbf48ce9)
+
+commit 2131fb291c49fc62cf8ac0c1b26c89193d2436dc
+Author: Stuart Auchterlonie <stuarta at mythtv.org>
+Date:   Tue Nov 15 22:02:47 2016 +0000
+
+    README update
+    
+    (cherry picked from commit 2550bdf6f268aa977985574aa2b547f366e4ba21)
+
+commit 43fcdd92737f70fcc1e45467c7ba78bcd0e5a9ab
+Author: Peter Bennett <pbennett at mythtv.org>
+Date:   Mon Nov 14 12:04:03 2016 -0500
+
+    Fix QT 5.6.1 seg fault in ~QNetworkConfiguration during exit from program.
+    
+    Make a copy of the QNetworkConfiguration in the QNetworkAccessManager object
+    in mythuiwebbrowser, in case the default QNetworkConfiguration object is
+    already deleted when the QNetworkAccessManager is deleted.
+    
+    Fixes #12917
+    
+    (cherry picked from commit 89bc8e7c2673ed6e4002ccffd1805bd6ea5ee5b2)
+
+commit 49b6e2e1dc99eda391bae2b3119d92ed4e1cabe6
+Author: Gregorio Gervasio <gregorio.gervasio at gmail.com>
+Date:   Mon Nov 14 11:56:47 2016 -0500
+
+    Add support for A53 captions.
+    
+    Refs #12893
+    
+    Signed-off-by: Peter Bennett <pbennett at mythtv.org>
+    (cherry picked from commit 59135e61f9c24ef2db30306afccc9cee1714d3d7)
+
+commit 1434df8592ad6bf1eae4fd2eb46955e0adedc8aa
+Author: Peter Bennett <pbennett at mythtv.org>
+Date:   Fri Nov 4 11:11:42 2016 -0400
+
+    Fix Artifacts that appear on VDPAU setups in Live TV.
+    
+    This problem was caused by commit 28fe92a (Fix Seg Fault due to OSD
+    painter being deleted while image loader threads are still using it)
+    
+    Leaving the OSD painter undeleted after the OSD has been reinitialized
+    results in artifacts displayed in the screen when the video has a
+    black image over the place where the initial Live TV OSD showed. This
+    only affect Live TV because only Live TV starts out with an OSD
+    display before the video starts running.
+    
+    Fix: Call Teardown on the osd painter when deleting the VDPAU
+    renderer. Leave the osd painter still allocated but ignoring
+    all requests, so that image loads in other threads do not crash.
+    
+    (cherry picked from commit e0d15446e7df50ec5f671a068a4e4392c54fe628)
+
+commit 2bb98e1749b4b0642076eae440a073b5649b88a6
+Author: Stuart Auchterlonie <stuarta at mythtv.org>
+Date:   Sun Sep 4 13:26:13 2016 +0100
+
+    Correctly identify Service Descriptor for UHD
+
+commit 7f8f1688e882cd0587097fe4867e20d8fa122cce
+Author: Peter Bennett <pbennett at mythtv.org>
+Date:   Sat Oct 22 12:16:00 2016 -0400
+
+    Frontend and backend changes to support music choice.
+    
+    Music choice channels from Comcast are mpeg2 video which internally
+    identifies as 30 fps but actually sends frames with intervals
+    5.939, 0.033, 0.033, repeat, ... This amounts to 3 frames at 30fps
+    every 6 seconds. These frames are never identified as key frames.
+    Tuning takes up to 8 seconds for these channels on CETON. This
+    stream breaks several MythTV timeouts, and causes havoc with the
+    audio-video synchronization routines. It causes the recorder to
+    report a great many 6 second gaps in the video and mark it as failed.
+    
+    Fix: Increase timeouts. Increase audio buffer size to allow up to
+    8 seconds to be buffered. In the backend allow recordings to start with a
+    non-key frame and set a high threshold for gaps in specific cases.
+    Change handling of video buffer waits so that audio data is not lost by
+    audio resets in music choice programs.
+    
+    Fixes #8096
+    
+    (cherry picked from commit 2a1ccc06a58af472bd3044bff81dc93c49c83885)
+
+commit 89e17dc0d65ca58cb3bcda4765c80986a00e4c71
+Author: Peter Bennett <pbennett at mythtv.org>
+Date:   Mon Oct 10 15:52:03 2016 -0400
+
+    Setup change to allow CETON users to set tuning timeout.
+    
+    The 3 second default tuning timeout is not enough. Many recordings
+    are marked as failed even though they are successful. Also allow
+    users who wish to watch music choice to set the timeout
+    sufficient for those slow to tune channels.
+    
+    Refs #8096
+    
+    (cherry picked from commit 2d24c4acbe858cc6eaa3dcb981d46b37b295f892)
+
+commit ed7df02899f3a8dbfe67566797168c2f9d9446ce
+Author: Peter Bennett <pbennett at mythtv.org>
+Date:   Mon Oct 10 15:49:01 2016 -0400
+
+    Fix Seg fault in OSD due to notification being displayed using a painter that is no longer valid.
+    
+    The OSD goes through all notifications in the notification center
+    and displays them. Each notification screen has a painter stored in
+    it. The painter will be invalid if the notification started being
+    displayed before the playback started or before an inputchanged
+    notification caused it to be deleted
+    
+    Exception Details:
+    1   in MythUIType::HandleMovementPulse at mythuitype.cpp:374
+    ...
+    3   in OSD::DrawDirect at osd.cpp:702
+    
+    Fix: Always update the painter to the latest one before painting
+    notifications.
+    
+    Refs #8096
+    
+    (cherry picked from commit 5b011ca7e7706efe15e21d6435be72429b50194f)
+
+commit c2c1465f474158492f7f7f77f7bf37f64afeb40f
+Author: Peter Bennett <pbennett at mythtv.org>
+Date:   Mon Oct 10 15:43:38 2016 -0400
+
+    Fix Seg Fault due to OSD painter being deleted while image loader threads are still using it.
+    
+    Image loading for the OSD uses ImageLoadThread and continues
+    loading while the video is playing. If the video playback
+    encounters an "InputChanged" situation it deletes the OSD and its
+    painter and re-creates it.  If the Image load is still running and
+    using the painter, it gets a Seg Fault calling a virtual function
+    using a corrupted object
+    
+    Exception Details:
+    1   in MythPainter::GetFormatImage at mythpainter.cpp:540
+    
+    Fix: Keep the old osd painter valid until either it changes again
+    or the OSD is deleted.
+    
+    Refs #8096
+    
+    (cherry picked from commit 28fe92a74d0cd903ad0c154fa3cd9a74019d1ca8)
+
 commit 228b05bd7a8103192957a9abfc0a5baa551e8ba6
 Author: Stuart Auchterlonie <stuarta at mythtv.org>
 Date:   Wed Oct 12 16:02:04 2016 +0100
diff --git a/mythtv-0.28-fixes.patch b/mythtv-0.28-fixes.patch
index 2ccdbd7..32f1662 100644
--- a/mythtv-0.28-fixes.patch
+++ b/mythtv-0.28-fixes.patch
@@ -3,25 +3,26 @@
  mythplugins/mythmusic/mythmusic/main.cpp           |    14 +-
  mythplugins/mythnews/mythnews/mythnews.cpp         |    22 +-
  .../mythzoneminder/mythzmserver/zmserver.cpp       |    20 +-
- mythtv/README                                      |     8 +-
+ mythtv/README                                      |    12 +-
  mythtv/bindings/python/MythTV/dataheap.py          |     1 +
  .../python/MythTV/wikiscripts/wikiscripts.py       |     4 +-
  mythtv/configure                                   |    34 +-
  mythtv/html/css/Status.css                         |    13 +
- mythtv/html/menu.qsp                               |     2 +-
+ mythtv/html/menu.qsp                               |    10 +-
  mythtv/i18n/mythfrontend_cs.qm                     |   Bin 599995 -> 726083 bytes
  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/audio/audiooutputbase.cpp      |    54 +-
+ mythtv/libs/libmyth/audio/audiooutputbase.h        |     7 +-
  mythtv/libs/libmyth/mythmediamonitor.cpp           |    29 +-
  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/libmythbase/mythversion.h              |     2 +-
  mythtv/libs/libmythmetadata/imagemanager.cpp       |     2 +-
  .../services/captureServices.h                     |     1 -
  .../services/channelServices.h                     |     1 -
@@ -31,37 +32,63 @@
  .../services/mythServices.h                        |     5 +-
  .../services/rttiServices.h                        |     5 +-
  .../services/videoServices.h                       |     1 -
- mythtv/libs/libmythtv/avformatdecoder.cpp          |    11 +
+ mythtv/libs/libmythtv/audioplayer.cpp              |     2 +-
+ mythtv/libs/libmythtv/avformatdecoder.cpp          |    35 +-
+ mythtv/libs/libmythtv/avformatdecoder.h            |     1 +
+ mythtv/libs/libmythtv/avformatwriter.cpp           |    18 +-
  .../libmythtv/channelscan/vboxchannelfetcher.cpp   |    30 +-
  .../libmythtv/channelscan/vboxchannelfetcher.h     |     1 +
+ mythtv/libs/libmythtv/decoderbase.cpp              |     2 +-
  mythtv/libs/libmythtv/eitfixup.cpp                 |    33 +-
  mythtv/libs/libmythtv/eitfixup.h                   |     4 +-
  mythtv/libs/libmythtv/eithelper.cpp                |     5 +
- mythtv/libs/libmythtv/mythplayer.cpp               |   162 +-
- mythtv/libs/libmythtv/mythplayer.h                 |     5 +
- mythtv/libs/libmythtv/osd.cpp                      |     9 +-
+ mythtv/libs/libmythtv/iptvtuningdata.h             |     4 +-
+ mythtv/libs/libmythtv/libmythtv.pro                |     2 +-
+ mythtv/libs/libmythtv/mpeg/dvbdescriptors.cpp      |     2 +
+ mythtv/libs/libmythtv/mpeg/dvbdescriptors.h        |     8 +-
+ mythtv/libs/libmythtv/mythavutil.cpp               |     4 +-
+ mythtv/libs/libmythtv/mythavutil.h                 |     9 +-
+ mythtv/libs/libmythtv/mythframe.h                  |     4 +-
+ mythtv/libs/libmythtv/mythplayer.cpp               |   197 +-
+ mythtv/libs/libmythtv/mythplayer.h                 |     8 +
+ mythtv/libs/libmythtv/osd.cpp                      |    12 +-
  mythtv/libs/libmythtv/osd.h                        |     1 +
  mythtv/libs/libmythtv/privatedecoder_omx.cpp       |     4 +-
+ .../libmythtv/recorders/NuppelVideoRecorder.cpp    |    55 +-
  mythtv/libs/libmythtv/recorders/asichannel.cpp     |     6 +-
  mythtv/libs/libmythtv/recorders/channelbase.cpp    |     7 +-
+ mythtv/libs/libmythtv/recorders/dtvrecorder.cpp    |    16 +-
+ mythtv/libs/libmythtv/recorders/dtvrecorder.h      |     4 +
  mythtv/libs/libmythtv/recorders/vboxutils.cpp      |    10 +-
  mythtv/libs/libmythtv/recorders/vboxutils.h        |     2 +-
+ mythtv/libs/libmythtv/ringbuffer.cpp               |     8 +-
  .../test/test_eitfixups/test_eitfixups.cpp         |    28 +
+ .../test/test_iptvrecorder/test_iptvrecorder.h     |     5 +
  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_d3d.cpp             |    13 +-
  mythtv/libs/libmythtv/videoout_omx.cpp             |   254 +-
  mythtv/libs/libmythtv/videoout_omx.h               |    11 +-
+ mythtv/libs/libmythtv/videoout_opengl.cpp          |    10 +-
+ mythtv/libs/libmythtv/videoout_vdpau.cpp           |    10 +-
+ mythtv/libs/libmythtv/videooutbase.cpp             |     4 +
+ mythtv/libs/libmythtv/videooutbase.h               |     2 +
+ mythtv/libs/libmythtv/videosource.cpp              |    35 +
+ mythtv/libs/libmythtv/videosource.h                |     5 +
  .../visualisations/videovisualcircles.cpp          |     2 +-
  mythtv/libs/libmythui/cecadapter.cpp               |    41 +-
  mythtv/libs/libmythui/libmythui.pro                |     4 +-
  mythtv/libs/libmythui/mythdialogbox.cpp            |    10 +
  mythtv/libs/libmythui/mythmainwindow.cpp           |     7 +
- mythtv/libs/libmythui/mythpainter_ogl.h            |     2 +-
+ mythtv/libs/libmythui/mythpainter_d3d9.h           |     1 +
+ mythtv/libs/libmythui/mythpainter_ogl.h            |     3 +-
+ mythtv/libs/libmythui/mythpainter_vdpau.h          |     1 +
  mythtv/libs/libmythui/mythrender_opengl.cpp        |     4 +-
  mythtv/libs/libmythui/mythrender_opengl.h          |     4 +
  mythtv/libs/libmythui/mythuibuttonlist.cpp         |     5 +-
+ mythtv/libs/libmythui/mythuiwebbrowser.cpp         |     5 +
  mythtv/libs/libmythui/screensaver-dbus.cpp         |     2 +-
  mythtv/libs/libmythupnp/httprequest.cpp            |   172 +-
  mythtv/libs/libmythupnp/httprequest.h              |    55 +-
@@ -96,11 +123,15 @@
  mythtv/programs/mythfrontend/globalsettings.cpp    |    12 +-
  mythtv/programs/mythfrontend/main.cpp              |    14 +-
  mythtv/programs/mythfrontend/mythfrontend.pro      |    24 +
+ mythtv/programs/mythfrontend/playbackboxhelper.cpp |     1 +
  mythtv/programs/mythfrontend/themechooser.cpp      |     2 +-
+ .../programs/mythtranscode/commandlineparser.cpp   |     4 +-
+ mythtv/programs/mythtranscode/main.cpp             |    12 +-
+ mythtv/programs/mythtranscode/transcode.cpp        |   177 +-
  mythtv/programs/mythtv-setup/importicons.cpp       |     6 +-
  mythtv/programs/mythtv-setup/mythtv-setup.pro      |    12 +
  mythtv/programs/mythwelcome/mythwelcome.pro        |    11 +
- 102 files changed, 31832 insertions(+), 19706 deletions(-)
+ 133 files changed, 32178 insertions(+), 19869 deletions(-)
 
 diff --git a/README.rst b/README.rst
 index 8b8014d..ec3fa1f 100644
@@ -284,10 +315,19 @@ index 6749a47..5511df2 100644
  
  ///////////////////////////////////////////////////////////////////////
 diff --git a/mythtv/README b/mythtv/README
-index 6fe1eee..448695c 100644
+index 6fe1eee..cc990dc 100644
 --- a/mythtv/README
 +++ b/mythtv/README
-@@ -60,18 +60,18 @@ keys.txt has a listing of all the various default key bindings.  All
+@@ -53,25 +53,25 @@ version 1.0.17.
+ 
+ See the UPGRADING file for information on upgrading between releases.
+ 
+-Compiling and setup instructions are all in the documentation in the docs/
+-subdir (or at http://www.mythtv.org/docs/ ) these days.  Read those carefully.
++Compiling and setup instructions are all in the wiki these day
++https://www.mythtv.org/wiki/MythTV-HOWTO
+ 
+ keys.txt has a listing of all the various default key bindings.  All
  keybindings can be changed via MythWeb.
  
  If you want to check out the theme format, and perhaps make your own,
@@ -481,9 +521,18 @@ index 43ede02..a50fca0 100644
  
    div.schedule a {
 diff --git a/mythtv/html/menu.qsp b/mythtv/html/menu.qsp
-index 5a2137f..48331c8 100644
+index 5a2137f..0839c5a 100644
 --- a/mythtv/html/menu.qsp
 +++ b/mythtv/html/menu.qsp
+@@ -29,7 +29,7 @@
+                 <li><a href='#' onClick="hideMainMenu();loadSetupPage('channeleditor')"><i18n>Channel Editor</i18n></a></li>
+               </ul>
+             </li>
+-            <li><a href='#' onClick="hideMainMenu();loadContent('/misc/placeholder.html')"><i18n>Recording Devices</i18n></a></li>
++            <li><a href='#' onClick="hideMainMenu();loadFrontendContent('/misc/placeholder.html')"><i18n>Recording Devices</i18n></a></li>
+             <li><a href='#' onClick="hideMainMenu();loadSetupPage('storagegroups')"><i18n>Storage Groups</i18n></a></li>
+             <li><a href='#' onClick="hideMainMenu();loadSetupPage('jobqueue')"><i18n>Job Queue</i18n></a></li>
+             <li><a href='#' onClick="hideMainMenu();loadSetupPage('systemevents')"><i18n>System Events</i18n></a></li>
 @@ -49,7 +49,7 @@
      <li><a href='#'><i18n>Information</i18n></a>
        <ul class="acitem collapsible">
@@ -493,6 +542,26 @@ index 5a2137f..48331c8 100644
          <li><a class='menuitem' href='#' onClick="hideMainMenu();loadMiscPage('viewlogs')"><i18n>View Logs</i18n></a></li>
        </ul>
      </li>
+@@ -85,8 +85,8 @@
+ %>
+         <li><a href='#'><i18n>Server Side Scripting</i18n></a>
+           <ul class="acitem">
+-            <li><a href='#' onClick="hideMainMenu();loadContent('/samples/serverside.qsp', '/samples/js/samples.js')"><i18n>Overview</i18n></a></li>
+-            <li><a href='#' onClick="hideMainMenu();loadContent('/samples/storagegroups.qsp', '/samples/js/samples.js')"><i18n>GetStorageGroups()</i18n></a></li>
++            <li><a href='#' onClick="hideMainMenu();loadFrontendContent('/samples/serverside.qsp', '/samples/js/samples.js')"><i18n>Overview</i18n></a></li>
++            <li><a href='#' onClick="hideMainMenu();loadFrontendContent('/samples/storagegroups.qsp', '/samples/js/samples.js')"><i18n>GetStorageGroups()</i18n></a></li>
+           </ul>
+         </li>
+ <%
+@@ -96,7 +96,7 @@
+     </li>
+     <li><a href='#'><i18n>3rd Party Software</i18n></a>
+       <ul class="acitem collapsible">
+-        <li><a class='menuitem' href='#' onClick="hideMainMenu();loadContent('/3rdParty/jwplayer.qsp')"><i18n>JW Player&trade;</i18n></a></li>
++        <li><a class='menuitem' href='#' onClick="hideMainMenu();loadFrontendContent('/3rdParty/jwplayer.qsp')"><i18n>JW Player&trade;</i18n></a></li>
+       </ul>
+     </li>
+   </ul>
 diff --git a/mythtv/i18n/mythfrontend_cs.qm b/mythtv/i18n/mythfrontend_cs.qm
 index 80dd5d1..a688c2c 100644
 Binary files a/mythtv/i18n/mythfrontend_cs.qm and b/mythtv/i18n/mythfrontend_cs.qm differ
@@ -61886,7 +61955,7 @@ index 94966b6..1903d37 100644
      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
+index 833dff6..a93b608 100644
 --- a/mythtv/libs/libmyth/audio/audiooutputbase.cpp
 +++ b/mythtv/libs/libmyth/audio/audiooutputbase.cpp
 @@ -24,6 +24,7 @@ using namespace std;
@@ -62006,11 +62075,30 @@ index 833dff6..4dcc49b 100644
                );
  
      return audiotime;
+@@ -1448,7 +1464,7 @@ bool AudioOutputBase::AddData(void *in_buffer, int in_len,
+ 
+     if (len > afree)
+     {
+-        VBAUDIOTS("Buffer is full, AddData returning false");
++        VBERROR("Buffer is full, AddData returning false");
+         return false; // would overflow
+     }
+ 
 diff --git a/mythtv/libs/libmyth/audio/audiooutputbase.h b/mythtv/libs/libmyth/audio/audiooutputbase.h
-index 6ed5b60..634823e 100644
+index 6ed5b60..e7fc7e4 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
+@@ -119,7 +119,8 @@ class AudioOutputBase : public AudioOutput, public MThread
+     static const uint kAudioSRCInputSize = 16384;
+ 
+     /// Audio Buffer Size -- should be divisible by 32,24,16,12,10,8,6,4,2..
+-    static const uint kAudioRingBufferSize   = 3072000u;
++    // In other words, divisible by 96.
++    static const uint kAudioRingBufferSize   = 10239936u;
+ 
+  protected:
+     // Following function must be called from subclass constructor
+@@ -201,6 +202,8 @@ class AudioOutputBase : public AudioOutput, public MThread
          QUALITY_HIGH     =  2,
      };
      int src_quality;
@@ -62019,7 +62107,7 @@ index 6ed5b60..634823e 100644
  
   private:
      bool SetupPassthrough(int codec, int codec_profile,
-@@ -219,7 +221,6 @@ class AudioOutputBase : public AudioOutput, public MThread
+@@ -219,7 +222,6 @@ class AudioOutputBase : public AudioOutput, public MThread
      FreeSurround              *upmixer;
  
      int source_channels;
@@ -62027,7 +62115,7 @@ index 6ed5b60..634823e 100644
      int source_bytes_per_frame;
      bool upmix_default;
      bool needs_upmix;
-@@ -265,7 +266,6 @@ class AudioOutputBase : public AudioOutput, public MThread
+@@ -265,7 +267,6 @@ class AudioOutputBase : public AudioOutput, public MThread
      QMutex killAudioLock;
  
      long current_seconds;
@@ -62443,6 +62531,19 @@ index a56c492..63a2905 100644
          " WHERE " + GetWhereClause(bindings));
      query.bindValues(bindings);
  
+diff --git a/mythtv/libs/libmythbase/mythversion.h b/mythtv/libs/libmythbase/mythversion.h
+index 024f09b..91c9b7f 100644
+--- a/mythtv/libs/libmythbase/mythversion.h
++++ b/mythtv/libs/libmythbase/mythversion.h
+@@ -12,7 +12,7 @@
+ /// Update this whenever the plug-in ABI changes.
+ /// Including changes in the libmythbase, libmyth, libmythtv, libmythav* and
+ /// libmythui class methods in exported headers.
+-#define MYTH_BINARY_VERSION "0.28.20160309-1"
++#define MYTH_BINARY_VERSION "0.28.20161120-1"
+ 
+ /** \brief Increment this whenever the MythTV network protocol changes.
+  *   Note that the token currently cannot contain spaces.
 diff --git a/mythtv/libs/libmythmetadata/imagemanager.cpp b/mythtv/libs/libmythmetadata/imagemanager.cpp
 index a9c802f..e0e72d9 100644
 --- a/mythtv/libs/libmythmetadata/imagemanager.cpp
@@ -62675,8 +62776,21 @@ index f2b5bd9..511b6ee 100644
  
  #endif
 -
+diff --git a/mythtv/libs/libmythtv/audioplayer.cpp b/mythtv/libs/libmythtv/audioplayer.cpp
+index d634209..01fdbbb 100644
+--- a/mythtv/libs/libmythtv/audioplayer.cpp
++++ b/mythtv/libs/libmythtv/audioplayer.cpp
+@@ -514,7 +514,7 @@ bool AudioPlayer::IsBufferAlmostFull(void)
+         othresh =  ((ototal>>1) + (ototal>>2));
+         if (ofill > othresh)
+             return true;
+-        return GetAudioBufferedTime() > 2000;
++        return GetAudioBufferedTime() > 8000;
+     }
+     return false;
+ }
 diff --git a/mythtv/libs/libmythtv/avformatdecoder.cpp b/mythtv/libs/libmythtv/avformatdecoder.cpp
-index fb7d793..218f68a 100644
+index fb7d793..a62cf59 100644
 --- a/mythtv/libs/libmythtv/avformatdecoder.cpp
 +++ b/mythtv/libs/libmythtv/avformatdecoder.cpp
 @@ -42,6 +42,8 @@ using namespace std;
@@ -62701,7 +62815,49 @@ index fb7d793..218f68a 100644
      return retval;
  }
  
-@@ -5325,6 +5333,9 @@ bool AvFormatDecoder::SetupAudioStream(void)
+@@ -2989,14 +2997,22 @@ void AvFormatDecoder::DecodeDTVCC(const uint8_t *buf, uint len, bool scte)
+     if (len < 2+(3*cc_count))
+         return;
+ 
++    DecodeCCx08(buf+2, cc_count*3, scte);
++}
++
++void AvFormatDecoder::DecodeCCx08(const uint8_t *buf, uint len, bool scte)
++{
++    if (len < 3)
++        return;
++
+     bool had_608 = false, had_708 = false;
+-    for (uint cur = 0; cur < cc_count; cur++)
++    for (uint cur = 0; cur + 3 < len; cur += 3)
+     {
+-        uint cc_code  = buf[2+(cur*3)];
++        uint cc_code  = buf[cur];
+         bool cc_valid = cc_code & 0x04;
+ 
+-        uint data1    = buf[3+(cur*3)];
+-        uint data2    = buf[4+(cur*3)];
++        uint data1    = buf[cur+1];
++        uint data2    = buf[cur+2];
+         uint data     = (data2 << 8) | data1;
+         uint cc_type  = cc_code & 0x03;
+         uint field;
+@@ -3669,6 +3685,14 @@ bool AvFormatDecoder::ProcessVideoFrame(AVStream *stream, AVFrame *mpa_pic)
+     for (uint i = 0; i < cc_len; i += ((cc_buf[i] & 0x1f) * 3) + 2)
+         DecodeDTVCC(cc_buf + i, cc_len - i, scte);
+ 
++    if (cc_len == 0) {
++        // look for A53 captions
++        AVFrameSideData *side_data = av_frame_get_side_data(mpa_pic, AV_FRAME_DATA_A53_CC);
++        if (side_data && (side_data->size > 0)) {
++            DecodeCCx08(side_data->data, side_data->size, false);
++        }
++    }
++
+     VideoFrame *picframe = (VideoFrame *)(mpa_pic->opaque);
+ 
+     if (FlagIsSet(kDecodeNoDecode))
+@@ -5325,6 +5349,9 @@ bool AvFormatDecoder::SetupAudioStream(void)
                              audioOut.codec_id, audioOut.sample_rate,
                              audioOut.do_passthru, audioOut.codec_profile);
      m_audio->ReinitAudio();
@@ -62711,6 +62867,64 @@ index fb7d793..218f68a 100644
  
      if (LCD *lcd = LCD::Get())
      {
+diff --git a/mythtv/libs/libmythtv/avformatdecoder.h b/mythtv/libs/libmythtv/avformatdecoder.h
+index 46e93d9..2a796b4 100644
+--- a/mythtv/libs/libmythtv/avformatdecoder.h
++++ b/mythtv/libs/libmythtv/avformatdecoder.h
+@@ -216,6 +216,7 @@ class AvFormatDecoder : public DecoderBase
+     friend int close_avf(URLContext *h);
+ 
+     void DecodeDTVCC(const uint8_t *buf, uint buf_size, bool scte);
++    void DecodeCCx08(const uint8_t *buf, uint buf_size, bool scte);
+     void InitByteContext(bool forceseek = false);
+     void InitVideoCodec(AVStream *stream, AVCodecContext *enc,
+                         bool selectedStream = false);
+diff --git a/mythtv/libs/libmythtv/avformatwriter.cpp b/mythtv/libs/libmythtv/avformatwriter.cpp
+index bfe197b..1aa17f7 100644
+--- a/mythtv/libs/libmythtv/avformatwriter.cpp
++++ b/mythtv/libs/libmythtv/avformatwriter.cpp
+@@ -24,6 +24,7 @@
+ //#include "NuppelVideoRecorder.h"
+ #include "avformatwriter.h"
+ #include "audiooutpututil.h"
++#include "mythavutil.h"
+ 
+ extern "C" {
+ #if HAVE_BIGENDIAN
+@@ -31,7 +32,6 @@ extern "C" {
+ #endif
+ #include "libavutil/opt.h"
+ #include "libavutil/samplefmt.h"
+-#include "libavutil/mem.h" // for av_free
+ }
+ 
+ #define LOC QString("AVFW(%1): ").arg(m_filename)
+@@ -235,24 +235,10 @@ bool AVFormatWriter::NextFrameIsKeyFrame(void)
+ 
+ int AVFormatWriter::WriteVideoFrame(VideoFrame *frame)
+ {
+-    //AVCodecContext *c = m_videoStream->codec;
+-
+-    uint8_t *planes[3];
+-    unsigned char *buf = frame->buf;
+     int framesEncoded = m_framesWritten + m_bufferedVideoFrameTimes.size();
+ 
+-    planes[0] = buf;
+-    planes[1] = planes[0] + frame->width * frame->height;
+-    planes[2] = planes[1] + (frame->width * frame->height) /
+-        4; // (pictureFormat == AV_PIX_FMT_YUV422P ? 2 : 4);
+-
+     av_frame_unref(m_picture);
+-    m_picture->data[0] = planes[0];
+-    m_picture->data[1] = planes[1];
+-    m_picture->data[2] = planes[2];
+-    m_picture->linesize[0] = frame->width;
+-    m_picture->linesize[1] = frame->width / 2;
+-    m_picture->linesize[2] = frame->width / 2;
++    AVPictureFill(reinterpret_cast<AVPicture*>(m_picture), frame);
+     m_picture->pts = framesEncoded + 1;
+ 
+     if ((framesEncoded % m_keyFrameDist) == 0)
 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
@@ -62777,6 +62991,19 @@ index 7f970f4..01a372f 100644
  
    protected:
      virtual void run(void); // QRunnable
+diff --git a/mythtv/libs/libmythtv/decoderbase.cpp b/mythtv/libs/libmythtv/decoderbase.cpp
+index 51b42dd..89cc826 100644
+--- a/mythtv/libs/libmythtv/decoderbase.cpp
++++ b/mythtv/libs/libmythtv/decoderbase.cpp
+@@ -508,7 +508,7 @@ bool DecoderBase::FindPosition(long long desired_value, bool search_adjusted,
+         QString(" --> \n\t\t\t[%1:%2(%3),%4:%5(%6)]")
+             .arg(lower_bound)
+             .arg(empty ? -1 : GetKey(m_positionMap[lower_bound]))
+-            .arg(m_positionMap[lower_bound].pos)
++            .arg(empty ? -1 : m_positionMap[lower_bound].pos)
+             .arg(upper_bound)
+             .arg(empty ? -1 : GetKey(m_positionMap[upper_bound]))
+             .arg(empty ? -1 : m_positionMap[upper_bound].pos));
 diff --git a/mythtv/libs/libmythtv/eitfixup.cpp b/mythtv/libs/libmythtv/eitfixup.cpp
 index 13fa264..6c664c9 100644
 --- a/mythtv/libs/libmythtv/eitfixup.cpp
@@ -62877,11 +63104,157 @@ index b0e493c..5b66988 100644
      fix[ 2301LL << 32 | 2U << 16] = EITFixUp::kFixUK | EITFixUp::kFixHTML;
      fix[ 2302LL << 32 | 2U << 16] = EITFixUp::kFixUK;
      fix[ 2303LL << 32 | 2U << 16] = EITFixUp::kFixUK;
+diff --git a/mythtv/libs/libmythtv/iptvtuningdata.h b/mythtv/libs/libmythtv/iptvtuningdata.h
+index 43b4456..c5a3c2e 100644
+--- a/mythtv/libs/libmythtv/iptvtuningdata.h
++++ b/mythtv/libs/libmythtv/iptvtuningdata.h
+@@ -209,9 +209,9 @@ class MTV_PUBLIC IPTVTuningData
+             m_protocol = IPTVTuningData::rtp;
+         else if (m_data_url.scheme() == "rtsp")
+             m_protocol = IPTVTuningData::rtsp;
+-        else if ((m_data_url.scheme() == "http") && IsHLSPlaylist())
++        else if (((m_data_url.scheme() == "http") || (m_data_url.scheme() == "https")) && IsHLSPlaylist())
+             m_protocol = IPTVTuningData::http_hls;
+-        else if (m_data_url.scheme() == "http")
++        else if ((m_data_url.scheme() == "http") || (m_data_url.scheme() == "https"))
+             m_protocol = IPTVTuningData::http_ts;
+         else
+             m_protocol = IPTVTuningData::inValid;
+diff --git a/mythtv/libs/libmythtv/libmythtv.pro b/mythtv/libs/libmythtv/libmythtv.pro
+index 4c72eab..5c29520 100644
+--- a/mythtv/libs/libmythtv/libmythtv.pro
++++ b/mythtv/libs/libmythtv/libmythtv.pro
+@@ -251,7 +251,7 @@ SOURCES += srtwriter.cpp
+ inc.path = $${PREFIX}/include/mythtv/
+ inc.files  = playgroup.h
+ inc.files += mythtvexp.h            metadataimagehelper.h
+-inc.files += mythavutil.h
++inc.files += mythavutil.h           mythframe.h
+ 
+ INSTALLS += inc
+ 
+diff --git a/mythtv/libs/libmythtv/mpeg/dvbdescriptors.cpp b/mythtv/libs/libmythtv/mpeg/dvbdescriptors.cpp
+index 4d75c95..b7cc2ec 100644
+--- a/mythtv/libs/libmythtv/mpeg/dvbdescriptors.cpp
++++ b/mythtv/libs/libmythtv/mpeg/dvbdescriptors.cpp
+@@ -510,6 +510,8 @@ QString ServiceDescriptorMapping::toString() const
+         str.append(" (Radio)");
+     else if (IsHDTV())
+         str.append(" (HDTV)");
++    else if (IsUHDTV())
++        str.append(" (UHDTV)");
+     else if (IsTeletext())
+         str.append(" (Teletext)");
+     else
+diff --git a/mythtv/libs/libmythtv/mpeg/dvbdescriptors.h b/mythtv/libs/libmythtv/mpeg/dvbdescriptors.h
+index 5a6fd55..f583f67 100644
+--- a/mythtv/libs/libmythtv/mpeg/dvbdescriptors.h
++++ b/mythtv/libs/libmythtv/mpeg/dvbdescriptors.h
+@@ -1467,6 +1467,7 @@ class ServiceDescriptorMapping
+         kServiceTypeAdvancedCodecSDDigitalTelevision       = 0x16,
+         kServiceTypeAdvancedCodecHDDigitalTelevision       = 0x19,
+         kServiceTypeAdvancedCodecFrameCompatiblePlanoStereoscopicHDTelevisionService = 0x1c,
++        kServiceTypeUltraHD                  = 0x1f,
+         kServiceTypeEchoStarTV1              = 0x91,
+         kServiceTypeEchoStarTV2              = 0x9a,
+         kServiceTypeEchoStarTV3              = 0xa4,
+@@ -1488,7 +1489,7 @@ class ServiceDescriptorMapping
+         return ((ServiceType() == kServiceTypeDigitalTelevision) ||
+                 (ServiceType() ==
+                  kServiceTypeAdvancedCodecSDDigitalTelevision) ||
+-                IsHDTV() ||
++                IsHDTV() || IsUHDTV() ||
+                 (ServiceType() == kServiceTypeEchoStarTV1) ||
+                 (ServiceType() == kServiceTypeEchoStarTV2) ||
+                 (ServiceType() == kServiceTypeEchoStarTV3) ||
+@@ -1515,6 +1516,11 @@ class ServiceDescriptorMapping
+             (ServiceType() == kServiceTypeAdvancedCodecHDDigitalTelevision) ||
+             (ServiceType() == kServiceTypeAdvancedCodecFrameCompatiblePlanoStereoscopicHDTelevisionService);
+     }
++    bool IsUHDTV(void) const
++    {
++        return
++            (ServiceType() == kServiceTypeUltraHD);
++    }
+     bool IsTeletext(void) const
+     {
+         return ServiceType() == kServiceTypeDataBroadcast;
+diff --git a/mythtv/libs/libmythtv/mythavutil.cpp b/mythtv/libs/libmythtv/mythavutil.cpp
+index 48d5c7e..afed323 100644
+--- a/mythtv/libs/libmythtv/mythavutil.cpp
++++ b/mythtv/libs/libmythtv/mythavutil.cpp
+@@ -17,7 +17,7 @@ extern "C" {
+ #include "libavfilter/buffersink.h"
+ }
+ 
+-static AVPixelFormat FrameTypeToPixelFormat(VideoFrameType type)
++AVPixelFormat FrameTypeToPixelFormat(VideoFrameType type)
+ {
+     switch (type)
+     {
+@@ -38,7 +38,7 @@ static AVPixelFormat FrameTypeToPixelFormat(VideoFrameType type)
+     }
+ }
+ 
+-static VideoFrameType PixelFormatToFrameType(AVPixelFormat fmt)
++VideoFrameType PixelFormatToFrameType(AVPixelFormat fmt)
+ {
+     switch (fmt)
+     {
+diff --git a/mythtv/libs/libmythtv/mythavutil.h b/mythtv/libs/libmythtv/mythavutil.h
+index ccda602..4a4d3a9 100644
+--- a/mythtv/libs/libmythtv/mythavutil.h
++++ b/mythtv/libs/libmythtv/mythavutil.h
+@@ -10,6 +10,7 @@
+ #define MythTV_mythavutil_h
+ 
+ #include "mythtvexp.h" // for MUNUSED
++#include "mythframe.h"
+ extern "C" {
+ #include "libavcodec/avcodec.h"
+ }
+@@ -78,7 +79,6 @@ private:
+     AVFrame *m_frame;
+ };
+ 
+-typedef struct VideoFrame_ VideoFrame;
+ class MythAVCopyPrivate;
+ 
+ /**
+@@ -128,6 +128,13 @@ int MTV_PUBLIC AVPictureFill(AVPicture *pic, const VideoFrame *frame,
+                              AVPixelFormat fmt = AV_PIX_FMT_NONE);
+ 
+ /**
++ * Convert VideoFrameType into FFmpeg's PixelFormat equivalent and
++ * vice-versa.
++ */
++MTV_PUBLIC AVPixelFormat FrameTypeToPixelFormat(VideoFrameType type);
++MTV_PUBLIC VideoFrameType PixelFormatToFrameType(AVPixelFormat fmt);
++
++/**
+  * MythPictureDeinterlacer
+  * simple deinterlacer based on FFmpeg's yadif filter.
+  * Yadif requires 3 frames before starting to return a deinterlaced frame.
+diff --git a/mythtv/libs/libmythtv/mythframe.h b/mythtv/libs/libmythtv/mythframe.h
+index 444b676..3d3ad3d 100644
+--- a/mythtv/libs/libmythtv/mythframe.h
++++ b/mythtv/libs/libmythtv/mythframe.h
+@@ -305,7 +305,9 @@ static inline uint buffersize(VideoFrameType type, int width, int height,
+     {
+         adj_w = (width  + _aligned - 1) & ~(_aligned - 1);
+     }
+-    return (adj_w * height * bpp + 4/* to round up */) / bpb;
++    // Calculate rounding as necessary.
++    uint remainder = (adj_w * height * bpp) % bpb;
++    return (adj_w * height * bpp) / bpb + (remainder ? 1 : 0);
+ }
+ 
+ static inline void copybuffer(VideoFrame *dst, uint8_t *buffer,
 diff --git a/mythtv/libs/libmythtv/mythplayer.cpp b/mythtv/libs/libmythtv/mythplayer.cpp
-index f953e11..23f70b4 100644
+index f953e11..3db086f 100644
 --- a/mythtv/libs/libmythtv/mythplayer.cpp
 +++ b/mythtv/libs/libmythtv/mythplayer.cpp
-@@ -211,6 +211,10 @@ MythPlayer::MythPlayer(PlayerFlags flags)
+@@ -211,17 +211,27 @@ MythPlayer::MythPlayer(PlayerFlags flags)
        refreshrate(0),
        lastsync(false),              repeat_delay(0),
        disp_timecode(0),             avsync_audiopaused(false),
@@ -62892,7 +63265,13 @@ index f953e11..23f70b4 100644
        // Time Code stuff
        prevtc(0),                    prevrp(0),
        savedAudioTimecodeOffset(0),
-@@ -222,6 +226,10 @@ MythPlayer::MythPlayer(PlayerFlags flags)
+       // LiveTVChain stuff
+       m_tv(NULL),                   isDummy(false),
++      // Counter for buffering messages
++      bufferingCounter(0),
+       // Debugging variables
+       output_jmeter(new Jitterometer(LOC)),
+       disable_passthrough(false)
  {
      memset(&tc_lastval, 0, sizeof(tc_lastval));
      memset(&tc_wrap,    0, sizeof(tc_wrap));
@@ -62903,7 +63282,7 @@ index f953e11..23f70b4 100644
  
      playerThread = QThread::currentThread();
  #ifdef Q_OS_ANDROID
-@@ -383,7 +391,7 @@ bool MythPlayer::Pause(void)
+@@ -383,7 +393,7 @@ bool MythPlayer::Pause(void)
  
  bool MythPlayer::Play(float speed, bool normal, bool unpauseaudio)
  {
@@ -62912,7 +63291,7 @@ index f953e11..23f70b4 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 +399,7 @@ bool MythPlayer::Play(float speed, bool normal, bool unpauseaudio)
+@@ -391,6 +401,7 @@ bool MythPlayer::Play(float speed, bool normal, bool unpauseaudio)
      if (deleteMap.IsEditing())
      {
          LOG(VB_GENERAL, LOG_ERR, LOC + "Ignoring Play(), in edit mode.");
@@ -62920,7 +63299,7 @@ index f953e11..23f70b4 100644
          return false;
      }
  
-@@ -403,6 +412,7 @@ bool MythPlayer::Play(float speed, bool normal, bool unpauseaudio)
+@@ -403,6 +414,7 @@ bool MythPlayer::Play(float speed, bool normal, bool unpauseaudio)
      allpaused = false;
      next_play_speed   = speed;
      next_normal_speed = normal;
@@ -62928,7 +63307,25 @@ index f953e11..23f70b4 100644
      return true;
  }
  
-@@ -949,7 +959,7 @@ int MythPlayer::OpenFile(uint retries)
+@@ -931,14 +943,15 @@ int MythPlayer::OpenFile(uint retries)
+     int testreadsize = 2048;
+ 
+     MythTimer bigTimer; bigTimer.start();
+-    int timeout = max((retries + 1) * 500, 15000U);
++    int timeout = max((retries + 1) * 500, 30000U);
+     while (testreadsize <= kDecoderProbeBufferSize)
+     {
+         MythTimer peekTimer; peekTimer.start();
+         while (player_ctx->buffer->Peek(testbuf, testreadsize) != testreadsize)
+         {
+             // NB need to allow for streams encountering network congestion
+-            if (peekTimer.elapsed() > 30000 || bigTimer.elapsed() > timeout)
++            if (peekTimer.elapsed() > 30000 || bigTimer.elapsed() > timeout
++                || player_ctx->buffer->GetStopReads())
+             {
+                 LOG(VB_GENERAL, LOG_ERR, LOC +
+                     QString("OpenFile(): Could not read first %1 bytes of '%2'")
+@@ -949,7 +962,7 @@ int MythPlayer::OpenFile(uint retries)
                  return -1;
              }
              LOG(VB_GENERAL, LOG_WARNING, LOC + "OpenFile() waiting on data");
@@ -62937,7 +63334,7 @@ index f953e11..23f70b4 100644
          }
  
          player_ctx->LockPlayingInfo(__FILE__, __LINE__);
-@@ -1385,7 +1395,10 @@ void MythPlayer::DisableCaptions(uint mode, bool osd_msg)
+@@ -1385,7 +1398,10 @@ void MythPlayer::DisableCaptions(uint mode, bool osd_msg)
  
      QMutexLocker locker(&osdLock);
  
@@ -62949,7 +63346,7 @@ index f953e11..23f70b4 100644
      QString msg = "";
      if (kDisplayNUVTeletextCaptions & mode)
          msg += tr("TXT CAP");
-@@ -1422,7 +1435,10 @@ void MythPlayer::DisableCaptions(uint mode, bool osd_msg)
+@@ -1422,7 +1438,10 @@ void MythPlayer::DisableCaptions(uint mode, bool osd_msg)
  void MythPlayer::EnableCaptions(uint mode, bool osd_msg)
  {
      QMutexLocker locker(&osdLock);
@@ -62961,7 +63358,7 @@ index f953e11..23f70b4 100644
      QString msg = "";
      if ((kDisplayCC608 & mode) || (kDisplayCC708 & mode) ||
          (kDisplayAVSubtitle & mode) || kDisplayRawTextSubtitle & mode)
-@@ -1492,7 +1508,9 @@ void MythPlayer::SetCaptionsEnabled(bool enable, bool osd_msg)
+@@ -1492,7 +1511,9 @@ void MythPlayer::SetCaptionsEnabled(bool enable, bool osd_msg)
      enableCaptions = disableCaptions = false;
      uint origMode = textDisplayMode;
  
@@ -62972,7 +63369,7 @@ index f953e11..23f70b4 100644
  
      if (!enable)
      {
-@@ -1772,6 +1790,7 @@ void MythPlayer::ResetAVSync(void)
+@@ -1772,6 +1793,7 @@ void MythPlayer::ResetAVSync(void)
      if (!avsync_predictor_enabled || avsync_predictor >= refreshrate)
          avsync_predictor = 0;
      prevtc = 0;
@@ -62980,7 +63377,7 @@ index f953e11..23f70b4 100644
      LOG(VB_PLAYBACK | VB_TIMESTAMP, LOG_INFO, LOC + "A/V sync reset");
  }
  
-@@ -1785,6 +1804,24 @@ void MythPlayer::InitAVSync(void)
+@@ -1785,6 +1807,24 @@ void MythPlayer::InitAVSync(void)
  
      refreshrate = MythDisplay::GetDisplayInfo(frame_interval).Rate();
  
@@ -63005,7 +63402,7 @@ index f953e11..23f70b4 100644
      if (!FlagIsSet(kVideoIsNull))
      {
          QString timing_type = videosync->getName();
-@@ -1813,8 +1850,6 @@ int64_t MythPlayer::AVSyncGetAudiotime(void)
+@@ -1813,8 +1853,6 @@ int64_t MythPlayer::AVSyncGetAudiotime(void)
      return currentaudiotime;
  }
  
@@ -63014,7 +63411,7 @@ index f953e11..23f70b4 100644
  void MythPlayer::AVSync(VideoFrame *buffer, bool limit_delay)
  {
      int repeat_pict  = 0;
-@@ -1840,18 +1875,25 @@ void MythPlayer::AVSync(VideoFrame *buffer, bool limit_delay)
+@@ -1840,18 +1878,25 @@ void MythPlayer::AVSync(VideoFrame *buffer, bool limit_delay)
          return;
      }
  
@@ -63044,7 +63441,7 @@ index f953e11..23f70b4 100644
      bool dropframe = false;
      QString dbg;
  
-@@ -1988,7 +2030,7 @@ void MythPlayer::AVSync(VideoFrame *buffer, bool limit_delay)
+@@ -1988,7 +2033,7 @@ void MythPlayer::AVSync(VideoFrame *buffer, bool limit_delay)
  
      avsync_adjustment = 0;
  
@@ -63053,7 +63450,7 @@ index f953e11..23f70b4 100644
      {
          // 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)
+@@ -2006,7 +2051,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 "
@@ -63063,7 +63460,7 @@ index f953e11..23f70b4 100644
                  .arg(currentaudiotime)
                  .arg(timecode)
                  .arg(frame_interval)
-@@ -2017,6 +2060,7 @@ void MythPlayer::AVSync(VideoFrame *buffer, bool limit_delay)
+@@ -2017,6 +2063,7 @@ void MythPlayer::AVSync(VideoFrame *buffer, bool limit_delay)
                  .arg(avsync_predictor)
                  .arg(avsync_predictor_enabled)
                  .arg(vsync_delay_clock)
@@ -63071,7 +63468,7 @@ index f953e11..23f70b4 100644
                   );
          if (currentaudiotime != 0 && timecode != 0)
          { // currentaudiotime == 0 after a seek
-@@ -2054,7 +2098,7 @@ void MythPlayer::AVSync(VideoFrame *buffer, bool limit_delay)
+@@ -2054,7 +2101,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;
@@ -63080,7 +63477,47 @@ index f953e11..23f70b4 100644
  
              int avsync_used = avsync_avg;
              if (labs(avsync_used) > labs(avsync_delay))
-@@ -2240,10 +2284,7 @@ void MythPlayer::DisplayNormalFrame(bool check_prebuffer)
+@@ -2171,17 +2218,34 @@ bool MythPlayer::PrebufferEnoughFrames(int min_buffers)
+         int last_msg = buffering_last_msg.msecsTo(QTime::currentTime());
+         if (last_msg > 100)
+         {
+-            LOG(VB_GENERAL, LOG_NOTICE, LOC +
+-                QString("Waited %1ms for video buffers %2")
+-                    .arg(waited_for).arg(videoOutput->GetFrameStatus()));
++            if (++bufferingCounter == 10)
++                LOG(VB_GENERAL, LOG_NOTICE, LOC +
++                    "To see more buffering messages use -v playback");
++            if (bufferingCounter >= 10)
++                LOG(VB_PLAYBACK, LOG_NOTICE, LOC +
++                    QString("Waited %1ms for video buffers %2")
++                    .arg(waited_for).arg(videoOutput->GetFrameStatus())); 
++            else
++                LOG(VB_GENERAL, LOG_NOTICE, LOC +
++                    QString("Waited %1ms for video buffers %2")
++                        .arg(waited_for).arg(videoOutput->GetFrameStatus()));
+             buffering_last_msg = QTime::currentTime();
+-            if (audio.IsBufferAlmostFull())
++            // music choice only sends a frame every 6 seconds
++            // so wait 7 seconds before doing this reset
++            if (waited_for > 7000 && audio.IsBufferAlmostFull())
+             {
+                 // We are likely to enter this condition
+                 // if the audio buffer was too full during GetFrame in AVFD
+-                LOG(VB_AUDIO, LOG_INFO, LOC + "Resetting audio buffer");
++                LOG(VB_GENERAL, LOG_NOTICE, LOC + "Resetting audio buffer");
+                 audio.Reset();
+             }
++            // Finish audio pause for sync after 1 second
++            // in case of infrequent video frames (e.g. music choice)
++            if (avsync_audiopaused && waited_for > 1000)
++            {
++                avsync_audiopaused = false;
++                audio.Pause(false);
++            }
+         }
+         if ((waited_for > 500) && !videoOutput->EnoughFreeFrames())
+         {
+@@ -2240,10 +2304,7 @@ void MythPlayer::DisplayNormalFrame(bool check_prebuffer)
          videoOutput->DoneDisplayingFrame(videoOutput->GetLastShownFrame());
  
      // retrieve the next frame
@@ -63092,7 +63529,7 @@ index f953e11..23f70b4 100644
      VideoFrame *frame = videoOutput->GetLastShownFrame();
  
      // Check aspect ratio
-@@ -2252,12 +2293,9 @@ void MythPlayer::DisplayNormalFrame(bool check_prebuffer)
+@@ -2252,12 +2313,9 @@ void MythPlayer::DisplayNormalFrame(bool check_prebuffer)
      // Player specific processing (dvd, bd, mheg etc)
      PreProcessNormalFrame();
  
@@ -63108,7 +63545,7 @@ index f953e11..23f70b4 100644
  
      FrameScanType ps = m_scan;
      if (kScan_Detect == m_scan || kScan_Ignore == m_scan)
-@@ -2265,9 +2303,7 @@ void MythPlayer::DisplayNormalFrame(bool check_prebuffer)
+@@ -2265,9 +2323,7 @@ void MythPlayer::DisplayNormalFrame(bool check_prebuffer)
  
      AVSync(frame, 0);
      // If PiP then keep this frame for MythPlayer::GetCurrentFrame
@@ -63119,7 +63556,7 @@ index f953e11..23f70b4 100644
          videoOutput->DoneDisplayingFrame(frame);
  }
  
-@@ -2277,12 +2313,10 @@ void MythPlayer::PreProcessNormalFrame(void)
+@@ -2277,12 +2333,10 @@ void MythPlayer::PreProcessNormalFrame(void)
      // handle Interactive TV
      if (GetInteractiveTV())
      {
@@ -63134,7 +63571,7 @@ index f953e11..23f70b4 100644
              InteractiveScreen *window =
                  (InteractiveScreen*)osd->GetWindow(OSD_WIN_INTERACT);
              if ((interactiveTV->ImageHasChanged() || !itvVisible) && window)
-@@ -2291,6 +2325,8 @@ void MythPlayer::PreProcessNormalFrame(void)
+@@ -2291,6 +2345,8 @@ void MythPlayer::PreProcessNormalFrame(void)
                  itvVisible = true;
              }
          }
@@ -63143,7 +63580,7 @@ index f953e11..23f70b4 100644
      }
  #endif // USING_MHEG
  }
-@@ -2388,6 +2424,7 @@ void MythPlayer::VideoStart(void)
+@@ -2388,6 +2444,7 @@ void MythPlayer::VideoStart(void)
  
      avsync_delay = 0;
      avsync_avg = 0;
@@ -63151,7 +63588,7 @@ index f953e11..23f70b4 100644
      refreshrate = 0;
      lastsync = false;
  
-@@ -2467,7 +2504,7 @@ bool MythPlayer::VideoLoop(void)
+@@ -2467,7 +2524,7 @@ bool MythPlayer::VideoLoop(void)
          DisplayPauseFrame();
      }
      else
@@ -63160,7 +63597,7 @@ index f953e11..23f70b4 100644
  
      if (FlagIsSet(kVideoIsNull) && decoder)
          decoder->UpdateFramesPlayed();
-@@ -2597,10 +2634,7 @@ void MythPlayer::SwitchToProgram(void)
+@@ -2597,10 +2654,7 @@ void MythPlayer::SwitchToProgram(void)
      ProgramInfo *pginfo = player_ctx->tvchain->GetSwitchProgram(
          discontinuity, newtype, newid);
      if (!pginfo)
@@ -63171,7 +63608,7 @@ index f953e11..23f70b4 100644
  
      bool newIsDummy = player_ctx->tvchain->GetInputType(newid) == "DUMMY";
  
-@@ -2735,10 +2769,7 @@ void MythPlayer::JumpToProgram(void)
+@@ -2735,10 +2789,7 @@ void MythPlayer::JumpToProgram(void)
      ProgramInfo *pginfo = player_ctx->tvchain->GetSwitchProgram(
          discontinuity, newtype, newid);
      if (!pginfo)
@@ -63182,7 +63619,7 @@ index f953e11..23f70b4 100644
  
      inJumpToProgramPause = true;
  
-@@ -2746,6 +2777,7 @@ void MythPlayer::JumpToProgram(void)
+@@ -2746,6 +2797,7 @@ void MythPlayer::JumpToProgram(void)
      SetPlayingInfo(*pginfo);
  
      Pause();
@@ -63190,7 +63627,15 @@ index f953e11..23f70b4 100644
      ResetCaptions();
      player_ctx->tvchain->SetProgram(*pginfo);
      player_ctx->buffer->Reset(true);
-@@ -2996,11 +3028,12 @@ void MythPlayer::EventLoop(void)
+@@ -2872,6 +2924,7 @@ bool MythPlayer::StartPlaying(void)
+     next_play_speed = audio.GetStretchFactor();
+     jumpchapter = 0;
+     commBreakMap.SkipCommercials(0);
++    bufferingCounter=0;
+ 
+     if (!InitVideo())
+     {
+@@ -2996,11 +3049,12 @@ void MythPlayer::EventLoop(void)
          JumpToProgram();
      }
      else if ((!allpaused || GetEof() != kEofStateNone) &&
@@ -63206,7 +63651,7 @@ index f953e11..23f70b4 100644
      }
  
      // Jump to the next program in livetv
-@@ -3201,35 +3234,36 @@ void MythPlayer::AudioEnd(void)
+@@ -3201,35 +3255,36 @@ void MythPlayer::AudioEnd(void)
  
  bool MythPlayer::PauseDecoder(void)
  {
@@ -63252,7 +63697,7 @@ index f953e11..23f70b4 100644
          return;
      }
  
-@@ -3237,14 +3271,15 @@ void MythPlayer::UnpauseDecoder(void)
+@@ -3237,14 +3292,15 @@ void MythPlayer::UnpauseDecoder(void)
      {
          int tries = 0;
          unpauseDecoder = true;
@@ -63270,7 +63715,7 @@ index f953e11..23f70b4 100644
  }
  
  void MythPlayer::DecoderStart(bool start_paused)
-@@ -3271,7 +3306,7 @@ void MythPlayer::DecoderEnd(void)
+@@ -3271,7 +3327,7 @@ void MythPlayer::DecoderEnd(void)
      SetPlaying(false);
      killdecoder = true;
      int tries = 0;
@@ -63279,7 +63724,7 @@ index f953e11..23f70b4 100644
          LOG(VB_PLAYBACK, LOG_INFO, LOC +
              "Waited 100ms for decoder loop to stop");
  
-@@ -3284,23 +3319,12 @@ void MythPlayer::DecoderEnd(void)
+@@ -3284,23 +3340,12 @@ void MythPlayer::DecoderEnd(void)
  
  void MythPlayer::DecoderPauseCheck(void)
  {
@@ -63309,7 +63754,7 @@ index f953e11..23f70b4 100644
  }
  
 diff --git a/mythtv/libs/libmythtv/mythplayer.h b/mythtv/libs/libmythtv/mythplayer.h
-index bfdac87..140c6a0 100644
+index bfdac87..3123a95 100644
 --- a/mythtv/libs/libmythtv/mythplayer.h
 +++ b/mythtv/libs/libmythtv/mythplayer.h
 @@ -826,6 +826,11 @@ class MTV_PUBLIC MythPlayer
@@ -63324,8 +63769,18 @@ index bfdac87..140c6a0 100644
  
      // Time Code stuff
      int        prevtc;        ///< 32 bit timecode if last VideoFrame shown
+@@ -838,6 +843,9 @@ class MTV_PUBLIC MythPlayer
+     TV *m_tv;
+     bool isDummy;
+ 
++    // Counter for buffering messages
++    int  bufferingCounter;
++
+     // Debugging variables
+     Jitterometer *output_jmeter;
+ 
 diff --git a/mythtv/libs/libmythtv/osd.cpp b/mythtv/libs/libmythtv/osd.cpp
-index df59b70..098cc00 100644
+index df59b70..abca78b 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)
@@ -63337,7 +63792,17 @@ index df59b70..098cc00 100644
      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)
+@@ -696,6 +696,9 @@ bool OSD::DrawDirect(MythPainter* painter, QSize size, bool repaint)
+             {
+                 OverrideUIScale(false);
+             }
++
++            (*it2)->SetPainter(m_CurrentPainter);
++
+             nc->UpdateScreen(*it2);
+ 
+             visible = true;
+@@ -704,6 +707,8 @@ bool OSD::DrawDirect(MythPainter* painter, QSize size, bool repaint)
              {
                  QTime expires = nc->ScreenExpiryTime(*it2).time();
                  int left = now.msecsTo(expires);
@@ -63346,7 +63811,7 @@ index df59b70..098cc00 100644
                  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)
+@@ -741,6 +746,11 @@ bool OSD::DrawDirect(MythPainter* painter, QSize size, bool repaint)
          painter->End();
      }
  
@@ -63386,6 +63851,132 @@ index a7ce174..b2999ad 100644
              ret = 0;
              break;
          }
+diff --git a/mythtv/libs/libmythtv/recorders/NuppelVideoRecorder.cpp b/mythtv/libs/libmythtv/recorders/NuppelVideoRecorder.cpp
+index 919f790..b1598a7 100644
+--- a/mythtv/libs/libmythtv/recorders/NuppelVideoRecorder.cpp
++++ b/mythtv/libs/libmythtv/recorders/NuppelVideoRecorder.cpp
+@@ -930,10 +930,9 @@ void NuppelVideoRecorder::InitBuffers(void)
+ 
+     if (!video_buffer_size)
+     {
+-        if (picture_format == AV_PIX_FMT_YUV422P)
+-            video_buffer_size = w_out * h_out * 2;
+-        else
+-            video_buffer_size = w_out * h_out * 3 / 2;
++        video_buffer_size =
++            buffersize(picture_format == AV_PIX_FMT_YUV422P ? FMT_YUV422P : FMT_YV12,
++                       w_out, h_out);
+     }
+ 
+     if (width >= 480 || height > 288)
+@@ -2878,19 +2877,15 @@ void NuppelVideoRecorder::WriteVideo(VideoFrame *frame, bool skipsync,
+     lzo_uint out_len = OUT_LEN;
+     struct rtframeheader frameheader;
+     int raw = 0, compressthis = compression;
+-    uint8_t *planes[3];
+-    int len = frame->size;
++    uint8_t *planes[3] = {
++        frame->buf + frame->offsets[0],
++        frame->buf + frame->offsets[1],
++        frame->buf + frame->offsets[2] };
+     int fnum = frame->frameNumber;
+     long long timecode = frame->timecode;
+-    unsigned char *buf = frame->buf;
+ 
+     memset(&frameheader, 0, sizeof(frameheader));
+ 
+-    planes[0] = buf;
+-    planes[1] = planes[0] + frame->width * frame->height;
+-    planes[2] = planes[1] + (frame->width * frame->height) /
+-                            (picture_format == AV_PIX_FMT_YUV422P ? 2 : 4);
+-
+     if (lf == 0)
+     {   // this will be triggered every new file
+         lf = fnum;
+@@ -2949,23 +2944,7 @@ void NuppelVideoRecorder::WriteVideo(VideoFrame *frame, bool skipsync,
+     if (useavcodec)
+     {
+         MythAVFrame mpa_picture;
+-
+-        switch (picture_format)
+-        {
+-            case AV_PIX_FMT_YUV420P:
+-            case AV_PIX_FMT_YUV422P:
+-            case AV_PIX_FMT_YUVJ420P:
+-                mpa_picture->linesize[0] = w_out;
+-                mpa_picture->linesize[1] = w_out / 2;
+-                mpa_picture->linesize[2] = w_out / 2;
+-                break;
+-        }
+-        mpa_picture->data[0] = planes[0];
+-        mpa_picture->data[1] = planes[1];
+-        mpa_picture->data[2] = planes[2];
+-        mpa_picture->linesize[0] = frame->width;
+-        mpa_picture->linesize[1] = frame->width / 2;
+-        mpa_picture->linesize[2] = frame->width / 2;
++        AVPictureFill(mpa_picture, frame);
+ 
+         if (wantkeyframe)
+             mpa_picture->pict_type = AV_PICTURE_TYPE_I;
+@@ -2977,7 +2956,7 @@ void NuppelVideoRecorder::WriteVideo(VideoFrame *frame, bool skipsync,
+             AVPacket packet;
+             av_init_packet(&packet);
+             packet.data = (uint8_t *)strm;
+-            packet.size = len;
++            packet.size = frame->size;
+ 
+             int got_packet = 0;
+ 
+@@ -3021,14 +3000,14 @@ void NuppelVideoRecorder::WriteVideo(VideoFrame *frame, bool skipsync,
+             tmp = rtjc->Compress(strm, planes);
+         }
+         else
+-            tmp = len;
++            tmp = frame->size;
+ 
+         // here is lzo compression afterwards
+         if (compressthis)
+         {
+             int r = 0;
+             if (raw)
+-                r = lzo1x_1_compress((unsigned char*)buf, len,
++                r = lzo1x_1_compress((unsigned char*)frame->buf, frame->size,
+                                      out, &out_len, wrkmem);
+             else
+                 r = lzo1x_1_compress((unsigned char *)strm, tmp, out,
+@@ -3052,16 +3031,16 @@ void NuppelVideoRecorder::WriteVideo(VideoFrame *frame, bool skipsync,
+         if (mpa_vidcodec->id == AV_CODEC_ID_RAWVIDEO)
+         {
+             frameheader.comptype = '0';
+-            frameheader.packetlength = len;
++            frameheader.packetlength = frame->size;
+             WriteFrameheader(&frameheader);
+-            ringBuffer->Write(buf, len);
++            ringBuffer->Write(frame->buf, frame->size);
+         }
+         else if (hardware_encode)
+         {
+             frameheader.comptype = '4';
+-            frameheader.packetlength = len;
++            frameheader.packetlength = frame->size;
+             WriteFrameheader(&frameheader);
+-            ringBuffer->Write(buf, len);
++            ringBuffer->Write(frame->buf, frame->size);
+         }
+         else
+         {
+@@ -3083,9 +3062,9 @@ void NuppelVideoRecorder::WriteVideo(VideoFrame *frame, bool skipsync,
+         else
+         {
+             frameheader.comptype  = '0'; // raw YUV420
+-            frameheader.packetlength = len;
++            frameheader.packetlength = frame->size;
+             WriteFrameheader(&frameheader);
+-            ringBuffer->Write(buf, len); // we write buf directly
++            ringBuffer->Write(frame->buf, frame->size); // we write buf directly
+         }
+     }
+     else
 diff --git a/mythtv/libs/libmythtv/recorders/asichannel.cpp b/mythtv/libs/libmythtv/recorders/asichannel.cpp
 index 6956b20..94cba8d 100644
 --- a/mythtv/libs/libmythtv/recorders/asichannel.cpp
@@ -63437,6 +64028,69 @@ index c629ec5..f10ae6a 100644
      {
          LOG(VB_GENERAL, LOG_ERR, loc + " " +
              QString("Channel is valid, but tuner is busy "
+diff --git a/mythtv/libs/libmythtv/recorders/dtvrecorder.cpp b/mythtv/libs/libmythtv/recorders/dtvrecorder.cpp
+index 7e60f1d..3f13aa5 100644
+--- a/mythtv/libs/libmythtv/recorders/dtvrecorder.cpp
++++ b/mythtv/libs/libmythtv/recorders/dtvrecorder.cpp
+@@ -88,7 +88,8 @@ DTVRecorder::DTVRecorder(TVRec *rec) :
+     _total_duration(0),
+     _td_base(0),
+     _td_tick_count(0),
+-    _td_tick_framerate(0)
++    _td_tick_framerate(0),
++    music_choice(false)
+ {
+     SetPositionMapType(MARK_GOP_BYFRAME);
+     _payload_buffer.reserve(TSPacket::kSize * (50 + 1));
+@@ -538,6 +539,14 @@ bool DTVRecorder::FindMPEG2Keyframes(const TSPacket* tspacket)
+                 int64_t dts = extract_timestamp(
+                     bufptr, bytes_left, kExtractPTS);
+                 HandleTimestamps(stream_id, pts, dts);
++                // Detect music choice program (very slow frame rate and audio)
++                if (_first_keyframe < 0
++                    &&  _ts_last[stream_id] - _ts_first[stream_id] > 3*90000)
++                {
++                    hasKeyFrame = true;
++                    music_choice = true;
++                    LOG(VB_GENERAL, LOG_INFO, LOC + "Music Choice program detected");
++                }
+             }
+         }
+     }
+@@ -636,6 +645,9 @@ void DTVRecorder::HandleTimestamps(int stream_id, int64_t pts, int64_t dts)
+         gap_threshold = 2*90000; // two seconds, compensate for GOP ordering
+     }
+ 
++    if (music_choice)
++        gap_threshold = 8*90000; // music choice uses frames every 6 seconds
++
+     if (_ts_last[stream_id] >= 0)
+     {
+         int64_t diff = ts - _ts_last[stream_id];
+@@ -649,7 +661,7 @@ void DTVRecorder::HandleTimestamps(int stream_id, int64_t pts, int64_t dts)
+         if (diff < 0)
+             diff = -diff;
+ 
+-        if (diff > gap_threshold)
++        if (diff > gap_threshold && _first_keyframe >= 0)
+         {
+             QMutexLocker locker(&statisticsLock);
+ 
+diff --git a/mythtv/libs/libmythtv/recorders/dtvrecorder.h b/mythtv/libs/libmythtv/recorders/dtvrecorder.h
+index e657722..51c81f5 100644
+--- a/mythtv/libs/libmythtv/recorders/dtvrecorder.h
++++ b/mythtv/libs/libmythtv/recorders/dtvrecorder.h
+@@ -195,6 +195,10 @@ class DTVRecorder :
+     uint64_t _td_tick_count;
+     FrameRate _td_tick_framerate;
+ 
++    // Music Choice
++    // Comcast Music Choice uses 3 frames every 6 seconds and no key frames
++    bool music_choice;
++
+     // constants
+     /// If the number of regular frames detected since the last
+     /// detected keyframe exceeds this value, then we begin marking
 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
@@ -63496,6 +64150,41 @@ index 3481837..676d643 100644
  
  class VBox
  {
+diff --git a/mythtv/libs/libmythtv/ringbuffer.cpp b/mythtv/libs/libmythtv/ringbuffer.cpp
+index 2ca7dd7..9316267 100644
+--- a/mythtv/libs/libmythtv/ringbuffer.cpp
++++ b/mythtv/libs/libmythtv/ringbuffer.cpp
+@@ -1297,10 +1297,10 @@ int RingBuffer::Peek(void *buf, int count)
+ 
+ bool RingBuffer::WaitForReadsAllowed(void)
+ {
+-    // Wait up to 10000 ms for reads allowed (or readsdesired if post seek/open)
++    // Wait up to 30000 ms for reads allowed (or readsdesired if post seek/open)
+     bool &check = (recentseek || readInternalMode) ? readsdesired : readsallowed;
+     recentseek = false;
+-    int timeout_ms = 10000;
++    int timeout_ms = 30000;
+     int count = 0;
+     MythTimer t;
+     t.start();
+@@ -1309,7 +1309,7 @@ bool RingBuffer::WaitForReadsAllowed(void)
+            !request_pause && !commserror && readaheadrunning)
+     {
+         generalWait.wait(&rwlock, clamp(timeout_ms - t.elapsed(), 10, 100));
+-        if (!check && t.elapsed() > 1000 && (count % 10) == 0)
++        if (!check && t.elapsed() > 1000 && (count % 100) == 0)
+         {
+             LOG(VB_GENERAL, LOG_WARNING, LOC +
+                 "Taking too long to be allowed to read..");
+@@ -1517,7 +1517,7 @@ int RingBuffer::ReadPriv(void *buf, int count, bool peek)
+         if (avail > 0)
+             break;
+     }
+-    if (t.elapsed() > 2000)
++    if (t.elapsed() > 6000)
+     {
+         LOG(VB_GENERAL, LOG_WARNING, LOC + loc_desc +
+             QString(" -- waited %1 ms for avail(%2) > count(%3)")
 diff --git a/mythtv/libs/libmythtv/test/test_eitfixups/test_eitfixups.cpp b/mythtv/libs/libmythtv/test/test_eitfixups/test_eitfixups.cpp
 index 77f85e1..80b7d1d 100644
 --- a/mythtv/libs/libmythtv/test/test_eitfixups/test_eitfixups.cpp
@@ -63535,6 +64224,22 @@ index 77f85e1..80b7d1d 100644
  }
  
  void TestEITFixups::testUnitymedia()
+diff --git a/mythtv/libs/libmythtv/test/test_iptvrecorder/test_iptvrecorder.h b/mythtv/libs/libmythtv/test/test_iptvrecorder/test_iptvrecorder.h
+index c2bd423..c3d8709 100644
+--- a/mythtv/libs/libmythtv/test/test_iptvrecorder/test_iptvrecorder.h
++++ b/mythtv/libs/libmythtv/test/test_iptvrecorder/test_iptvrecorder.h
+@@ -67,6 +67,11 @@ class TestIPTVRecorder: public QObject
+         tuning.SetDataURL(QUrl(QString("http://yourdreambox:8001/1:0:1:488:3FE:22F1:EEEE0000:0:0:0:")));
+         QVERIFY (tuning.IsValid());
+         QVERIFY (tuning.IsHTTPTS());
++
++        /* test url from #12820 with https protocol */
++        tuning.SetDataURL(QUrl(QString("https://svt10-lh.akamaihd.net/i/svt10_0@77505/master.m3u8")));
++        QVERIFY (tuning.IsValid());
++        QVERIFY (tuning.IsHTTPTS());
+     }
+ 
+ 
 diff --git a/mythtv/libs/libmythtv/tv_play.cpp b/mythtv/libs/libmythtv/tv_play.cpp
 index 9b9511b..f397506 100644
 --- a/mythtv/libs/libmythtv/tv_play.cpp
@@ -63670,6 +64375,30 @@ index 61119bb..c148861 100644
  
      static QStringList GetVideoRenderers(const QString &decoder);
      static QString     GetVideoRendererHelp(const QString &renderer);
+diff --git a/mythtv/libs/libmythtv/videoout_d3d.cpp b/mythtv/libs/libmythtv/videoout_d3d.cpp
+index 983bcd9..f8af475 100644
+--- a/mythtv/libs/libmythtv/videoout_d3d.cpp
++++ b/mythtv/libs/libmythtv/videoout_d3d.cpp
+@@ -81,8 +81,17 @@ void VideoOutputD3D::TearDown(void)
+         m_pauseFrame.buf = NULL;
+     }
+ 
+-    delete m_osd_painter;
+-    m_osd_painter = NULL;
++    if (m_osd_painter)
++    {
++        // Hack to ensure that the osd painter is not
++        // deleted while image load thread is still busy
++        // loading images with that painter
++        m_osd_painter->Teardown();
++        if (invalid_osd_painter)
++            delete invalid_osd_painter;
++        invalid_osd_painter = m_osd_painter;
++        m_osd_painter = NULL;
++    }
+ 
+     DeleteDecoder();
+     DestroyContext();
 diff --git a/mythtv/libs/libmythtv/videoout_omx.cpp b/mythtv/libs/libmythtv/videoout_omx.cpp
 index 1b90ceb..3c5c448 100644
 --- a/mythtv/libs/libmythtv/videoout_omx.cpp
@@ -64098,6 +64827,164 @@ index 4760377..fb162d1 100644
  };
  
  #endif // ndef VIDEOOUT_OMX_H
+diff --git a/mythtv/libs/libmythtv/videoout_opengl.cpp b/mythtv/libs/libmythtv/videoout_opengl.cpp
+index 5621e31..7a13935 100644
+--- a/mythtv/libs/libmythtv/videoout_opengl.cpp
++++ b/mythtv/libs/libmythtv/videoout_opengl.cpp
+@@ -152,7 +152,15 @@ void VideoOutputOpenGL::DestroyGPUResources(void)
+ #endif
+ 
+     if (gl_created_painter)
+-        delete gl_painter;
++    {
++        // Hack to ensure that the osd painter is not
++        // deleted while image load thread is still busy
++        // loading images with that painter
++        gl_painter->Teardown();
++        if (invalid_osd_painter)
++            delete invalid_osd_painter;
++        invalid_osd_painter = gl_painter;
++    }
+     else if (gl_painter)
+         gl_painter->SetSwapControl(true);
+ 
+diff --git a/mythtv/libs/libmythtv/videoout_vdpau.cpp b/mythtv/libs/libmythtv/videoout_vdpau.cpp
+index 3eb6398..3b2153e 100644
+--- a/mythtv/libs/libmythtv/videoout_vdpau.cpp
++++ b/mythtv/libs/libmythtv/videoout_vdpau.cpp
+@@ -158,7 +158,15 @@ void VideoOutputVDPAU::DeleteRender(void)
+     QMutexLocker locker(&m_lock);
+ 
+     if (m_osd_painter)
+-        delete m_osd_painter;
++    {
++        // Hack to ensure that the osd painter is not
++        // deleted while image load thread is still busy
++        // loading images with that painter
++        m_osd_painter->Teardown();
++        if (invalid_osd_painter)
++            delete invalid_osd_painter;
++        invalid_osd_painter = m_osd_painter;
++    }
+ 
+     if (m_render)
+     {
+diff --git a/mythtv/libs/libmythtv/videooutbase.cpp b/mythtv/libs/libmythtv/videooutbase.cpp
+index 5d60efe..6ddbbaa 100644
+--- a/mythtv/libs/libmythtv/videooutbase.cpp
++++ b/mythtv/libs/libmythtv/videooutbase.cpp
+@@ -427,6 +427,7 @@ VideoOutput::VideoOutput() :
+ 
+     // OSD
+     osd_painter(NULL),                  osd_image(NULL),
++    invalid_osd_painter(0),
+ 
+     // Visualisation
+     m_visual(NULL),
+@@ -459,6 +460,9 @@ VideoOutput::~VideoOutput()
+         osd_image->DecrRef();
+     if (osd_painter)
+         delete osd_painter;
++    if (invalid_osd_painter)
++        delete invalid_osd_painter;
++    invalid_osd_painter = 0;
+ 
+     ShutdownPipResize();
+ 
+diff --git a/mythtv/libs/libmythtv/videooutbase.h b/mythtv/libs/libmythtv/videooutbase.h
+index c8ca444..afc7abf 100644
+--- a/mythtv/libs/libmythtv/videooutbase.h
++++ b/mythtv/libs/libmythtv/videooutbase.h
+@@ -355,6 +355,8 @@ class VideoOutput
+     // OSD painter and surface
+     MythYUVAPainter *osd_painter;
+     MythImage       *osd_image;
++    // Hack to ensure osd painter not deleted to soon
++    MythPainter     *invalid_osd_painter;
+ 
+     // Visualisation
+     VideoVisual     *m_visual;
+diff --git a/mythtv/libs/libmythtv/videosource.cpp b/mythtv/libs/libmythtv/videosource.cpp
+index fd2d496..97618ad 100644
+--- a/mythtv/libs/libmythtv/videosource.cpp
++++ b/mythtv/libs/libmythtv/videosource.cpp
+@@ -2415,6 +2415,25 @@ void CetonDeviceID::UpdateValues(void)
+         emit LoadedInstances((int)_parent.GetInstanceCount());
+ }
+ 
++class CetonExtra : public ConfigurationWizard
++{
++  public:
++    CetonExtra(CetonConfigurationGroup &parent);
++};
++
++CetonExtra::CetonExtra(CetonConfigurationGroup &parent)
++{
++    VerticalConfigurationGroup* rec = new VerticalConfigurationGroup(false);
++    rec->setLabel(QObject::tr("Recorder Options"));
++    rec->setUseLabel(false);
++
++    rec->addChild(new SignalTimeout(parent.parent, 1000, 250));
++    rec->addChild(new ChannelTimeout(parent.parent, 3000, 1750));
++
++    addChild(rec);
++}
++
++
+ CetonConfigurationGroup::CetonConfigurationGroup(CaptureCard& a_parent) :
+     VerticalConfigurationGroup(false, true, false, false),
+     parent(a_parent), instances(new InstanceCount(parent))
+@@ -2437,6 +2456,10 @@ CetonConfigurationGroup::CetonConfigurationGroup(CaptureCard& a_parent) :
+     addChild(desc);
+     addChild(instances);
+ 
++    TransButtonSetting *buttonRecOpt = new TransButtonSetting();
++    buttonRecOpt->setLabel(tr("Recording Options"));
++    addChild(buttonRecOpt);
++
+     connect(ip,       SIGNAL(NewValue(const QString&)),
+             deviceid, SLOT(  SetIP(const QString&)));
+     connect(tuner,    SIGNAL(NewValue(const QString&)),
+@@ -2451,8 +2474,20 @@ CetonConfigurationGroup::CetonConfigurationGroup(CaptureCard& a_parent) :
+     connect(instances, SIGNAL(valueChanged(int)),
+             &parent,   SLOT(  SetInstanceCount(int)));
+ 
++    connect(buttonRecOpt, SIGNAL(pressed()),
++            this,         SLOT(  CetonExtraPanel()));
++
+ };
+ 
++void CetonConfigurationGroup::CetonExtraPanel(void)
++{
++    parent.reload(); // ensure card id is valid
++
++    CetonExtra acw(*this);
++    acw.exec();
++}
++
++
+ V4LConfigurationGroup::V4LConfigurationGroup(CaptureCard& a_parent) :
+     VerticalConfigurationGroup(false, true, false, false),
+     parent(a_parent),
+diff --git a/mythtv/libs/libmythtv/videosource.h b/mythtv/libs/libmythtv/videosource.h
+index b97e9c8..8bd135f 100644
+--- a/mythtv/libs/libmythtv/videosource.h
++++ b/mythtv/libs/libmythtv/videosource.h
+@@ -463,9 +463,14 @@ class CetonConfigurationGroup : public VerticalConfigurationGroup
+ {
+     Q_OBJECT
+ 
++    friend class CetonExtra;
++
+   public:
+     CetonConfigurationGroup(CaptureCard &parent);
+ 
++  public slots:
++    void CetonExtraPanel(void);
++
+   private:
+     CaptureCard         &parent;
+     TransLabelSetting   *desc;
 diff --git a/mythtv/libs/libmythtv/visualisations/videovisualcircles.cpp b/mythtv/libs/libmythtv/visualisations/videovisualcircles.cpp
 index 1140372..e9cbf8f 100644
 --- a/mythtv/libs/libmythtv/visualisations/videovisualcircles.cpp
@@ -64288,11 +65175,31 @@ index 56b8dfb..8a903c6 100644
      }
      else if ((MythEvent::Type)(ce->type()) == MythEvent::MythUserMessage)
      {
+diff --git a/mythtv/libs/libmythui/mythpainter_d3d9.h b/mythtv/libs/libmythui/mythpainter_d3d9.h
+index d548ed4..52f458c 100644
+--- a/mythtv/libs/libmythui/mythpainter_d3d9.h
++++ b/mythtv/libs/libmythui/mythpainter_d3d9.h
+@@ -12,6 +12,7 @@ class MythRenderD3D9;
+ 
+ class MUI_PUBLIC MythD3D9Painter : public MythPainter
+ {
++    friend class VideoOutputD3D;
+   public:
+     explicit MythD3D9Painter(MythRenderD3D9 *render = NULL);
+    ~MythD3D9Painter();
 diff --git a/mythtv/libs/libmythui/mythpainter_ogl.h b/mythtv/libs/libmythui/mythpainter_ogl.h
-index 629dca7..13af273 100644
+index 629dca7..2ae8ee0 100644
 --- a/mythtv/libs/libmythui/mythpainter_ogl.h
 +++ b/mythtv/libs/libmythui/mythpainter_ogl.h
-@@ -37,13 +37,13 @@ class MUI_PUBLIC MythOpenGLPainter : public MythPainter
+@@ -13,6 +13,7 @@ class MythRenderOpenGL;
+ 
+ class MUI_PUBLIC MythOpenGLPainter : public MythPainter
+ {
++    friend class VideoOutputOpenGL;
+   public:
+     MythOpenGLPainter(MythRenderOpenGL *render =  NULL, QWidget *parent = NULL);
+    ~MythOpenGLPainter();
+@@ -37,13 +38,13 @@ class MUI_PUBLIC MythOpenGLPainter : public MythPainter
  
      virtual void PushTransformation(const UIEffects &fx, QPointF center = QPointF());
      virtual void PopTransformation(void);
@@ -64307,6 +65214,18 @@ index 629dca7..13af273 100644
      int        GetTextureFromCache(MythImage *im);
  
      QWidget          *realParent;
+diff --git a/mythtv/libs/libmythui/mythpainter_vdpau.h b/mythtv/libs/libmythui/mythpainter_vdpau.h
+index dd64ffe..238f47f 100644
+--- a/mythtv/libs/libmythui/mythpainter_vdpau.h
++++ b/mythtv/libs/libmythui/mythpainter_vdpau.h
+@@ -12,6 +12,7 @@ class MythRenderVDPAU;
+ 
+ class MUI_PUBLIC MythVDPAUPainter : public MythPainter
+ {
++    friend class VideoOutputVDPAU;
+   public:
+     explicit MythVDPAUPainter(MythRenderVDPAU *render = NULL);
+    ~MythVDPAUPainter();
 diff --git a/mythtv/libs/libmythui/mythrender_opengl.cpp b/mythtv/libs/libmythui/mythrender_opengl.cpp
 index 8884190..b376008 100644
 --- a/mythtv/libs/libmythui/mythrender_opengl.cpp
@@ -64363,6 +65282,29 @@ index 9c25ff4..d87f419 100644
                  m_topPosition = m_selPosition -
                                  (static_cast<int>(m_itemsVisible) - 1);
  
+diff --git a/mythtv/libs/libmythui/mythuiwebbrowser.cpp b/mythtv/libs/libmythui/mythuiwebbrowser.cpp
+index 803f238..489e5d9 100644
+--- a/mythtv/libs/libmythui/mythuiwebbrowser.cpp
++++ b/mythtv/libs/libmythui/mythuiwebbrowser.cpp
+@@ -35,6 +35,7 @@
+ #include <QKeyEvent>
+ #include <QDomDocument>
+ #include <QNetworkCookieJar>
++#include <QNetworkConfiguration>
+ 
+ #include <unistd.h> // for usleep()
+ 
+@@ -108,6 +109,10 @@ static QNetworkAccessManager *GetNetworkAccessManager(void)
+         return networkManager;
+ 
+     networkManager = new MythNetworkAccessManager();
++//  This next line prevents seg fault at program exit in
++//  QNetworkConfiguration::~QNetworkConfiguration()
++//  when destructor is called by DestroyNetworkAccessManager
++    networkManager->setConfiguration(networkManager->configuration());
+     LOG(VB_GENERAL, LOG_DEBUG, "Copying DLManager's Cookie Jar");
+     GetMythDownloadManager()->loadCookieJar(GetConfDir() + "/MythBrowser/cookiejar.txt");
+     networkManager->setCookieJar(GetMythDownloadManager()->copyCookieJar());
 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
@@ -66375,6 +67317,18 @@ index fcab29e..ed69b93 100644
 +        }
 +    }
 +}
+diff --git a/mythtv/programs/mythfrontend/playbackboxhelper.cpp b/mythtv/programs/mythfrontend/playbackboxhelper.cpp
+index f16276d..8fbb966 100644
+--- a/mythtv/programs/mythfrontend/playbackboxhelper.cpp
++++ b/mythtv/programs/mythfrontend/playbackboxhelper.cpp
+@@ -217,6 +217,7 @@ bool PBHEventHandler::event(QEvent *e)
+                 QStringList &res = (ok) ? successes : failures;
+ 
+                 res.push_back(QString::number(recordingID));
++                list.pop_front();
+             }
+             if (!successes.empty())
+             {
 diff --git a/mythtv/programs/mythfrontend/themechooser.cpp b/mythtv/programs/mythfrontend/themechooser.cpp
 index d090a3e..f0f4ea1 100644
 --- a/mythtv/programs/mythfrontend/themechooser.cpp
@@ -66388,6 +67342,407 @@ index d090a3e..f0f4ea1 100644
          int pos = subexp.indexIn(MYTH_SOURCE_VERSION);
          if (pos > -1)
          {
+diff --git a/mythtv/programs/mythtranscode/commandlineparser.cpp b/mythtv/programs/mythtranscode/commandlineparser.cpp
+index 7410f88..56b97bd 100644
+--- a/mythtv/programs/mythtranscode/commandlineparser.cpp
++++ b/mythtv/programs/mythtranscode/commandlineparser.cpp
+@@ -113,5 +113,7 @@ void MythTranscodeCommandLineParser::LoadArguments(void)
+         ->SetChildOf("hls");
+     add("--hlsstreamid", "hlsstreamid", -1, "Stream ID to process", "")
+         ->SetChildOf("hls");
++    add(QStringList(QStringList() << "-d" << "--delete" ), "delete", false,
++            "Delete original after successful transcoding", "")
++        ->SetGroup("Encoding");
+ }
+-
+diff --git a/mythtv/programs/mythtranscode/main.cpp b/mythtv/programs/mythtranscode/main.cpp
+index d6bd389..f68683c 100644
+--- a/mythtv/programs/mythtranscode/main.cpp
++++ b/mythtv/programs/mythtranscode/main.cpp
+@@ -34,7 +34,7 @@ using namespace std;
+ 
+ static void CompleteJob(int jobID, ProgramInfo *pginfo, bool useCutlist,
+                         frm_dir_map_t *deleteMap, int &exitCode,
+-                        int resultCode);
++                        int resultCode, bool forceDelete);
+ 
+ static int glbl_jobID = -1;
+ static QString recorderOptions = "";
+@@ -367,6 +367,8 @@ int main(int argc, char *argv[])
+         AudioTrackNo = cmdline.toInt("audiotrack");
+     if (cmdline.toBool("passthru"))
+         passthru = true;
++    // Set if we want to delete the original file once conversion succeeded.
++    bool deleteOriginal = cmdline.toBool("delete");
+ 
+     CleanupGuard callCleanup(cleanup);
+ 
+@@ -732,8 +734,8 @@ int main(int argc, char *argv[])
+         exitcode = result;
+     }
+ 
+-    if (!cmdline.toBool("hls"))
+-        CompleteJob(jobID, pginfo, useCutlist, &deleteMap, exitcode, result);
++    if (deleteOriginal || jobID >= 0)
++        CompleteJob(jobID, pginfo, useCutlist, &deleteMap, exitcode, result, deleteOriginal);
+ 
+     transcode->deleteLater();
+ 
+@@ -858,7 +860,7 @@ static void WaitToDelete(ProgramInfo *pginfo)
+ }
+ 
+ static void CompleteJob(int jobID, ProgramInfo *pginfo, bool useCutlist,
+-                 frm_dir_map_t *deleteMap, int &exitCode, int resultCode)
++                 frm_dir_map_t *deleteMap, int &exitCode, int resultCode, bool forceDelete)
+ {
+     int status = JOB_UNKNOWN;
+     if (jobID >= 0)
+@@ -940,7 +942,7 @@ static void CompleteJob(int jobID, ProgramInfo *pginfo, bool useCutlist,
+                     .arg(tmpfile).arg(newfile) + ENO);
+         }
+ 
+-        if (!gCoreContext->GetNumSetting("SaveTranscoding", 0))
++        if (!gCoreContext->GetNumSetting("SaveTranscoding", 0) || forceDelete)
+         {
+             int err;
+             bool followLinks =
+diff --git a/mythtv/programs/mythtranscode/transcode.cpp b/mythtv/programs/mythtranscode/transcode.cpp
+index ea05590..cd28a00 100644
+--- a/mythtv/programs/mythtranscode/transcode.cpp
++++ b/mythtv/programs/mythtranscode/transcode.cpp
+@@ -38,6 +38,7 @@ extern "C" {
+ #include "libavcodec/avcodec.h"
+ #include "libswscale/swscale.h"
+ }
++#include "mythavutil.h"
+ 
+ #include <unistd.h> // for unlink()
+ 
+@@ -666,6 +667,11 @@ int Transcode::TranscodeFile(const QString &inputname,
+             while (loop < options.size())
+             {
+                 QStringList tokens = options[loop].split("=");
++                if (tokens.length() < 2)
++                {
++                    LOG(VB_GENERAL, LOG_ERR, "Transcoding aborted, invalid option settings.");
++                    return REENCODE_ERROR;
++                }
+                 recorderOptionsMap[tokens[0]] = tokens[1];
+ 
+                 loop++;
+@@ -900,21 +906,48 @@ int Transcode::TranscodeFile(const QString &inputname,
+         return REENCODE_ERROR;
+     }
+ 
+-    int vidSize = 0;
+-
+-    // 1080i/p video is actually 1088 because of the 16x16 blocks so
+-    // we have to fudge the output size here.  nuvexport knows how to handle
+-    // this and as of right now it is the only app that uses the fifo ability.
+-    if (video_height == 1080)
+-        vidSize = (1088 * video_width) * 3 / 2;
+-    else
+-        vidSize = (video_height * video_width) * 3 / 2;
+-
+     VideoFrame frame;
+-    frame.codec = FMT_YV12;
+-    frame.width = newWidth;
+-    frame.height = newHeight;
+-    frame.size = newWidth * newHeight * 3 / 2;
++    memset(&frame, 0, sizeof(frame));
++    // Do not use padding when compressing to RTjpeg or when in fifomode.
++    // The RTjpeg compressor doesn't know how to handle strides different to
++    // video width.
++    bool nonAligned = vidsetting == "RTjpeg" || !fifodir.isEmpty(); 
++    bool rescale =
++        (video_width != newWidth) || (video_height != newHeight)
++        || nonAligned;
++
++    if (rescale)
++    {
++        size_t newSize;
++        if (nonAligned)
++        {
++            // Set a stride identical to actual width, to ease fifo post-conversion process.
++            // 1080i/p video is actually 1088 because of the 16x16 blocks so
++            // we have to fudge the output size here.  nuvexport knows how to handle
++            // this and as of right now it is the only app that uses the fifo ability.
++            newSize = buffersize(FMT_YV12, video_width, video_height == 1080 ? 1088 : video_height, 0 /* aligned */);
++        }
++        else
++        {
++            newSize = buffersize(FMT_YV12, newWidth, newHeight);
++        }
++        unsigned char *newFrame = (unsigned char *)av_malloc(newSize);
++        if (!newFrame)
++        {
++            // OOM
++            return REENCODE_ERROR;
++        }
++        if (nonAligned)
++        {
++            // Set a stride identical to actual width, to ease fifo post-conversion process.
++            init(&frame, FMT_YV12, newFrame, video_width, video_height, newSize, NULL, NULL, -1, -1, 0 /* aligned */);
++        }
++        else
++        {
++            // use default stride size.
++            init(&frame, FMT_YV12, newFrame, newWidth, newHeight, newSize);
++        }
++    }
+ 
+     if (!fifodir.isEmpty())
+     {
+@@ -991,6 +1024,10 @@ int Transcode::TranscodeFile(const QString &inputname,
+             // the actual transcode, so stop here.
+             unlink(outputname.toLocal8Bit().constData());
+             SetPlayerContext(NULL);
++            if (rescale)
++            {
++                av_freep(&frame.buf);
++            }
+             delete hls;
+             return REENCODE_OK;
+         }
+@@ -1003,13 +1040,17 @@ int Transcode::TranscodeFile(const QString &inputname,
+             LOG(VB_GENERAL, LOG_INFO, "Enforcing sync on fifos");
+         fifow = new FIFOWriter(2, framecontrol);
+ 
+-        if (!fifow->FIFOInit(0, QString("video"), vidfifo, vidSize, 50) ||
++        if (!fifow->FIFOInit(0, QString("video"), vidfifo, frame.size, 50) ||
+             !fifow->FIFOInit(1, QString("audio"), audfifo, audio_size, 25))
+         {
+             LOG(VB_GENERAL, LOG_ERR,
+                 "Error initializing fifo writer.  Aborting");
+             unlink(outputname.toLocal8Bit().constData());
+             SetPlayerContext(NULL);
++            if (rescale)
++            {
++                av_freep(&frame.buf);
++            }
+             delete hls;
+             return REENCODE_ERROR;
+         }
+@@ -1048,8 +1089,6 @@ int Transcode::TranscodeFile(const QString &inputname,
+     VideoOutput *videoOutput = GetPlayer()->GetVideoOutput();
+     bool is_key = 0;
+     bool first_loop = true;
+-    unsigned char *newFrame = (unsigned char *)av_malloc(frame.size);
+-    frame.buf = newFrame;
+     AVPicture imageIn, imageOut;
+     struct SwsContext  *scontext = NULL;
+ 
+@@ -1106,7 +1145,18 @@ int Transcode::TranscodeFile(const QString &inputname,
+ 
+         if (fifow)
+         {
+-            frame.buf = lastDecode->buf;
++            AVPictureFill(&imageIn, lastDecode);
++            AVPictureFill(&imageOut, &frame);
++
++            scontext = sws_getCachedContext(scontext,
++                           lastDecode->width, lastDecode->height, FrameTypeToPixelFormat(lastDecode->codec),
++                           frame.width, frame.height, FrameTypeToPixelFormat(frame.codec),
++                           SWS_FAST_BILINEAR, NULL, NULL, NULL);
++            // Typically, wee aren't rescaling per say, we're just correcting the stride set by the decoder.
++            // However, it allows to properly handle recordings that see their resolution change half-way.
++            sws_scale(scontext, imageIn.data, imageIn.linesize, 0,
++                      lastDecode->height, imageOut.data, imageOut.linesize);
++
+             totalAudio += arb->GetSamples(frame.timecode);
+             int audbufTime = (int)(totalAudio / rateTimeConv);
+             int auddelta = frame.timecode - audbufTime;
+@@ -1141,7 +1191,7 @@ int Transcode::TranscodeFile(const QString &inputname,
+                     while (delta > vidFrameTime)
+                     {
+                         if (!cutter || !cutter->InhibitDummyFrame())
+-                            fifow->FIFOWrite(0, frame.buf, vidSize);
++                            fifow->FIFOWrite(0, frame.buf, frame.size);
+ 
+                         count++;
+                         delta -= (int)vidFrameTime;
+@@ -1184,7 +1234,7 @@ int Transcode::TranscodeFile(const QString &inputname,
+             if (dropvideo < 0)
+             {
+                 if (cutter && cutter->InhibitDropFrame())
+-                    fifow->FIFOWrite(0, frame.buf, vidSize);
++                    fifow->FIFOWrite(0, frame.buf, frame.size);
+ 
+                 LOG(VB_GENERAL, LOG_INFO, "Dropping video frame");
+                 dropvideo++;
+@@ -1193,12 +1243,12 @@ int Transcode::TranscodeFile(const QString &inputname,
+             else
+             {
+                 if (!cutter || !cutter->InhibitUseVideoFrame())
+-                    fifow->FIFOWrite(0, frame.buf, vidSize);
++                    fifow->FIFOWrite(0, frame.buf, frame.size);
+ 
+                 if (dropvideo)
+                 {
+                     if (!cutter || !cutter->InhibitDummyFrame())
+-                        fifow->FIFOWrite(0, frame.buf, vidSize);
++                        fifow->FIFOWrite(0, frame.buf, frame.size);
+ 
+                     curFrameNum++;
+                     dropvideo--;
+@@ -1219,7 +1269,10 @@ int Transcode::TranscodeFile(const QString &inputname,
+                                          "is not in raw audio mode.");
+ 
+                 unlink(outputname.toLocal8Bit().constData());
+-                av_free(newFrame);
++                if (rescale)
++                {
++                    av_freep(&frame.buf);
++                }
+                 SetPlayerContext(NULL);
+                 if (videoBuffer)
+                     videoBuffer->stop();
+@@ -1298,30 +1351,23 @@ int Transcode::TranscodeFile(const QString &inputname,
+                   writekeyframe = true;
+                 }
+ 
+-                if ((video_width == newWidth) && (video_height == newHeight))
++                if (rescale)
+                 {
+-                    frame.buf = lastDecode->buf;
+-                }
+-                else
+-                {
+-                    frame.buf = newFrame;
+-                    avpicture_fill(&imageIn, lastDecode->buf, AV_PIX_FMT_YUV420P,
+-                                   video_width, video_height);
+-                    avpicture_fill(&imageOut, frame.buf, AV_PIX_FMT_YUV420P,
+-                                   newWidth, newHeight);
+-
+-                    int bottomBand = (video_height == 1088) ? 8 : 0;
+-                    scontext = sws_getCachedContext(scontext, video_width,
+-                                   video_height, AV_PIX_FMT_YUV420P, newWidth,
+-                                   newHeight, AV_PIX_FMT_YUV420P,
++                    AVPictureFill(&imageIn, lastDecode);
++                    AVPictureFill(&imageOut, &frame);
++
++                    int bottomBand = (lastDecode->height == 1088) ? 8 : 0;
++                    scontext = sws_getCachedContext(scontext,
++                                   lastDecode->width, lastDecode->height, FrameTypeToPixelFormat(lastDecode->codec),
++                                   frame.width, frame.height, FrameTypeToPixelFormat(frame.codec),
+                                    SWS_FAST_BILINEAR, NULL, NULL, NULL);
+ 
+                     sws_scale(scontext, imageIn.data, imageIn.linesize, 0,
+-                              video_height - bottomBand,
++                              lastDecode->height - bottomBand,
+                               imageOut.data, imageOut.linesize);
+                 }
+ 
+-                nvr->WriteVideo(&frame, true, writekeyframe);
++                nvr->WriteVideo(rescale ? &frame : lastDecode, true, writekeyframe);
+             }
+             GetPlayer()->GetCC608Reader()->FlushTxtBuffers();
+         }
+@@ -1356,26 +1402,19 @@ int Transcode::TranscodeFile(const QString &inputname,
+                         .arg(newWidth).arg(newHeight));
+             }
+ 
+-            if ((video_width == newWidth) && (video_height == newHeight))
+-            {
+-                frame.buf = lastDecode->buf;
+-            }
+-            else
++            if (rescale)
+             {
+-                frame.buf = newFrame;
+-                avpicture_fill(&imageIn, lastDecode->buf, AV_PIX_FMT_YUV420P,
+-                               video_width, video_height);
+-                avpicture_fill(&imageOut, frame.buf, AV_PIX_FMT_YUV420P,
+-                               newWidth, newHeight);
+-
+-                int bottomBand = (video_height == 1088) ? 8 : 0;
+-                scontext = sws_getCachedContext(scontext, video_width,
+-                               video_height, AV_PIX_FMT_YUV420P, newWidth,
+-                               newHeight, AV_PIX_FMT_YUV420P,
++                AVPictureFill(&imageIn, lastDecode);
++                AVPictureFill(&imageOut, &frame);
++
++                int bottomBand = (lastDecode->height == 1088) ? 8 : 0;
++                scontext = sws_getCachedContext(scontext,
++                               lastDecode->width, lastDecode->height, FrameTypeToPixelFormat(lastDecode->codec),
++                               frame.width, frame.height, FrameTypeToPixelFormat(frame.codec),
+                                SWS_FAST_BILINEAR, NULL, NULL, NULL);
+ 
+                 sws_scale(scontext, imageIn.data, imageIn.linesize, 0,
+-                          video_height - bottomBand,
++                          lastDecode->height - bottomBand,
+                           imageOut.data, imageOut.linesize);
+             }
+ 
+@@ -1418,7 +1457,10 @@ int Transcode::TranscodeFile(const QString &inputname,
+                             "Transcode: Encountered irrecoverable error in "
+                             "NVR::WriteAudio");
+ 
+-                        av_free(newFrame);
++                        if (rescale)
++                        {
++                            av_freep(&frame.buf);
++                        }
+                         SetPlayerContext(NULL);
+                         if (videoBuffer)
+                             videoBuffer->stop();
+@@ -1463,7 +1505,7 @@ int Transcode::TranscodeFile(const QString &inputname,
+                         hlsSegmentFrames = 0;
+                     }
+ 
+-                    if (avfw->WriteVideoFrame(&frame) > 0)
++                    if (avfw->WriteVideoFrame(rescale ? &frame : lastDecode) > 0)
+                     {
+                         lastWrittenTime = frame.timecode + timecodeOffset;
+                         if (hls)
+@@ -1475,9 +1517,9 @@ int Transcode::TranscodeFile(const QString &inputname,
+             else
+             {
+                 if (forceKeyFrames)
+-                    nvr->WriteVideo(&frame, true, true);
++                    nvr->WriteVideo(rescale ? &frame : lastDecode, true, true);
+                 else
+-                    nvr->WriteVideo(&frame);
++                    nvr->WriteVideo(rescale ? &frame : lastDecode);
+                 lastWrittenTime = frame.timecode + timecodeOffset;
+             }
+         }
+@@ -1508,7 +1550,10 @@ int Transcode::TranscodeFile(const QString &inputname,
+                     "Transcoding aborted, cutlist updated");
+ 
+                 unlink(outputname.toLocal8Bit().constData());
+-                av_free(newFrame);
++                if (rescale)
++                {
++                    av_freep(&frame.buf);
++                }
+                 SetPlayerContext(NULL);
+                 if (videoBuffer)
+                     videoBuffer->stop();
+@@ -1523,7 +1568,10 @@ int Transcode::TranscodeFile(const QString &inputname,
+                         "Transcoding STOPped by JobQueue");
+ 
+                     unlink(outputname.toLocal8Bit().constData());
+-                    av_free(newFrame);
++                    if (rescale)
++                    {
++                        av_freep(&frame.buf);
++                    }
+                     SetPlayerContext(NULL);
+                     if (videoBuffer)
+                         videoBuffer->stop();
+@@ -1624,7 +1672,10 @@ int Transcode::TranscodeFile(const QString &inputname,
+         videoBuffer->stop();
+     }
+ 
+-    av_free(newFrame);
++    if (rescale)
++    {
++        av_freep(&frame.buf);
++    }
+     SetPlayerContext(NULL);
+ 
+     return REENCODE_OK;
 diff --git a/mythtv/programs/mythtv-setup/importicons.cpp b/mythtv/programs/mythtv-setup/importicons.cpp
 index 26a2850..66945d1 100644
 --- a/mythtv/programs/mythtv-setup/importicons.cpp
diff --git a/mythtv.spec b/mythtv.spec
index 345a003..f48c27b 100644
--- a/mythtv.spec
+++ b/mythtv.spec
@@ -82,7 +82,7 @@ Version:        0.28
 %if "%{branch}" == "master"
 Release:        0.5.git.%{_gitrev}%{?dist}
 %else
-Release:        9%{?dist}
+Release:        10%{?dist}
 %endif
 
 # The primary license is GPLv2+, but bits are borrowed from a number of
@@ -1397,6 +1397,10 @@ fi
 
 
 %changelog
+* Sun Nov 27 2016 Richard Shaw <hobbes1069 at gmail.com> - 0.28-10
+- Update to latest fixes/0.28 from git.
+- Add patch for libcec 4, fixes RFBZ#4345.
+
 * Thu Nov 17 2016 Adrian Reber <adrian at lisas.de> - 0.28-9
 - Rebuilt for libcdio-0.94
 


More information about the rpmfusion-commits mailing list