commit ecdfd5868bc8e161d374683e25eb791d17924d8c
Author: Sérgio M. Basto <sergio(a)serjux.com>
Date: Sun Sep 11 21:14:45 2016 +0100
Update to latest fixes/0.28, rfbz#4241
mythtv-0.28-fixes.patch | 1938 ++++++++++++++++++++++++++++++++++++++++++++++-
mythtv.spec | 7 +-
2 files changed, 1926 insertions(+), 19 deletions(-)
---
diff --git a/mythtv-0.28-fixes.patch b/mythtv-0.28-fixes.patch
index 6960eb2..5c9d72a 100644
--- a/mythtv-0.28-fixes.patch
+++ b/mythtv-0.28-fixes.patch
@@ -4,7 +4,8 @@
.../mythzoneminder/mythzmserver/zmserver.cpp | 20 +-
mythtv/README | 8 +-
mythtv/bindings/python/MythTV/dataheap.py | 1 +
- mythtv/configure | 29 +-
+ .../python/MythTV/wikiscripts/wikiscripts.py | 4 +-
+ mythtv/configure | 34 +-
mythtv/html/css/Status.css | 13 +
mythtv/html/menu.qsp | 2 +-
mythtv/i18n/mythfrontend_cs.qm | Bin 599995 -> 726083 bytes
@@ -15,35 +16,59 @@
mythtv/libs/libmyth/programinfo.cpp | 178 +-
mythtv/libs/libmyth/programinfo.h | 18 +-
mythtv/libs/libmythbase/mythmedia.cpp | 2 +-
+ mythtv/libs/libmythbase/mythstorage.cpp | 4 +-
mythtv/libs/libmythmetadata/imagemanager.cpp | 2 +-
.../libmythservicecontracts/services/dvrServices.h | 14 +-
+ mythtv/libs/libmythtv/avformatdecoder.cpp | 6 +
.../libmythtv/channelscan/vboxchannelfetcher.cpp | 30 +-
.../libmythtv/channelscan/vboxchannelfetcher.h | 1 +
mythtv/libs/libmythtv/eitfixup.cpp | 33 +-
mythtv/libs/libmythtv/eitfixup.h | 4 +-
mythtv/libs/libmythtv/eithelper.cpp | 5 +
+ mythtv/libs/libmythtv/mythplayer.cpp | 109 +-
mythtv/libs/libmythtv/privatedecoder_omx.cpp | 4 +-
- mythtv/libs/libmythtv/recorders/vboxutils.cpp | 8 +-
+ mythtv/libs/libmythtv/recorders/asichannel.cpp | 6 +-
+ mythtv/libs/libmythtv/recorders/vboxutils.cpp | 10 +-
mythtv/libs/libmythtv/recorders/vboxutils.h | 2 +-
.../test/test_eitfixups/test_eitfixups.cpp | 28 +
- mythtv/libs/libmythtv/videodisplayprofile.cpp | 2 +-
+ mythtv/libs/libmythtv/tv_play.cpp | 4 +-
+ mythtv/libs/libmythtv/videodisplayprofile.cpp | 33 +-
+ mythtv/libs/libmythtv/videodisplayprofile.h | 2 +-
+ mythtv/libs/libmythtv/videoout_omx.cpp | 251 +-
+ mythtv/libs/libmythtv/videoout_omx.h | 11 +-
.../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/mythrender_opengl.cpp | 4 +-
+ mythtv/libs/libmythui/mythrender_opengl.h | 4 +
mythtv/libs/libmythui/screensaver-dbus.cpp | 2 +-
+ mythtv/libs/libmythupnp/httprequest.cpp | 172 +-
+ mythtv/libs/libmythupnp/httprequest.h | 55 +-
+ mythtv/programs/mythbackend/autoexpire.cpp | 75 +-
+ mythtv/programs/mythbackend/autoexpire.h | 20 +-
mythtv/programs/mythbackend/backendhousekeeper.cpp | 2 +-
+ mythtv/programs/mythbackend/scheduler.cpp | 26 +-
mythtv/programs/mythbackend/services/dvr.cpp | 71 +
mythtv/programs/mythbackend/services/dvr.h | 12 +
mythtv/programs/mythbackend/services/video.cpp | 3 +-
- mythtv/programs/mythfrontend/galleryconfig.cpp | 11 +
+ mythtv/programs/mythfrontend/galleryconfig.cpp | 13 +-
+ mythtv/programs/mythfrontend/galleryconfig.h | 10 +-
mythtv/programs/mythfrontend/galleryslideview.cpp | 93 +-
mythtv/programs/mythfrontend/galleryslideview.h | 11 +-
mythtv/programs/mythfrontend/gallerythumbview.cpp | 22 +
mythtv/programs/mythfrontend/galleryviews.cpp | 80 +-
mythtv/programs/mythfrontend/galleryviews.h | 8 +-
+ mythtv/programs/mythfrontend/globalsettings.cpp | 12 +-
mythtv/programs/mythfrontend/main.cpp | 11 +-
+ mythtv/programs/mythfrontend/mythfrontend.pro | 24 +
mythtv/programs/mythfrontend/themechooser.cpp | 2 +-
mythtv/programs/mythtv-setup/importicons.cpp | 6 +-
- 45 files changed, 30819 insertions(+), 18423 deletions(-)
+ mythtv/programs/mythtv-setup/mythtv-setup.pro | 12 +
+ mythtv/programs/mythwelcome/mythwelcome.pro | 11 +
+ 70 files changed, 31433 insertions(+), 18694 deletions(-)
diff --git a/mythplugins/mythgallery/mythgallery/main.cpp
b/mythplugins/mythgallery/mythgallery/main.cpp
index 3237dfe..3aab56b 100644
@@ -243,11 +268,65 @@ index 3506878..859e060 100644
_defaults = {'title':u'Unknown', 'subtitle':'',
'description':'',
'category':'', 'hostname':'',
'bookmark':0,
'editing':0, 'cutlist':0,
'autoexpire':0,
+diff --git a/mythtv/bindings/python/MythTV/wikiscripts/wikiscripts.py
b/mythtv/bindings/python/MythTV/wikiscripts/wikiscripts.py
+index 22d4730..2bc7017 100644
+--- a/mythtv/bindings/python/MythTV/wikiscripts/wikiscripts.py
++++ b/mythtv/bindings/python/MythTV/wikiscripts/wikiscripts.py
+@@ -15,7 +15,7 @@ import lxml.html
+ import os
+ import stat
+
+-BASEURL = 'http://mythtv.org/wiki'
++BASEURL = 'https://www.mythtv.org/wiki'
+
+ def getScripts():
+ return Script.getAll()
+@@ -23,7 +23,7 @@ def getScripts():
+ def getPage(**kwargs):
+ url = "{0}?{1}".format(BASEURL,
+ '&'.join(['{0}={1}'.format(k,v) for k,v in
kwargs.items()]))
+- return lxml.html.parse(url).getroot()
++ return lxml.html.parse(urlopen(url)).getroot()
+
+ def getWhatLinksHere(page):
+ root = getPage(title='Special:WhatLinksHere',
diff --git a/mythtv/configure b/mythtv/configure
-index 17d42d6..ba2fc6e 100755
+index 17d42d6..af0d6a6 100755
--- a/mythtv/configure
+++ b/mythtv/configure
-@@ -6521,19 +6521,28 @@ check_type "vdpau/vdpau.h"
"VdpPictureInfoHEVC"
+@@ -136,6 +136,7 @@ Advanced options (experts only):
+ --disable-openmax disable OpenMAX hardware accelerated video decoding
+ --disable-dxva2 disable hardware accelerated decoding on windows
+ --disable-opengl-video disable OpenGL based video display
++ --disable-opengl-themepainter disable OpenGL based theme painting
+ --disable-libass disable libass SSA/ASS subtitle support
+ --disable-systemd_notify disable systemd notify support
+
+@@ -2344,6 +2345,7 @@ MYTHTV_CONFIG_LIST='
+ mheg
+ opengl
+ opengl_video
++ opengl_themepainter
+ qtwebkit
+ qtscript
+ qtdbus
+@@ -3365,6 +3367,7 @@ mythtranscode_deps="backend frontend"
+ opengl_deps_any="agl_h GL_gl_h EGL_egl_h GLES2_gl2_h darwin windows x11"
+ opengles_deps="GLES2_gl2_h"
+ opengl_video_deps="opengl"
++opengl_themepainter_deps="opengl"
+ v4l2_deps="backend linux_videodev2_h"
+ v4l1_deps="backend v4l2 linux_videodev_h"
+ xrandr_deps="x11"
+@@ -3538,6 +3541,7 @@ enable mythtranscode
+ enable opengl
+ enable opengles
+ enable opengl_video
++enable opengl_themepainter
+ enable symbol_visibility
+ enable v4l1
+ enable v4l2
+@@ -6521,19 +6525,28 @@ check_type "vdpau/vdpau.h"
"VdpPictureInfoHEVC"
check_cpp_condition windows.h
"!WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)" && enable winrt ||
disable winrt
# check for OpenMAX header & lib
@@ -279,7 +358,7 @@ index 17d42d6..ba2fc6e 100755
if ! disabled w32threads && ! enabled pthreads; then
check_func_headers "windows.h process.h" _beginthreadex &&
enable w32threads || disable w32threads
-@@ -7242,11 +7251,13 @@ int main(void) { return 1; }
+@@ -7242,11 +7255,13 @@ int main(void) { return 1; }
EOF
if enabled systemd_notify ; then
@@ -296,7 +375,7 @@ index 17d42d6..ba2fc6e 100755
fi
# Check that all MythTV build "requirements" are met:
-@@ -7349,7 +7360,7 @@ enabled libass && check_lib2 ass/ass.h ass_flush_events
-lass || disable libass
+@@ -7349,7 +7364,7 @@ enabled libass && check_lib2 ass/ass.h ass_flush_events
-lass || disable libass
if enabled libcec ; then
if pkg-config --exists libcec; then
@@ -305,7 +384,7 @@ index 17d42d6..ba2fc6e 100755
else
check_cxx -I"$libcec_path" <<EOF || { disable libcec; }
#include <libcec/cec.h>
-@@ -8028,6 +8039,10 @@ if enabled x11 ; then
+@@ -8028,8 +8043,13 @@ if enabled x11 ; then
echo "VAAPI support ${vaapi-no}"
echo "CrystalHD support ${crystalhd-no}"
echo "OpenMAX support ${openmax-no}"
@@ -315,7 +394,10 @@ index 17d42d6..ba2fc6e 100755
+ fi
fi
echo "OpenGL video ${opengl_video-no}"
++ echo "OpenGL ThemePainter ${opengl_themepainter-no}"
if test x"$target_os" = x"darwin" ; then
+ echo "VDA support ${vda-no}"
+ fi
diff --git a/mythtv/html/css/Status.css b/mythtv/html/css/Status.css
index 43ede02..a50fca0 100644
--- a/mythtv/html/css/Status.css
@@ -61081,6 +61163,21 @@ index 527c7af..9f5da10 100644
.arg(quintptr(this),0,16).arg(it.key()));
}
}
+diff --git a/mythtv/libs/libmythbase/mythstorage.cpp
b/mythtv/libs/libmythbase/mythstorage.cpp
+index a56c492..63a2905 100644
+--- a/mythtv/libs/libmythbase/mythstorage.cpp
++++ b/mythtv/libs/libmythbase/mythstorage.cpp
+@@ -9,8 +9,8 @@ void SimpleDBStorage::Load(void)
+ MSqlQuery query(MSqlQuery::InitCon());
+ MSqlBindings bindings;
+ query.prepare(
+- "SELECT " + GetColumnName() +
+- " FROM " + GetTableName() +
++ "SELECT CAST(" + GetColumnName() + " AS CHAR)"
++ " FROM " + GetTableName() +
+ " WHERE " + GetWhereClause(bindings));
+ query.bindValues(bindings);
+
diff --git a/mythtv/libs/libmythmetadata/imagemanager.cpp
b/mythtv/libs/libmythmetadata/imagemanager.cpp
index a9c802f..e0e72d9 100644
--- a/mythtv/libs/libmythmetadata/imagemanager.cpp
@@ -61130,6 +61227,23 @@ index 3fde9d0..44fd2f3 100644
virtual DTC::CutList* GetRecordedCutList ( int RecordedId,
int ChanId,
const QDateTime
&StartTime,
+diff --git a/mythtv/libs/libmythtv/avformatdecoder.cpp
b/mythtv/libs/libmythtv/avformatdecoder.cpp
+index fb7d793..f02af21 100644
+--- a/mythtv/libs/libmythtv/avformatdecoder.cpp
++++ b/mythtv/libs/libmythtv/avformatdecoder.cpp
+@@ -1021,6 +1021,12 @@ int AvFormatDecoder::FindStreamInfo(void)
+ silence_ffmpeg_logging = true;
+ int retval = avformat_find_stream_info(ic, NULL);
+ silence_ffmpeg_logging = false;
++ // ffmpeg 3.0 is returning -1 code when there is a channel
++ // change or some encoding error just after the start
++ // of the file, but is has found the correct stream info
++ // Set rc to 0 so that playing can continue.
++ if (retval == -1)
++ retval = 0;
+ return retval;
+ }
+
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
@@ -61296,6 +61410,299 @@ 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/mythplayer.cpp b/mythtv/libs/libmythtv/mythplayer.cpp
+index f953e11..4ddde4d 100644
+--- a/mythtv/libs/libmythtv/mythplayer.cpp
++++ b/mythtv/libs/libmythtv/mythplayer.cpp
+@@ -383,7 +383,7 @@ bool MythPlayer::Pause(void)
+
+ bool MythPlayer::Play(float speed, bool normal, bool unpauseaudio)
+ {
+- QMutexLocker locker(&pauseLock);
++ pauseLock.lock();
+ LOG(VB_PLAYBACK, LOG_INFO, LOC +
+ QString("Play(%1, normal %2, unpause audio %3)")
+ .arg(speed,5,'f',1).arg(normal).arg(unpauseaudio));
+@@ -391,6 +391,7 @@ bool MythPlayer::Play(float speed, bool normal, bool unpauseaudio)
+ if (deleteMap.IsEditing())
+ {
+ LOG(VB_GENERAL, LOG_ERR, LOC + "Ignoring Play(), in edit mode.");
++ pauseLock.unlock();
+ return false;
+ }
+
+@@ -403,6 +404,7 @@ bool MythPlayer::Play(float speed, bool normal, bool unpauseaudio)
+ allpaused = false;
+ next_play_speed = speed;
+ next_normal_speed = normal;
++ pauseLock.unlock();
+ return true;
+ }
+
+@@ -949,7 +951,7 @@ int MythPlayer::OpenFile(uint retries)
+ return -1;
+ }
+ LOG(VB_GENERAL, LOG_WARNING, LOC + "OpenFile() waiting on data");
+- usleep(150 * 1000);
++ usleep(50 * 1000);
+ }
+
+ player_ctx->LockPlayingInfo(__FILE__, __LINE__);
+@@ -1385,7 +1387,10 @@ void MythPlayer::DisableCaptions(uint mode, bool osd_msg)
+
+ QMutexLocker locker(&osdLock);
+
+- textDesired = textDisplayMode & kDisplayAllTextCaptions;
++ bool newTextDesired = textDisplayMode & kDisplayAllTextCaptions;
++ // Only turn off textDesired if the Operator requested it.
++ if (osd_msg || newTextDesired)
++ textDesired = newTextDesired;
+ QString msg = "";
+ if (kDisplayNUVTeletextCaptions & mode)
+ msg += tr("TXT CAP");
+@@ -1422,7 +1427,10 @@ void MythPlayer::DisableCaptions(uint mode, bool osd_msg)
+ void MythPlayer::EnableCaptions(uint mode, bool osd_msg)
+ {
+ QMutexLocker locker(&osdLock);
+- textDesired = mode & kDisplayAllTextCaptions;
++ bool newTextDesired = mode & kDisplayAllTextCaptions;
++ // Only turn off textDesired if the Operator requested it.
++ if (osd_msg || newTextDesired)
++ textDesired = newTextDesired;
+ QString msg = "";
+ if ((kDisplayCC608 & mode) || (kDisplayCC708 & mode) ||
+ (kDisplayAVSubtitle & mode) || kDisplayRawTextSubtitle & mode)
+@@ -1492,7 +1500,9 @@ void MythPlayer::SetCaptionsEnabled(bool enable, bool osd_msg)
+ enableCaptions = disableCaptions = false;
+ uint origMode = textDisplayMode;
+
+- textDesired = enable;
++ // Only turn off textDesired if the Operator requested it.
++ if (osd_msg || enable)
++ textDesired = enable;
+
+ if (!enable)
+ {
+@@ -2240,10 +2250,7 @@ void MythPlayer::DisplayNormalFrame(bool check_prebuffer)
+ videoOutput->DoneDisplayingFrame(videoOutput->GetLastShownFrame());
+
+ // retrieve the next frame
+- bool const bDisplayFrame = videoOutput->ValidVideoFrames() > 0;
+- if (bDisplayFrame)
+- videoOutput->StartDisplayingFrame();
+-
++ videoOutput->StartDisplayingFrame();
+ VideoFrame *frame = videoOutput->GetLastShownFrame();
+
+ // Check aspect ratio
+@@ -2252,12 +2259,9 @@ void MythPlayer::DisplayNormalFrame(bool check_prebuffer)
+ // Player specific processing (dvd, bd, mheg etc)
+ PreProcessNormalFrame();
+
+- if (GetTrackCount(kTrackTypeVideo))
+- {
+- // handle scan type changes
+- AutoDeint(frame);
+- detect_letter_box->SwitchTo(frame);
+- }
++ // handle scan type changes
++ AutoDeint(frame);
++ detect_letter_box->SwitchTo(frame);
+
+ FrameScanType ps = m_scan;
+ if (kScan_Detect == m_scan || kScan_Ignore == m_scan)
+@@ -2265,9 +2269,7 @@ void MythPlayer::DisplayNormalFrame(bool check_prebuffer)
+
+ AVSync(frame, 0);
+ // If PiP then keep this frame for MythPlayer::GetCurrentFrame
+- if (player_ctx->IsPIP())
+- return;
+- if (bDisplayFrame)
++ if (!player_ctx->IsPIP())
+ videoOutput->DoneDisplayingFrame(frame);
+ }
+
+@@ -2277,12 +2279,10 @@ void MythPlayer::PreProcessNormalFrame(void)
+ // handle Interactive TV
+ if (GetInteractiveTV())
+ {
+- QMutexLocker lk1(&osdLock);
+-
++ osdLock.lock();
++ itvLock.lock();
+ if (osd && videoOutput->GetOSDPainter())
+ {
+- QMutexLocker lk2(&itvLock);
+-
+ InteractiveScreen *window =
+ (InteractiveScreen*)osd->GetWindow(OSD_WIN_INTERACT);
+ if ((interactiveTV->ImageHasChanged() || !itvVisible) && window)
+@@ -2291,6 +2291,8 @@ void MythPlayer::PreProcessNormalFrame(void)
+ itvVisible = true;
+ }
+ }
++ itvLock.unlock();
++ osdLock.unlock();
+ }
+ #endif // USING_MHEG
+ }
+@@ -2467,7 +2469,7 @@ bool MythPlayer::VideoLoop(void)
+ DisplayPauseFrame();
+ }
+ else
+- DisplayNormalFrame(GetTrackCount(kTrackTypeVideo));
++ DisplayNormalFrame();
+
+ if (FlagIsSet(kVideoIsNull) && decoder)
+ decoder->UpdateFramesPlayed();
+@@ -2597,10 +2599,7 @@ void MythPlayer::SwitchToProgram(void)
+ ProgramInfo *pginfo = player_ctx->tvchain->GetSwitchProgram(
+ discontinuity, newtype, newid);
+ if (!pginfo)
+- {
+- LOG(VB_GENERAL, LOG_ERR, LOC + "SwitchToProgram - No ProgramInfo");
+ return;
+- }
+
+ bool newIsDummy = player_ctx->tvchain->GetInputType(newid) ==
"DUMMY";
+
+@@ -2735,10 +2734,7 @@ void MythPlayer::JumpToProgram(void)
+ ProgramInfo *pginfo = player_ctx->tvchain->GetSwitchProgram(
+ discontinuity, newtype, newid);
+ if (!pginfo)
+- {
+- LOG(VB_GENERAL, LOG_ERR, LOC + "JumpToProgram - No ProgramInfo");
+ return;
+- }
+
+ inJumpToProgramPause = true;
+
+@@ -2746,6 +2742,7 @@ void MythPlayer::JumpToProgram(void)
+ SetPlayingInfo(*pginfo);
+
+ Pause();
++ ChangeSpeed();
+ ResetCaptions();
+ player_ctx->tvchain->SetProgram(*pginfo);
+ player_ctx->buffer->Reset(true);
+@@ -2996,11 +2993,12 @@ void MythPlayer::EventLoop(void)
+ JumpToProgram();
+ }
+ else if ((!allpaused || GetEof() != kEofStateNone) &&
+- decoder && !decoder->GetWaitForChange() &&
+- player_ctx->tvchain &&
player_ctx->tvchain->NeedsToSwitch())
++ player_ctx->tvchain &&
++ (decoder && !decoder->GetWaitForChange()))
+ {
+ // Switch to the next program in livetv
+- SwitchToProgram();
++ if (player_ctx->tvchain->NeedsToSwitch())
++ SwitchToProgram();
+ }
+
+ // Jump to the next program in livetv
+@@ -3201,35 +3199,36 @@ void MythPlayer::AudioEnd(void)
+
+ bool MythPlayer::PauseDecoder(void)
+ {
+- QMutexLocker locker(&decoderPauseLock);
++ decoderPauseLock.lock();
+ if (is_current_thread(decoderThread))
+ {
+- pauseDecoder = false;
+ decoderPaused = true;
+ decoderThreadPause.wakeAll();
+- return true;
++ decoderPauseLock.unlock();
++ return decoderPaused;
+ }
+
+- pauseDecoder = true;
+ int tries = 0;
+- while (!decoderPaused && decoderThread && !killdecoder &&
(tries++ < 10) &&
+- !decoderThreadPause.wait(locker.mutex(), 100))
++ pauseDecoder = true;
++ while (decoderThread && !killdecoder && (tries++ < 100)
&&
++ !decoderThreadPause.wait(&decoderPauseLock, 100))
+ {
+ LOG(VB_GENERAL, LOG_WARNING, LOC + "Waited 100ms for decoder to
pause");
+ }
+ pauseDecoder = false;
++ decoderPauseLock.unlock();
+ return decoderPaused;
+- }
++}
+
+ void MythPlayer::UnpauseDecoder(void)
+ {
+- QMutexLocker locker(&decoderPauseLock);
++ decoderPauseLock.lock();
+
+ if (is_current_thread(decoderThread))
+ {
+- unpauseDecoder = false;
+ decoderPaused = false;
+ decoderThreadUnpause.wakeAll();
++ decoderPauseLock.unlock();
+ return;
+ }
+
+@@ -3237,14 +3236,15 @@ void MythPlayer::UnpauseDecoder(void)
+ {
+ int tries = 0;
+ unpauseDecoder = true;
+- while (decoderPaused && decoderThread && !killdecoder &&
(tries++ < 10) &&
+- !decoderThreadUnpause.wait(locker.mutex(), 100))
++ while (decoderThread && !killdecoder && (tries++ < 100)
&&
++ !decoderThreadUnpause.wait(&decoderPauseLock, 100))
+ {
+ LOG(VB_GENERAL, LOG_WARNING, LOC +
+ "Waited 100ms for decoder to unpause");
+ }
+ unpauseDecoder = false;
+ }
++ decoderPauseLock.unlock();
+ }
+
+ void MythPlayer::DecoderStart(bool start_paused)
+@@ -3271,7 +3271,7 @@ void MythPlayer::DecoderEnd(void)
+ SetPlaying(false);
+ killdecoder = true;
+ int tries = 0;
+- while (decoderThread && !decoderThread->wait(100) && (tries++
< 20))
++ while (decoderThread && !decoderThread->wait(100) && (tries++
< 50))
+ LOG(VB_PLAYBACK, LOG_INFO, LOC +
+ "Waited 100ms for decoder loop to stop");
+
+@@ -3284,23 +3284,12 @@ void MythPlayer::DecoderEnd(void)
+
+ void MythPlayer::DecoderPauseCheck(void)
+ {
+- if (!is_current_thread(decoderThread))
+- return;
+-
+- QMutexLocker locker(&decoderPauseLock);
+-
+- if (pauseDecoder)
+- {
+- pauseDecoder = false;
+- decoderPaused = true;
+- decoderThreadPause.wakeAll();
+- }
+-
+- if (unpauseDecoder)
++ if (is_current_thread(decoderThread))
+ {
+- unpauseDecoder = false;
+- decoderPaused = false;
+- decoderThreadUnpause.wakeAll();
++ if (pauseDecoder)
++ PauseDecoder();
++ if (unpauseDecoder)
++ UnpauseDecoder();
+ }
+ }
+
diff --git a/mythtv/libs/libmythtv/privatedecoder_omx.cpp
b/mythtv/libs/libmythtv/privatedecoder_omx.cpp
index a7ce174..b2999ad 100644
--- a/mythtv/libs/libmythtv/privatedecoder_omx.cpp
@@ -61312,8 +61719,34 @@ index a7ce174..b2999ad 100644
ret = 0;
break;
}
+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
++++ b/mythtv/libs/libmythtv/recorders/asichannel.cpp
+@@ -7,7 +7,7 @@
+ #include "mpegtables.h"
+ #include "asichannel.h"
+
+-#define LOC QString("ASIChan[%1](%2):
").arg(GetCardID()).arg(GetDevice())
++#define LOC QString("ASIChan[%1](%2):
").arg(GetInputID()).arg(GetDevice())
+
+ ASIChannel::ASIChannel(TVRec *parent, const QString &device) :
+ DTVChannel(parent), m_device(device), m_isopen(false)
+@@ -31,10 +31,10 @@ bool ASIChannel::Open(void)
+ if (m_isopen)
+ return true;
+
+- if (!InitializeInputs())
++ if (!InitializeInput())
+ return false;
+
+- if (!m_input.inputid)
++ if (!m_inputid)
+ return false;
+
+ m_isopen = true;
diff --git a/mythtv/libs/libmythtv/recorders/vboxutils.cpp
b/mythtv/libs/libmythtv/recorders/vboxutils.cpp
-index f1fc301..f1c417e 100644
+index f1fc301..629e276 100644
--- a/mythtv/libs/libmythtv/recorders/vboxutils.cpp
+++ b/mythtv/libs/libmythtv/recorders/vboxutils.cpp
@@ -77,14 +77,14 @@ QStringList VBox::doUPNPSearch(void)
@@ -61342,6 +61775,15 @@ index f1fc301..f1c417e 100644
if (friendlyName.startsWith("VBox"))
{
+@@ -246,7 +246,7 @@ bool VBox::checkVersion(QString &version)
+ sList = version.split('.');
+
+ // sanity check this looks like a VBox version string
+- if (sList.count() != 3 || !version.startsWith("VB."))
++ if (sList.count() != 3 || !(version.startsWith("VB.") ||
version.startsWith("VJ.")))
+ {
+ LOG(VB_GENERAL, LOG_INFO, LOC + QString("Failed to parse version from
%1").arg(version));
+ delete xmlDoc;
@@ -433,4 +433,4 @@ QString VBox::getFirstText(QDomElement &element)
return t.data();
}
@@ -61401,19 +61843,508 @@ index 77f85e1..80b7d1d 100644
}
void TestEITFixups::testUnitymedia()
+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
++++ b/mythtv/libs/libmythtv/tv_play.cpp
+@@ -7870,8 +7870,7 @@ void TV::ChangeChannel(PlayerContext *ctx, uint chanid, const
QString &chan)
+ if (ctx->prevChan.empty())
+ ctx->PushPreviousChannel();
+
+- if (ctx->player)
+- ctx->player->GetAudio()->Pause(true);
++ PauseAudioUntilBuffered(ctx);
+ PauseLiveTV(ctx);
+
+ ctx->LockDeletePlayer(__FILE__, __LINE__);
+@@ -7888,7 +7887,6 @@ void TV::ChangeChannel(PlayerContext *ctx, uint chanid, const
QString &chan)
+ ctx->player->GetAudio()->Reset();
+
+ UnpauseLiveTV(ctx, chanid && GetQueuedChanID());
+- PauseAudioUntilBuffered(ctx);
+
+ if (oldinputname != ctx->recorder->GetInput())
+ UpdateOSDInput(ctx);
diff --git a/mythtv/libs/libmythtv/videodisplayprofile.cpp
b/mythtv/libs/libmythtv/videodisplayprofile.cpp
-index 4d10fe3..e93499c 100644
+index 4d10fe3..083ea98 100644
--- a/mythtv/libs/libmythtv/videodisplayprofile.cpp
+++ b/mythtv/libs/libmythtv/videodisplayprofile.cpp
-@@ -1179,7 +1179,7 @@ void VideoDisplayProfile::CreateOpenMAXProfiles(const QString
&hostname)
- DeleteProfileGroup("OpenMAX Normal", hostname);
- uint groupid = CreateProfileGroup("OpenMAX Normal", hostname);
+@@ -695,6 +695,11 @@ QString VideoDisplayProfile::GetDecoderHelp(QString decoder)
+ "accelerate video decoding. "
+ "(H264 only, requires Mac OS 10.6.3)");
+
++ if (decoder == "openmax")
++ msg += QObject::tr(
++ "Openmax will use the graphics hardware to "
++ "accelerate video decoding on Raspberry Pi. ");
++
+ return msg;
+ }
+
+@@ -1173,15 +1178,27 @@ void VideoDisplayProfile::CreateVAAPIProfiles(const QString
&hostname)
+ "");
+ }
+
+-void VideoDisplayProfile::CreateOpenMAXProfiles(const QString &hostname)
++// upgrade = 1 means adding high quality
++void VideoDisplayProfile::CreateOpenMAXProfiles(const QString &hostname, int
upgrade)
+ {
+- (void) QObject::tr("OpenMAX Normal", "Sample: OpenMAX Normal");
+- DeleteProfileGroup("OpenMAX Normal", hostname);
+- uint groupid = CreateProfileGroup("OpenMAX Normal", hostname);
++#ifdef USING_OPENGLES
++ (void) QObject::tr("OpenMAX High Quality", "Sample: OpenMAX High
Quality");
++ DeleteProfileGroup("OpenMAX High Quality", hostname);
++ uint groupid = CreateProfileGroup("OpenMAX High Quality", hostname);
CreateProfile(groupid, 1, ">", 0, 0, "", 0, 0,
- "openmax", 1, true, "openmax",
"softblend", false,
-+ "openmax", 4, true, "openmax",
"softblend", false,
++ "openmax", 4, true, "openmax", "opengl",
true,
"openmaxadvanced", "onefield",
"");
++#endif
++ if (!upgrade) {
++ (void) QObject::tr("OpenMAX Normal", "Sample: OpenMAX
Normal");
++ DeleteProfileGroup("OpenMAX Normal", hostname);
++ uint groupid = CreateProfileGroup("OpenMAX Normal", hostname);
++ CreateProfile(groupid, 1, ">", 0, 0, "", 0, 0,
++ "openmax", 4, true, "openmax",
"softblend", false,
++ "openmaxadvanced", "onefield",
++ "");
++ }
+ }
+
+ void VideoDisplayProfile::CreateProfiles(const QString &hostname)
+@@ -1451,6 +1468,12 @@ QString VideoDisplayProfile::GetOSDHelp(const QString &osd)
+ "Uses OpenGL to alpha blend the OSD onto the video.");
+ }
+
++ if (osd =="threaded")
++ {
++ msg = QObject::tr(
++ "Uses OpenGL in a separate thread to overlay the OSD onto the
video.");
++ }
++
+ #ifdef USING_OPENMAX
+ if (osd.contains("openmax"))
+ {
+diff --git a/mythtv/libs/libmythtv/videodisplayprofile.h
b/mythtv/libs/libmythtv/videodisplayprofile.h
+index 61119bb..c148861 100644
+--- a/mythtv/libs/libmythtv/videodisplayprofile.h
++++ b/mythtv/libs/libmythtv/videodisplayprofile.h
+@@ -153,7 +153,7 @@ class MTV_PUBLIC VideoDisplayProfile
+ static void CreateVDAProfiles(const QString &hostname);
+ static void CreateOpenGLProfiles(const QString &hostname);
+ static void CreateVAAPIProfiles(const QString &hostname);
+- static void CreateOpenMAXProfiles(const QString &hostname);
++ static void CreateOpenMAXProfiles(const QString &hostname, int upgrade =
0);
+
+ static QStringList GetVideoRenderers(const QString &decoder);
+ static QString GetVideoRendererHelp(const QString &renderer);
+diff --git a/mythtv/libs/libmythtv/videoout_omx.cpp
b/mythtv/libs/libmythtv/videoout_omx.cpp
+index 1b90ceb..2af88f9 100644
+--- a/mythtv/libs/libmythtv/videoout_omx.cpp
++++ b/mythtv/libs/libmythtv/videoout_omx.cpp
+@@ -4,6 +4,7 @@
+
+ #ifdef OSD_EGL /* includes QJson with enum value named Bool, must go before EGL/egl.h
*/
+ # include "mythpainter_ogl.h"
++# include "mythpainter_qimage.h"
+ #endif //def OSD_EGL
+
+ /* must go before X11/X.h due to #define None 0L */
+@@ -57,7 +58,7 @@ using namespace omxcontext;
+ /*
+ * Macros
+ */
+-#define LOC QString("VOMX:%1 ").arg(m_render.Id())
++#define LOC QString("VideoOutputOMX: ")
+
+ // Roundup a value: y = ROUNDUP(x,4)
+ #define ROUNDUP( _x,_z) ((_x) + ((-(int)(_x)) & ((_z) -1)) )
+@@ -118,8 +119,110 @@ private:
+ DISPMANX_DISPLAY_HANDLE_T m_dispman_display;
+ #endif
+ };
+-#endif //def OSD_EGL
+
++class GlOsdThread : public MThread
++{
++ public:
++ GlOsdThread() :
++ MThread("GlOsdThread")
++ {
++ isRunning = true;
++ m_osdImage = 0;
++ m_EGLRender = 0;
++ m_Painter = 0;
++ rectsChanged = false;
++ m_lock.lock();
++ }
++ virtual void run()
++ {
++ RunProlog();
++ m_EGLRender = new MythRenderEGL();
++ if (m_EGLRender->create())
++ {
++ m_EGLRender->Init();
++ m_Painter = new MythOpenGLPainter(m_EGLRender);
++ m_Painter->SetSwapControl(false);
++ LOG(VB_GENERAL, LOG_INFO, LOC + __func__ +
++ ": OSD display uses threaded opengl");
++
++ }
++ else
++ {
++ LOG(VB_GENERAL, LOG_ERR, LOC + __func__ +
++ ": failed to create MythRenderEGL for OSD");
++ m_EGLRender = 0;
++ m_Painter = 0;
++ isRunning = false;
++ }
++ m_lock.unlock();
++ while (isRunning)
++ {
++ m_lock.lock();
++ m_wait.wait(&m_lock);
++ if (!isRunning) {
++ m_lock.unlock();
++ break;
++ }
++
++ if (rectsChanged)
++ {
++ m_EGLRender->SetViewPort(m_displayRect);
++ m_EGLRender->SetViewPort(m_glRect,true);
++ rectsChanged = false;
++ }
++ m_EGLRender->makeCurrent();
++ m_EGLRender->BindFramebuffer(0);
++ m_Painter->DrawImage(m_bounds, m_osdImage,
++ m_bounds, 255);
++ m_EGLRender->swapBuffers();
++ m_EGLRender->SetBackground(0, 0, 0, 0);
++ m_EGLRender->ClearFramebuffer();
++ m_Painter->DeleteTextures();
++ m_EGLRender->doneCurrent();
++
++ m_lock.unlock();
++ }
++ if (m_osdImage)
++ m_osdImage->DecrRef(), m_osdImage = 0;
++ if (m_Painter)
++ delete m_Painter, m_Painter = 0;
++ if (m_EGLRender)
++ m_EGLRender->DecrRef(), m_EGLRender = 0;
++ RunEpilog();
++ }
++ // All of the below methods are called from another thread
++ void shutdown()
++ {
++ isRunning=false;
++ m_lock.tryLock(2000);
++ m_wait.wakeAll();
++ m_lock.unlock();
++ wait(2000);
++ }
++ bool isValid() {
++ return isRunning;
++ }
++ void setRects(const QRect &displayRect,const QRect &glRect)
++ {
++ m_displayRect = displayRect;
++ m_glRect = glRect;
++ rectsChanged = true;
++ }
++ private:
++ MythRenderEGL *m_EGLRender;
++ MythOpenGLPainter *m_Painter;
++ bool isRunning;
++ QRect m_displayRect;
++ QRect m_glRect;
++ bool rectsChanged;
++ public:
++ QMutex m_lock;
++ QWaitCondition m_wait;
++ MythImage *m_osdImage;
++ QRect m_bounds;
++};
++
++#endif //def OSD_EGL
+
+ /*
+ * Constants
+@@ -150,7 +253,8 @@ void VideoOutputOMX::GetRenderOptions(render_opts &opts,
+ (*opts.deints)[kName].append(kName + "linedouble");
+ #endif
+ #ifdef OSD_EGL
+- (*opts.osds)[kName].append("opengl2");
++ (*opts.osds)[kName].append("opengl");
++ (*opts.osds)[kName].append("threaded");
+ #endif
+ (*opts.osds)[kName].append("softblend");
+
+@@ -180,8 +284,13 @@ QStringList VideoOutputOMX::GetAllowedRenderers(
+ VideoOutputOMX::VideoOutputOMX() :
+ m_render(gCoreContext->GetSetting("OMXVideoRender", VIDEO_RENDER),
*this),
+ m_imagefx(gCoreContext->GetSetting("OMXVideoFilter", IMAGE_FX),
*this),
+- m_context(0), m_osdpainter(0), m_backgroundscreen(0)
++ m_context(0),
++ m_backgroundscreen(0), m_glOsdThread(0), m_changed(false)
+ {
++#ifdef OSD_EGL
++ m_osdpainter = 0;
++ m_threaded_osdpainter = 0;
++#endif
+ init(&av_pause_frame, FMT_YV12, NULL, 0, 0, 0);
+
+ if (gCoreContext->GetNumSetting("UseVideoModes", 0))
+@@ -225,9 +334,18 @@ VideoOutputOMX::~VideoOutputOMX()
+ DeleteBuffers();
+
+ #ifdef OSD_EGL
+- delete m_osdpainter, m_osdpainter = 0;
++ if (m_osdpainter)
++ delete m_osdpainter, m_osdpainter = 0;
+ if (m_context)
+ m_context->DecrRef(), m_context = 0;
++ if (m_glOsdThread)
++ {
++ m_glOsdThread->shutdown();
++ delete m_glOsdThread;
++ m_glOsdThread = 0;
++ }
++ if (m_threaded_osdpainter)
++ delete m_threaded_osdpainter, m_threaded_osdpainter = 0;
+ #endif
+
+ if (m_backgroundscreen)
+@@ -309,8 +427,9 @@ bool VideoOutputOMX::Init( // Return true if successful
+ if (!CreateBuffers(video_dim_buf, video_dim_disp, winid))
+ return false;
+
++ bool osdIsSet = false;
+ #ifdef OSD_EGL
+- if (GetOSDRenderer() == "opengl2")
++ if (GetOSDRenderer() == "opengl")
+ {
+ MythRenderEGL *render = new MythRenderEGL();
+ if (render->create())
+@@ -320,16 +439,35 @@ bool VideoOutputOMX::Init( // Return true if successful
+ MythOpenGLPainter *p = new MythOpenGLPainter(m_context);
+ p->SetSwapControl(false);
+ m_osdpainter = p;
++ LOG(VB_GENERAL, LOG_INFO, LOC + __func__ +
++ ": OSD display uses opengl");
++ osdIsSet = true;
+ }
+ else
+ {
+ LOG(VB_GENERAL, LOG_ERR, LOC + __func__ +
+- " failed to create MythRenderEGL");
++ ": failed to create MythRenderEGL");
+ render->DecrRef();
++ m_context = 0;
++ m_osdpainter = 0;
+ }
+ }
++ if (GetOSDRenderer() == "threaded")
++ {
++ m_glOsdThread = new GlOsdThread();
++ m_glOsdThread->start();
++ // Wait until set up
++ m_glOsdThread->m_lock.lock();
++ m_glOsdThread->m_lock.unlock();
++ if (m_glOsdThread->isValid())
++ osdIsSet = true;
++ }
+ #endif
+
++ if (!osdIsSet)
++ LOG(VB_GENERAL, LOG_INFO, LOC + __func__ +
++ ": OSD display uses softblend");
++
+ MoveResize();
+
+ m_disp_rect = m_vid_rect = QRect();
+@@ -756,7 +894,11 @@ void VideoOutputOMX::MoveResizeWindow(QRect)
+ bool VideoOutputOMX::hasFullScreenOSD(void) const
+ {
+ #ifdef OSD_EGL
+- if (m_context && m_osdpainter)
++ if (GetOSDRenderer() == "opengl"
++ && m_context && m_osdpainter)
++ return true;
++ if (GetOSDRenderer() == "threaded"
++ && m_glOsdThread && m_glOsdThread->isValid())
+ return true;
+ #endif
+ return VideoOutput::hasFullScreenOSD();
+@@ -765,17 +907,23 @@ bool VideoOutputOMX::hasFullScreenOSD(void) const
+ // virtual
+ MythPainter *VideoOutputOMX::GetOSDPainter(void)
+ {
+- return m_osdpainter ? m_osdpainter : VideoOutput::GetOSDPainter();
++#ifdef OSD_EGL
++ if (GetOSDRenderer() == "opengl")
++ return m_osdpainter;
++ if (GetOSDRenderer() == "threaded")
++ return m_threaded_osdpainter;
++#endif
++ return VideoOutput::GetOSDPainter();
+ }
+
+ // virtual
+ bool VideoOutputOMX::DisplayOSD(VideoFrame *frame, OSD *osd)
+ {
+ #ifdef OSD_EGL
+- if (m_context && m_osdpainter)
++ if (GetOSDRenderer() == "opengl"
++ && m_context && m_osdpainter)
+ {
+ m_context->makeCurrent();
+-
+ m_context->BindFramebuffer(0);
+
+ QRect bounds = GetTotalOSDBounds();
+@@ -799,6 +947,61 @@ bool VideoOutputOMX::DisplayOSD(VideoFrame *frame, OSD *osd)
+ m_context->doneCurrent();
+ return true;
+ }
++
++ if (GetOSDRenderer() == "threaded"
++ && m_glOsdThread && m_glOsdThread->isValid())
++ {
++ if (!m_threaded_osdpainter)
++ {
++ m_threaded_osdpainter = new MythQImagePainter();
++ if (!m_threaded_osdpainter)
++ return false;
++ }
++ QSize osd_size = GetTotalOSDBounds().size();
++ if (m_glOsdThread->m_osdImage &&
(m_glOsdThread->m_osdImage->size() != osd_size))
++ {
++ LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("OSD size changed."));
++ m_glOsdThread->m_osdImage->DecrRef();
++ m_glOsdThread->m_osdImage = 0;
++ }
++ if (!m_glOsdThread->m_osdImage)
++ {
++ m_glOsdThread->m_osdImage = m_threaded_osdpainter->GetFormatImage();
++ if (m_glOsdThread->m_osdImage)
++ {
++ QImage blank = QImage(osd_size,
++ QImage::Format_ARGB32_Premultiplied);
++ m_glOsdThread->m_osdImage->Assign(blank);
++ m_threaded_osdpainter->Clear(m_glOsdThread->m_osdImage,
++ QRegion(QRect(QPoint(0,0), osd_size)));
++ LOG(VB_GENERAL, LOG_INFO, LOC + QString("Created OSD
QImage."));
++ }
++ else {
++ LOG(VB_GENERAL, LOG_ERR, LOC + QString("Unable to create OSD
QImage."));
++ return false;
++ }
++ }
++ if (m_visual)
++ {
++ LOG(VB_GENERAL, LOG_ERR, LOC + "Visualiser not supported here");
++ m_visual->Draw(QRect(), NULL, NULL);
++ }
++
++ if (m_glOsdThread->m_lock.tryLock(0)) {
++ QRegion dirty = QRegion();
++ QRegion visible = osd->Draw(m_threaded_osdpainter,
++ m_glOsdThread->m_osdImage, osd_size, dirty);
++ m_changed = m_changed || !dirty.isEmpty();
++ m_glOsdThread->m_osdImage->SetChanged(m_changed);
++ m_glOsdThread->m_bounds = GetTotalOSDBounds();
++ m_glOsdThread->m_lock.unlock();
++ if (m_changed) {
++ m_glOsdThread->m_wait.wakeAll();
++ m_changed = false;
++ }
++ }
++ return true;
++ }
+ #endif
+ return VideoOutput::DisplayOSD(frame, osd);
}
+@@ -1072,8 +1275,27 @@ bool VideoOutputOMX::SetVideoRect(const QRect &d_rect, const
QRect &vid_rect)
+ #endif // USING_BROADCOM
+
+ #ifdef OSD_EGL
+- if (m_context)
+- m_context->SetViewPort(window.GetDisplayVisibleRect());
++ if (m_context
++ || ( m_glOsdThread && m_glOsdThread->isValid() ) )
++ {
++ QRect displayRect = window.GetDisplayVisibleRect();
++ QRect mainRect = GetMythMainWindow()->geometry();
++ uint32_t maxwidth = 0, maxheight = 0;
++ graphics_get_display_size(DISPMANX_ID_MAIN_LCD, &maxwidth, &maxheight);
++ QRect glRect(mainRect.x(), // left
++ maxheight-mainRect.bottom(), // top
++ 0,0);
++ glRect.setRight(mainRect.right());
++ glRect.setBottom(glRect.top()+mainRect.height());
++ if (m_context)
++ {
++ m_context->SetViewPort(displayRect);
++ m_context->SetViewPort(glRect,true);
++ }
++ if (m_glOsdThread && m_glOsdThread->isValid()) {
++ m_glOsdThread->setRects(displayRect,glRect);
++ }
++ }
+ #endif
+
+ m_disp_rect = disp_rect;
+@@ -1193,6 +1415,8 @@ MythRenderEGL::MythRenderEGL() :
+ m_window(0),
+ m_surface(EGL_NO_SURFACE)
+ {
++ // Disable flush to get performance improvement
++ m_flushEnabled = false;
+ // get an EGL display connection
+ m_display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
+ if (m_display == EGL_NO_DISPLAY)
+@@ -1320,6 +1544,7 @@ MythRenderEGL::~MythRenderEGL()
+ assert(b == EGL_TRUE);
+ #endif
+ m_display = EGL_NO_DISPLAY;
++ DeleteOpenGLResources();
+ }
+
+ EGLNativeWindowType MythRenderEGL::createNativeWindow()
+diff --git a/mythtv/libs/libmythtv/videoout_omx.h b/mythtv/libs/libmythtv/videoout_omx.h
+index 4760377..fb162d1 100644
+--- a/mythtv/libs/libmythtv/videoout_omx.h
++++ b/mythtv/libs/libmythtv/videoout_omx.h
+@@ -12,6 +12,10 @@
+ #include "omxcontext.h"
+
+ class MythRenderEGL;
++class GlOsdThread;
++#ifdef OSD_EGL
++class MythOpenGLPainter;
++#endif
+
+ class VideoOutputOMX : public VideoOutput, private OMXComponentCtx
+ {
+@@ -77,8 +81,13 @@ class VideoOutputOMX : public VideoOutput, private OMXComponentCtx
+ QRect m_disp_rect, m_vid_rect;
+ QVector<void*> m_bufs;
+ MythRenderEGL *m_context;
+- MythPainter *m_osdpainter;
++#ifdef OSD_EGL
++ MythOpenGLPainter *m_osdpainter;
++ MythPainter *m_threaded_osdpainter;
++#endif
+ MythScreenType *m_backgroundscreen;
++ GlOsdThread *m_glOsdThread;
++ bool m_changed;
+ };
+
+ #endif // ndef VIDEOOUT_OMX_H
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
@@ -61536,6 +62467,130 @@ index 00a8c73..a761e32 100644
return m_priv->valid;
}
+diff --git a/mythtv/libs/libmythui/libmythui.pro b/mythtv/libs/libmythui/libmythui.pro
+index 47e46e1..321e9a3 100644
+--- a/mythtv/libs/libmythui/libmythui.pro
++++ b/mythtv/libs/libmythui/libmythui.pro
+@@ -175,8 +175,8 @@ mingw | win32-msvc*{
+ }
+
+ using_opengl {
+- DEFINES += USE_OPENGL_PAINTER
+- SOURCES += mythpainter_ogl.cpp mythrender_opengl.cpp
++ using_opengl_themepainter:DEFINES += USE_OPENGL_PAINTER
++ SOURCES += mythpainter_ogl.cpp mythrender_opengl.cpp
+ SOURCES += mythrender_opengl2.cpp
+ HEADERS += mythpainter_ogl.h mythrender_opengl.h mythrender_opengl_defs.h
+ HEADERS += mythrender_opengl2.h mythrender_opengl_defs2.h
+diff --git a/mythtv/libs/libmythui/mythdialogbox.cpp
b/mythtv/libs/libmythui/mythdialogbox.cpp
+index c5fa698..4467e4a 100644
+--- a/mythtv/libs/libmythui/mythdialogbox.cpp
++++ b/mythtv/libs/libmythui/mythdialogbox.cpp
+@@ -274,6 +274,10 @@ void MythDialogBox::updateMenu(void)
+ if (m_currentMenu->m_selectedItem == x)
+ m_buttonList->SetItemCurrent(button);
+ }
++ // GetVisibleCount here makes sure that the dialog size is
++ // calculated correctly
++ m_buttonList->GetVisibleCount();
++ GetMythMainWindow()->GetMainStack()->GetTopScreen()->SetRedraw();
+ }
+
+ void MythDialogBox::Select(MythUIButtonListItem* item)
+@@ -354,6 +358,9 @@ void MythDialogBox::AddButton(const QString &title, QVariant
data, bool newMenu,
+
+ if (setCurrent)
+ m_buttonList->SetItemCurrent(button);
++ // GetVisibleCount here makes sure that the dialog size is
++ // calculated correctly
++ m_buttonList->GetVisibleCount();
+ }
+
+ void MythDialogBox::AddButton(const QString &title, const char *slot,
+@@ -369,6 +376,9 @@ void MythDialogBox::AddButton(const QString &title, const char
*slot,
+
+ if (setCurrent)
+ m_buttonList->SetItemCurrent(button);
++ // GetVisibleCount here makes sure that the dialog size is
++ // calculated correctly
++ m_buttonList->GetVisibleCount();
+ }
+
+ bool MythDialogBox::keyPressEvent(QKeyEvent *event)
+diff --git a/mythtv/libs/libmythui/mythmainwindow.cpp
b/mythtv/libs/libmythui/mythmainwindow.cpp
+index 56b8dfb..8a903c6 100644
+--- a/mythtv/libs/libmythui/mythmainwindow.cpp
++++ b/mythtv/libs/libmythui/mythmainwindow.cpp
+@@ -2711,6 +2711,13 @@ void MythMainWindow::customEvent(QEvent *ce)
+ MythNotificationCenter::GetInstance()->Queue(mn);
+ return;
+ }
++ else if (message == "RECONNECT_SUCCESS" && d->standby ==
true)
++ {
++ // If the connection to the master backend has just been (re-)established
++ // but we're in standby, make sure the backend is not blocked from
++ // shutting down.
++ gCoreContext->AllowShutdown();
++ }
+ }
+ else if ((MythEvent::Type)(ce->type()) == MythEvent::MythUserMessage)
+ {
+diff --git a/mythtv/libs/libmythui/mythpainter_ogl.h
b/mythtv/libs/libmythui/mythpainter_ogl.h
+index 629dca7..13af273 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
+
+ virtual void PushTransformation(const UIEffects &fx, QPointF center =
QPointF());
+ virtual void PopTransformation(void);
++ void DeleteTextures(void);
+
+ protected:
+ virtual MythImage* GetFormatImagePriv(void) { return new MythImage(this); }
+ virtual void DeleteFormatImagePriv(MythImage *im);
+
+ void ClearCache(void);
+- void DeleteTextures(void);
+ int GetTextureFromCache(MythImage *im);
+
+ QWidget *realParent;
+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
++++ b/mythtv/libs/libmythui/mythrender_opengl.cpp
+@@ -365,7 +365,8 @@ void MythRenderOpenGL::Flush(bool use_fence)
+ }
+ else
+ {
+- glFlush();
++ if (m_flushEnabled)
++ glFlush();
+ }
+
+ doneCurrent();
+@@ -1136,6 +1137,7 @@ void MythRenderOpenGL::ResetVars(void)
+ m_active_fb = 0;
+ m_blend = false;
+ m_background = 0x00000000;
++ m_flushEnabled = true;
+ }
+
+ void MythRenderOpenGL::ResetProcs(void)
+diff --git a/mythtv/libs/libmythui/mythrender_opengl.h
b/mythtv/libs/libmythui/mythrender_opengl.h
+index 3543fa9..adaf302 100644
+--- a/mythtv/libs/libmythui/mythrender_opengl.h
++++ b/mythtv/libs/libmythui/mythrender_opengl.h
+@@ -271,6 +271,10 @@ class MUI_PUBLIC MythRenderOpenGL : protected MythRenderContext,
public MythRend
+ QMap<uint64_t,GLuint> m_cachedVBOS;
+ QList<uint64_t> m_vboExpiry;
+
++ // For Performance improvement set false to disable glFlush.
++ // Needed for Raspberry pi
++ bool m_flushEnabled;
++
+ // 1D Textures (not available on GL ES 2.0)
+ MYTH_GLTEXIMAGE1DPROC m_glTexImage1D;
+
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
@@ -61549,6 +62604,640 @@ index b099c46..af41c91 100644
m_interface->lastError().message());
}
else
+diff --git a/mythtv/libs/libmythupnp/httprequest.cpp
b/mythtv/libs/libmythupnp/httprequest.cpp
+index 12acb04..c32e1d9 100644
+--- a/mythtv/libs/libmythupnp/httprequest.cpp
++++ b/mythtv/libs/libmythupnp/httprequest.cpp
+@@ -3,10 +3,10 @@
+ // Created : Oct. 21, 2005
+ //
+ // Purpose : Http Request/Response
+-//
++//
+ // Copyright (c) 2005 David Blain <dblain(a)mythtv.org>
+-//
+-// Licensed under the GPL v2 or later, see COPYING for details
++//
++// Licensed under the GPL v2 or later, see COPYING for details
+ //
+ //////////////////////////////////////////////////////////////////////////////
+
+@@ -52,6 +52,8 @@
+ #include "serializers/jsonSerializer.h"
+ #include "serializers/xmlplistSerializer.h"
+
++#include <unistd.h> // for gethostname
++
+ #ifndef O_LARGEFILE
+ #define O_LARGEFILE 0
+ #endif
+@@ -289,7 +291,8 @@ QString HTTPRequest::BuildResponseHeader( long long nSize )
+ SetResponseHeader("contentFeatures.dlna.org",
"DLNA.ORG_OP=01;DLNA.ORG_CI=0;DLNA.ORG_FLAGS=01500000000000000000000000000000");
+ }
+
+- // ----------------------------------------------------------------------
++ if (!m_mapHeaders[ "origin" ].isEmpty())
++ AddCORSHeaders(m_mapHeaders[ "origin" ]);
+
+ if (getenv("HTTPREQUEST_DEBUG"))
+ {
+@@ -435,54 +438,6 @@ qint64 HTTPRequest::SendResponse( void )
+ }
+
+ // ----------------------------------------------------------------------
+- // SECURITY: Access-Control-Allow-Origin Wildcard
+- //
+- // This is a REALLY bad idea, so bad in fact that I'm including it here but
+- // commented out in the hope that anyone thinking of adding it in the future
+- // will see it and then read this comment.
+- //
+- // Browsers do not verify that the origin is on the same network. This means
+- // that a malicious script embedded or included into ANY webpage you visit
+- // could then access servers on your local network including MythTV. They
+- // can grab data, delete data including recordings and videos, schedule
+- // recordings and generally ruin your day.
+- //
+- // This might seem paranoid and a remote possibility, but then that's how
+- // a lot of exploits are born. Do NOT allow wildcards.
+- //
+- //m_mapRespHeaders[ "Access-Control-Allow-Origin" ] = "*";
+- // ----------------------------------------------------------------------
+-
+- // ----------------------------------------------------------------------
+- // SECURITY: Allow the WebFrontend on the Master backend and ONLY this
+- // machine to access resources on a frontend or slave web server
+- //
+- // TODO: Add hostname:port combo as well as ip:port
+- //
+- //
http://www.w3.org/TR/cors/#introduction
+- // ----------------------------------------------------------------------
+- QString masterAddrPort =
QString("%1:%2").arg(gCoreContext->GetMasterServerIP())
+-
.arg(gCoreContext->GetMasterServerStatusPort());
+- QString masterTLSAddrPort =
QString("%1:%2").arg(gCoreContext->GetMasterServerIP())
+- .arg(gCoreContext->GetSetting(
"BackendSSLPort",
+-
QString(gCoreContext->GetMasterServerStatusPort() + 10)));
+-
+- QStringList allowedOrigins;
+- allowedOrigins << QString("http://%1").arg(masterAddrPort);
+- allowedOrigins << QString("https://%2").arg(masterTLSAddrPort);
+-
+- if (!m_mapHeaders[ "origin" ].isEmpty())
+- {
+- if (allowedOrigins.contains(m_mapHeaders[ "origin" ]))
+- SetResponseHeader( "Access-Control-Allow-Origin" ,
+- m_mapHeaders[ "origin" ]);
+- else
+- LOG(VB_GENERAL, LOG_CRIT, QString("HTTPRequest: Cross-origin request
"
+- "received with origin (%1)")
+- .arg(m_mapHeaders[ "origin"
]));
+- }
+-
+- // ----------------------------------------------------------------------
+ // Write out Header.
+ // ----------------------------------------------------------------------
+
+@@ -590,10 +545,10 @@ qint64 HTTPRequest::SendResponseFile( QString sFileName )
+ {
+ bRange = ParseRange( sRange, llSize, &llStart, &llEnd );
+
+- // Adjust ranges that are too long.
++ // Adjust ranges that are too long.
+
+- if (llEnd >= llSize)
+- llEnd = llSize-1;
++ if (llEnd >= llSize)
++ llEnd = llSize-1;
+
+ if ((llSize > llStart) && (llSize > llEnd) && (llEnd
> llStart))
+ {
+@@ -741,7 +696,7 @@ qint64 HTTPRequest::SendData( QIODevice *pDevice, qint64 llStart,
qint64 llBytes
+ while ((sent < llBytes) && !pDevice->atEnd())
+ {
+ llBytesToRead = std::min( (qint64)SENDFILE_BUFFER_SIZE, llBytesRemaining );
+-
++
+ if (( llBytesRead = pDevice->read( aBuffer, llBytesToRead )) != -1 )
+ {
+ if (( llBytesWritten = WriteBlock( aBuffer, llBytesRead )) == -1)
+@@ -761,7 +716,7 @@ qint64 HTTPRequest::SendData( QIODevice *pDevice, qint64 llStart,
qint64 llBytes
+ }
+
+ /////////////////////////////////////////////////////////////////////////////
+-//
++//
+ /////////////////////////////////////////////////////////////////////////////
+
+ qint64 HTTPRequest::SendFile( QFile &file, qint64 llStart, qint64 llBytes )
+@@ -1570,7 +1525,7 @@ bool HTTPRequest::ParseRange( QString sRange,
+ long long *pllEnd )
+ {
+ // ----------------------------------------------------------------------
+- // -=>TODO: Only handle 1 range at this time...
++ // -=>TODO: Only handle 1 range at this time...
+ // should make work with full spec.
+ // ----------------------------------------------------------------------
+
+@@ -1753,7 +1708,7 @@ bool HTTPRequest::ProcessSOAPPayload( const QString
&sSOAPAction )
+ QDomNodeList oNodeList = doc.elementsByTagNameNS( m_sNameSpace, m_sMethod );
+
+ if (oNodeList.count() == 0)
+- oNodeList =
++ oNodeList =
+
doc.elementsByTagNameNS("http://schemas.xmlsoap.org/soap/envelope/",
+ "Body");
+
+@@ -1802,17 +1757,17 @@ Serializer *HTTPRequest::GetSerializer()
+ {
+ Serializer *pSerializer = NULL;
+
+- if (m_bSOAPRequest)
++ if (m_bSOAPRequest)
+ pSerializer = (Serializer *)new SoapSerializer(&m_response,
+ m_sNameSpace, m_sMethod);
+ else
+ {
+ QString sAccept = GetRequestHeader( "Accept", "*/*" );
+-
+- if (sAccept.contains( "application/json", Qt::CaseInsensitive ))
++
++ if (sAccept.contains( "application/json", Qt::CaseInsensitive ))
+ pSerializer = (Serializer *)new JSONSerializer(&m_response,
+ m_sMethod);
+- else if (sAccept.contains( "text/javascript", Qt::CaseInsensitive ))
++ else if (sAccept.contains( "text/javascript", Qt::CaseInsensitive ))
+ pSerializer = (Serializer *)new JSONSerializer(&m_response,
+ m_sMethod);
+ else if (sAccept.contains( "text/x-apple-plist+xml",
Qt::CaseInsensitive ))
+@@ -2303,6 +2258,97 @@ QString HTTPRequest::GetRequestType( ) const
+ return type;
+ }
+
++void HTTPRequest::AddCORSHeaders( const QString &sOrigin )
++{
++ // ----------------------------------------------------------------------
++ // SECURITY: Access-Control-Allow-Origin Wildcard
++ //
++ // This is a REALLY bad idea, so bad in fact that I'm including it here but
++ // commented out in the hope that anyone thinking of adding it in the future
++ // will see it and then read this comment.
++ //
++ // Browsers do not verify that the origin is on the same network. This means
++ // that a malicious script embedded or included into ANY webpage you visit
++ // could then access servers on your local network including MythTV. They
++ // can grab data, delete data including recordings and videos, schedule
++ // recordings and generally ruin your day.
++ //
++ // This might seem paranoid and a remote possibility, but then that's how
++ // a lot of exploits are born. Do NOT allow wildcards.
++ //
++ //m_mapRespHeaders[ "Access-Control-Allow-Origin" ] = "*";
++ // ----------------------------------------------------------------------
++
++ // ----------------------------------------------------------------------
++ // SECURITY: Allow the WebFrontend on the Master backend and ONLY this
++ // machine to access resources on a frontend or slave web server
++ //
++ //
http://www.w3.org/TR/cors/#introduction
++ // ----------------------------------------------------------------------
++
++ QStringList allowedOrigins;
++ char localhostname[1024]; // about HOST_NAME_MAX * 4
++
++ int serverStatusPort = gCoreContext->GetMasterServerStatusPort();
++ int backendSSLPort = gCoreContext->GetNumSetting( "BackendSSLPort",
++ serverStatusPort + 10);
++
++ QString masterAddrPort = QString("%1:%2")
++ .arg(gCoreContext->GetMasterServerIP())
++ .arg(serverStatusPort);
++ QString masterTLSAddrPort = QString("%1:%2")
++ .arg(gCoreContext->GetMasterServerIP())
++ .arg(backendSSLPort);
++
++ allowedOrigins << QString("http://%1").arg(masterAddrPort);
++ allowedOrigins << QString("https://%2").arg(masterTLSAddrPort);
++
++ if (!gethostname(localhostname, 1024))
++ {
++ allowedOrigins << QString("http://%1:%2")
++ .arg(localhostname).arg(serverStatusPort);
++ allowedOrigins << QString("https://%1:%2")
++ .arg(localhostname).arg(backendSSLPort);
++ }
++
++ QStringList allowedOriginsList =
++ gCoreContext->GetSetting("AllowedOriginsList", QString(
++ "https://chromecast.mythtv.org,"
++ "http://chromecast.mythtvcast.com"
++ )).split(",");
++
++ for (QStringList::const_iterator it = allowedOriginsList.begin();
++ it != allowedOriginsList.end(); it++)
++ {
++ if ((*it).isEmpty())
++ continue;
++
++ if (*it == "*" || (!(*it).startsWith("http://") &&
++ !(*it).startsWith("https://")))
++ LOG(VB_GENERAL, LOG_ERR, QString("Illegal AllowedOriginsList"
++ " entry '%1'. Must start with http[s]:// and not be
*")
++ .arg(*it));
++ else
++ allowedOrigins << *it;
++ }
++
++ if (VERBOSE_LEVEL_CHECK(VB_HTTP, LOG_DEBUG))
++ for (QStringList::const_iterator it = allowedOrigins.begin();
++ it != allowedOrigins.end(); it++)
++ LOG(VB_HTTP, LOG_DEBUG, QString("Will allow Origin:
%1").arg(*it));
++
++ if (allowedOrigins.contains(sOrigin))
++ {
++ SetResponseHeader( "Access-Control-Allow-Origin" , sOrigin);
++ SetResponseHeader( "Access-Control-Allow-Credentials" ,
"true");
++ SetResponseHeader( "Access-Control-Allow-Headers" ,
"Content-Type");
++ LOG(VB_HTTP, LOG_DEBUG, QString("Allow-Origin: %1)").arg(sOrigin));
++ }
++ else
++ LOG(VB_GENERAL, LOG_CRIT, QString("HTTPRequest: Cross-origin request
"
++ "received with origin (%1)")
++ .arg(sOrigin));
++}
+
+ /////////////////////////////////////////////////////////////////////////////
+ /////////////////////////////////////////////////////////////////////////////
+diff --git a/mythtv/libs/libmythupnp/httprequest.h
b/mythtv/libs/libmythupnp/httprequest.h
+index c52ae07..c3a9eb7 100644
+--- a/mythtv/libs/libmythupnp/httprequest.h
++++ b/mythtv/libs/libmythupnp/httprequest.h
+@@ -3,10 +3,10 @@
+ // Created : Oct. 21, 2005
+ //
+ // Purpose : Http Request/Response
+-//
++//
+ // Copyright (c) 2005 David Blain <dblain(a)mythtv.org>
+-//
+-// Licensed under the GPL v2 or later, see COPYING for details
++//
++// Licensed under the GPL v2 or later, see COPYING for details
+ //
+ //////////////////////////////////////////////////////////////////////////////
+
+@@ -36,7 +36,7 @@
+ // Typedefs / Defines
+ /////////////////////////////////////////////////////////////////////////////
+
+-typedef enum
++typedef enum
+ {
+ RequestTypeUnknown = 0x0000,
+ // HTTP 1.1
+@@ -56,9 +56,9 @@ typedef enum
+ // Not a request type
+ RequestTypeResponse = 0x1000
+
+-} RequestType;
++} RequestType;
+
+-typedef enum
++typedef enum
+ {
+ ContentType_Unknown = 0,
+ ContentType_Urlencoded = 1,
+@@ -66,7 +66,7 @@ typedef enum
+
+ } ContentType;
+
+-typedef enum
++typedef enum
+ {
+ ResponseTypeNone = -1,
+ ResponseTypeUnknown = 0,
+@@ -99,7 +99,7 @@ class IPostProcess
+ };
+
+ /////////////////////////////////////////////////////////////////////////////
+-//
++//
+ /////////////////////////////////////////////////////////////////////////////
+
+ class UPNP_PUBLIC HTTPRequest
+@@ -111,8 +111,8 @@ class UPNP_PUBLIC HTTPRequest
+ QRegExp m_procReqLineExp;
+ QRegExp m_parseRangeExp;
+
+- public:
+-
++ public:
++
+ RequestType m_eType;
+ ContentType m_eContentType;
+
+@@ -175,9 +175,9 @@ class UPNP_PUBLIC HTTPRequest
+ QString GetResponseType ( void );
+ QString GetResponseHeaders ( void );
+
+- bool ParseRange ( QString sRange,
+- long long llSize,
+- long long *pllStart,
++ bool ParseRange ( QString sRange,
++ long long llSize,
++ long long *pllStart,
+ long long *pllEnd );
+
+ bool ParseKeepAlive ( void );
+@@ -198,16 +198,17 @@ class UPNP_PUBLIC HTTPRequest
+
+ bool BasicAuthentication ();
+ bool DigestAuthentication ();
++ void AddCORSHeaders ( const QString &sOrigin );
+
+ public:
+-
++
+ HTTPRequest ();
+ virtual ~HTTPRequest () {};
+
+ bool ParseRequest ();
+
+- void FormatErrorResponse ( bool bServerError,
+- const QString &sFaultString,
++ void FormatErrorResponse ( bool bServerError,
++ const QString &sFaultString,
+ const QString &sDetails );
+
+ void FormatActionResponse( Serializer *ser );
+@@ -265,17 +266,17 @@ class UPNP_PUBLIC HTTPRequest
+ };
+
+ /////////////////////////////////////////////////////////////////////////////
+-//
++//
+ /////////////////////////////////////////////////////////////////////////////
+
+ class BufferedSocketDeviceRequest : public HTTPRequest
+ {
+- public:
++ public:
+
+ QTcpSocket *m_pSocket;
+
+ public:
+-
++
+ explicit BufferedSocketDeviceRequest( QTcpSocket *pSocket );
+ virtual ~BufferedSocketDeviceRequest() {};
+
+@@ -290,7 +291,7 @@ class BufferedSocketDeviceRequest : public HTTPRequest
+ };
+
+ /////////////////////////////////////////////////////////////////////////////
+-//
++//
+ /////////////////////////////////////////////////////////////////////////////
+
+ class UPNP_PUBLIC HttpException
+@@ -299,12 +300,12 @@ class UPNP_PUBLIC HttpException
+ int code;
+ QString msg;
+
+- HttpException( int nCode = -1, const QString &sMsg = "")
+- : code( nCode ), msg ( sMsg )
++ HttpException( int nCode = -1, const QString &sMsg = "")
++ : code( nCode ), msg ( sMsg )
+ {}
+
+ // Needed to force a v-table.
+- virtual ~HttpException()
++ virtual ~HttpException()
+ {}
+ };
+
+@@ -315,13 +316,13 @@ class UPNP_PUBLIC HttpRedirectException : public HttpException
+ QString hostName;
+ //int port;
+
+- HttpRedirectException( const QString &sHostName = "",
+- int nCode = -1,
+- const QString &sMsg = "" )
++ HttpRedirectException( const QString &sHostName = "",
++ int nCode = -1,
++ const QString &sMsg = "" )
+ : HttpException( nCode, sMsg ), hostName( sHostName )
+ {}
+
+- virtual ~HttpRedirectException()
++ virtual ~HttpRedirectException()
+ {}
+
+ };
+diff --git a/mythtv/programs/mythbackend/autoexpire.cpp
b/mythtv/programs/mythbackend/autoexpire.cpp
+index eb63ea4..0c1b9e8 100644
+--- a/mythtv/programs/mythbackend/autoexpire.cpp
++++ b/mythtv/programs/mythbackend/autoexpire.cpp
+@@ -59,14 +59,6 @@ void ExpireThread::run(void)
+ RunEpilog();
+ }
+
+-/// \brief This calls AutoExpire::RunUpdate() from within a new thread.
+-void UpdateThread::run(void)
+-{
+- RunProlog();
+- m_parent->RunUpdate();
+- RunEpilog();
+-}
+-
+ /** \class AutoExpire
+ * \brief Used to expire recordings to make space for new recordings.
+ */
+@@ -81,9 +73,7 @@ AutoExpire::AutoExpire(QMap<int, EncoderLink *> *tvList) :
+ expire_thread(new ExpireThread(this)),
+ desired_freq(15),
+ expire_thread_run(true),
+- main_server(NULL),
+- update_pending(false),
+- update_thread(NULL)
++ main_server(NULL)
+ {
+ expire_thread->start();
+ gCoreContext->addListener(this);
+@@ -97,9 +87,7 @@ AutoExpire::AutoExpire() :
+ expire_thread(NULL),
+ desired_freq(15),
+ expire_thread_run(false),
+- main_server(NULL),
+- update_pending(false),
+- update_thread(NULL)
++ main_server(NULL)
+ {
+ }
+
+@@ -115,9 +103,8 @@ AutoExpire::~AutoExpire()
+ }
+
+ {
+- QMutexLocker locker(&instance_lock);
+- while (update_pending)
+- instance_cond.wait(&instance_lock);
++ QMutexLocker locker(&update_lock);
++ update_queue.clear();
+ }
+
+ if (expire_thread)
+@@ -303,6 +290,15 @@ void AutoExpire::RunExpirer(void)
+ // recalculate auto expire parameters
+ if (curTime >= next_expire)
+ {
++ update_lock.lock();
++ while (!update_queue.empty())
++ {
++ UpdateEntry ue = update_queue.dequeue();
++ if (ue.encoder > 0)
++ used_encoders[ue.encoder] = ue.fsID;
++ }
++ update_lock.unlock();
++
+ locker.unlock();
+ CalcParams();
+ locker.relock();
+@@ -1032,24 +1028,6 @@ void AutoExpire::FillDBOrdered(pginfolist_t &expireList, int
expMethod)
+ }
+ }
+
+-/** \brief This is used by Update(QMap<int, EncoderLink*> *, bool)
+- * to run CalcParams(vector<EncoderLink*>).
+- *
+- * \param autoExpireInstance AutoExpire instance on which to call CalcParams.
+- */
+-void AutoExpire::RunUpdate(void)
+-{
+- QMutexLocker locker(&instance_lock);
+- Sleep(5 * 1000);
+- locker.unlock();
+- CalcParams();
+- locker.relock();
+- update_pending = false;
+- update_thread->deleteLater();
+- update_thread = NULL;
+- instance_cond.wakeAll();
+-}
+-
+ /**
+ * \brief This is used to update the global AutoExpire instance "expirer".
+ *
+@@ -1066,12 +1044,6 @@ void AutoExpire::Update(int encoder, int fsID, bool immediately)
+ if (!expirer)
+ return;
+
+- // make sure there is only one update pending
+- QMutexLocker locker(&expirer->instance_lock);
+- while (expirer->update_pending)
+- expirer->instance_cond.wait(&expirer->instance_lock);
+- expirer->update_pending = true;
+-
+ if (encoder > 0)
+ {
+ QString msg = QString("Cardid %1: is starting a recording on")
+@@ -1080,28 +1052,25 @@ void AutoExpire::Update(int encoder, int fsID, bool immediately)
+ msg.append(" an unknown fsID soon.");
+ else
+ msg.append(QString(" fsID %2 soon.").arg(fsID));
+-
+ LOG(VB_FILE, LOG_INFO, LOC + msg);
+- expirer->used_encoders[encoder] = fsID;
+ }
+
+- // do it..
+ if (immediately)
+ {
+- locker.unlock();
++ if (encoder > 0)
++ {
++ expirer->instance_lock.lock();
++ expirer->used_encoders[encoder] = fsID;
++ expirer->instance_lock.unlock();
++ }
+ expirer->CalcParams();
+- locker.relock();
+- expirer->update_pending = false;
+ expirer->instance_cond.wakeAll();
+ }
+ else
+ {
+- // create thread to do work, unless one is running still
+- if (!expirer->update_thread)
+- {
+- expirer->update_thread = new UpdateThread(expirer);
+- expirer->update_thread->start();
+- }
++ expirer->update_lock.lock();
++ expirer->update_queue.append(UpdateEntry(encoder, fsID));
++ expirer->update_lock.unlock();
+ }
+ }
+
+diff --git a/mythtv/programs/mythbackend/autoexpire.h
b/mythtv/programs/mythbackend/autoexpire.h
+index 59c6ede..a8646d7 100644
+--- a/mythtv/programs/mythbackend/autoexpire.h
++++ b/mythtv/programs/mythbackend/autoexpire.h
+@@ -12,6 +12,7 @@ using namespace std;
+ #include <QObject>
+ #include <QString>
+ #include <QMutex>
++#include <QQueue>
+ #include <QSet>
+ #include <QMap>
+
+@@ -48,15 +49,14 @@ class ExpireThread : public MThread
+ QPointer<AutoExpire> m_parent;
+ };
+
+-class UpdateThread : public QObject, public MThread
++class UpdateEntry
+ {
+- Q_OBJECT
+ public:
+- explicit UpdateThread(AutoExpire *p) : MThread("Update"), m_parent(p) {}
+- virtual ~UpdateThread() { wait(); }
+- virtual void run(void);
+- private:
+- QPointer<AutoExpire> m_parent;
++ UpdateEntry(int _encoder, int _fsID)
++ : encoder(_encoder), fsID(_fsID) {};
++
++ int encoder;
++ int fsID;
+ };
+
+ class AutoExpire : public QObject
+@@ -64,7 +64,6 @@ class AutoExpire : public QObject
+ Q_OBJECT
+
+ friend class ExpireThread;
+- friend class UpdateThread;
+ public:
+ explicit AutoExpire(QMap<int, EncoderLink *> *encoderList);
+ AutoExpire(void);
+@@ -92,7 +91,6 @@ class AutoExpire : public QObject
+
+ protected:
+ void RunExpirer(void);
+- void RunUpdate(void);
+
+ private:
+ void ExpireLiveTV(int type);
+@@ -126,8 +124,8 @@ class AutoExpire : public QObject
+ MainServer *main_server; // protected by instance_lock
+
+ // update info
+- bool update_pending; // protected by instance_lock
+- UpdateThread *update_thread;
++ QMutex update_lock;
++ QQueue<UpdateEntry> update_queue; // protected by update_lock
+ };
+
+ #endif
diff --git a/mythtv/programs/mythbackend/backendhousekeeper.cpp
b/mythtv/programs/mythbackend/backendhousekeeper.cpp
index 3d7296e..7c3ed2e 100644
--- a/mythtv/programs/mythbackend/backendhousekeeper.cpp
@@ -61562,6 +63251,71 @@ index 3d7296e..7c3ed2e 100644
int pos = subexp.indexIn(MYTH_SOURCE_VERSION);
if (pos > -1)
{
+diff --git a/mythtv/programs/mythbackend/scheduler.cpp
b/mythtv/programs/mythbackend/scheduler.cpp
+index 287b41b..9642eb4 100644
+--- a/mythtv/programs/mythbackend/scheduler.cpp
++++ b/mythtv/programs/mythbackend/scheduler.cpp
+@@ -306,12 +306,12 @@ static bool comp_recstart(RecordingInfo *a, RecordingInfo *b)
+ {
+ if (a->GetRecordingStartTime() != b->GetRecordingStartTime())
+ return a->GetRecordingStartTime() < b->GetRecordingStartTime();
+- if (a->GetRecordingEndTime() != b->GetRecordingEndTime())
+- return a->GetRecordingEndTime() < b->GetRecordingEndTime();
+ int cmp = a->GetChannelSchedulingID().compare(b->GetChannelSchedulingID(),
+ Qt::CaseInsensitive);
+ if (cmp != 0)
+ return cmp < 0;
++ if (a->GetRecordingEndTime() != b->GetRecordingEndTime())
++ return a->GetRecordingEndTime() < b->GetRecordingEndTime();
+ if (a->GetRecordingStatus() != b->GetRecordingStatus())
+ return a->GetRecordingStatus() < b->GetRecordingStatus();
+ if (a->GetChanNum() != b->GetChanNum())
+@@ -1090,6 +1090,11 @@ bool Scheduler::FindNextConflict(
+ continue;
+ }
+
++ bool mplexid_ok =
++ p->GetInputID() != q->GetInputID() &&
++ ((p->mplexid && p->mplexid == q->mplexid) ||
++ (!p->mplexid && p->GetChanID() == q->GetChanID()));
++
+ if (p->GetRecordingEndTime() == q->GetRecordingStartTime() ||
+ p->GetRecordingStartTime() == q->GetRecordingEndTime())
+ {
+@@ -1097,19 +1102,12 @@ bool Scheduler::FindNextConflict(
+ (openEnd == openEndDiffChannel &&
+ p->GetChanID() == q->GetChanID()) ||
+ (openEnd == openEndAlways &&
+- p->GetInputID() != q->GetInputID() &&
+- ((p->mplexid && p->mplexid == q->mplexid) ||
+- (!p->mplexid && p->GetChanID() == q->GetChanID()))))
++ mplexid_ok))
+ {
+ if (debugConflicts)
+ msg += " no-overlap ";
+- if ((m_openEnd == openEndDiffChannel &&
+- p->GetChanID() == q->GetChanID()) ||
+- (m_openEnd == openEndAlways &&
+- p->GetInputID() != q->GetInputID() &&
+- ((p->mplexid && p->mplexid == q->mplexid) ||
+- (!p->mplexid && p->GetChanID() ==
q->GetChanID()))))
+- ++affinity;
++ if (mplexid_ok)
++ ++affinity;
+ continue;
+ }
+ }
+@@ -1128,9 +1126,7 @@ bool Scheduler::FindNextConflict(
+
+ // if two inputs are in the same input group we have a conflict
+ // unless the programs are on the same multiplex.
+- if (p->GetInputID() != q->GetInputID() &&
+- ((p->mplexid && p->mplexid == q->mplexid) ||
+- (!p->mplexid && p->GetChanID() == q->GetChanID())))
++ if (mplexid_ok)
+ {
+ ++affinity;
+ continue;
diff --git a/mythtv/programs/mythbackend/services/dvr.cpp
b/mythtv/programs/mythbackend/services/dvr.cpp
index b699f29..3868136 100644
--- a/mythtv/programs/mythbackend/services/dvr.cpp
@@ -61689,7 +63443,7 @@ index 049c189..7f977c2 100644
}
diff --git a/mythtv/programs/mythfrontend/galleryconfig.cpp
b/mythtv/programs/mythfrontend/galleryconfig.cpp
-index 00c451e..79f9ed8 100644
+index 00c451e..45cdd79 100644
--- a/mythtv/programs/mythfrontend/galleryconfig.cpp
+++ b/mythtv/programs/mythfrontend/galleryconfig.cpp
@@ -46,14 +46,19 @@ ThumbSettings::ThumbSettings() : VerticalConfigurationGroup()
@@ -61725,6 +63479,51 @@ index 00c451e..79f9ed8 100644
HostCheckBox *browseTran = new HostCheckBox("GalleryBrowseTransition");
browseTran->setLabel(tr("Use transitions when browsing"));
browseTran->setHelpText(tr("When cleared, transitions will only be used
"
+@@ -138,7 +149,7 @@ ImportSettings::ImportSettings(bool enable) :
VerticalConfigurationGroup()
+ \brief Settings Page 2
+ \param enable True if password has been entered
+ */
+-DatabaseSettings::DatabaseSettings(bool enable)
++GalleryDbSettings::GalleryDbSettings(bool enable)
+ : VerticalConfigurationGroup(false)
+ {
+ setLabel(tr("Database Settings") + (enable ? "" : tr("
(Requires edit privileges)")));
+diff --git a/mythtv/programs/mythfrontend/galleryconfig.h
b/mythtv/programs/mythfrontend/galleryconfig.h
+index 300eac1..536773d 100644
+--- a/mythtv/programs/mythfrontend/galleryconfig.h
++++ b/mythtv/programs/mythfrontend/galleryconfig.h
+@@ -18,11 +18,11 @@ public:
+
+
+ //! Settings page 2
+-class DatabaseSettings : public VerticalConfigurationGroup
++class GalleryDbSettings : public VerticalConfigurationGroup
+ {
+ Q_OBJECT
+ public:
+- explicit DatabaseSettings(bool enable);
++ explicit GalleryDbSettings(bool enable);
+
+ signals:
+ void ClearDbPressed();
+@@ -36,14 +36,14 @@ public:
+ explicit GalleryConfig(bool editMode)
+ {
+ addChild(new GallerySettings());
+- m_dbGroup = new DatabaseSettings(editMode);
++ m_dbGroup = new GalleryDbSettings(editMode);
+ addChild(m_dbGroup);
+ }
+
+- DatabaseSettings *GetClearPage() { return m_dbGroup; }
++ GalleryDbSettings *GetClearPage() { return m_dbGroup; }
+
+ private:
+- DatabaseSettings *m_dbGroup;
++ GalleryDbSettings *m_dbGroup;
+ };
+
+
diff --git a/mythtv/programs/mythfrontend/galleryslideview.cpp
b/mythtv/programs/mythfrontend/galleryslideview.cpp
index 8006a6e..fb24c84 100644
--- a/mythtv/programs/mythfrontend/galleryslideview.cpp
@@ -62154,6 +63953,40 @@ index 28e1767..52042e1 100644
QString GetPosition() const;
bool Select(int id, int fallback = 0);
virtual bool LoadFromDb(int parentId);
+diff --git a/mythtv/programs/mythfrontend/globalsettings.cpp
b/mythtv/programs/mythfrontend/globalsettings.cpp
+index f07e4fe..b90d080 100644
+--- a/mythtv/programs/mythfrontend/globalsettings.cpp
++++ b/mythtv/programs/mythfrontend/globalsettings.cpp
+@@ -1247,11 +1247,19 @@ PlaybackProfileConfigs::PlaybackProfileConfigs(const QString
&str) :
+ #endif
+
+ #ifdef USING_OPENMAX
+- if (!profiles.contains("OpenMAX Normal"))
++ if (!profiles.contains("OpenMAX Normal") &&
++ !profiles.contains("OpenMAX High Quality"))
+ {
+ VideoDisplayProfile::CreateOpenMAXProfiles(host);
+ profiles = VideoDisplayProfile::GetProfiles(host);
+ }
++ // Special case for user upgrading from version that only
++ // has OpenMAX Normal
++ else if (!profiles.contains("OpenMAX High Quality"))
++ {
++ VideoDisplayProfile::CreateOpenMAXProfiles(host,1);
++ profiles = VideoDisplayProfile::GetProfiles(host);
++ }
+ #endif
+
+
+@@ -2608,7 +2616,7 @@ static HostComboBox *ThemePainter()
+ gc->addSelection(QCoreApplication::translate("(Common)",
"Qt"), QT_PAINTER);
+ gc->addSelection(QCoreApplication::translate("(Common)",
"Auto", "Automatic"),
+ AUTO_PAINTER);
+-#ifdef USING_OPENGL
++#if defined USING_OPENGL && ! defined USING_OPENGLES
+ gc->addSelection(QCoreApplication::translate("(Common)", "OpenGL
2"),
+ OPENGL2_PAINTER);
+ gc->addSelection(QCoreApplication::translate("(Common)", "OpenGL
1"),
diff --git a/mythtv/programs/mythfrontend/main.cpp
b/mythtv/programs/mythfrontend/main.cpp
index f8d7dd1..62ba4b2 100644
--- a/mythtv/programs/mythfrontend/main.cpp
@@ -62183,6 +64016,38 @@ index f8d7dd1..62ba4b2 100644
REG_MEDIA_HANDLER(QT_TRANSLATE_NOOP("MythControls",
"MythImage Media Handler 1/2"), "", "",
handleGalleryMedia,
MEDIATYPE_DATA | MEDIATYPE_MIXED, QString::null);
+diff --git a/mythtv/programs/mythfrontend/mythfrontend.pro
b/mythtv/programs/mythfrontend/mythfrontend.pro
+index fcab29e..ed69b93 100644
+--- a/mythtv/programs/mythfrontend/mythfrontend.pro
++++ b/mythtv/programs/mythfrontend/mythfrontend.pro
+@@ -154,3 +154,27 @@ android {
+
+ ANDROID_PACKAGE_SOURCE_DIR += $$(MYTHPACKAGEBASE)/android-package-source
+ }
++
++using_openmax {
++ contains( HAVE_OPENMAX_BROADCOM, yes ) {
++ using_opengl {
++ # For raspberry Pi Raspbian
++ exists(/opt/vc/lib/libEGL.so) {
++ DEFINES += USING_OPENGLES
++ # For raspberry pi raspbian
++ QMAKE_RPATHDIR += $${RUNPREFIX}/share/mythtv/lib
++ createlinks.path = $${PREFIX}/share/mythtv/lib
++ createlinks.extra = ln -fs /opt/vc/lib/libEGL.so
$(INSTALL_ROOT)/$${PREFIX}/share/mythtv/lib/libEGL.so.1.0.0 ;
++ createlinks.extra += ln -fs /opt/vc/lib/libEGL.so
$(INSTALL_ROOT)/$${PREFIX}/share/mythtv/lib/libEGL.so.1 ;
++ createlinks.extra += ln -fs /opt/vc/lib/libGLESv2.so
$(INSTALL_ROOT)/$${PREFIX}/share/mythtv/lib/libGLESv2.so.2.0.0 ;
++ createlinks.extra += ln -fs /opt/vc/lib/libGLESv2.so
$(INSTALL_ROOT)/$${PREFIX}/share/mythtv/lib/libGLESv2.so.2 ;
++ INSTALLS += createlinks
++ }
++ } else {
++ # For raspberry pi ubuntu
++ exists(/usr/lib/arm-linux-gnueabihf/mesa-egl/libEGL.so) {
++ QMAKE_RPATHDIR += /usr/lib/arm-linux-gnueabihf/mesa-egl
++ }
++ }
++ }
++}
diff --git a/mythtv/programs/mythfrontend/themechooser.cpp
b/mythtv/programs/mythfrontend/themechooser.cpp
index d090a3e..f0f4ea1 100644
--- a/mythtv/programs/mythfrontend/themechooser.cpp
@@ -62213,3 +64078,42 @@ index 26a2850..66945d1 100644
.arg(escape_csv(entry2.strTransportId))
.arg(escape_csv(entry2.strAtscMajorChan))
.arg(escape_csv(entry2.strAtscMinorChan))
+diff --git a/mythtv/programs/mythtv-setup/mythtv-setup.pro
b/mythtv/programs/mythtv-setup/mythtv-setup.pro
+index 2145358..24a9255 100644
+--- a/mythtv/programs/mythtv-setup/mythtv-setup.pro
++++ b/mythtv/programs/mythtv-setup/mythtv-setup.pro
+@@ -44,3 +44,15 @@ macx {
+ }
+
+ using_x11:DEFINES += USING_X11
++
++using_openmax {
++ contains( HAVE_OPENMAX_BROADCOM, yes ) {
++ ! using_opengl {
++ # For raspberry pi ubuntu
++ exists(/usr/lib/arm-linux-gnueabihf/mesa-egl/libEGL.so) {
++ QMAKE_RPATHDIR += /usr/lib/arm-linux-gnueabihf/mesa-egl
++ }
++ }
++ }
++}
++
+diff --git a/mythtv/programs/mythwelcome/mythwelcome.pro
b/mythtv/programs/mythwelcome/mythwelcome.pro
+index 2be37ed..edddbf1 100644
+--- a/mythtv/programs/mythwelcome/mythwelcome.pro
++++ b/mythtv/programs/mythwelcome/mythwelcome.pro
+@@ -33,3 +33,14 @@ win32 : !debug {
+ CONFIG -= console
+ DEFINES += WINDOWS_CLOSE_CONSOLE
+ }
++
++using_openmax {
++ contains( HAVE_OPENMAX_BROADCOM, yes ) {
++ ! using_opengl {
++ # For raspberry pi ubuntu
++ exists(/usr/lib/arm-linux-gnueabihf/mesa-egl/libEGL.so) {
++ QMAKE_RPATHDIR += /usr/lib/arm-linux-gnueabihf/mesa-egl
++ }
++ }
++ }
++}
diff --git a/mythtv.spec b/mythtv.spec
index 5b5d957..7e2770e 100644
--- a/mythtv.spec
+++ b/mythtv.spec
@@ -80,9 +80,9 @@ URL:
http://www.mythtv.org/
# Version/Release info
Version: 0.28
%if "%{branch}" == "master"
-Release: 0.4.git.%{_gitrev}%{?dist}
+Release: 0.5.git.%{_gitrev}%{?dist}
%else
-Release: 6%{?dist}
+Release: 7%{?dist}
%endif
# The primary license is GPLv2+, but bits are borrowed from a number of
@@ -1395,6 +1395,9 @@ fi
%changelog
+* Sun Sep 11 2016 Sérgio Basto <sergio(a)serjux.com> - 0.28-7
+- Update to latest fixes/0.28, rfbz#4241
+
* Sun Sep 11 2016 Sérgio Basto <sergio(a)serjux.com> - 0.28-6
- Change mythtv.spec to use %%bcond
- Add BuildRequires: perl-generators, since F25 we have buildroot without Perl