diff --git a/mythplugins/configure b/mythplugins/configure index bbeda10f4c..697e4df4bd 100755 --- a/mythplugins/configure +++ b/mythplugins/configure @@ -647,7 +647,11 @@ if ! check_lib libexif/exif-data.h exif_loader_new -lexif ; then fi if enabled game; then - if ! check_lib minizip/unzip.h unzGetCurrentFileInfo -lminizip ; then + if check_lib unzip.h unzGetCurrentFileInfo -lminizip ; then + MINIZIP_PREFIX= + elif check_lib minizip/unzip.h unzGetCurrentFileInfo -lminizip ; then + MINIZIP_PREFIX="minizip/" + else echo 'minizip required to compile mythgame' disable game fi @@ -943,6 +947,21 @@ if enabled gallery ; then fi fi +########################################################### +# # +# MythGame related configuration options # +# # +########################################################### + +if enabled game ; then + + echo "/*" > ./mythgame/mythgame/config.h + echo " Automatically generated by configure - do not modify" >> ./mythgame/mythgame/config.h + echo "*/" >> ./mythgame/mythgame/config.h + echo "#define MINIZIP_UNZIP_H \"${MINIZIP_PREFIX}unzip.h\"" >> ./mythgame/mythgame/config.h + +fi + ########################################################### # # # MythMusic related configuration options # diff --git a/mythplugins/mytharchive/mytharchivehelper/main.cpp b/mythplugins/mytharchive/mytharchivehelper/main.cpp index 13c7032e62..1960e0b925 100644 --- a/mythplugins/mytharchive/mytharchivehelper/main.cpp +++ b/mythplugins/mytharchive/mytharchivehelper/main.cpp @@ -524,7 +524,7 @@ int NativeArchive::exportRecording(QDomElement &itemNode, } // add any rating - query.prepare("SELECT system, rating FROM recordedrating " + query.prepare("SELECT `system`, rating FROM recordedrating " "WHERE chanid = :CHANID AND starttime = :STARTTIME;"); query.bindValue(":CHANID", chanID); query.bindValue(":STARTTIME", startTime); diff --git a/mythplugins/mythgame/mythgame/dbcheck.cpp b/mythplugins/mythgame/mythgame/dbcheck.cpp index a787feb821..6b9952a8e3 100644 --- a/mythplugins/mythgame/mythgame/dbcheck.cpp +++ b/mythplugins/mythgame/mythgame/dbcheck.cpp @@ -70,7 +70,7 @@ static bool InitializeDatabase(void) const QString updates[] = { "CREATE TABLE gamemetadata (" -" system varchar(128) NOT NULL default ''," +" `system` varchar(128) NOT NULL default ''," " romname varchar(128) NOT NULL default ''," " gamename varchar(128) NOT NULL default ''," " genre varchar(128) NOT NULL default ''," @@ -84,7 +84,7 @@ static bool InitializeDatabase(void) " crc_value varchar(64) NOT NULL default ''," " display tinyint(1) NOT NULL default '1'," " version varchar(64) NOT NULL default ''," -" KEY system (system)," +" KEY `system` (`system`)," " KEY year (year)," " KEY romname (romname)," " KEY gamename (gamename)," @@ -298,7 +298,7 @@ bool UpgradeGameDatabaseSchema(void) QString("ALTER DATABASE %1 DEFAULT CHARACTER SET latin1;") .arg(gContext->GetDatabaseParams().dbName), "ALTER TABLE gamemetadata" -" MODIFY system varbinary(128) NOT NULL default ''," +" MODIFY `system` varbinary(128) NOT NULL default ''," " MODIFY romname varbinary(128) NOT NULL default ''," " MODIFY gamename varbinary(128) NOT NULL default ''," " MODIFY genre varbinary(128) NOT NULL default ''," @@ -345,7 +345,7 @@ QString("ALTER DATABASE %1 DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;") .arg(gContext->GetDatabaseParams().dbName), "ALTER TABLE gamemetadata" " DEFAULT CHARACTER SET default," -" MODIFY system varchar(128) CHARACTER SET utf8 NOT NULL default ''," +" MODIFY `system` varchar(128) CHARACTER SET utf8 NOT NULL default ''," " MODIFY romname varchar(128) CHARACTER SET utf8 NOT NULL default ''," " MODIFY gamename varchar(128) CHARACTER SET utf8 NOT NULL default ''," " MODIFY genre varchar(128) CHARACTER SET utf8 NOT NULL default ''," diff --git a/mythplugins/mythgame/mythgame/gamehandler.cpp b/mythplugins/mythgame/mythgame/gamehandler.cpp index 9d5539e3f1..565662970f 100644 --- a/mythplugins/mythgame/mythgame/gamehandler.cpp +++ b/mythplugins/mythgame/mythgame/gamehandler.cpp @@ -243,7 +243,7 @@ static void updateDisplayRom(QString romname, int display, QString Systemname) { MSqlQuery query(MSqlQuery::InitCon()); query.prepare("UPDATE gamemetadata SET display = :DISPLAY " - "WHERE romname = :ROMNAME AND system = :SYSTEM"); + "WHERE romname = :ROMNAME AND `system` = :SYSTEM"); query.bindValue(":DISPLAY", display); query.bindValue(":ROMNAME", romname); @@ -273,7 +273,7 @@ static void updateGameName(QString romname, QString GameName, QString Systemname { MSqlQuery query(MSqlQuery::InitCon()); query.prepare("UPDATE gamemetadata SET GameName = :GAMENAME " - "WHERE romname = :ROMNAME AND system = :SYSTEM "); + "WHERE romname = :ROMNAME AND `system` = :SYSTEM "); query.bindValue(":GAMENAME", GameName); query.bindValue(":ROMNAME", romname); @@ -300,10 +300,10 @@ static void UpdateGameCounts(QStringList updatelist) LOG(VB_GENERAL, LOG_NOTICE, LOC + QString("Update gametype %1").arg(GameType)); - query.prepare("SELECT romname,system,spandisks,gamename FROM " + query.prepare("SELECT romname,`system`,spandisks,gamename FROM " "gamemetadata,gameplayers WHERE " "gamemetadata.gametype = :GAMETYPE AND " - "playername = system ORDER BY romname"); + "playername = `system` ORDER BY romname"); query.bindValue(":GAMETYPE",GameType); @@ -450,7 +450,7 @@ void GameHandler::UpdateGameDB(GameHandler *handler) #endif query.prepare("INSERT INTO gamemetadata " - "(system, romname, gamename, genre, year, gametype, " + "(`system`, romname, gamename, genre, year, gametype, " "rompath, country, crc_value, diskcount, display, plot, " "publisher, version, fanart, boxart, screenshot) " "VALUES (:SYSTEM, :ROMNAME, :GAMENAME, :GENRE, :YEAR, " @@ -501,7 +501,7 @@ void GameHandler::VerifyGameDB(GameHandler *handler) MSqlQuery query(MSqlQuery::InitCon()); query.prepare("SELECT romname,rompath,gamename FROM gamemetadata " - "WHERE system = :SYSTEM"); + "WHERE `system` = :SYSTEM"); query.bindValue(":SYSTEM",handler->SystemName()); diff --git a/mythplugins/mythgame/mythgame/rom_metadata.cpp b/mythplugins/mythgame/mythgame/rom_metadata.cpp index b9838769c3..9bc8ed61ee 100644 --- a/mythplugins/mythgame/mythgame/rom_metadata.cpp +++ b/mythplugins/mythgame/mythgame/rom_metadata.cpp @@ -1,10 +1,12 @@ +#include "config.h" #include "rom_metadata.h" #include <QFile> #include <mythcontext.h> -#include <minizip/unzip.h> +#include "zlib.h" +#include MINIZIP_UNZIP_H #undef Z_NULL #define Z_NULL nullptr diff --git a/mythplugins/mythgame/mythgame/rominfo.cpp b/mythplugins/mythgame/mythgame/rominfo.cpp index 53490b0054..0743c88fad 100644 --- a/mythplugins/mythgame/mythgame/rominfo.cpp +++ b/mythplugins/mythgame/mythgame/rominfo.cpp @@ -31,7 +31,7 @@ void RomInfo::SaveToDatabase() .arg(Romname())); query.prepare("INSERT INTO gamemetadata " - "(system, romname, gamename, genre, year, gametype, " + "(`system`, romname, gamename, genre, year, gametype, " "rompath, country, crc_value, diskcount, display, plot, " "publisher, version, fanart, boxart, screenshot) " "VALUES (:SYSTEM, :ROMNAME, :GAMENAME, :GENRE, :YEAR, " @@ -257,10 +257,10 @@ void RomInfo::fillData() QString systemtype; if (system != "") { - systemtype += " AND system = :SYSTEM "; + systemtype += " AND `system` = :SYSTEM "; } - QString thequery = "SELECT system,gamename,genre,year,romname,favorite," + QString thequery = "SELECT `system`,gamename,genre,year,romname,favorite," "rompath,country,crc_value,diskcount,gametype,plot,publisher," "version,screenshot,fanart,boxart,inetref,intid FROM gamemetadata " "WHERE gamename = :GAMENAME " @@ -299,7 +299,7 @@ void RomInfo::fillData() // systems available to play it. if (RomCount() > 1) { - query.prepare("SELECT DISTINCT system FROM gamemetadata " + query.prepare("SELECT DISTINCT `system` FROM gamemetadata " "WHERE romname = :ROMNAME"); query.bindValue(":ROMNAME", Romname()); if (!query.exec()) @@ -325,7 +325,7 @@ QList<RomInfo*> RomInfo::GetAllRomInfo() MSqlQuery query(MSqlQuery::InitCon()); - QString querystr = "SELECT intid,system,romname,gamename,genre,year,publisher," + QString querystr = "SELECT intid,`system`,romname,gamename,genre,year,publisher," "favorite,rompath,screenshot,fanart,plot,boxart," "gametype,diskcount,country,crc_value,inetref,display," "version FROM gamemetadata ORDER BY diskcount DESC"; @@ -373,7 +373,7 @@ RomInfo *RomInfo::GetRomInfoById(int id) MSqlQuery query(MSqlQuery::InitCon()); - QString querystr = "SELECT intid,system,romname,gamename,genre,year,publisher," + QString querystr = "SELECT intid,`system`,romname,gamename,genre,year,publisher," "favorite,rompath,screenshot,fanart,plot,boxart," "gametype,diskcount,country,crc_value,inetref,display," "version FROM gamemetadata WHERE intid = :INTID"; diff --git a/mythplugins/mythweather/mythweather/scripts/no_yrno/yrnoxml.pl b/mythplugins/mythweather/mythweather/scripts/no_yrno/yrnoxml.pl index b66376c080..d17c8e0cc0 100755 --- a/mythplugins/mythweather/mythweather/scripts/no_yrno/yrnoxml.pl +++ b/mythplugins/mythweather/mythweather/scripts/no_yrno/yrnoxml.pl @@ -5,7 +5,7 @@ use strict; use warnings; use utf8; -use encoding 'utf8'; + use LWP::UserAgent; use Getopt::Std; use URI::Escape; diff --git a/mythplugins/mythweather/mythweather/scripts/uk_metoffice/MetOffCommon.pm b/mythplugins/mythweather/mythweather/scripts/uk_metoffice/MetOffCommon.pm index 43eb2a9909..099a4e6bb9 100644 --- a/mythplugins/mythweather/mythweather/scripts/uk_metoffice/MetOffCommon.pm +++ b/mythplugins/mythweather/mythweather/scripts/uk_metoffice/MetOffCommon.pm @@ -7,7 +7,7 @@ use warnings; require Exporter; use utf8; -use encoding 'utf8'; + use LWP::UserAgent; use LWP::Simple; use XML::Simple; diff --git a/mythplugins/mythweather/mythweather/scripts/uk_metoffice/metoffice_fivedayapi.pl b/mythplugins/mythweather/mythweather/scripts/uk_metoffice/metoffice_fivedayapi.pl index 853d900e1c..ee4ef9ec2b 100755 --- a/mythplugins/mythweather/mythweather/scripts/uk_metoffice/metoffice_fivedayapi.pl +++ b/mythplugins/mythweather/mythweather/scripts/uk_metoffice/metoffice_fivedayapi.pl @@ -5,7 +5,7 @@ use strict; use warnings; use utf8; -use encoding 'utf8'; + use English; use File::Basename; diff --git a/mythplugins/mythweather/mythweather/scripts/uk_metoffice/metoffice_threehourapi.pl b/mythplugins/mythweather/mythweather/scripts/uk_metoffice/metoffice_threehourapi.pl index 9ec77f8964..6c566207c2 100755 --- a/mythplugins/mythweather/mythweather/scripts/uk_metoffice/metoffice_threehourapi.pl +++ b/mythplugins/mythweather/mythweather/scripts/uk_metoffice/metoffice_threehourapi.pl @@ -5,7 +5,7 @@ use strict; use warnings; use utf8; -use encoding 'utf8'; + use English; use File::Basename; diff --git a/mythplugins/mythweather/mythweather/scripts/wunderground/wunderground-animaps.pl b/mythplugins/mythweather/mythweather/scripts/wunderground/wunderground-animaps.pl index 382dda730b..5cb74644fc 100755 --- a/mythplugins/mythweather/mythweather/scripts/wunderground/wunderground-animaps.pl +++ b/mythplugins/mythweather/mythweather/scripts/wunderground/wunderground-animaps.pl @@ -13,7 +13,7 @@ use lib dirname(abs_path($0 or $PROGRAM_NAME)), '/usr/local/share/mythtv/mythweather/scripts/wunderground'; use utf8; -use encoding 'utf8'; + use LWP::UserAgent; use Getopt::Std; use URI::Escape; diff --git a/mythplugins/mythweather/mythweather/scripts/wunderground/wunderground-maps.pl b/mythplugins/mythweather/mythweather/scripts/wunderground/wunderground-maps.pl index b7797b5e49..9fb3561620 100755 --- a/mythplugins/mythweather/mythweather/scripts/wunderground/wunderground-maps.pl +++ b/mythplugins/mythweather/mythweather/scripts/wunderground/wunderground-maps.pl @@ -13,7 +13,7 @@ use lib dirname(abs_path($0 or $PROGRAM_NAME)), '/usr/local/share/mythtv/mythweather/scripts/wunderground'; use utf8; -use encoding 'utf8'; + use LWP::UserAgent; use Getopt::Std; use URI::Escape; diff --git a/mythplugins/mythweather/mythweather/scripts/wunderground/wunderground.pl b/mythplugins/mythweather/mythweather/scripts/wunderground/wunderground.pl index 2ce69c250e..c9a7896894 100755 --- a/mythplugins/mythweather/mythweather/scripts/wunderground/wunderground.pl +++ b/mythplugins/mythweather/mythweather/scripts/wunderground/wunderground.pl @@ -5,7 +5,7 @@ use strict; use warnings; use utf8; -use encoding 'utf8'; + use LWP::UserAgent; use Getopt::Std; use URI::Escape; diff --git a/mythplugins/mythzoneminder/mythzmserver/zmserver.cpp b/mythplugins/mythzoneminder/mythzmserver/zmserver.cpp index eefe9fbbbe..3c21697c5f 100644 --- a/mythplugins/mythzoneminder/mythzmserver/zmserver.cpp +++ b/mythplugins/mythzoneminder/mythzmserver/zmserver.cpp @@ -175,6 +175,12 @@ void loadZMConfig(const string &configfile) fclose(cfg); } +#if !defined(MARIADB_BASE_VERSION) && MYSQL_VERSION_ID >= 80000 +using reconnect_t = int; +#else +using reconnect_t = my_bool; +#endif + void connectToDatabase(void) { if (!mysql_init(&g_dbConn)) @@ -183,7 +189,7 @@ void connectToDatabase(void) exit(mysql_errno(&g_dbConn)); } - my_bool reconnect = 1; + reconnect_t reconnect = 1; mysql_options(&g_dbConn, MYSQL_OPT_RECONNECT, &reconnect); if (!mysql_real_connect(&g_dbConn, g_server.c_str(), g_user.c_str(), @@ -241,6 +247,9 @@ void MONITOR::initMonitor(bool debug, const string &mmapPath, int shmKey) int shared_data_size; int frame_size = width * height * bytes_per_pixel; + if (!enabled) + return; + if (checkVersion(1, 26, 0)) { shared_data_size = sizeof(SharedData26) + @@ -956,7 +965,7 @@ void ZMServer::handleGetMonitorStatus(void) string id = row[0]; string type = row[2]; string device = row[3]; - string host = row[4]; + string host = row[4] ? row[4] : ""; string channel = row[5]; string function = row[6]; string enabled = row[7]; @@ -1675,7 +1684,7 @@ void ZMServer::getMonitorList(void) m->function = row[8]; m->enabled = atoi(row[9]); m->device = row[10]; - m->host = row[11]; + m->host = row[11] ? row[11] : ""; m->controllable = atoi(row[12]); m->trackMotion = atoi(row[13]); diff --git a/mythplugins/mythzoneminder/mythzoneminder/zmclient.cpp b/mythplugins/mythzoneminder/mythzoneminder/zmclient.cpp index 0a99c93ac9..068a2dc0c9 100644 --- a/mythplugins/mythzoneminder/mythzoneminder/zmclient.cpp +++ b/mythplugins/mythzoneminder/mythzoneminder/zmclient.cpp @@ -26,6 +26,7 @@ ZMClient::ZMClient() : QObject(nullptr), m_listLock(QMutex::Recursive), + m_commandLock(QMutex::Recursive), m_socket(nullptr), m_socketLock(QMutex::Recursive), m_hostname("localhost"), @@ -135,8 +136,6 @@ bool ZMClient::connectToHost(const QString &lhostname, unsigned int lport) bool ZMClient::sendReceiveStringList(QStringList &strList) { - QMutexLocker locker(&m_socketLock); - QStringList origStrList = strList; bool ok = false; @@ -196,6 +195,8 @@ bool ZMClient::sendReceiveStringList(QStringList &strList) bool ZMClient::checkProtoVersion(void) { + QMutexLocker locker(&m_commandLock); + QStringList strList("HELLO"); if (!sendReceiveStringList(strList)) { @@ -272,6 +273,8 @@ ZMClient::~ZMClient() void ZMClient::getServerStatus(QString &status, QString &cpuStat, QString &diskStat) { + QMutexLocker locker(&m_commandLock); + QStringList strList("GET_SERVER_STATUS"); if (!sendReceiveStringList(strList)) return; @@ -290,6 +293,8 @@ void ZMClient::getServerStatus(QString &status, QString &cpuStat, QString &diskS void ZMClient::updateMonitorStatus(void) { + QMutexLocker clocker(&m_commandLock); + QStringList strList("GET_MONITOR_STATUS"); if (!sendReceiveStringList(strList)) return; @@ -359,6 +364,8 @@ static QString stateToString(State state) bool ZMClient::updateAlarmStates(void) { + QMutexLocker clocker(&m_commandLock); + QStringList strList("GET_ALARM_STATES"); if (!sendReceiveStringList(strList)) return false; @@ -410,6 +417,8 @@ void ZMClient::getEventList(const QString &monitorName, bool oldestFirst, const QString &date, bool includeContinuous, vector<Event*> *eventList) { + QMutexLocker locker(&m_commandLock); + eventList->clear(); QStringList strList("GET_EVENT_LIST"); @@ -462,6 +471,8 @@ void ZMClient::getEventList(const QString &monitorName, bool oldestFirst, void ZMClient::getEventDates(const QString &monitorName, bool oldestFirst, QStringList &dateList) { + QMutexLocker locker(&m_commandLock); + dateList.clear(); QStringList strList("GET_EVENT_DATES"); @@ -505,6 +516,8 @@ void ZMClient::getEventDates(const QString &monitorName, bool oldestFirst, void ZMClient::getFrameList(int eventID, vector<Frame*> *frameList) { + QMutexLocker locker(&m_commandLock); + frameList->clear(); QStringList strList("GET_FRAME_LIST"); @@ -549,6 +562,8 @@ void ZMClient::getFrameList(int eventID, vector<Frame*> *frameList) void ZMClient::deleteEvent(int eventID) { + QMutexLocker locker(&m_commandLock); + QStringList strList("DELETE_EVENT"); strList << QString::number(eventID); sendReceiveStringList(strList); @@ -556,6 +571,8 @@ void ZMClient::deleteEvent(int eventID) void ZMClient::deleteEventList(vector<Event*> *eventList) { + QMutexLocker locker(&m_commandLock); + // delete events in 100 event chunks QStringList strList("DELETE_EVENT_LIST"); int count = 0; @@ -641,6 +658,8 @@ bool ZMClient::readData(unsigned char *data, int dataSize) void ZMClient::getEventFrame(Event *event, int frameNo, MythImage **image) { + QMutexLocker locker(&m_commandLock); + if (*image) { (*image)->DecrRef(); @@ -690,6 +709,8 @@ void ZMClient::getEventFrame(Event *event, int frameNo, MythImage **image) void ZMClient::getAnalyseFrame(Event *event, int frameNo, QImage &image) { + QMutexLocker locker(&m_commandLock); + QStringList strList("GET_ANALYSE_FRAME"); strList << QString::number(event->monitorID()); strList << QString::number(event->eventID()); @@ -735,6 +756,8 @@ void ZMClient::getAnalyseFrame(Event *event, int frameNo, QImage &image) int ZMClient::getLiveFrame(int monitorID, QString &status, unsigned char* buffer, int bufferSize) { + QMutexLocker locker(&m_commandLock); + QStringList strList("GET_LIVE_FRAME"); strList << QString::number(monitorID); if (!sendReceiveStringList(strList)) @@ -794,6 +817,8 @@ int ZMClient::getLiveFrame(int monitorID, QString &status, unsigned char* buffer void ZMClient::getCameraList(QStringList &cameraList) { + QMutexLocker locker(&m_commandLock); + cameraList.clear(); QStringList strList("GET_CAMERA_LIST"); @@ -860,6 +885,7 @@ Monitor* ZMClient::getMonitorByID(int monID) void ZMClient::doGetMonitorList(void) { + QMutexLocker clocker(&m_commandLock); QMutexLocker locker(&m_listLock); for (int x = 0; x < m_monitorList.count(); x++) @@ -926,6 +952,8 @@ void ZMClient::doGetMonitorList(void) void ZMClient::setMonitorFunction(const int monitorID, const QString &function, const int enabled) { + QMutexLocker locker(&m_commandLock); + QStringList strList("SET_MONITOR_FUNCTION"); strList << QString::number(monitorID); strList << function; @@ -942,10 +970,13 @@ void ZMClient::saveNotificationMonitors(void) for (int x = 0; x < m_monitorList.count(); x++) { Monitor *mon = m_monitorList.at(x); - if (!s.isEmpty()) - s += QString(",%1").arg(mon->id); - else - s = QString("%1").arg(mon->id); + if (mon->showNotifications) + { + if (!s.isEmpty()) + s += QString(",%1").arg(mon->id); + else + s = QString("%1").arg(mon->id); + } } gCoreContext->SaveSetting("ZoneMinderNotificationMonitors", s); diff --git a/mythplugins/mythzoneminder/mythzoneminder/zmclient.h b/mythplugins/mythzoneminder/mythzoneminder/zmclient.h index 3dd5c20faa..75369f0f92 100644 --- a/mythplugins/mythzoneminder/mythzoneminder/zmclient.h +++ b/mythplugins/mythzoneminder/mythzoneminder/zmclient.h @@ -76,6 +76,8 @@ class MPUBLIC ZMClient : public QObject bool sendReceiveStringList(QStringList &strList); QMutex m_listLock; + QMutex m_commandLock; + QList<Monitor*> m_monitorList; QMap<int, Monitor*> m_monitorMap; diff --git a/mythtv/FAQ b/mythtv/FAQ index 593d3b9fea..e4f6c45109 100644 --- a/mythtv/FAQ +++ b/mythtv/FAQ @@ -1,5 +1,5 @@ MythTV FAQ The FAQ is available on the MythTV wiki at -http://www.mythtv.org/wiki/Frequently_Asked_Questions +https://www.mythtv.org/wiki/Frequently_Asked_Questions diff --git a/mythtv/bindings/php/MythBackend.php b/mythtv/bindings/php/MythBackend.php index 54472e9489..a703620982 100644 --- a/mythtv/bindings/php/MythBackend.php +++ b/mythtv/bindings/php/MythBackend.php @@ -191,7 +191,7 @@ class MythBackend { // Parse the records, starting at the offset point $row = 0; $col = 0; - $count = count($records); + $count = (is_array($records) ? count($records) : 0); for($i = $offset; $i < $count; $i++) { $rows[$row][$col] = $records[$i]; // Every $NUMPROGRAMLINES fields (0 through ($NUMPROGRAMLINES-1)) means diff --git a/mythtv/bindings/python/MythTV/services_api/send.py b/mythtv/bindings/python/MythTV/services_api/send.py index 0d5946a8c0..4c30aec8ca 100644 --- a/mythtv/bindings/python/MythTV/services_api/send.py +++ b/mythtv/bindings/python/MythTV/services_api/send.py @@ -397,8 +397,6 @@ class Send(object): # TODO: Problem with the BE not accepting postdata in the initial # authorized query, Send a GET first as a workaround. - # - # Looks like a bug, Myth/version works for the backend. try: if self.opts['user'] and self.opts['pass']: @@ -407,7 +405,11 @@ class Send(object): if self.postdata: saved_endpoint = self.endpoint saved_postdata = self.postdata - self.send(endpoint='Myth/version', opts=self.opts) + # Need to adjust this if a service other than Frontend is + # added. + self.send(endpoint='{}/version'.format( + 'Myth' if self.endpoint[:8] != 'Frontend' + else 'Frontend'), opts=self.opts) self.endpoint = saved_endpoint self.postdata = saved_postdata except KeyError: diff --git a/mythtv/configure b/mythtv/configure index a80828efc7..4f526864a5 100755 --- a/mythtv/configure +++ b/mythtv/configure @@ -6651,6 +6651,14 @@ if enabled x11; then # This is hopefully temporary. disable xnvctrl_external ;; + *gentoo*) + if [ -e "/usr/bin/nvidia-settings" ] + then + require XNVctrl "X11/Xlib.h NVCtrl/NVCtrl.h NVCtrl/NVCtrlLib.h" XNVCTRLIsNvScreen -lXNVCtrl || disable xnvctrl + else + disable xnvctrl_external + fi + ;; *) require XNVctrl "X11/Xlib.h NVCtrl/NVCtrl.h NVCtrl/NVCtrlLib.h" XNVCTRLIsNvScreen -lXNVCtrl || disable xnvctrl ;; diff --git a/mythtv/database/mc.sql b/mythtv/database/mc.sql index 58fcd36a1d..a583cb9525 100644 --- a/mythtv/database/mc.sql +++ b/mythtv/database/mc.sql @@ -1,6 +1,7 @@ CREATE DATABASE IF NOT EXISTS mythconverg; -GRANT ALL ON mythconverg.* TO mythtv@localhost IDENTIFIED BY "mythtv"; +CREATE USER IF NOT EXISTS 'mythtv'@'localhost' IDENTIFIED BY 'mythtv'; +GRANT ALL ON mythconverg.* TO mythtv@localhost; FLUSH PRIVILEGES; -GRANT CREATE TEMPORARY TABLES ON mythconverg.* TO mythtv@localhost IDENTIFIED BY "mythtv"; +GRANT CREATE TEMPORARY TABLES ON mythconverg.* TO mythtv@localhost; FLUSH PRIVILEGES; ALTER DATABASE mythconverg DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci; diff --git a/mythtv/html/tv/programsearch.qsp b/mythtv/html/tv/programsearch.qsp index cfce0300ca..6441e769a8 100644 --- a/mythtv/html/tv/programsearch.qsp +++ b/mythtv/html/tv/programsearch.qsp @@ -76,7 +76,7 @@ import "/tv/js/tvutil.qjs" var Count = 30; var Details = 1; var progLoadTimeStart = new Date(); - var Channels = channel.GetChannelInfoList(0,0,0,1).ChannelInfos; + var Channels = channel.GetChannelInfoList(0,0,0,0,1).ChannelInfos; var programList = Array(); var programs = Array(); diff --git a/mythtv/libs/libmythbase/logging.cpp b/mythtv/libs/libmythbase/logging.cpp index 92de0eb539..e127f40ae4 100644 --- a/mythtv/libs/libmythbase/logging.cpp +++ b/mythtv/libs/libmythbase/logging.cpp @@ -428,6 +428,7 @@ bool LoggerThread::logConsole(LoggingItem *item) item->IncrRef(); +#ifndef Q_OS_ANDROID if (item->m_type & kStandardIO) snprintf( line, MAX_STRING_LENGTH, "%s", item->m_message ); else @@ -462,11 +463,42 @@ bool LoggerThread::logConsole(LoggingItem *item) #endif } -#ifdef Q_OS_ANDROID - __android_log_print(ANDROID_LOG_INFO, "mfe", line); -#else int result = write( 1, line, strlen(line) ); (void)result; + +#else // Q_OS_ANDROID + + android_LogPriority aprio; + switch (item->m_level) + { + case LOG_EMERG: + aprio = ANDROID_LOG_FATAL; + case LOG_ALERT: + case LOG_CRIT: + case LOG_ERR: + aprio = ANDROID_LOG_ERROR; + break; + case LOG_WARNING: + aprio = ANDROID_LOG_WARN; + break; + case LOG_NOTICE: + case LOG_INFO: + aprio = ANDROID_LOG_INFO; + break; + case LOG_DEBUG: + aprio = ANDROID_LOG_DEBUG; + break; + case LOG_UNKNOWN: + default: + aprio = ANDROID_LOG_UNKNOWN; + break; + } +#if CONFIG_DEBUGTYPE + __android_log_print(aprio, "mfe", "%s:%d:%s %s", item->m_file, + item->m_line, item->m_function, item->m_message); +#else + __android_log_print(aprio, "mfe", "%s", item->m_message); +#endif #endif item->DecrRef(); diff --git a/mythtv/libs/libmythbase/mythsocket.cpp b/mythtv/libs/libmythbase/mythsocket.cpp index 69cba58448..61fbba0f66 100644 --- a/mythtv/libs/libmythbase/mythsocket.cpp +++ b/mythtv/libs/libmythbase/mythsocket.cpp @@ -490,7 +490,7 @@ bool MythSocket::Announce(const QStringList &new_announce) WriteStringList(new_announce); QStringList tmplist; - if (!ReadStringList(tmplist, true)) + if (!ReadStringList(tmplist, MythSocket::kShortTimeout)) { LOG(VB_GENERAL, LOG_ERR, LOC + QString("\n\t\t\tCould not read string list from server %1:%2") diff --git a/mythtv/libs/libmythbase/remotefile.cpp b/mythtv/libs/libmythbase/remotefile.cpp index 3bbfcff034..d3ee79895c 100644 --- a/mythtv/libs/libmythbase/remotefile.cpp +++ b/mythtv/libs/libmythbase/remotefile.cpp @@ -1073,7 +1073,19 @@ int RemoteFile::Read(void *data, int size) if (error || sent != recv) { + LOG(VB_GENERAL, LOG_WARNING, + QString("RemoteFile::Read(): sent %1 != recv %2") + .arg(sent).arg(recv)); recv = -1; + + // The TCP socket is dropped if there's a timeout, so we reconnect + if (!Resume()) + { + LOG(VB_GENERAL, LOG_WARNING, "RemoteFile::Read(): Resume failed."); + sent = -1; + } + else + LOG(VB_GENERAL, LOG_NOTICE, "RemoteFile::Read(): Resume success."); } else { diff --git a/mythtv/libs/libmythbase/storagegroup.cpp b/mythtv/libs/libmythbase/storagegroup.cpp index 1349f00f7f..15ff64c468 100644 --- a/mythtv/libs/libmythbase/storagegroup.cpp +++ b/mythtv/libs/libmythbase/storagegroup.cpp @@ -615,7 +615,7 @@ QString StorageGroup::FindFile(const QString &filename) if (!recDir.isEmpty()) { result = recDir + "/" + filename; - LOG(VB_FILE, LOG_DEBUG, LOC + + LOG(VB_FILE, LOG_INFO, LOC + QString("FindFile: Found '%1'") .arg(result)); } else diff --git a/mythtv/libs/libmythbase/test/test_mythsystem/test_mythsystem.h b/mythtv/libs/libmythbase/test/test_mythsystem/test_mythsystem.h index 37de6be88c..0dd793042c 100644 --- a/mythtv/libs/libmythbase/test/test_mythsystem/test_mythsystem.h +++ b/mythtv/libs/libmythbase/test/test_mythsystem/test_mythsystem.h @@ -83,7 +83,8 @@ class TestMythSystem: public QObject { QScopedPointer<MythSystem> cmd( MythSystem::Create( - QString("echo %1").arg(__FUNCTION__), kMSStdOut)); + QString("echo %1; sleep 1").arg(__FUNCTION__), + kMSStdOut | kMSRunShell)); cmd->Wait(); QVERIFY(QString(cmd->GetStandardOutputStream()->readAll()) .contains(__FUNCTION__)); @@ -128,8 +129,8 @@ class TestMythSystem: public QObject void stdout_works(void) { QScopedPointer<MythSystem> cmd( - MythSystem::Create(QString("echo %1").arg(__FUNCTION__), - kMSStdOut)); + MythSystem::Create(QString("echo %1; sleep 1").arg(__FUNCTION__), + kMSStdOut | kMSRunShell)); cmd->Wait(); QVERIFY(cmd->GetExitCode() == 0); QVERIFY(cmd->GetStandardOutputStream()); @@ -142,7 +143,7 @@ class TestMythSystem: public QObject void stderr_works(void) { QScopedPointer<MythSystem> cmd( - MythSystem::Create(QString("echo %1 >&2").arg(__FUNCTION__), + MythSystem::Create(QString("echo %1 >&2; sleep 1").arg(__FUNCTION__), kMSRunShell | kMSStdErr)); cmd->Wait(); QVERIFY(cmd->GetExitCode() == 0); @@ -156,7 +157,7 @@ class TestMythSystem: public QObject void shell_used_when_requested(void) { QScopedPointer<MythSystem> cmd( - MythSystem::Create("if [ x != y ] ; then echo X ; else echo Y ; fi", + MythSystem::Create("if [ x != y ] ; then echo X ; else echo Y ; fi; sleep 1", kMSRunShell | kMSStdOut)); cmd->Wait(); QVERIFY(QString(cmd->GetStandardOutputStream()->readAll()) @@ -166,7 +167,7 @@ class TestMythSystem: public QObject void shell_not_used_when_not_requested(void) { QScopedPointer<MythSystem> cmd( - MythSystem::Create("if [ x != y ] ; then echo X ; else echo Y ; fi", + MythSystem::Create("if [ x != y ] ; then echo X ; else echo Y ; fi; sleep 1", kMSStdOut)); cmd->Wait(); QVERIFY(!QString(cmd->GetStandardOutputStream()->readAll()) diff --git a/mythtv/libs/libmythbase/test/test_mythsystemlegacy/test_mythsystemlegacy.h b/mythtv/libs/libmythbase/test/test_mythsystemlegacy/test_mythsystemlegacy.h index 53a4601989..51e669eb8b 100644 --- a/mythtv/libs/libmythbase/test/test_mythsystemlegacy/test_mythsystemlegacy.h +++ b/mythtv/libs/libmythbase/test/test_mythsystemlegacy/test_mythsystemlegacy.h @@ -88,7 +88,8 @@ class TestMythSystemLegacy: public QObject void constructed_command_is_run(void) { - MythSystemLegacy cmd(QString("echo %1").arg(__FUNCTION__), kMSStdOut); + MythSystemLegacy cmd(QString("echo %1; sleep 1").arg(__FUNCTION__), + kMSStdOut | kMSRunShell); Go(cmd); QVERIFY(QString(cmd.ReadAll()).contains(__FUNCTION__)); } @@ -139,7 +140,8 @@ class TestMythSystemLegacy: public QObject // kMSStdOut -- allow access to stdout void stdout_works(void) { - MythSystemLegacy cmd(QString("echo %1").arg(__FUNCTION__), kMSStdOut); + MythSystemLegacy cmd(QString("echo %1; sleep 1").arg(__FUNCTION__), + kMSStdOut | kMSRunShell); Go(cmd); QVERIFY(cmd.GetStatus() == 0); QVERIFY(QString(cmd.ReadAll()).contains(__FUNCTION__)); @@ -148,7 +150,7 @@ class TestMythSystemLegacy: public QObject // kMSStdErr -- allow access to stderr void stderr_works(void) { - MythSystemLegacy cmd(QString("echo %1 >&2").arg(__FUNCTION__), + MythSystemLegacy cmd(QString("echo %1 >&2; sleep 1").arg(__FUNCTION__), kMSRunShell | kMSStdErr); Go(cmd); QVERIFY(cmd.GetStatus() == 0); @@ -158,7 +160,7 @@ class TestMythSystemLegacy: public QObject // kMSRunShell -- run process through shell void shell_used_when_requested(void) { - MythSystemLegacy cmd("if [ x != y ] ; then echo X ; else echo Y ; fi", + MythSystemLegacy cmd("if [ x != y ] ; then echo X ; else echo Y ; fi; sleep 1", kMSRunShell | kMSStdOut); Go(cmd); QVERIFY(QString(cmd.ReadAll()).contains("X")); @@ -166,7 +168,7 @@ class TestMythSystemLegacy: public QObject void shell_not_used_when_not_requested(void) { - MythSystemLegacy cmd("if [ x != y ] ; then echo X ; else echo Y ; fi", + MythSystemLegacy cmd("if [ x != y ] ; then echo X ; else echo Y ; fi; sleep 1", kMSStdOut); Go(cmd); QVERIFY(!QString(cmd.ReadAll()).contains("X")); diff --git a/mythtv/libs/libmythbase/test/test_mythtimer/test_mythtimer.h b/mythtv/libs/libmythbase/test/test_mythtimer/test_mythtimer.h index 2c4dddfeca..6d0b8705c7 100644 --- a/mythtv/libs/libmythbase/test/test_mythtimer/test_mythtimer.h +++ b/mythtv/libs/libmythbase/test/test_mythtimer/test_mythtimer.h @@ -47,76 +47,76 @@ class TestMythTimer: public QObject { MythTimer t; t.start(); - std::this_thread::sleep_for(std::chrono::milliseconds(52)); - QVERIFY(t.elapsed() > 50); + std::this_thread::sleep_for(std::chrono::milliseconds(520)); + QVERIFY(t.elapsed() > 500); } void TimeElapsesAfterRestart(void) { MythTimer t; t.restart(); - std::this_thread::sleep_for(std::chrono::milliseconds(52)); - QVERIFY(t.elapsed() > 50); + std::this_thread::sleep_for(std::chrono::milliseconds(520)); + QVERIFY(t.elapsed() > 500); } void TimeDoesNotElapseImmediatelyAfterConstructionByDefault(void) { MythTimer t; - std::this_thread::sleep_for(std::chrono::milliseconds(52)); + std::this_thread::sleep_for(std::chrono::milliseconds(520)); QVERIFY(t.elapsed() == 0); } void TimeDoesNotElapsesImmediatelyAfterContructionIfIntended(void) { MythTimer t(MythTimer::kStartRunning); - std::this_thread::sleep_for(std::chrono::milliseconds(52)); - QVERIFY(t.elapsed() > 50); + std::this_thread::sleep_for(std::chrono::milliseconds(520)); + QVERIFY(t.elapsed() > 500); } void TimeElapsesContinually(void) { MythTimer t; t.start(); - std::this_thread::sleep_for(std::chrono::milliseconds(52)); - QVERIFY(t.elapsed() > 50); - std::this_thread::sleep_for(std::chrono::milliseconds(50)); - QVERIFY(t.elapsed() > 100); + std::this_thread::sleep_for(std::chrono::milliseconds(520)); + QVERIFY(t.elapsed() > 500); + std::this_thread::sleep_for(std::chrono::milliseconds(500)); + QVERIFY(t.elapsed() > 1000); } void TimeResetsOnRestart(void) { MythTimer t; t.start(); - std::this_thread::sleep_for(std::chrono::milliseconds(52)); - QVERIFY(t.restart() > 50); - std::this_thread::sleep_for(std::chrono::milliseconds(52)); - QVERIFY(t.elapsed() > 50 && t.elapsed() < 75); + std::this_thread::sleep_for(std::chrono::milliseconds(520)); + QVERIFY(t.restart() > 500); + std::this_thread::sleep_for(std::chrono::milliseconds(520)); + QVERIFY(t.elapsed() > 500 && t.elapsed() < 750); } void AddMSecsWorks(void) { MythTimer t; t.start(); - t.addMSecs(-25); - std::this_thread::sleep_for(std::chrono::milliseconds(52)); - QVERIFY(t.elapsed() > 25 && t.elapsed() < 50); + t.addMSecs(-250); + std::this_thread::sleep_for(std::chrono::milliseconds(520)); + QVERIFY(t.elapsed() > 250 && t.elapsed() < 500); } void AddMSecsIsResetOnStart(void) { MythTimer t; - t.addMSecs(-25); + t.addMSecs(-250); t.start(); - std::this_thread::sleep_for(std::chrono::milliseconds(52)); - QVERIFY(t.elapsed() > 50); + std::this_thread::sleep_for(std::chrono::milliseconds(520)); + QVERIFY(t.elapsed() > 500); } void AddMSecsIsResetOnRestart(void) { MythTimer t; - t.addMSecs(-25); + t.addMSecs(-250); t.restart(); - std::this_thread::sleep_for(std::chrono::milliseconds(52)); - QVERIFY(t.elapsed() > 50); + std::this_thread::sleep_for(std::chrono::milliseconds(520)); + QVERIFY(t.elapsed() > 500); } }; diff --git a/mythtv/libs/libmythmetadata/imagemetadata.cpp b/mythtv/libs/libmythmetadata/imagemetadata.cpp index f1a57d4f8e..b7c71d2ed8 100644 --- a/mythtv/libs/libmythmetadata/imagemetadata.cpp +++ b/mythtv/libs/libmythmetadata/imagemetadata.cpp @@ -7,14 +7,7 @@ #include "exitcodes.h" // for ffprobe // libexiv2 for Exif metadata -//#include <exiv2/exiv2.hpp> -// Note: Older versions of Exiv2 don't have the exiv2.hpp include -// file. Using image.hpp instead seems to work. -#ifdef _MSC_VER -#include <exiv2/src/image.hpp> -#else -#include <exiv2/image.hpp> -#endif +#include <exiv2/exiv2.hpp> // To read FFMPEG Metadata extern "C" { diff --git a/mythtv/libs/libmythmetadata/metaioflacvorbis.cpp b/mythtv/libs/libmythmetadata/metaioflacvorbis.cpp index 3ac353dbc4..8452ffe71f 100644 --- a/mythtv/libs/libmythmetadata/metaioflacvorbis.cpp +++ b/mythtv/libs/libmythmetadata/metaioflacvorbis.cpp @@ -198,10 +198,9 @@ TagLib::FLAC::Picture *MetaIOFLACVorbis::getPictureFromFile( // From what I can tell, FLAC::File maintains ownership of the Picture pointers, so no need to delete const TagLib::List<Picture *>& picList = flacfile->pictureList(); - for (TagLib::List<Picture *>::ConstIterator it = picList.begin(); - it != picList.end(); it++) + for (auto it = picList.begin(); it != picList.end(); it++) { - if (pic->type() == artType) + if ((*it)->type() == artType) { //found the type we were looking for pic = *it; diff --git a/mythtv/libs/libmythprotoserver/requesthandler/fileserverutil.cpp b/mythtv/libs/libmythprotoserver/requesthandler/fileserverutil.cpp index 3e990f019d..bb79ae3e32 100644 --- a/mythtv/libs/libmythprotoserver/requesthandler/fileserverutil.cpp +++ b/mythtv/libs/libmythprotoserver/requesthandler/fileserverutil.cpp @@ -39,11 +39,11 @@ void DeleteHandler::Close(void) m_fd = -1; } -QMap <QString, QString> recordingPathCache; +static QMap <QString, QString> recordingPathCache; +static QMutex recordingPathLock; QString GetPlaybackURL(ProgramInfo *pginfo, bool storePath) { - static QMutex recordingPathLock; QString result = ""; QMutexLocker locker(&recordingPathLock); QString cacheKey = QString("%1:%2").arg(pginfo->GetChanID()) @@ -57,7 +57,9 @@ QString GetPlaybackURL(ProgramInfo *pginfo, bool storePath) } else { + locker.unlock(); result = pginfo->GetPlaybackURL(false, true); + locker.relock(); if (storePath && result.startsWith("/")) recordingPathCache[cacheKey] = result; } diff --git a/mythtv/libs/libmythservicecontracts/service.h b/mythtv/libs/libmythservicecontracts/service.h index b87995d94a..fed7eb3047 100644 --- a/mythtv/libs/libmythservicecontracts/service.h +++ b/mythtv/libs/libmythservicecontracts/service.h @@ -71,7 +71,10 @@ class SERVICE_PUBLIC Service : public QObject // ////////////////////////////////////////////////////////////////////////////// -inline Service::Service(QObject *parent) : QObject(parent) {} +inline Service::Service(QObject *parent) : QObject(parent) +{ + qRegisterMetaType< QFileInfo >(); +} ////////////////////////////////////////////////////////////////////////////// // diff --git a/mythtv/libs/libmythservicecontracts/services/mythServices.h b/mythtv/libs/libmythservicecontracts/services/mythServices.h index 9c2f7f505e..b4fc7834d4 100644 --- a/mythtv/libs/libmythservicecontracts/services/mythServices.h +++ b/mythtv/libs/libmythservicecontracts/services/mythServices.h @@ -54,6 +54,7 @@ class SERVICE_PUBLIC MythServices : public Service //, public QScriptable ??? Q_CLASSINFO( "SendNotification_Method", "POST" ) Q_CLASSINFO( "BackupDatabase_Method", "POST" ) Q_CLASSINFO( "CheckDatabase_Method", "POST" ) + Q_CLASSINFO( "DelayShutdown_Method", "POST" ) Q_CLASSINFO( "ProfileSubmit_Method", "POST" ) Q_CLASSINFO( "ProfileDelete_Method", "POST" ) Q_CLASSINFO( "ManageDigestUser_Method", "POST" ) @@ -164,6 +165,8 @@ class SERVICE_PUBLIC MythServices : public Service //, public QScriptable ??? virtual bool CheckDatabase ( bool Repair ) = 0; + virtual bool DelayShutdown ( void ) = 0; + virtual bool ProfileSubmit ( void ) = 0; virtual bool ProfileDelete ( void ) = 0; diff --git a/mythtv/libs/libmythtv/Bluray/bdringbuffer.cpp b/mythtv/libs/libmythtv/Bluray/bdringbuffer.cpp index 06258070e1..d7e4707d40 100644 --- a/mythtv/libs/libmythtv/Bluray/bdringbuffer.cpp +++ b/mythtv/libs/libmythtv/Bluray/bdringbuffer.cpp @@ -142,7 +142,7 @@ static int _img_read(void *handle, void *buf, int lba, int num_blocks) { int result = -1; - if (mythfile_seek(*((int*)handle), lba * 2048, SEEK_SET) != -1) + if (mythfile_seek(*((int*)handle), lba * 2048LL, SEEK_SET) != -1) result = mythfile_read(*((int*)handle), buf, num_blocks * 2048) / 2048; return result; diff --git a/mythtv/libs/libmythtv/HLS/httplivestreambuffer.cpp b/mythtv/libs/libmythtv/HLS/httplivestreambuffer.cpp index 6067814cce..43a0e9d219 100644 --- a/mythtv/libs/libmythtv/HLS/httplivestreambuffer.cpp +++ b/mythtv/libs/libmythtv/HLS/httplivestreambuffer.cpp @@ -342,6 +342,7 @@ public: { LOG(VB_PLAYBACK, LOG_ERR, LOC + QString("bad padding character (0x%1)").arg(pad, 0, 16, QLatin1Char('0'))); + delete[] decrypted_data; return RET_ERROR; } aeslen = m_data.size() - pad; diff --git a/mythtv/libs/libmythtv/avformatdecoder.cpp b/mythtv/libs/libmythtv/avformatdecoder.cpp index b25516c795..b97ff0e4be 100644 --- a/mythtv/libs/libmythtv/avformatdecoder.cpp +++ b/mythtv/libs/libmythtv/avformatdecoder.cpp @@ -1459,7 +1459,6 @@ float AvFormatDecoder::normalized_fps(AVStream *stream, AVCodecContext *enc) QString("Selected FPS is %1 (avg %2 codec %3 " "container %4 estimated %5)").arg(fps).arg(avg_fps) .arg(codec_fps).arg(container_fps).arg(estimated_fps)); - m_fps = fps; } return fps; @@ -1685,6 +1684,7 @@ void AvFormatDecoder::InitVideoCodec(AVStream *stream, AVCodecContext *enc, { enc->get_buffer2 = get_avf_buffer_vaapi2; enc->get_format = get_format_vaapi2; + enc->slice_flags = SLICE_FLAG_CODED_ORDER | SLICE_FLAG_ALLOW_FIELD; } else #endif diff --git a/mythtv/libs/libmythtv/cc708decoder.cpp b/mythtv/libs/libmythtv/cc708decoder.cpp index 718bdbeef7..f8638a7830 100644 --- a/mythtv/libs/libmythtv/cc708decoder.cpp +++ b/mythtv/libs/libmythtv/cc708decoder.cpp @@ -15,7 +15,8 @@ #define DEBUG_CC_SERVICE_2 0 #define DEBUG_CC_RAWPACKET 0 #define DEBUG_CC_VALIDPACKET 0 -#define DEBUG_CC_SERVICE_BLOCK 0 +#define DEBUG_CC_DECODE 0 +#define DEBUG_CC_PARSE 0 typedef enum { @@ -40,7 +41,7 @@ void CC708Decoder::decode_cc_data(uint cc_type, uint data1, uint data2) { if (DTVCC_PACKET_START == cc_type) { -#if 0 +#if DEBUG_CC_DECODE LOG(VB_VBI, LOG_DEBUG, LOC + QString("CC ST data(0x%1 0x%2)") .arg(data1,0,16).arg(data2,0,16)); #endif @@ -54,7 +55,7 @@ void CC708Decoder::decode_cc_data(uint cc_type, uint data1, uint data2) } else if (DTVCC_PACKET_DATA == cc_type) { -#if 0 +#if DEBUG_CC_DECODE LOG(VB_VBI, LOG_DEBUG, LOC + QString("CC Ex data(0x%1 0x%2)") .arg(data1,0,16).arg(data2,0,16)); #endif @@ -197,10 +198,10 @@ static void parse_cc_service_stream(CC708Reader* cc, uint service_num) dlc_loc = blk_size - 1; } -#if 0 +#if DEBUG_CC_PARSE LOG(VB_VBI, LOG_ERR, QString("cc_ss delayed(%1) blk_start(%2) blk_size(%3)") - .arg(cc->delayed) .arg(blk_start) .arg(blk_size)); + .arg(cc->delayed[service_num]) .arg(blk_start) .arg(blk_size)); #endif for (i = (cc->delayed[service_num]) ? blk_size : blk_start; @@ -492,7 +493,7 @@ static int handle_cc_c1(CC708Reader* cc, uint service_num, int i) else { LOG(VB_VBI, LOG_ERR, QString("handle_cc_c1: (NOT HANDLED) " - "code(0x%1) i(%2) blk_size(%3)").arg(code, 2, 16, '0') + "code(0x%1) i(%2) blk_size(%3)").arg(code, 2, 16, QLatin1Char('0')) .arg(i).arg(blk_size)); } #endif @@ -555,18 +556,25 @@ static int handle_cc_c3(CC708Reader* cc, uint service_num, int i) return i; } -static void rightsize_buf(CC708Reader* cc, uint service_num, uint block_size) +static bool rightsize_buf(CC708Reader* cc, uint service_num, uint block_size) { - uint min_new_size = block_size + cc->buf_size[service_num]; + size_t min_new_size = block_size + cc->buf_size[service_num]; + bool ret = true; if (min_new_size >= cc->buf_alloc[service_num]) { - uint new_alloc = cc->buf_alloc[service_num]; + size_t new_alloc = cc->buf_alloc[service_num]; for (uint i = 0; (i < 32) && (new_alloc <= min_new_size); i++) new_alloc *= 2; - - cc->buf[service_num] = - (unsigned char*) realloc(cc->buf[service_num], new_alloc); - cc->buf_alloc[service_num] = (cc->buf[service_num]) ? new_alloc : 0; + void *new_buf = realloc(cc->buf[service_num], new_alloc); + if (new_buf) + { + cc->buf[service_num] = (uchar *)new_buf; + cc->buf_alloc[service_num] = new_alloc; + } + else + { + ret = false; + } #if DEBUG_CC_SERVICE_2 LOG(VB_VBI, LOG_DEBUG, QString("rightsize_buf: srv %1 to %1 bytes") @@ -579,12 +587,17 @@ static void rightsize_buf(CC708Reader* cc, uint service_num, uint block_size) .arg(min_new_size) .arg(service_num) .arg(cc->buf_alloc[service_num])); + return ret; } static void append_cc(CC708Reader* cc, uint service_num, const unsigned char* blk_buf, int block_size) { - rightsize_buf(cc, service_num, block_size); + if (!rightsize_buf(cc, service_num, block_size)) + { + // The buffer resize failed. Drop the new data. + return; + } memcpy(cc->buf[service_num] + cc->buf_size[service_num], blk_buf, block_size); diff --git a/mythtv/libs/libmythtv/channelscan/channelscanner.cpp b/mythtv/libs/libmythtv/channelscan/channelscanner.cpp index d4532cd226..a6a55340d9 100644 --- a/mythtv/libs/libmythtv/channelscan/channelscanner.cpp +++ b/mythtv/libs/libmythtv/channelscan/channelscanner.cpp @@ -39,7 +39,9 @@ using namespace std; #include "hdhrchannel.h" #include "scanmonitor.h" #include "asichannel.h" +#ifdef USING_DVB // for bug in gcc 8.3 #include "dvbchannel.h" +#endif #include "v4lchannel.h" #include "iptvchannel.h" #include "ExternalChannel.h" diff --git a/mythtv/libs/libmythtv/channelutil.cpp b/mythtv/libs/libmythtv/channelutil.cpp index 1c35d7ca4f..bec67d0236 100644 --- a/mythtv/libs/libmythtv/channelutil.cpp +++ b/mythtv/libs/libmythtv/channelutil.cpp @@ -1875,7 +1875,8 @@ bool ChannelUtil::GetChannelData( "FROM channel, videosource " "WHERE videosource.sourceid = channel.sourceid AND " " channum = :CHANNUM AND " - " channel.sourceid = :SOURCEID"); + " channel.sourceid = :SOURCEID " + "ORDER BY channel.visible DESC, channel.chanid "); query.bindValue(":CHANNUM", channum); query.bindValue(":SOURCEID", sourceid); @@ -1885,35 +1886,38 @@ bool ChannelUtil::GetChannelData( return false; } - while (query.next()) + if (query.next()) { + finetune = query.value(0).toInt(); + freqid = query.value(1).toString(); + tvformat = query.value(2).toString(); + freqtable = query.value(3).toString(); + commfree = (query.value(4).toInt() == -2); + mplexid = query.value(5).toUInt(); + atsc_major = query.value(6).toUInt(); + atsc_minor = query.value(7).toUInt(); + mpeg_prog_num = (query.value(8).isNull()) ? -1 + : query.value(8).toInt(); + chanid = query.value(9).toUInt(); + found += query.value(10).toInt(); - if (found) - { - finetune = query.value(0).toInt(); - freqid = query.value(1).toString(); - tvformat = query.value(2).toString(); - freqtable = query.value(3).toString(); - commfree = (query.value(4).toInt() == -2); - mplexid = query.value(5).toUInt(); - atsc_major = query.value(6).toUInt(); - atsc_minor = query.value(7).toUInt(); - mpeg_prog_num = (query.value(8).isNull()) ? -1 - : query.value(8).toInt(); - chanid = query.value(9).toUInt(); - } } - if (!found) + while (query.next()) + found += query.value(10).toInt(); + + if (found == 0 && chanid) { - LOG(VB_GENERAL, LOG_INFO, - QString("No visible channels for %1").arg(channum)); + LOG(VB_GENERAL, LOG_WARNING, + QString("No visible channels for %1, using invisble chanid %2") + .arg(channum).arg(chanid)); } if (found > 1) { LOG(VB_GENERAL, LOG_WARNING, - QString("Found multiple visible channels for %1").arg(channum)); + QString("Found multiple visible channels for %1, using chanid %2") + .arg(channum).arg(chanid)); } if (!chanid) @@ -2409,7 +2413,7 @@ ChannelInfoList ChannelUtil::LoadChannels(uint startIndex, uint count, cond << "channel.sourceid = :SOURCEID "; if (liveTVOnly) - cond << "channel.livetvorder > 0 "; + cond << "capturecard.livetvorder > 0 "; if (!cond.isEmpty()) sql += QString("WHERE %1").arg(cond.join("AND ")); @@ -2429,7 +2433,7 @@ ChannelInfoList ChannelUtil::LoadChannels(uint startIndex, uint count, } else // kChanOrderByLiveTV { - sql += "ORDER BY callsign = :CALLSIGN1 AND channum = :CHANNUM, " + sql += "ORDER BY callsign = :CALLSIGN1 AND channum = :CHANNUM DESC, " " callsign = :CALLSIGN2 DESC, " " livetvorder, " " channel.recpriority DESC, " diff --git a/mythtv/libs/libmythtv/datadirect.cpp b/mythtv/libs/libmythtv/datadirect.cpp index e6477fdf21..9cd7178786 100644 --- a/mythtv/libs/libmythtv/datadirect.cpp +++ b/mythtv/libs/libmythtv/datadirect.cpp @@ -881,7 +881,7 @@ void DataDirectProcessor::DataDirectProgramUpdate(void) #endif if (!query.exec("INSERT IGNORE INTO programrating (chanid, starttime, " - "system, rating) SELECT dd_v_program.chanid, " + "`system`, rating) SELECT dd_v_program.chanid, " "DATE_ADD(starttime, INTERVAL channel.tmoffset MINUTE), " " 'MPAA', " "mpaarating FROM dd_v_program, channel WHERE " @@ -890,7 +890,7 @@ void DataDirectProcessor::DataDirectProgramUpdate(void) MythDB::DBError("Inserting into programrating table", query); if (!query.exec("INSERT IGNORE INTO programrating (chanid, starttime, " - "system, rating) SELECT dd_v_program.chanid, " + "`system`, rating) SELECT dd_v_program.chanid, " "DATE_ADD(starttime, INTERVAL channel.tmoffset MINUTE), " "'VCHIP', " "tvrating FROM dd_v_program, channel WHERE tvrating != ''" diff --git a/mythtv/libs/libmythtv/dbcheck.cpp b/mythtv/libs/libmythtv/dbcheck.cpp index f3485aca9a..c55f1b207c 100644 --- a/mythtv/libs/libmythtv/dbcheck.cpp +++ b/mythtv/libs/libmythtv/dbcheck.cpp @@ -2636,9 +2636,9 @@ nullptr "UNIQUE KEY recgroup ( recgroup )" ") ENGINE=MyISAM DEFAULT CHARSET=utf8;", // Create the built-in, 'special', groups - "INSERT INTO recgroups ( recgroup, special ) VALUES ( 'Default', '1' );", - "INSERT INTO recgroups ( recgroup, special ) VALUES ( 'LiveTV', '1' );", - "INSERT INTO recgroups ( recgroup, special ) VALUES ( 'Deleted', '1' );", + "INSERT INTO recgroups ( recgroupid, recgroup, special ) VALUES ( 1, 'Default', '1' );", + "INSERT INTO recgroups ( recgroupid, recgroup, special ) VALUES ( 2, 'LiveTV', '1' );", + "INSERT INTO recgroups ( recgroupid, recgroup, special ) VALUES ( 3, 'Deleted', '1' );", // Copy in the passwords for the built-in groups "DELETE FROM recgrouppassword WHERE password = '';", "UPDATE recgroups r, recgrouppassword p SET r.password = p.password WHERE r.recgroup = p.recgroup;", @@ -3442,7 +3442,7 @@ nullptr if (dbver == "1349") { const char *updates[] = { - "DELETE FROM settings WHERE value='AltClearSavedPosition';", + // Incorrect DB update removed nullptr }; if (!performActualUpdate(updates, "1350", dbver)) @@ -4125,10 +4125,10 @@ bool InitializeMythSchema(void) "CREATE TABLE programrating (" " chanid int(10) unsigned NOT NULL DEFAULT '0'," " starttime datetime NOT NULL DEFAULT '0000-00-00 00:00:00'," -" system varchar(8) DEFAULT NULL," +" `system` varchar(8) DEFAULT NULL," " rating varchar(16) DEFAULT NULL," -" UNIQUE KEY chanid (chanid,starttime,system,rating)," -" KEY starttime (starttime,system)" +" UNIQUE KEY chanid (chanid,starttime,`system`,rating)," +" KEY starttime (starttime,`system`)" ") ENGINE=MyISAM DEFAULT CHARSET=utf8;", "CREATE TABLE recgrouppassword (" " recgroup varchar(32) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL DEFAULT ''," @@ -4335,10 +4335,10 @@ bool InitializeMythSchema(void) "CREATE TABLE recordedrating (" " chanid int(10) unsigned NOT NULL DEFAULT '0'," " starttime datetime NOT NULL DEFAULT '0000-00-00 00:00:00'," -" system varchar(8) DEFAULT NULL," +" `system` varchar(8) DEFAULT NULL," " rating varchar(16) DEFAULT NULL," -" UNIQUE KEY chanid (chanid,starttime,system,rating)," -" KEY starttime (starttime,system)" +" UNIQUE KEY chanid (chanid,starttime,`system`,rating)," +" KEY starttime (starttime,`system`)" ") ENGINE=MyISAM DEFAULT CHARSET=utf8;", "CREATE TABLE recordedseek (" " chanid int(10) unsigned NOT NULL DEFAULT '0'," diff --git a/mythtv/libs/libmythtv/decoderbase.h b/mythtv/libs/libmythtv/decoderbase.h index 22bbd9fbae..4ee216d02c 100644 --- a/mythtv/libs/libmythtv/decoderbase.h +++ b/mythtv/libs/libmythtv/decoderbase.h @@ -208,6 +208,7 @@ class DecoderBase virtual void UpdateFramesPlayed(void); long long GetFramesRead(void) const { return framesRead; } long long GetFramesPlayed(void) const { return framesPlayed; } + void SetFramesPlayed(long long newValue) {framesPlayed = newValue;} virtual QString GetCodecDecoderName(void) const = 0; virtual QString GetRawEncodingType(void) { return QString(); } diff --git a/mythtv/libs/libmythtv/dsmccobjcarousel.cpp b/mythtv/libs/libmythtv/dsmccobjcarousel.cpp index 0ace9e6a29..4109a52cc5 100644 --- a/mythtv/libs/libmythtv/dsmccobjcarousel.cpp +++ b/mythtv/libs/libmythtv/dsmccobjcarousel.cpp @@ -105,6 +105,13 @@ unsigned char *DSMCCCacheModuleData::AddModuleData(DsmccDb *ddb, for (uint i = 0; i < m_blocks.size(); i++) { QByteArray *block = m_blocks[i]; + if (block == nullptr) + { + LOG(VB_DSMCC, LOG_INFO, + QString("[dsmcc] Null data found, aborting reconstruction")); + free(tmp_data); + return nullptr; + } m_blocks[i] = nullptr; uint size = block->size(); memcpy(tmp_data + curp, block->data(), size); diff --git a/mythtv/libs/libmythtv/eitcache.cpp b/mythtv/libs/libmythtv/eitcache.cpp index c1ef93d608..9bbb724382 100644 --- a/mythtv/libs/libmythtv/eitcache.cpp +++ b/mythtv/libs/libmythtv/eitcache.cpp @@ -388,9 +388,7 @@ bool EITCache::IsNewEIT(uint chanid, uint tableid, uint version, tblChgCnt++; } else if ((extract_table_id(*it) == tableid) && - ((extract_version(*it) < version) || - ((extract_version(*it) == kVersionMax) && - version < kVersionMax))) + (extract_version(*it) != version)) { // EIT updated version on current table verChgCnt++; diff --git a/mythtv/libs/libmythtv/eitfixup.cpp b/mythtv/libs/libmythtv/eitfixup.cpp index 7807484ae5..0fda92942e 100644 --- a/mythtv/libs/libmythtv/eitfixup.cpp +++ b/mythtv/libs/libmythtv/eitfixup.cpp @@ -144,6 +144,8 @@ EITFixUp::EITFixUp() m_RTLEpisodeNo2("^(\\d{1,2}\\/[IVX]+)\\.*\\s*"), m_fiRerun("\\ ?Uusinta[a-zA-Z\\ ]*\\.?"), m_fiRerun2("\\([Uu]\\)"), + m_fiAgeLimit("\\(((1?[0-9]?)|[ST])\\)$"), + m_fiFilm("^(Film|Elokuva): "), m_dePremiereLength("\\s?[0-9]+\\sMin\\."), m_dePremiereAirdate("\\s?([^\\s^\\.]+)\\s((?:1|2)[0-9]{3})\\."), m_dePremiereCredits("\\sVon\\s([^,]+)(?:,|\\su\\.\\sa\\.)\\smit\\s([^\\.]*)\\."), @@ -198,24 +200,28 @@ EITFixUp::EITFixUp() m_HTML("</?EM>", Qt::CaseInsensitive), m_grReplay("\\([ΕE]\\)"), m_grDescriptionFinale("\\s*Τελευταίο\\sΕπεισόδιο\\.\\s*"), - m_grActors("(?:[Ππ]α[ιί]ζουν:|[Μμ]ε τους:|Πρωταγωνιστο[υύ]ν:|Πρωταγωνιστε[ιί]:?)(?:\\s+στο ρόλο(?: του| της)?\\s(?:\\w+\\s[οη]\\s))?([-\\w\\s']+(?:,[-\\w\\s']+)*)(?:κ\\.[αά])?(?:\\W?)"), + m_grActors("(?:[Ππ]α[ιί]ζουν:|[ΜMμ]ε τους:|Πρωταγωνιστο[υύ]ν:|Πρωταγωνιστε[ιί]:?)(?:\\s+στο ρόλο(?: του| της)?\\s(?:\\w+\\s[οη]\\s))?([-\\w\\s']+(?:,[-\\w\\s']+)*)(?:κ\\.[αά])?(?:\\W?)"), // cap(1) actors, just names m_grFixnofullstopActors("(\\w\\s(Παίζουν:|Πρωταγων))"), m_grFixnofullstopDirectors("((\\w\\s(Σκηνοθ[εέ]))"), - m_grPeopleSeparator("(,\\s+)"), - m_grDirector("(?:Σκηνοθεσία: |Σκηνοθέτης: )(\\w+\\s\\w+\\s?)(?:\\W?)"), - m_grPres("(?:Παρουσ[ιί]αση:(?:\\b)*|Παρουσι[αά]ζ(?:ουν|ει)(?::|\\sο|\\sη)|Με τ(?:ον |ην )(?:[\\s|:|ο|η])*(?:\\b)*)([-\\w\\s]+(?:,[-\\w\\s]+)*)(?:\\W?)"), + m_grPeopleSeparator("([,-]\\s+)"), + m_grDirector("(?:Σκηνοθεσία: |Σκηνοθέτης: |Σκηνοθέτης - Επιμέλεια: )(\\w+\\s\\w+\\s?)(?:\\W?)"), + m_grPres("(?:Παρουσ[ιί]αση:(?:\\b)*|Παρουσι[αά]ζ(?:ουν|ει)(?::|\\sο|\\sη)|Παρουσι[αά]στ(?:[ηή]ς|ρια|ριες|[εέ]ς)(?::|\\sο|\\sη)|Με τ(?:ον |ην )(?:[\\s|:|ο|η])*(?:\\b)*)([-\\w\\s]+(?:,[-\\w\\s]+)*)(?:\\W?)"), m_grYear("(?:\\W?)(?:\\s?παραγωγ[ηή]ς|\\s?-|,)\\s*([1-2]{1}[0-9]{3})(?:-\\d{1,4})?",Qt::CaseInsensitive), m_grCountry("(?:\\W|\\b)(?:(ελλην|τουρκ|αμερικ[αά]ν|γαλλ|αγγλ|βρεττ?αν|γερμαν|ρωσσ?|ιταλ|ελβετ|σουηδ|ισπαν|πορτογαλ|μεξικ[αά]ν|κιν[εέ]ζικ|ιαπων|καναδ|βραζιλι[αά]ν)(ικ[ηή][ςσ]))",Qt::CaseInsensitive), m_grlongEp("\\b(?:Επ.|επεισ[οό]διο:?)\\s*(\\d+)(?:\\W?)",Qt::CaseInsensitive), - m_grSeason("(?:-\\s)?\\b((\\D{1,2})(?:')?|(\\d{1,2})(?:ος|ου)?)(?:\\sκ[υύ]κλο(?:[σς]|υ)){1}\\s?",Qt::CaseInsensitive), - m_grRealTitleinDescription("(?:^\\()([\\w\\s\\d\\D-]+)(?:\\))(?:\\s*)"), + m_grSeason_as_RomanNumerals(",\\s*([MDCLXVIΙΧ]+)$",Qt::CaseInsensitive), + m_grSeason("(?:\\W-?)*(?:\\(-\\s*)?\\b(([Α-Ω]{1,2})(?:'|΄)?|(\\d{1,2})(?:ος|ου|oς|os)?)(?:\\s*κ[υύ]κλο(?:[σς]|υ)){1}\\s?",Qt::CaseInsensitive), + m_grRealTitleinDescription("(?:^\\()([A-Za-z\\s\\d-]+)(?:\\))(?:\\s*)"), // cap1 = real title // cap0 = real title in parentheses. - m_grRealTitleinTitle("(?:\\()([\\w\\s\\d\\D-]+)(?:\\))(?:\\s*$)*"), + m_grRealTitleinTitle("(?:\\()([A-Za-z\\s\\d-]+)(?:\\))(?:\\s*$)*"), // cap1 = real title // cap0 = real title in parentheses. - m_grNotPreviouslyShown("(?:\\b[Α1]['η]?\\s*(?:τηλεοπτικ[ηή]\\s*)?(?:μετ[αά]δοση|προβολ[ηή]))(?:\\W?)"), + m_grCommentsinTitle("(?:\\()([Α-Ωα-ω\\s\\d-]+)(?:\\))(?:\\s*$)*"), + // cap1 = real title + // cap0 = real title in parentheses. + m_grNotPreviouslyShown("(?:\\W?)(?:-\\s*)*(?:\\b[Α1]['΄η]?\\s*(?:τηλεοπτικ[ηή]\\s*)?(?:μετ[αά]δοση|προβολ[ηή]))(?:\\W?)",Qt::CaseInsensitive), // Try to exctract Greek categories from keywords in description. m_grEpisodeAsSubtitle("(?:^Επεισ[οό]διο:\\s?)([\\w\\s-,']+)\\.(?:\\s)?"), m_grCategFood("(?:\\W)?(?:εκπομπ[ηή]\\W)?(Γαστρονομ[ιί]α[σς]?|μαγειρικ[ηή][σς]?|chef|συνταγ[εέηή]|διατροφ|wine|μ[αά]γειρα[σς]?)(?:\\W)?",Qt::CaseInsensitive), @@ -1924,6 +1930,21 @@ void EITFixUp::FixFI(DBEventEIT &event) const event.audioProps |= AUD_STEREO; event.description = event.description.replace(m_Stereo, ""); } + + // Remove age limit in parenthesis at end of title + position = event.title.indexOf(m_fiAgeLimit); + if (position != -1) + { + event.title = event.title.replace(m_fiAgeLimit, ""); + } + + // Remove Film or Elokuva at start of title + position = event.title.indexOf(m_fiFilm); + if (position != -1) + { + event.title = event.title.replace(m_fiFilm, ""); + } + } /** \fn EITFixUp::FixPremiere(DBEventEIT&) const @@ -2552,6 +2573,8 @@ void EITFixUp::FixGreekSubtitle(DBEventEIT &event) const void EITFixUp::FixGreekEIT(DBEventEIT &event) const { + int position1; + int position2; //Live show int position; QRegExp tmpRegEx; @@ -2567,7 +2590,7 @@ void EITFixUp::FixGreekEIT(DBEventEIT &event) const if (position != -1) { event.previouslyshown = false; - event.title = event.title.replace(m_grNotPreviouslyShown.cap(0), ""); + event.title = event.title.replace(m_grNotPreviouslyShown, ""); } // Greek Replay (Ε) @@ -2580,6 +2603,23 @@ void EITFixUp::FixGreekEIT(DBEventEIT &event) const event.title = event.title.replace(tmpRegEx, ""); } + // Check for (HD) in the decription + position = event.description.indexOf("(HD)"); + if (position != -1) + { + event.description = event.description.replace("(HD)", ""); + event.videoProps |= VID_HDTV; + } + + // Check for (Full HD) in the decription + position = event.description.indexOf("(Full HD)"); + if (position != -1) + { + event.description = event.description.replace("(Full HD)", ""); + event.videoProps |= VID_HDTV; + } + + tmpRegEx = m_grFixnofullstopActors; position = event.description.indexOf(tmpRegEx); if (position != -1) @@ -2639,37 +2679,6 @@ void EITFixUp::FixGreekEIT(DBEventEIT &event) const event.description.replace(tmpRegEx.cap(0), ""); } -/* - - tmpRegEx = m_grDirector; - position = event.description.indexOf(tmpRegEx); - if (position != -1) - { - // director is captured in cap(1).Due to sometimes miswritten data in - // eit, e.g no fullstop present(!) - QString tmpDirectorsString = tmpRegEx.cap(1); - // look for actors in director string (lack of fullstop, etc) - tmpRegEx = m_grActors; - int actposition = tmpDirectorsString.indexOf(tmpRegEx); - if (actposition != -1) - { - tmpDirectorsString = tmpDirectorsString.replace(tmpRegEx,""); - } - const QStringList directors = - tmpDirectorsString.split(m_grPeopleSeparator, QString::SkipEmptyParts); - QStringList::const_iterator it = directors.begin(); - for (; it != directors.end(); ++it) - { - tmpDirectorsString = it->split(":").last().trimmed(). - remove(QRegExp("\\.$")); - if (tmpDirectorsString != "") - event.AddPerson(DBPerson::kDirector, tmpDirectorsString); - - } - event.description.replace(tmpRegEx.cap(0), ""); - // directorPresent = true; - } -*/ //Try to find presenter tmpRegEx = m_grPres; position = event.description.indexOf(tmpRegEx); @@ -2709,6 +2718,8 @@ void EITFixUp::FixGreekEIT(DBEventEIT &event) const event.description = event.description.trimmed(); event.title = event.title.trimmed(); event.subtitle = event.subtitle.trimmed(); + // Remove " ." + event.description = event.description.replace(" .",".").trimmed(); //find country of origin and remove it from description. tmpRegEx = m_grCountry; @@ -2724,9 +2735,8 @@ void EITFixUp::FixGreekEIT(DBEventEIT &event) const QRegExp tmpSeries = m_grSeason; // cap(2) is the season for ΑΒΓΔ // cap(3) is the season for 1234 - int position1 = tmpSeries.indexIn(event.title); - int position2 = tmpSeries.indexIn(event.description); - if ((position1 != -1) || (position2 != -1)) + if ((position1 = tmpSeries.indexIn(event.title)) != -1 + || (position2 = tmpSeries.indexIn(event.description)) != -1) { if (!tmpSeries.cap(2).isEmpty()) // we found a letter representing a number { @@ -2756,6 +2766,73 @@ void EITFixUp::FixGreekEIT(DBEventEIT &event) const if (position2 != -1) event.description.replace(tmpSeries.cap(0),""); } + // If Season is in Roman Numerals (I,II,etc) + tmpSeries = m_grSeason_as_RomanNumerals; + if ((position1 = tmpSeries.indexIn(event.title)) != -1 + || (position2 = tmpSeries.indexIn(event.description)) != -1) + { + if (!tmpSeries.isEmpty()) //number + { + // make sure I replace greek Ι with english I + QString romanSeries = tmpSeries.cap(1).replace("Ι","I").toUpper(); + if (romanSeries == "I") + event.season = 1; + else if (romanSeries == "II") + event.season = 2; + else if (romanSeries== "III") + event.season = 3; + else if (romanSeries == "IV") + event.season = 4; + else if (romanSeries == "V") + event.season = 5; + else if (romanSeries== "VI") + event.season = 6; + else if (romanSeries == "VII") + event.season = 7; + else if (romanSeries == "VIII") + event.season = 8; + else if (romanSeries == "IX") + event.season = 9; + else if (romanSeries == "X") + event.season = 10; + else if (romanSeries == "XI") + event.season = 11; + else if (romanSeries == "XII") + event.season = 12; + else if (romanSeries == "XII") + event.season = 13; + else if (romanSeries == "XIV") + event.season = 14; + else if (romanSeries == "XV") + event.season = 15; + else if (romanSeries == "XVI") + event.season = 16; + else if (romanSeries == "XVII") + event.season = 17; + else if (romanSeries == "XIII") + event.season = 18; + else if (romanSeries == "XIX") + event.season = 19; + else if (romanSeries == "XX") + event.season = 20; + } + series = true; + if (position1 != -1) + { + event.title.replace(tmpSeries.cap(0),""); + event.title = event.title.trimmed(); + if (event.title.right(1) == ",") + event.title.chop(1); + } + if (position2 != -1) + { + event.description.replace(tmpSeries.cap(0),""); + event.description = event.description.trimmed(); + if (event.description.right(1) == ",") + event.description.chop(1); + } + } + QRegExp tmpEpisode = m_grlongEp; //tmpEpisode.setMinimal(true); @@ -2776,6 +2853,17 @@ void EITFixUp::FixGreekEIT(DBEventEIT &event) const event.season = 1; } } + // Sometimes, especially on greek national tv, they include comments in the + // title, e.g "connection to ert1", "ert archives". + // Because they obscure the real title, I'll isolate and remove them. + + QRegExp tmpComment = m_grCommentsinTitle; + tmpComment.setMinimal(true); + position = event.title.indexOf(tmpComment); + if (position != -1) + { + event.title.replace(tmpComment.cap(0),""); + } // Sometimes the real (mostly English) title of a movie or series is // enclosed in parentheses in the event title, subtitle or description. diff --git a/mythtv/libs/libmythtv/eitfixup.h b/mythtv/libs/libmythtv/eitfixup.h index 67cbcd0846..35ed11753a 100644 --- a/mythtv/libs/libmythtv/eitfixup.h +++ b/mythtv/libs/libmythtv/eitfixup.h @@ -212,6 +212,8 @@ class EITFixUp const QRegExp m_RTLEpisodeNo2; const QRegExp m_fiRerun; const QRegExp m_fiRerun2; + const QRegExp m_fiAgeLimit; + const QRegExp m_fiFilm; const QRegExp m_dePremiereLength; const QRegExp m_dePremiereAirdate; const QRegExp m_dePremiereCredits; @@ -272,10 +274,12 @@ class EITFixUp const QRegExp m_grYear; // Greek release year. const QRegExp m_grCountry; // Greek event country of origin. const QRegExp m_grlongEp; // Greek Episode + const QRegExp m_grSeason_as_RomanNumerals; // Greek Episode in Roman numerals const QRegExp m_grSeason; // Greek Season const QRegExp m_grSeries; const QRegExp m_grRealTitleinDescription; // The original title is often in the descr in parenthesis. const QRegExp m_grRealTitleinTitle; // The original title is often in the title in parenthesis. + const QRegExp m_grCommentsinTitle; // Sometimes esp. national stations include comments in the title eg "(ert arxeio)" const QRegExp m_grNotPreviouslyShown; // Not previously shown on TV const QRegExp m_grEpisodeAsSubtitle; // Description field: "^Episode: Lion in the cage. (Description follows)" const QRegExp m_grCategFood; // Greek category food diff --git a/mythtv/libs/libmythtv/eithelper.cpp b/mythtv/libs/libmythtv/eithelper.cpp index 1caa158d9f..7a839d1c42 100644 --- a/mythtv/libs/libmythtv/eithelper.cpp +++ b/mythtv/libs/libmythtv/eithelper.cpp @@ -89,13 +89,12 @@ uint EITHelper::ProcessEvents(void) if (!insertCount) return 0; - if (incomplete_events.size() || unmatched_etts.size()) + if (!incomplete_events.empty()) { LOG(VB_EIT, LOG_INFO, - LOC + QString("Added %1 events -- complete(%2) " - "incomplete(%3) unmatched(%4)") + LOC + QString("Added %1 events -- complete: %2 incomplete: %3") .arg(insertCount).arg(db_events.size()) - .arg(incomplete_events.size()).arg(unmatched_etts.size())); + .arg(incomplete_events.size())); } else { @@ -147,7 +146,6 @@ void EITHelper::AddEIT(uint atsc_major, uint atsc_minor, { uint atsc_key = (atsc_major << 16) | atsc_minor; EventIDToATSCEvent &events = incomplete_events[atsc_key]; - EventIDToETT &etts = unmatched_etts[atsc_key]; for (uint i = 0; i < eit->EventCount(); i++) { @@ -156,29 +154,24 @@ void EITHelper::AddEIT(uint atsc_major, uint atsc_minor, eit->title(i).GetBestMatch(languagePreferences), eit->Descriptors(i), eit->DescriptorsLength(i)); - // Look to see if there has been a recent ett message with the same event id. - EventIDToETT::iterator it = etts.find(eit->EventID(i)); - QString ett_text; - bool found_matching_ett = false; - if (it != etts.end()) + // Create an event immediately if the ETM_location specifies + // that there is no ETT event coming; otherwise save the EIT + // event in the incomplete_events for this channel. + if (!ev.etm) { - // Don't use an ett description if it was scanned long in the past. - if (!it->IsStale()) { - ett_text = it->ett_text; - found_matching_ett = true; - } - etts.erase(it); - } - - // Create an event immediately if a matching ett description was found, - // or if item is false, indicating that no ett description should be - // expected. - if (found_matching_ett || !ev.etm) - { - CompleteEvent(atsc_major, atsc_minor, ev, ett_text); + CompleteEvent(atsc_major, atsc_minor, ev, ""); } else { + // If there is an existing EIT event with this event_id then + // delete the descriptor to avoid a memory leak. + EventIDToATSCEvent::iterator it = events.find(eit->EventID(i)); + if (it != events.end()) + { + delete [] (*it).desc; + } + + // Save the EIT event in the incomplete_events for this channel. unsigned char *tmp = new unsigned char[ev.desc_length]; memcpy(tmp, eit->Descriptors(i), ev.desc_length); ev.desc = tmp; @@ -190,52 +183,27 @@ void EITHelper::AddEIT(uint atsc_major, uint atsc_minor, void EITHelper::AddETT(uint atsc_major, uint atsc_minor, const ExtendedTextTable *ett) { + // Find the matching incomplete EIT event for this ETT + // If we have no EIT event then just discard the ETT. uint atsc_key = (atsc_major << 16) | atsc_minor; - // Try to match up the ett with an eit event. ATSCSRCToEvents::iterator eits_it = incomplete_events.find(atsc_key); if (eits_it != incomplete_events.end()) { EventIDToATSCEvent::iterator it = (*eits_it).find(ett->EventID()); if (it != (*eits_it).end()) { - bool completed_event = false; - // Only consider eit events from the recent past. + // Only consider EIT events from the very recent past. if (!it->IsStale()) { - completed_event = true; CompleteEvent( atsc_major, atsc_minor, *it, ett->ExtendedTextMessage().GetBestMatch(languagePreferences)); } - if ((*it).desc) - delete [] (*it).desc; - + // Remove EIT event from the incomplete_event list. + delete [] (*it).desc; (*eits_it).erase(it); - - if (completed_event) return; } } - - // Report if an unmatched ett was previously noted and overwrite it. - // See also https://code.mythtv.org/trac/ticket/11739 - EventIDToETT &elist = unmatched_etts[atsc_key]; - EventIDToETT::iterator existing_unmatched_ett_it = - elist.find(ett->EventID()); - const QString next_ett_text = ett->ExtendedTextMessage() - .GetBestMatch(languagePreferences); - if (existing_unmatched_ett_it != elist.end() && - existing_unmatched_ett_it->ett_text != next_ett_text) - { - LOG(VB_EIT, LOG_DEBUG, LOC + - QString("Overwriting previously unmatched ett. stale: %1 major: %2 " - "minor: %3 old ett: %4 new ett: %5") - .arg(existing_unmatched_ett_it->IsStale()) - .arg(atsc_major) - .arg(atsc_minor) - .arg(existing_unmatched_ett_it->ett_text) - .arg(next_ett_text)); - } - elist.insert(ett->EventID(), ATSCEtt(next_ett_text)); } static void parse_dvb_event_descriptors(desc_list_t list, FixupValue fix, @@ -1421,6 +1389,7 @@ static void init_fixup(FixupMap &fix) fix[ 100LL << 32 | 8492LL << 16 ] = // Ant1,Alpha,Art,10E fix[ 102LL << 32 | 8492LL << 16 ] = // Mega,Star,SKAI,M.tv fix[ 320LL << 32 | 8492LL << 16 ] = // Astra,Thessalia,TRT,TV10,ZEYS + EITFixUp::kEFixForceISO8859_7 | EITFixUp::kFixGreekEIT | EITFixUp::kFixGreekCategories; fix[ 2LL << 32 | 8492LL << 16 ] = // N1,Nplus,NHD,Vouli @@ -1429,6 +1398,16 @@ static void init_fixup(FixupMap &fix) EITFixUp::kFixGreekEIT | // cut in db. Will move to descr. EITFixUp::kFixGreekCategories; + //DVB-S & S2 Greek Nova Provider + // Hotbird 11823H DVB-S + fix[ 5500LL << 32 | 318LL << 16 ] = EITFixUp::kEFixForceISO8859_7; + // Hotbird 11938H DVB-S + fix[ 6100LL << 32 | 318LL << 16 ] = EITFixUp::kEFixForceISO8859_7; + // Hotbird 12130H DVB-S2 + fix[ 7100LL << 32 | 318LL << 16 ] = EITFixUp::kEFixForceISO8859_7; + // Hotbird 12169H DVB-S2 + fix[ 7300LL << 32 | 318LL << 16 ] = EITFixUp::kEFixForceISO8859_7; + // DVB-S Star One C2 70W (Brazil) // it has original_network_id = 1 like Astra on 19.2E, but transport_id does // not collide at the moment diff --git a/mythtv/libs/libmythtv/eithelper.h b/mythtv/libs/libmythtv/eithelper.h index fc2cff469a..5c06615fac 100644 --- a/mythtv/libs/libmythtv/eithelper.h +++ b/mythtv/libs/libmythtv/eithelper.h @@ -67,11 +67,9 @@ class ATSCEtt time_t scan_time; }; - typedef QMap<uint,ATSCEvent> EventIDToATSCEvent; typedef QMap<uint,ATSCEtt> EventIDToETT; typedef QMap<uint,EventIDToATSCEvent> ATSCSRCToEvents; -typedef QMap<uint,EventIDToETT> ATSCSRCToETTs; typedef QMap<unsigned long long,uint> ServiceToChanID; typedef uint64_t FixupKey; @@ -153,7 +151,6 @@ class EITHelper FixupMap fixup; ATSCSRCToEvents incomplete_events; - ATSCSRCToETTs unmatched_etts; MythDeque<DBEventEIT*> db_events; diff --git a/mythtv/libs/libmythtv/mythplayer.cpp b/mythtv/libs/libmythtv/mythplayer.cpp index 5b80c452a3..9b766d5852 100644 --- a/mythtv/libs/libmythtv/mythplayer.cpp +++ b/mythtv/libs/libmythtv/mythplayer.cpp @@ -223,6 +223,9 @@ MythPlayer::MythPlayer(PlayerFlags flags) rtcbase(0), maxtcval(0), maxtcframes(0), numdroppedframes(0), + prior_audiotimecode(0), + prior_videotimecode(0), + m_timeOffsetBase(0), // LiveTVChain stuff m_tv(nullptr), isDummy(false), // Counter for buffering messages @@ -415,6 +418,8 @@ bool MythPlayer::Play(float speed, bool normal, bool unpauseaudio) return false; } rtcbase = 0; + prior_audiotimecode = 0; + prior_videotimecode = 0; SetEof(kEofStateNone); UnpauseBuffer(); UnpauseDecoder(); @@ -912,15 +917,17 @@ void MythPlayer::OpenDummy(void) void MythPlayer::CreateDecoder(char *testbuf, int testreadsize) { - if (NuppelDecoder::CanHandle(testbuf, testreadsize)) - SetDecoder(new NuppelDecoder(this, *player_ctx->playingInfo)); - else if (AvFormatDecoder::CanHandle(testbuf, + if (AvFormatDecoder::CanHandle(testbuf, player_ctx->buffer->GetFilename(), testreadsize)) { SetDecoder(new AvFormatDecoder(this, *player_ctx->playingInfo, playerFlags)); } + else if (NuppelDecoder::CanHandle(testbuf, testreadsize)) + { + SetDecoder(new NuppelDecoder(this, *player_ctx->playingInfo)); + } } int MythPlayer::OpenFile(uint retries) @@ -1806,6 +1813,8 @@ void MythPlayer::ResetAVSync(void) prevtc = 0; avsync_next = avsync_interval; // Frames till next sync check rtcbase = 0; + prior_audiotimecode = 0; + prior_videotimecode = 0; LOG(VB_PLAYBACK | VB_TIMESTAMP, LOG_INFO, LOC + "A/V sync reset"); } @@ -1822,6 +1831,8 @@ void MythPlayer::InitAVSync(void) // Number of frames over which to average time divergence avsync_averaging=4; rtcbase = 0; + prior_audiotimecode = 0; + prior_videotimecode = 0; // Special averaging default of 60 for OpenMAX passthru QString device = gCoreContext->GetSetting("AudioOutputDevice",""); @@ -2170,7 +2181,7 @@ void wait_for_time(int64_t framedue) QThread::usleep(delay); } -#define AVSYNC_MAX_LATE 1000000 +#define AVSYNC_MAX_LATE 10000000 void MythPlayer::AVSync2(VideoFrame *buffer) { if (videoOutput->IsErrored()) @@ -2180,7 +2191,6 @@ void MythPlayer::AVSync2(VideoFrame *buffer) SetErrored(tr("Failed to initialize A/V Sync")); return; } - int64_t audiotimecode = audio.GetAudioTime(); int64_t videotimecode = 0; bool dropframe = false; @@ -2191,10 +2201,10 @@ void MythPlayer::AVSync2(VideoFrame *buffer) int64_t unow = 0; int64_t lateness = 0; int64_t playspeed1000 = (float)1000 / play_speed; + bool reset = false; while (framedue == 0) { - bool reset = false; if (buffer) { videotimecode = buffer->timecode & 0x0000ffffffffffff; @@ -2205,12 +2215,18 @@ void MythPlayer::AVSync2(VideoFrame *buffer) now = QDateTime::currentDateTimeUtc(); unow = now.toMSecsSinceEpoch() * 1000; + + if (!normal_speed || FlagIsSet(kMusicChoice)) + { + framedue = unow + frame_interval; + break; + } // first time or after a seek - setup of rtcbase if (rtcbase == 0) { // cater for DVB radio if (videotimecode == 0) - videotimecode = audiotimecode; + videotimecode = audio.GetAudioTime();; // On first frame we get nothing, so exit out. if (videotimecode == 0) return; @@ -2218,6 +2234,7 @@ void MythPlayer::AVSync2(VideoFrame *buffer) maxtcval = 0; maxtcframes = 0; numdroppedframes = 0; + m_timeOffsetBase = TranslatePositionFrameToMs(framesPlayed, false) - videotimecode; } if (videotimecode == 0) @@ -2239,29 +2256,44 @@ void MythPlayer::AVSync2(VideoFrame *buffer) else framedue = unow + frame_interval / 2; + // recalculate framesPlayed to conform to actual time code. + framesPlayed = TranslatePositionMsToFrame(videotimecode + m_timeOffsetBase, false); + decoder->SetFramesPlayed(framesPlayed); + lateness = unow - framedue; dropframe = false; if (lateness > 30000) - dropframe = !FlagIsSet(kMusicChoice) && numdroppedframes < 10; + dropframe = numdroppedframes < 10; - if (lateness <= 30000 && audiotimecode > 0 && normal_speed && !FlagIsSet(kMusicChoice)) + if (lateness <= 30000 && prior_audiotimecode > 0 + && prior_videotimecode > 0) { // Get video in sync with audio - audio_adjustment = audiotimecode - videotimecode; - int sign = audio_adjustment < 0 ? -1 : 1; - if (audio_adjustment * sign > 40) + audio_adjustment = prior_audiotimecode - prior_videotimecode; + // If there is excess audio - throw it away. + if (audio_adjustment < -200) { - // adjust by AVSyncIncrementMS milliseconds at a time (range 1-40) - rtcbase -= (int64_t)1000000 * avsync2adjustms * sign / playspeed1000; + audio.Reset(); + audio_adjustment = 0; + } + int sign = audio_adjustment < 0 ? -1 : 1; + int64_t fix_amount = audio_adjustment * sign; + if (fix_amount > avsync2adjustms) + fix_amount = avsync2adjustms; + // Faster catch-up when off by more than 200 ms + if (audio_adjustment * sign > 200) + // fix the sync within 15 - 20 frames + fix_amount = audio_adjustment * sign / 15; + int64_t speedup1000 = (float)1000 * play_speed; + rtcbase -= (int64_t)1000000 * fix_amount * sign / speedup1000; + if (audio_adjustment * sign > 20 || (framesPlayed % 400 == 0)) LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("AV Sync, audio ahead by %1 ms").arg(audio_adjustment)); - } - if (audio_adjustment > 1000) + if (audio_adjustment > 200) pause_audio = true; } // sanity check - reset rtcbase if time codes have gone crazy. - if ((lateness > AVSYNC_MAX_LATE || lateness < - AVSYNC_MAX_LATE) - && !FlagIsSet(kMusicChoice)) + if ((lateness > AVSYNC_MAX_LATE || lateness < - AVSYNC_MAX_LATE)) { framedue = 0; rtcbase = 0; @@ -2277,7 +2309,7 @@ void MythPlayer::AVSync2(VideoFrame *buffer) reset = true; } } - + prior_videotimecode = videotimecode; disp_timecode = videotimecode; output_jmeter && output_jmeter->RecordCycleTime(); @@ -2307,17 +2339,6 @@ void MythPlayer::AVSync2(VideoFrame *buffer) audio.Pause(true); } - LOG(VB_PLAYBACK | VB_TIMESTAMP, LOG_INFO, LOC + - QString("A/V timecodes audio=%1 video=%2 frameinterval=%3 " - "audioadj=%4 tcoffset=%5 unow=%6 udue=%7") - .arg(audiotimecode) - .arg(videotimecode) - .arg(frame_interval) - .arg(audio_adjustment) - .arg(tc_wrap[TC_AUDIO]) - .arg(unow) - .arg(framedue) - ); if (dropframe) numdroppedframes++; @@ -2338,6 +2359,8 @@ void MythPlayer::AVSync2(VideoFrame *buffer) // the primary PBP will become out of sync if (!player_ctx->IsPBP() || player_ctx->IsPrimaryPBP()) wait_for_time(framedue); + // get time codes for calculating difference next time + prior_audiotimecode = audio.GetAudioTime(); videoOutput->Show(ps); if (videoOutput->IsErrored()) { @@ -2373,6 +2396,19 @@ void MythPlayer::AVSync2(VideoFrame *buffer) } else wait_for_time(framedue); + + LOG(VB_PLAYBACK | VB_TIMESTAMP, LOG_INFO, LOC + + QString("A/V timecodes audio=%1 video=%2 frameinterval=%3 " + "audioadj=%4 tcoffset=%5 unow=%6 udue=%7") + .arg(prior_audiotimecode) + .arg(prior_videotimecode) + .arg(frame_interval) + .arg(audio_adjustment) + .arg(tc_wrap[TC_AUDIO]) + .arg(unow) + .arg(framedue) + ); + } void MythPlayer::RefreshPauseFrame(void) @@ -2451,7 +2487,6 @@ bool MythPlayer::PrebufferEnoughFrames(int min_buffers) if (!videoOutput) return false; - bool paused_now = false; if (!(min_buffers ? (videoOutput->ValidVideoFrames() >= min_buffers) : (GetEof() != kEofStateNone) || (videoOutput->hasHWAcceleration() ? @@ -2467,19 +2502,20 @@ bool MythPlayer::PrebufferEnoughFrames(int min_buffers) // for the jerking is detected. bool watchingTV = IsWatchingInprogress(); - if (!paused_now && (livetv || watchingTV) && !FlagIsSet(kMusicChoice)) + if ( (livetv || watchingTV) && !FlagIsSet(kMusicChoice)) { uint64_t frameCount = GetCurrentFrameCount(); uint64_t framesLeft = frameCount - framesPlayed; uint64_t margin = (uint64_t) (video_frame_rate * 3); if (framesLeft < margin) { - LOG(VB_PLAYBACK, LOG_NOTICE, LOC + - QString("Pause to allow live tv catch up. Position in sec. Current: %2, Total: %3") - .arg(framesPlayed).arg(frameCount)); + if (rtcbase) + LOG(VB_PLAYBACK, LOG_NOTICE, LOC + + QString("Pause to allow live tv catch up. Position in sec. Current: %2, Total: %3") + .arg(framesPlayed).arg(frameCount)); audio.Pause(true); avsync_audiopaused = true; - paused_now = true; + rtcbase = 0; } } usleep(frame_interval >> 3); @@ -2499,7 +2535,7 @@ bool MythPlayer::PrebufferEnoughFrames(int min_buffers) QString("Waited %1ms for video buffers %2") .arg(waited_for).arg(videoOutput->GetFrameStatus())); buffering_last_msg = QTime::currentTime(); - if (audio.GetAudioBufferedTime() > 2000 && framesPlayed < 5 + if (audio.IsBufferAlmostFull() && framesPlayed < 5 && gCoreContext->GetBoolSetting("MusicChoiceEnabled", false)) { playerFlags = (PlayerFlags)(playerFlags | kMusicChoice); @@ -3143,8 +3179,8 @@ void MythPlayer::JumpToProgram(void) pginfo->GetPlaybackURL(), RingBuffer::kLiveTVOpenTimeout); QString subfn = player_ctx->buffer->GetSubtitleFilename(); TVState desiredState = player_ctx->GetState(); - bool isInProgress = - desiredState == kState_WatchingRecording || kState_WatchingLiveTV; + bool isInProgress = (desiredState == kState_WatchingRecording || + desiredState == kState_WatchingLiveTV); if (GetSubReader()) GetSubReader()->LoadExternalSubtitles(subfn, isInProgress && !subfn.isEmpty()); diff --git a/mythtv/libs/libmythtv/mythplayer.h b/mythtv/libs/libmythtv/mythplayer.h index 7358d617a9..088da8a04e 100644 --- a/mythtv/libs/libmythtv/mythplayer.h +++ b/mythtv/libs/libmythtv/mythplayer.h @@ -856,6 +856,9 @@ class MTV_PUBLIC MythPlayer int maxtcframes; // number of frames seen since max to date tc int64_t avsync2adjustms; // number of milliseconds to adjust for av sync errors int numdroppedframes; // number of consecutive dropped frames. + int64_t prior_audiotimecode; // time code from prior frame + int64_t prior_videotimecode; // time code from prior frame + int64_t m_timeOffsetBase; // LiveTV TV *m_tv; diff --git a/mythtv/libs/libmythtv/openglvideo.cpp b/mythtv/libs/libmythtv/openglvideo.cpp index 8b572b8d76..484c3f9a66 100644 --- a/mythtv/libs/libmythtv/openglvideo.cpp +++ b/mythtv/libs/libmythtv/openglvideo.cpp @@ -297,6 +297,7 @@ void OpenGLVideo::CheckResize(bool deinterlacing, bool allow) { RemoveFilter(kGLFilterResize); AddFilter(kGLFilterBicubic); + SetFiltering(); return; } @@ -304,6 +305,7 @@ void OpenGLVideo::CheckResize(bool deinterlacing, bool allow) { RemoveFilter(kGLFilterBicubic); AddFilter(kGLFilterResize); + SetFiltering(); return; } diff --git a/mythtv/libs/libmythtv/playercontext.cpp b/mythtv/libs/libmythtv/playercontext.cpp index a373d690f8..8e113c1e81 100644 --- a/mythtv/libs/libmythtv/playercontext.cpp +++ b/mythtv/libs/libmythtv/playercontext.cpp @@ -421,8 +421,8 @@ bool PlayerContext::CreatePlayer(TV *tv, QWidget *widget, else { QString subfn = buffer->GetSubtitleFilename(); - bool isInProgress = - desiredState == kState_WatchingRecording || kState_WatchingLiveTV; + bool isInProgress = (desiredState == kState_WatchingRecording || + desiredState == kState_WatchingLiveTV); if (!subfn.isEmpty() && player->GetSubReader()) player->GetSubReader()->LoadExternalSubtitles(subfn, isInProgress); } diff --git a/mythtv/libs/libmythtv/programdata.cpp b/mythtv/libs/libmythtv/programdata.cpp index b46a15d64b..f8b9791375 100644 --- a/mythtv/libs/libmythtv/programdata.cpp +++ b/mythtv/libs/libmythtv/programdata.cpp @@ -759,7 +759,7 @@ uint DBEvent::UpdateDB( { query.prepare( "INSERT IGNORE INTO programrating " - " ( chanid, starttime, system, rating) " + " ( chanid, starttime, `system`, rating) " "VALUES (:CHANID, :START, :SYS, :RATING)"); query.bindValue(":CHANID", chanid); query.bindValue(":START", starttime); @@ -1062,7 +1062,7 @@ uint DBEvent::InsertDB(MSqlQuery &query, uint chanid) const { query.prepare( "INSERT IGNORE INTO programrating " - " ( chanid, starttime, system, rating) " + " ( chanid, starttime, `system`, rating) " "VALUES (:CHANID, :START, :SYS, :RATING)"); query.bindValue(":CHANID", chanid); query.bindValue(":START", starttime); @@ -1231,7 +1231,7 @@ uint ProgInfo::InsertDB(MSqlQuery &query, uint chanid) const { query.prepare( "INSERT IGNORE INTO programrating " - " ( chanid, starttime, system, rating) " + " ( chanid, starttime, `system`, rating) " "VALUES (:CHANID, :START, :SYS, :RATING)"); query.bindValue(":CHANID", chanid); query.bindValue(":START", starttime); diff --git a/mythtv/libs/libmythtv/recorders/ExternalStreamHandler.cpp b/mythtv/libs/libmythtv/recorders/ExternalStreamHandler.cpp index 4f541d30e5..74aea1419d 100644 --- a/mythtv/libs/libmythtv/recorders/ExternalStreamHandler.cpp +++ b/mythtv/libs/libmythtv/recorders/ExternalStreamHandler.cpp @@ -719,8 +719,6 @@ void ExternalStreamHandler::run(void) if (read_len == 0) { - std::this_thread::sleep_for(std::chrono::microseconds(50)); - if (!nodata_timer.isRunning()) nodata_timer.start(); else @@ -731,15 +729,20 @@ void ExternalStreamHandler::run(void) "No data for 50 seconds, Restarting stream."); if (!RestartStream()) { - LOG(VB_RECORD, LOG_ERR, LOC + "Failed to restart stream."); + LOG(VB_RECORD, LOG_ERR, LOC + + "Failed to restart stream."); _error = true; } nodata_timer.stop(); continue; } - - std::this_thread::sleep_for(std::chrono::milliseconds(50)); } + + std::this_thread::sleep_for(std::chrono::milliseconds(50)); + + // HLS type streams may only produce data every ~10 seconds + if (nodata_timer.elapsed() < 12000 && buffer.size() < TS_PACKET_SIZE) + continue; } else { @@ -1138,7 +1141,7 @@ bool ExternalStreamHandler::StartStreaming(void) if (StreamingCount() == 0) { - if (!ProcessCommand("StartStreaming", result, 10000)) + if (!ProcessCommand("StartStreaming", result, 15000)) { LogLevel_t level = LOG_ERR; if (result.toLower().startsWith("warn")) @@ -1168,8 +1171,6 @@ bool ExternalStreamHandler::StartStreaming(void) bool ExternalStreamHandler::StopStreaming(void) { - QString result; - QMutexLocker locker(&m_stream_lock); LOG(VB_RECORD, LOG_INFO, LOC + @@ -1206,7 +1207,8 @@ bool ExternalStreamHandler::StopStreaming(void) return false; } - if (!ProcessCommand("StopStreaming", result, 6000)) + QString result; + if (!ProcessCommand("StopStreaming", result, 10000)) { LogLevel_t level = LOG_ERR; if (result.toLower().startsWith("warn")) diff --git a/mythtv/libs/libmythtv/recorders/dvbchannel.cpp b/mythtv/libs/libmythtv/recorders/dvbchannel.cpp index a21d35df3f..70a354c67a 100644 --- a/mythtv/libs/libmythtv/recorders/dvbchannel.cpp +++ b/mythtv/libs/libmythtv/recorders/dvbchannel.cpp @@ -122,7 +122,11 @@ DVBChannel::~DVBChannel() if (!master_map[key].empty()) new_master = dynamic_cast<DVBChannel*>(master_map[key].front()); if (new_master) + { + QMutexLocker master_locker(&(master->hw_lock)); + QMutexLocker new_master_locker(&(new_master->hw_lock)); new_master->is_open = master->is_open; + } } else { @@ -147,14 +151,14 @@ void DVBChannel::Close(DVBChannel *who) { LOG(VB_CHANNEL, LOG_INFO, LOC + "Closing DVB channel"); + QMutexLocker locker(&hw_lock); + IsOpenMap::iterator it = is_open.find(who); if (it == is_open.end()) return; // this caller didn't have it open in the first place.. is_open.erase(it); - QMutexLocker locker(&hw_lock); - DVBChannel *master = GetMasterLock(); if (master != nullptr && master != this) { @@ -371,6 +375,8 @@ bool DVBChannel::Open(DVBChannel *who) bool DVBChannel::IsOpen(void) const { + //Have to acquire the hw lock to prevent is_open being modified whilst we're searching it + QMutexLocker locker(&hw_lock); IsOpenMap::const_iterator it = is_open.find(this); return it != is_open.end(); } diff --git a/mythtv/libs/libmythtv/recorders/hdhrstreamhandler.cpp b/mythtv/libs/libmythtv/recorders/hdhrstreamhandler.cpp index 9eb32c9c78..88ad4be5c3 100644 --- a/mythtv/libs/libmythtv/recorders/hdhrstreamhandler.cpp +++ b/mythtv/libs/libmythtv/recorders/hdhrstreamhandler.cpp @@ -117,16 +117,20 @@ void HDHRStreamHandler::run(void) { RunProlog(); - /* Create TS socket. */ - if (!hdhomerun_device_stream_start(_hdhomerun_device)) { - LOG(VB_GENERAL, LOG_ERR, LOC + - "Starting recording (set target failed). Aborting."); - _error = true; - RunEpilog(); - return; + QMutexLocker locker(&_hdhr_lock); + + /* Create TS socket. */ + if (!hdhomerun_device_stream_start(_hdhomerun_device)) + { + LOG(VB_GENERAL, LOG_ERR, LOC + + "Starting recording (set target failed). Aborting."); + _error = true; + RunEpilog(); + return; + } + hdhomerun_device_stream_flush(_hdhomerun_device); } - hdhomerun_device_stream_flush(_hdhomerun_device); SetRunning(true, false, false); @@ -188,7 +192,10 @@ void HDHRStreamHandler::run(void) RemoveAllPIDFilters(); - hdhomerun_device_stream_stop(_hdhomerun_device); + { + QMutexLocker locker(&_hdhr_lock); + hdhomerun_device_stream_stop(_hdhomerun_device); + } if (VERBOSE_LEVEL_CHECK(VB_RECORD, LOG_INFO)) { @@ -476,6 +483,8 @@ QString HDHRStreamHandler::TunerSet( void HDHRStreamHandler::GetTunerStatus(struct hdhomerun_tuner_status_t *status) { + QMutexLocker locker(&_hdhr_lock); + hdhomerun_device_get_tuner_status(_hdhomerun_device, nullptr, status); } diff --git a/mythtv/libs/libmythtv/recorders/hlsstreamhandler.cpp b/mythtv/libs/libmythtv/recorders/hlsstreamhandler.cpp index 12e9a09ab0..880cadeb29 100644 --- a/mythtv/libs/libmythtv/recorders/hlsstreamhandler.cpp +++ b/mythtv/libs/libmythtv/recorders/hlsstreamhandler.cpp @@ -181,7 +181,7 @@ void HLSStreamHandler::run(void) { LOG(VB_RECORD, LOG_INFO, LOC + QString("Packet not starting with SYNC Byte (got 0x%1)") - .arg((char)m_readbuffer[0], 2, QLatin1Char('0'))); + .arg((char)m_readbuffer[0], 2, 16, QLatin1Char('0'))); continue; } diff --git a/mythtv/libs/libmythtv/recorders/recorderbase.cpp b/mythtv/libs/libmythtv/recorders/recorderbase.cpp index 24a5ff4630..024d81efbc 100644 --- a/mythtv/libs/libmythtv/recorders/recorderbase.cpp +++ b/mythtv/libs/libmythtv/recorders/recorderbase.cpp @@ -391,7 +391,14 @@ void RecorderBase::CheckForRingBufferSwitch(void) nextRingBufferLock.unlock(); if (recq && tvrec) + { + // This call will free recq. tvrec->RingBufferChanged(ringBuffer, curRecording, recq); + } + else + { + delete recq; + } ringBufferCheckTimer.restart(); } diff --git a/mythtv/libs/libmythtv/recordinginfo.cpp b/mythtv/libs/libmythtv/recordinginfo.cpp index f93da0bbea..143b37f431 100644 --- a/mythtv/libs/libmythtv/recordinginfo.cpp +++ b/mythtv/libs/libmythtv/recordinginfo.cpp @@ -1305,11 +1305,12 @@ void RecordingInfo::AddHistory(bool resched, bool forcedup, bool future) result.prepare("REPLACE INTO oldrecorded (chanid,starttime," "endtime,title,subtitle,description,season,episode," "category,seriesid,programid,inetref,findid,recordid," - "station,rectype,recstatus,duplicate,reactivate,future) " + "station,rectype,recstatus,duplicate,reactivate,generic," + "future) " "VALUES(:CHANID,:START,:END,:TITLE,:SUBTITLE,:DESC,:SEASON," ":EPISODE,:CATEGORY,:SERIESID,:PROGRAMID,:INETREF," ":FINDID,:RECORDID,:STATION,:RECTYPE,:RECSTATUS,:DUPLICATE," - ":REACTIVATE,:FUTURE);"); + ":REACTIVATE,:GENERIC,:FUTURE);"); result.bindValue(":CHANID", chanid); result.bindValue(":START", startts); result.bindValue(":END", endts); @@ -1329,6 +1330,7 @@ void RecordingInfo::AddHistory(bool resched, bool forcedup, bool future) result.bindValue(":RECSTATUS", rs); result.bindValue(":DUPLICATE", dup); result.bindValue(":REACTIVATE", 0); + result.bindValue(":GENERIC", IsGeneric()); result.bindValue(":FUTURE", future); if (!result.exec()) diff --git a/mythtv/libs/libmythtv/ringbuffer.cpp b/mythtv/libs/libmythtv/ringbuffer.cpp index bd8aa4f18e..36ad31099b 100644 --- a/mythtv/libs/libmythtv/ringbuffer.cpp +++ b/mythtv/libs/libmythtv/ringbuffer.cpp @@ -1085,7 +1085,7 @@ void RingBuffer::run(void) uint64_t bps = !sr_elapsed ? 1000000001 : (uint64_t)(((double)read_return * 8000.0) / (double)sr_elapsed); - LOG(VB_FILE, LOG_INFO, LOC + + LOG(VB_FILE, LOG_DEBUG, LOC + QString("safe_read(...@%1, %2) -> %3, took %4 ms %5 avg %6 ms") .arg(rbwposcopy).arg(totfree).arg(read_return) .arg(sr_elapsed) @@ -1271,6 +1271,8 @@ void RingBuffer::run(void) rbrlock.unlock(); rwlock.unlock(); + LOG(VB_FILE, LOG_INFO, LOC + QString("Exiting readahead thread")); + RunEpilog(); } diff --git a/mythtv/libs/libmythtv/subtitlescreen.cpp b/mythtv/libs/libmythtv/subtitlescreen.cpp index c210b28efd..f0322fe1ff 100644 --- a/mythtv/libs/libmythtv/subtitlescreen.cpp +++ b/mythtv/libs/libmythtv/subtitlescreen.cpp @@ -2335,9 +2335,6 @@ void SubtitleScreen::AddScaledImage(QImage &img, QRect &pos) #ifdef USING_LIBASS static void myth_libass_log(int level, const char *fmt, va_list vl, void */*ctx*/) { - static QString full_line("libass:"); - static const int msg_len = 255; - static QMutex string_lock; uint64_t verbose_mask = VB_GENERAL; LogLevel_t verbose_level = LOG_INFO; @@ -2366,25 +2363,21 @@ static void myth_libass_log(int level, const char *fmt, va_list vl, void */*ctx* if (!VERBOSE_LEVEL_CHECK(verbose_mask, verbose_level)) return; + static QMutex string_lock; string_lock.lock(); - char str[msg_len+1]; - int bytes = vsnprintf(str, msg_len+1, fmt, vl); + char str[1024]; + int bytes = vsnprintf(str, sizeof str, fmt, vl); // check for truncated messages and fix them - if (bytes > msg_len) + int truncated = bytes - ((sizeof str)-1); + if (truncated > 0) { LOG(VB_GENERAL, LOG_ERR, QString("libASS log output truncated %1 of %2 bytes written") - .arg(msg_len).arg(bytes)); - str[msg_len-1] = '\n'; + .arg(truncated).arg(bytes)); } - full_line += QString(str); - if (full_line.endsWith("\n")) - { - LOG(verbose_mask, verbose_level, full_line.trimmed()); - full_line.truncate(0); - } + LOG(verbose_mask, verbose_level, QString("libass: %s").arg(str)); string_lock.unlock(); } @@ -2412,7 +2405,17 @@ bool SubtitleScreen::InitialiseAssLibrary(void) if (!m_assRenderer) return false; - ass_set_fonts(m_assRenderer, nullptr, "sans-serif", 1, nullptr, 1); +#ifdef Q_OS_ANDROID + // fontconfig doesn't yet work for us on Android. For the + // time being, more explicitly set a font we know should + // exist. This was adapted from VLC master as of 2019-01-21. + const char *psz_font = "/system/fonts/DroidSans.ttf"; + const char *psz_font_family = "Droid Sans"; +#else + const char *psz_font = nullptr; + const char *psz_font_family = "sans-serif"; +#endif + ass_set_fonts(m_assRenderer, psz_font, psz_font_family, 1, nullptr, 1); ass_set_hinting(m_assRenderer, ASS_HINTING_LIGHT); LOG(VB_PLAYBACK, LOG_INFO, LOC + "Initialised libass renderer."); } diff --git a/mythtv/libs/libmythtv/tv_play.cpp b/mythtv/libs/libmythtv/tv_play.cpp index ea0aa806d5..7a58929fed 100644 --- a/mythtv/libs/libmythtv/tv_play.cpp +++ b/mythtv/libs/libmythtv/tv_play.cpp @@ -605,10 +605,37 @@ void TV::InitKeys(void) "Change Group View"), ""); REG_KEY("TV Frontend", ACTION_LISTRECORDEDEPISODES, QT_TRANSLATE_NOOP("MythControls", "List recorded episodes"), ""); + /* + * TODO DB update needs to perform the necessary conversion and delete + * the following upgrade code and replace bkmKeys and togBkmKeys with "" in the + * REG_KEY for ACTION_SETBOOKMARK and ACTION_TOGGLEBOOKMARK. + */ + // Bookmarks - Instead of SELECT to add or toggle, + // Use separate bookmark actions. This code is to convert users + // who may already be using SELECT. If they are not already using + // this frontend then nothing will be assigned to bookmark actions. + QString bkmKeys; + QString togBkmKeys; + // Check if this is a new frontend - if PAUSE returns + // "?" then frontend is new, never used before, so we will not assign + // any default bookmark keys + QString testKey = GetMythMainWindow()->GetKey("TV Playback", ACTION_PAUSE); + if (testKey != "?") + { + int alternate = gCoreContext->GetNumSetting("AltClearSavedPosition",0); + QString selectKeys = GetMythMainWindow()->GetKey("Global", ACTION_SELECT); + if (selectKeys != "?") + { + if (alternate) + togBkmKeys = selectKeys; + else + bkmKeys = selectKeys; + } + } REG_KEY("TV Playback", ACTION_SETBOOKMARK, QT_TRANSLATE_NOOP("MythControls", - "Add Bookmark"), ""); + "Add Bookmark"), bkmKeys); REG_KEY("TV Playback", ACTION_TOGGLEBOOKMARK, QT_TRANSLATE_NOOP("MythControls", - "Toggle Bookmark"), ""); + "Toggle Bookmark"), togBkmKeys); REG_KEY("TV Playback", "BACK", QT_TRANSLATE_NOOP("MythControls", "Exit or return to DVD menu"), "Esc"); REG_KEY("TV Playback", ACTION_MENUCOMPACT, QT_TRANSLATE_NOOP("MythControls", diff --git a/mythtv/libs/libmythtv/tv_rec.cpp b/mythtv/libs/libmythtv/tv_rec.cpp index 421aff6823..00c7968a35 100644 --- a/mythtv/libs/libmythtv/tv_rec.cpp +++ b/mythtv/libs/libmythtv/tv_rec.cpp @@ -1198,7 +1198,9 @@ void TVRec::CloseChannel(void) { if (channel && ((genOpt.inputtype == "DVB" && dvbOpt.dvb_on_demand) || - genOpt.inputtype == "FREEBOX" || genOpt.inputtype == "VBOX" || + genOpt.inputtype == "FREEBOX" || + genOpt.inputtype == "VBOX" || + genOpt.inputtype == "HDHOMERUN" || CardUtil::IsV4L(genOpt.inputtype))) { channel->Close(); diff --git a/mythtv/libs/libmythtv/videodev2.h b/mythtv/libs/libmythtv/videodev2.h index c64b5e5a30..6c2e9bb41c 100644 --- a/mythtv/libs/libmythtv/videodev2.h +++ b/mythtv/libs/libmythtv/videodev2.h @@ -59,15 +59,14 @@ #include <sys/time.h> #ifdef __FreeBSD__ -#include <linux/input.h> // For __[us][0-9]+ types -#define __le64 __u64 -#define __le32 __u32 -#define __le16 __u16 -#define __le8 __u8 -#define __be64 __u64 -#define __be32 __u32 -#define __be16 __u16 -#define __be8 __u8 +typedef uint64_t __u64; +typedef uint32_t __u32; +typedef uint16_t __u16; +typedef uint8_t __u8; +typedef int64_t __s64; +typedef int32_t __s32; +typedef int16_t __s16; +typedef int8_t __s8; #else #include <linux/ioctl.h> #include <linux/types.h> @@ -1906,7 +1905,7 @@ struct v4l2_mpeg_vbi_itv0_line { } __attribute__ ((packed)); struct v4l2_mpeg_vbi_itv0 { - __le32 linemask[2]; /* Bitmasks of VBI service lines present */ + __u32 linemask[2]; /* Bitmasks of VBI service lines present */ struct v4l2_mpeg_vbi_itv0_line line[35]; } __attribute__ ((packed)); diff --git a/mythtv/libs/libmythtv/videooutwindow.cpp b/mythtv/libs/libmythtv/videooutwindow.cpp index a38a2786e5..2d7b2a3408 100644 --- a/mythtv/libs/libmythtv/videooutwindow.cpp +++ b/mythtv/libs/libmythtv/videooutwindow.cpp @@ -952,7 +952,9 @@ void VideoOutWindow::ToggleMoveBottomLine(void) { if (bottomline) { + mz_move.setX(0); mz_move.setY(0); + mz_scale_h = 1.0; mz_scale_v = 1.0; bottomline = false; } @@ -960,11 +962,21 @@ void VideoOutWindow::ToggleMoveBottomLine(void) { const float zf = 0.02; - int y = gCoreContext->GetNumSetting("OSDMoveBottomLine", 4); + int x = gCoreContext->GetNumSetting("OSDMoveXBottomLine", 0); + mz_move.setX(x); + + int y = gCoreContext->GetNumSetting("OSDMoveYBottomLine", 5); mz_move.setY(y); - double z = static_cast<double> - (gCoreContext->GetNumSetting("OSDZoomBottomLine", 112)) / 100.0; - mz_scale_v = snap(z, 1.0f, zf / 2); + + double h = static_cast<double> + (gCoreContext->GetNumSetting("OSDScaleHBottomLine", 100)) / + 100.0; + mz_scale_h = snap(h, 1.0f, zf / 2); + + double v = static_cast<double> + (gCoreContext->GetNumSetting("OSDScaleVBottomLine", 112)) / + 100.0; + mz_scale_v = snap(v, 1.0f, zf / 2); bottomline = true; } @@ -974,8 +986,11 @@ void VideoOutWindow::ToggleMoveBottomLine(void) void VideoOutWindow::SaveBottomLine(void) { - gCoreContext->SaveSetting("OSDMoveBottomLine", GetMzMove().y()); - gCoreContext->SaveSetting("OSDZoomBottomLine", GetMzScaleV() * 100.0f); + gCoreContext->SaveSetting("OSDMoveXBottomLine", GetMzMove().x()); + gCoreContext->SaveSetting("OSDMoveYBottomLine", GetMzMove().y()); + + gCoreContext->SaveSetting("OSDScaleHBottomLine", GetMzScaleH() * 100.0f); + gCoreContext->SaveSetting("OSDScaleVBottomLine", GetMzScaleV() * 100.0f); } QString VideoOutWindow::GetZoomString(void) const diff --git a/mythtv/libs/libmythtv/videosource.cpp b/mythtv/libs/libmythtv/videosource.cpp index f5be42d142..f206478089 100644 --- a/mythtv/libs/libmythtv/videosource.cpp +++ b/mythtv/libs/libmythtv/videosource.cpp @@ -159,7 +159,7 @@ class SchedGroup : public MythUICheckBoxSetting MythUICheckBoxSetting(new CardInputDBStorage(this, parent, "schedgroup")) { setLabel(QObject::tr("Schedule as group")); - setValue(false); + setValue(true); setHelpText( QObject::tr( "Schedule all virtual inputs on this device as a group. " @@ -3192,9 +3192,6 @@ CardInput::CardInput(const QString & cardtype, const QString & device, this, SLOT( SetSourceID (const QString&))); connect(ingrpbtn, SIGNAL(clicked()), this, SLOT( CreateNewInputGroup())); - if (schedgroup) - connect(instancecount, SIGNAL(valueChanged(const QString &)), - this, SLOT(UpdateSchedGroup(const QString &))); } CardInput::~CardInput() @@ -3216,14 +3213,6 @@ void CardInput::SetSourceID(const QString &sourceid) srcfetch->setEnabled(enable); } -void CardInput::UpdateSchedGroup(const QString &val) -{ - int value = val.toInt(); - if (value <= 1) - schedgroup->setValue(false); - schedgroup->setEnabled(value > 1); -} - QString CardInput::getSourceName(void) const { return sourceid->getValueLabel(); diff --git a/mythtv/libs/libmythtv/videosource.h b/mythtv/libs/libmythtv/videosource.h index 51e15e1dec..bb17f61e82 100644 --- a/mythtv/libs/libmythtv/videosource.h +++ b/mythtv/libs/libmythtv/videosource.h @@ -863,7 +863,6 @@ class CardInput : public GroupSetting void channelScanner(); void sourceFetch(); void SetSourceID(const QString &sourceid); - void UpdateSchedGroup(const QString &value); void CreateNewInputGroupSlot(const QString &name); private: diff --git a/mythtv/libs/libmythui/mythfontproperties.cpp b/mythtv/libs/libmythui/mythfontproperties.cpp index 4e7fa3516a..5354f9229f 100644 --- a/mythtv/libs/libmythui/mythfontproperties.cpp +++ b/mythtv/libs/libmythui/mythfontproperties.cpp @@ -9,6 +9,7 @@ #include <QFontInfo> #include <QFontDatabase> #include <QRect> +#include <QRegularExpression> #include "mythlogging.h" #include "mythdb.h" @@ -432,7 +433,9 @@ MythFontProperties *MythFontProperties::ParseFromXml( newFont->Unfreeze(); QFontInfo fi(newFont->m_face); - if (newFont->m_face.family() != fi.family()) + QString fi_family = + fi.family().remove(QRegularExpression("\\[.*]")).trimmed(); + if (newFont->m_face.family() != fi_family) { VERBOSE_XML(VB_GENERAL, LOG_ERR, filename, element, QString("Failed to load '%1', got '%2' instead") diff --git a/mythtv/libs/libmythui/mythrender_opengl2es.cpp b/mythtv/libs/libmythui/mythrender_opengl2es.cpp index e27ec76f0f..65e2fcc168 100644 --- a/mythtv/libs/libmythui/mythrender_opengl2es.cpp +++ b/mythtv/libs/libmythui/mythrender_opengl2es.cpp @@ -20,6 +20,8 @@ void MythRenderOpenGL2ES::InitProcs() // GLSL ES precision qualifiers m_qualifiers = "#ifdef GL_FRAGMENT_PRECISION_HIGH\n" "precision highp float;\n" + "#else\n" + "precision mediump float;\n" "#endif\n"; // Default OpenGL ES 2.0 diff --git a/mythtv/libs/libmythui/mythuiguidegrid.cpp b/mythtv/libs/libmythui/mythuiguidegrid.cpp index 4fbd523e4a..994401adb4 100644 --- a/mythtv/libs/libmythui/mythuiguidegrid.cpp +++ b/mythtv/libs/libmythui/mythuiguidegrid.cpp @@ -329,10 +329,13 @@ void MythUIGuideGrid::DrawSelf(MythPainter *p, int xoffset, int yoffset, drawBox(p, xoffset, yoffset, data, m_recordingColor, alphaMod); else drawBox(p, xoffset, yoffset, data, m_conflictingColor, alphaMod); + drawText(p, xoffset, yoffset, data, alphaMod); } } drawCurrent(p, xoffset, yoffset, &m_selectedItem, alphaMod); + // Redraw the current selection's text in case it was clobbered by the above call. + drawText(p, xoffset, yoffset, &m_selectedItem, alphaMod); for (int i = 0; i < m_rowCount; i++) { @@ -341,10 +344,7 @@ void MythUIGuideGrid::DrawSelf(MythPainter *p, int xoffset, int yoffset, for (; it != m_allData[i].end(); ++it) { UIGTCon *data = *it; - drawText(p, xoffset, yoffset, data, alphaMod); - - if (data->m_recType != 0 || data->m_arrow != GridTimeNormal) - drawRecDecoration(p, xoffset, yoffset, data, alphaMod); + drawRecDecoration(p, xoffset, yoffset, data, alphaMod); } } } @@ -747,12 +747,14 @@ bool MythUIGuideGrid::parseDefaultCategoryColors(QMap<QString, QString> &catColo break; } +#ifndef Q_OS_ANDROID // Android does not get a file handle for assets file system if (f.handle() == -1) { LOG(VB_GENERAL, LOG_ERR, LOC + QString("Unable to open '%1'") .arg(f.fileName())); return false; } +#endif QDomDocument doc; QString errorMsg; diff --git a/mythtv/libs/libmythui/mythuiwebbrowser.cpp b/mythtv/libs/libmythui/mythuiwebbrowser.cpp index 0ebcb89daa..8b5fbad19c 100644 --- a/mythtv/libs/libmythui/mythuiwebbrowser.cpp +++ b/mythtv/libs/libmythui/mythuiwebbrowser.cpp @@ -861,6 +861,10 @@ void MythUIWebBrowser::Finalize(void) */ void MythUIWebBrowser::Init(void) { + // only do the initialisation for widgets not being stored in the global object store + if (parent() == GetGlobalObjectStore()) + return; + if (m_initialized) return; @@ -1116,6 +1120,9 @@ void MythUIWebBrowser::SetBackgroundColor(QColor color) */ void MythUIWebBrowser::SetActive(bool active) { + if (!m_browser) + return; + if (m_active == active) return; @@ -1318,6 +1325,9 @@ QVariant MythUIWebBrowser::evaluateJavaScript(const QString &scriptSource) void MythUIWebBrowser::Scroll(int dx, int dy) { + if (!m_browser) + return; + QPoint startPos = m_browser->page()->currentFrame()->scrollPosition(); QPoint endPos = startPos + QPoint(dx, dy); @@ -1427,6 +1437,9 @@ bool MythUIWebBrowser::IsOnTopScreen(void) void MythUIWebBrowser::UpdateScrollBars(void) { + if (!m_browser) + return; + QPoint position = m_browser->page()->currentFrame()->scrollPosition(); if (m_verticalScrollbar) { @@ -1453,7 +1466,7 @@ void MythUIWebBrowser::UpdateBuffer(void) { UpdateScrollBars(); - if (!m_image) + if (!m_image || !m_browser) return; if (!m_active || (m_active && !m_browser->hasFocus())) @@ -1472,6 +1485,9 @@ void MythUIWebBrowser::UpdateBuffer(void) */ void MythUIWebBrowser::Pulse(void) { + if (!m_browser) + return; + if (m_scrollAnimation.IsActive() && m_destinationScrollPos != m_browser->page()->currentFrame()->scrollPosition()) @@ -1514,6 +1530,9 @@ void MythUIWebBrowser::DrawSelf(MythPainter *p, int xoffset, int yoffset, */ bool MythUIWebBrowser::keyPressEvent(QKeyEvent *event) { + if (!m_browser) + return false; + QStringList actions; bool handled = false; handled = GetMythMainWindow()->TranslateKeyPress("Browser", event, actions); diff --git a/mythtv/libs/libmythupnp/serializers/serializer.cpp b/mythtv/libs/libmythupnp/serializers/serializer.cpp index e86d406ee5..28a84fab89 100644 --- a/mythtv/libs/libmythupnp/serializers/serializer.cpp +++ b/mythtv/libs/libmythupnp/serializers/serializer.cpp @@ -71,7 +71,8 @@ void Serializer::Serialize( const QVariant &vValue, const QString &_sName ) if ((sName.length() > 0) && sName.at(0) == 'Q') sName = sName.mid( 1 ); - m_hash.reset(); + if ( !vValue.isNull() ) + m_hash.addData( vValue.toString().toUtf8() ); BeginSerialize( sName ); diff --git a/mythtv/programs/mythbackend/autoexpire.cpp b/mythtv/programs/mythbackend/autoexpire.cpp index e05ab7cbbe..b6e16f8e8e 100644 --- a/mythtv/programs/mythbackend/autoexpire.cpp +++ b/mythtv/programs/mythbackend/autoexpire.cpp @@ -36,7 +36,7 @@ using namespace std; #include "remoteutil.h" #include "remoteencoder.h" #include "encoderlink.h" -#include "backendutil.h" +#include "requesthandler/fileserverutil.h" #include "mainserver.h" #include "compat.h" #include "mythlogging.h" @@ -141,7 +141,16 @@ void AutoExpire::CalcParams() instance_lock.lock(); if (main_server) - main_server->GetFilesystemInfos(fsInfos); + { + // The scheduler relies on something forcing the mainserver + // fsinfos cache to get updated periodically. Currently, that + // is done here. Don't remove or change this invocation + // without handling that issue too. It is done this way + // because the scheduler thread can't afford to be blocked by + // an unresponsive, remote filesystem and the autoexpirer + // thrad can. + main_server->GetFilesystemInfos(fsInfos, false); + } instance_lock.unlock(); if (fsInfos.empty()) @@ -415,7 +424,7 @@ void AutoExpire::ExpireRecordings(void) LOG(VB_FILE, LOG_INFO, LOC + "ExpireRecordings()"); if (main_server) - main_server->GetFilesystemInfos(fsInfos); + main_server->GetFilesystemInfos(fsInfos, true); if (fsInfos.empty()) { diff --git a/mythtv/programs/mythbackend/backendutil.cpp b/mythtv/programs/mythbackend/backendutil.cpp deleted file mode 100644 index 7ad22dae16..0000000000 --- a/mythtv/programs/mythbackend/backendutil.cpp +++ /dev/null @@ -1,47 +0,0 @@ - -#include <cstdlib> // for llabs - -#include "mythconfig.h" -#if CONFIG_DARWIN || defined(__FreeBSD__) -#include <sys/param.h> -#include <sys/mount.h> -#elif __linux__ -#include <sys/vfs.h> -#endif - -#include <QMutex> -#include <QFile> -#include <QMap> - -#include "backendutil.h" -#include "programinfo.h" - -QMutex recordingPathLock; -QMap <QString, QString> recordingPathCache; - -QString GetPlaybackURL(ProgramInfo *pginfo, bool storePath) -{ - QString result = ""; - QMutexLocker locker(&recordingPathLock); - QString cacheKey = QString("%1:%2").arg(pginfo->GetChanID()) - .arg(pginfo->GetRecordingStartTime(MythDate::ISODate)); - if ((recordingPathCache.contains(cacheKey)) && - (QFile::exists(recordingPathCache[cacheKey]))) - { - result = recordingPathCache[cacheKey]; - if (!storePath) - recordingPathCache.remove(cacheKey); - } - else - { - locker.unlock(); - result = pginfo->GetPlaybackURL(false, true); - locker.relock(); - if (storePath && result.startsWith("/")) - recordingPathCache[cacheKey] = result; - } - - return result; -} - -/* vim: set expandtab tabstop=4 shiftwidth=4: */ diff --git a/mythtv/programs/mythbackend/backendutil.h b/mythtv/programs/mythbackend/backendutil.h deleted file mode 100644 index c43f13953c..0000000000 --- a/mythtv/programs/mythbackend/backendutil.h +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef _BACKENDUTIL_H -#define _BACKENDUTIL_H - -#include <vector> -using namespace std; - -#include <QMap> - -#include "remoteutil.h" - -class QStringList; -class EncoderLink; - -void BackendQueryDiskSpace(QStringList &strlist, - QMap <int, EncoderLink *> *encoderList, - bool consolidated = false, bool allHosts = false); - -QString GetPlaybackURL(ProgramInfo *pginfo, bool storePath = true); - -#endif - -/* vim: set expandtab tabstop=4 shiftwidth=4: */ diff --git a/mythtv/programs/mythbackend/encoderlink.cpp b/mythtv/programs/mythbackend/encoderlink.cpp index d76301dcbc..422ce90f35 100644 --- a/mythtv/programs/mythbackend/encoderlink.cpp +++ b/mythtv/programs/mythbackend/encoderlink.cpp @@ -11,7 +11,7 @@ #include "playbacksock.h" #include "tv_rec.h" #include "mythdate.h" -#include "backendutil.h" +#include "requesthandler/fileserverutil.h" #include "compat.h" #include "referencecounter.h" #include "inputinfo.h" // for InputInfo diff --git a/mythtv/programs/mythbackend/filetransfer.cpp b/mythtv/programs/mythbackend/filetransfer.cpp index 29b226f611..4a879f2234 100644 --- a/mythtv/programs/mythbackend/filetransfer.cpp +++ b/mythtv/programs/mythbackend/filetransfer.cpp @@ -19,7 +19,7 @@ FileTransfer::FileTransfer(QString &filename, MythSocket *remote, { pginfo = new ProgramInfo(filename); pginfo->MarkAsInUse(true, kFileTransferInUseID); - if (rbuffer) + if (rbuffer && rbuffer->IsOpen()) rbuffer->Start(); } diff --git a/mythtv/programs/mythbackend/httpconfig.cpp b/mythtv/programs/mythbackend/httpconfig.cpp index 48ccff8eb7..24ea02274e 100644 --- a/mythtv/programs/mythbackend/httpconfig.cpp +++ b/mythtv/programs/mythbackend/httpconfig.cpp @@ -7,7 +7,6 @@ // MythTV headers #include "httpconfig.h" -#include "backendutil.h" #include "mythcontext.h" #include "mythdb.h" #include "mythdirs.h" diff --git a/mythtv/programs/mythbackend/httpstatus.cpp b/mythtv/programs/mythbackend/httpstatus.cpp index 10cbbf2c30..24224ef0c6 100644 --- a/mythtv/programs/mythbackend/httpstatus.cpp +++ b/mythtv/programs/mythbackend/httpstatus.cpp @@ -19,7 +19,6 @@ // Qt headers #include <QTextStream> #include <QRegExp> -#include <QLocale> // MythTV headers #include "httpstatus.h" @@ -1266,38 +1265,38 @@ int HttpStatus::PrintMachineInfo( QTextStream &os, QDomElement info ) os << " <li>Total Disk Space:\r\n" << " <ul>\r\n"; - QLocale c(QLocale::C); os << " <li>Total Space: "; - sRep = c.toString(nTotal) + " MB"; + sRep = QString("%L1").arg(nTotal) + " MB"; os << sRep << "</li>\r\n"; os << " <li>Space Used: "; - sRep = c.toString(nUsed) + " MB"; + sRep = QString("%L1").arg(nUsed) + " MB"; os << sRep << "</li>\r\n"; os << " <li>Space Free: "; - sRep = c.toString(nFree) + " MB"; + sRep = QString("%L1").arg(nFree) + " MB"; os << sRep << "</li>\r\n"; if ((nLiveTV + nDeleted + nExpirable) > 0) { os << " <li>Space Available " "After Auto-expire: "; - sRep = c.toString(nFree + nLiveTV + + sRep = QString("%L1").arg(nUsed) + " MB"; + sRep = QString("%L1").arg(nFree + nLiveTV + nDeleted + nExpirable) + " MB"; os << sRep << "\r\n"; os << " <ul>\r\n"; os << " <li>Space Used by LiveTV: "; - sRep = c.toString(nLiveTV) + " MB"; + sRep = QString("%L1").arg(nLiveTV) + " MB"; os << sRep << "</li>\r\n"; os << " <li>Space Used by " "Deleted Recordings: "; - sRep = c.toString(nDeleted) + " MB"; + sRep = QString("%L1").arg(nDeleted) + " MB"; os << sRep << "</li>\r\n"; os << " <li>Space Used by " "Auto-expirable Recordings: "; - sRep = c.toString(nExpirable) + " MB"; + sRep = QString("%L1").arg(nExpirable) + " MB"; os << sRep << "</li>\r\n"; os << " </ul>\r\n"; os << " </li>\r\n"; @@ -1350,18 +1349,16 @@ int HttpStatus::PrintMachineInfo( QTextStream &os, QDomElement info ) os << nDir << "</li>\r\n"; - QLocale c(QLocale::C); - os << " <li>Total Space: "; - sRep = c.toString(nTotal) + " MB"; + sRep = QString("%L1").arg(nTotal) + " MB"; os << sRep << "</li>\r\n"; os << " <li>Space Used: "; - sRep = c.toString(nUsed) + " MB"; + sRep = QString("%L1").arg(nUsed) + " MB"; os << sRep << "</li>\r\n"; os << " <li>Space Free: "; - sRep = c.toString(nFree) + " MB"; + sRep = QString("%L1").arg(nFree) + " MB"; os << sRep << "</li>\r\n"; os << " </ul>\r\n" diff --git a/mythtv/programs/mythbackend/mainserver.cpp b/mythtv/programs/mythbackend/mainserver.cpp index b6ba9bb9c9..794ef06901 100644 --- a/mythtv/programs/mythbackend/mainserver.cpp +++ b/mythtv/programs/mythbackend/mainserver.cpp @@ -54,7 +54,7 @@ using namespace std; #include "server.h" #include "mthread.h" #include "scheduler.h" -#include "backendutil.h" +#include "requesthandler/fileserverutil.h" #include "programinfo.h" #include "mythtimezone.h" #include "recordinginfo.h" @@ -323,7 +323,13 @@ MainServer::MainServer(bool master, int port, deferredDeleteTimer->start(30 * 1000); if (sched) + { + // Make sure we have a good, fsinfo cache before setting + // mainServer in the scheduler. + QList<FileSystemInfo> fsInfos; + GetFilesystemInfos(fsInfos, false); sched->SetMainServer(this); + } if (expirer) expirer->SetMainServer(this); @@ -2039,7 +2045,9 @@ void MainServer::HandleAnnounce(QStringList &slist, QStringList commands, QString("adding: %1(%2) as a file transfer") .arg(commands[2]) .arg(quintptr(socket),0,16)); + sockListLock.lockForWrite(); fileTransferList.push_back(ft); + sockListLock.unlock(); retlist << QString::number(socket->GetSocketDescriptor()); retlist << QString::number(ft->GetFileSize()); @@ -5341,8 +5349,17 @@ void MainServer::BackendQueryDiskSpace(QStringList &strlist, bool consolidated, } } -void MainServer::GetFilesystemInfos(QList<FileSystemInfo> &fsInfos) +void MainServer::GetFilesystemInfos(QList<FileSystemInfo> &fsInfos, + bool useCache) { + // Return cached information if requested. + if (useCache) + { + QMutexLocker locker(&fsInfosCacheLock); + fsInfos = fsInfosCache; + return; + } + QStringList strlist; FileSystemInfo fsInfo; @@ -5411,6 +5428,10 @@ void MainServer::GetFilesystemInfos(QList<FileSystemInfo> &fsInfos) LOG(VB_FILE | VB_SCHEDULE, LOG_INFO, LOC + "--- GetFilesystemInfos directory list end ---"); } + + // Save these results to the cache. + QMutexLocker locker(&fsInfosCacheLock); + fsInfosCache = fsInfos; } void MainServer::HandleMoveFile(PlaybackSock *pbs, const QString &storagegroup, diff --git a/mythtv/programs/mythbackend/mainserver.h b/mythtv/programs/mythbackend/mainserver.h index 4c6bc0b4b5..f32fe5fa6a 100644 --- a/mythtv/programs/mythbackend/mainserver.h +++ b/mythtv/programs/mythbackend/mainserver.h @@ -143,7 +143,8 @@ class MainServer : public QObject, public MythSocketCBs size_t GetCurrentMaxBitrate(void); void BackendQueryDiskSpace(QStringList &strlist, bool consolidated, bool allHosts); - void GetFilesystemInfos(QList<FileSystemInfo> &fsInfos); + void GetFilesystemInfos(QList<FileSystemInfo> &fsInfos, + bool useCache=true); int GetExitCode() const { return m_exitCode; } @@ -352,6 +353,8 @@ class MainServer : public QObject, public MythSocketCBs QMap<QString, int> fsIDcache; QMutex fsIDcacheLock; + QList<FileSystemInfo> fsInfosCache; + QMutex fsInfosCacheLock; QMutex m_downloadURLsLock; QMap<QString, QString> m_downloadURLs; diff --git a/mythtv/programs/mythbackend/mythbackend.pro b/mythtv/programs/mythbackend/mythbackend.pro index 6d6e1083c4..9dde76944d 100644 --- a/mythtv/programs/mythbackend/mythbackend.pro +++ b/mythtv/programs/mythbackend/mythbackend.pro @@ -27,7 +27,6 @@ QMAKE_CLEAN += $(TARGET) # Input HEADERS += autoexpire.h encoderlink.h filetransfer.h httpstatus.h mainserver.h HEADERS += playbacksock.h scheduler.h server.h backendhousekeeper.h -HEADERS += backendutil.h HEADERS += upnpcdstv.h upnpcdsmusic.h upnpcdsvideo.h mediaserver.h HEADERS += internetContent.h main_helpers.h backendcontext.h HEADERS += httpconfig.h mythsettings.h commandlineparser.h @@ -45,7 +44,7 @@ HEADERS += services/capture.h services/image.h services/music.h SOURCES += autoexpire.cpp encoderlink.cpp filetransfer.cpp httpstatus.cpp SOURCES += main.cpp mainserver.cpp playbacksock.cpp scheduler.cpp server.cpp -SOURCES += backendhousekeeper.cpp backendutil.cpp +SOURCES += backendhousekeeper.cpp SOURCES += upnpcdstv.cpp upnpcdsmusic.cpp upnpcdsvideo.cpp mediaserver.cpp SOURCES += internetContent.cpp main_helpers.cpp backendcontext.cpp SOURCES += httpconfig.cpp mythsettings.cpp commandlineparser.cpp diff --git a/mythtv/programs/mythbackend/scheduler.cpp b/mythtv/programs/mythbackend/scheduler.cpp index aaacb87205..838d8e8b75 100644 --- a/mythtv/programs/mythbackend/scheduler.cpp +++ b/mythtv/programs/mythbackend/scheduler.cpp @@ -33,7 +33,6 @@ using namespace std; #include "encoderlink.h" #include "mainserver.h" #include "remoteutil.h" -#include "backendutil.h" #include "mythdate.h" #include "exitcodes.h" #include "mythcontext.h" @@ -96,8 +95,6 @@ Scheduler::Scheduler(bool runthread, QMap<int, EncoderLink *> *tvList, InitInputInfoMap(); - fsInfoCacheFillTime = MythDate::current().addSecs(-1000); - if (doRun) { ProgramInfo::CheckProgramIDAuthorities(); @@ -2474,8 +2471,6 @@ bool Scheduler::HandleReschedule(void) static_cast<double>(placeTime)); LOG(VB_GENERAL, LOG_INFO, msg); - fsInfoCacheFillTime = MythDate::current().addSecs(-1000); - // Write changed entries to oldrecorded. RecIter it = reclist.begin(); for ( ; it != reclist.end(); ++it) @@ -2673,6 +2668,7 @@ bool Scheduler::HandleRecording( QDateTime curtime = MythDate::current(); QDateTime nextrectime = ri.GetRecordingStartTime(); + int origprerollseconds = prerollseconds; if (ri.GetRecordingStatus() != RecStatus::WillRecord && ri.GetRecordingStatus() != RecStatus::Pending) @@ -2844,21 +2840,18 @@ bool Scheduler::HandleRecording( if (ri.GetRecordingStatus() != RecStatus::Pending) { - if (sinputinfomap[ri.GetInputID()].schedgroup) + if (!AssignGroupInput(tempri, origprerollseconds)) { - if (!AssignGroupInput(tempri)) - { - // We failed to assign an input. Keep asking the main - // server to add one until we get one. - MythEvent me(QString("ADD_CHILD_INPUT %1") - .arg(tempri.GetInputID())); - gCoreContext->dispatch(me); - nextWakeTime = min(nextWakeTime, curtime.addSecs(1)); - return reclist_changed; - } - ri.SetInputID(tempri.GetInputID()); - nexttv = (*m_tvList)[ri.GetInputID()]; + // We failed to assign an input. Keep asking the main + // server to add one until we get one. + MythEvent me(QString("ADD_CHILD_INPUT %1") + .arg(tempri.GetInputID())); + gCoreContext->dispatch(me); + nextWakeTime = min(nextWakeTime, curtime.addSecs(1)); + return reclist_changed; } + ri.SetInputID(tempri.GetInputID()); + nexttv = (*m_tvList)[ri.GetInputID()]; ri.SetRecordingStatus(RecStatus::Pending); tempri.SetRecordingStatus(RecStatus::Pending); @@ -2953,7 +2946,8 @@ void Scheduler::HandleRecordingStatusChange( } } -bool Scheduler::AssignGroupInput(RecordingInfo &ri) +bool Scheduler::AssignGroupInput(RecordingInfo &ri, + int prerollseconds) { if (!sinputinfomap[ri.GetInputID()].schedgroup) return true; @@ -2982,7 +2976,8 @@ bool Scheduler::AssignGroupInput(RecordingInfo &ri) for ( ; j != reclist.end(); ++j) { RecordingInfo *p = (*j); - if (now.secsTo(p->GetRecordingStartTime()) > 300) + if (now.secsTo(p->GetRecordingStartTime()) > + prerollseconds + 60) break; if (p->GetInputID() != inputid) continue; @@ -3089,6 +3084,13 @@ bool Scheduler::AssignGroupInput(RecordingInfo &ri) return bestid; } +// Called to delay shutdown for 5 minutes +void Scheduler::DelayShutdown() +{ + m_delayShutdownTime = QDateTime::currentMSecsSinceEpoch() + 5*60*1000; +} + + void Scheduler::HandleIdleShutdown( bool &blockShutdown, QDateTime &idleSince, int prerollseconds, int idleTimeoutSecs, int idleWaitForRecordingTime, @@ -3111,7 +3113,12 @@ void Scheduler::HandleIdleShutdown( // the frontend may have connected then gone idle between scheduler runs if (blockShutdown) { - if (m_mainServer->isClientConnected()) + schedLock.unlock(); + bool b = m_mainServer->isClientConnected(); + schedLock.lock(); + if (reclist_changed) + return; + if (b) { LOG(VB_GENERAL, LOG_NOTICE, "Client is connected, removing startup block on shutdown"); blockShutdown = false; @@ -3119,10 +3126,14 @@ void Scheduler::HandleIdleShutdown( } else { + // Check for delay shutdown request + bool delay = (m_delayShutdownTime > QDateTime::currentMSecsSinceEpoch()); + QDateTime curtime = MythDate::current(); // find out, if we are currently recording (or LiveTV) bool recording = false; + schedLock.unlock(); TVRec::inputsLock.lockForRead(); QMap<int, EncoderLink *>::Iterator it; for (it = m_tvList->begin(); (it != m_tvList->end()) && @@ -3135,7 +3146,10 @@ void Scheduler::HandleIdleShutdown( // If there are BLOCKING clients, then we're not idle bool blocking = m_mainServer->isClientConnected(true); - if (!blocking && !recording) + schedLock.lock(); + if (reclist_changed) + return; + if (!blocking && !recording && !delay) { // have we received a RESET_IDLETIME message? resetIdleTime_lock.lock(); @@ -3277,6 +3291,10 @@ void Scheduler::HandleIdleShutdown( LOG(logmask, LOG_NOTICE, "Blocking shutdown because " "of a connected client"); + if (delay) + LOG(logmask, LOG_NOTICE, "Blocking shutdown because " + "of delay request from external application"); + // not idle, make the time invalid if (idleSince.isValid()) { @@ -4477,8 +4495,9 @@ void Scheduler::AddNewRecords(void) " capturecard.hostname, recordmatch.oldrecstatus, NULL, "//43-45 " oldrecstatus.future, capturecard.schedorder, " //46-47 " p.syndicatedepisodenumber, p.partnumber, p.parttotal, " //48-50 - " c.mplexid, capturecard.displayname, ") + //51-52 - pwrpri + QString( //53 + " c.mplexid, capturecard.displayname, "//51-52 + " p.season, p.episode, p.totalepisodes, ") + //53-55 + pwrpri + QString( //56 "FROM recordmatch " "INNER JOIN RECTABLE ON (recordmatch.recordid = RECTABLE.recordid) " "INNER JOIN program AS p " @@ -4552,9 +4571,9 @@ void Scheduler::AddNewRecords(void) result.value(5).toString(),//subtitle QString(),//sortsubtitle result.value(6).toString(),//description - 0, // season - 0, // episode - 0, // total episodes + result.value(53).toInt(), // season + result.value(54).toInt(), // episode + result.value(55).toInt(), // total episodes result.value(48).toString(),//synidcatedepisode result.value(11).toString(),//category @@ -4623,7 +4642,7 @@ void Scheduler::AddNewRecords(void) p->SetRecordingStatus(p->oldrecstatus); } - p->SetRecordingPriority2(result.value(53).toInt()); + p->SetRecordingPriority2(result.value(56).toInt()); // Check to see if the program is currently recording and if // the end time was changed. Ideally, checking for a new end @@ -5587,18 +5606,14 @@ int Scheduler::FillRecordingDir( return fsID; } -void Scheduler::FillDirectoryInfoCache(bool force) +void Scheduler::FillDirectoryInfoCache(void) { - if ((!force) && - (fsInfoCacheFillTime > MythDate::current().addSecs(-180))) - return; - QList<FileSystemInfo> fsInfos; fsInfoCache.clear(); if (m_mainServer) - m_mainServer->GetFilesystemInfos(fsInfos); + m_mainServer->GetFilesystemInfos(fsInfos, true); QMap <int, bool> fsMap; QList<FileSystemInfo>::iterator it1; @@ -5611,8 +5626,6 @@ void Scheduler::FillDirectoryInfoCache(bool force) LOG(VB_FILE, LOG_INFO, LOC + QString("FillDirectoryInfoCache: found %1 unique filesystems") .arg(fsMap.size())); - - fsInfoCacheFillTime = MythDate::current(); } void Scheduler::SchedLiveTV(void) diff --git a/mythtv/programs/mythbackend/scheduler.h b/mythtv/programs/mythbackend/scheduler.h index b583161483..062c0c4edb 100644 --- a/mythtv/programs/mythbackend/scheduler.h +++ b/mythtv/programs/mythbackend/scheduler.h @@ -122,6 +122,7 @@ class Scheduler : public MThread, public MythScheduler int GetError(void) const { return error; } void AddChildInput(uint parentid, uint childid); + void DelayShutdown(); protected: void run(void) override; // MThread @@ -201,7 +202,7 @@ class Scheduler : public MThread, public MythScheduler uint cardid, QString &recording_dir, const RecList &reclist); - void FillDirectoryInfoCache(bool force = false); + void FillDirectoryInfoCache(void); void OldRecordedFixups(void); void ResetDuplicates(uint recordid, uint findid, const QString &title, @@ -216,7 +217,7 @@ class Scheduler : public MThread, public MythScheduler int prerollseconds); void HandleRecordingStatusChange( RecordingInfo &ri, RecStatus::Type recStatus, const QString &details); - bool AssignGroupInput(RecordingInfo &ri); + bool AssignGroupInput(RecordingInfo &ri, int prerollseconds); void HandleIdleShutdown( bool &blockShutdown, QDateTime &idleSince, int prerollseconds, int idleTimeoutSecs, int idleWaitForRecordingTime, @@ -273,7 +274,6 @@ class Scheduler : public MThread, public MythScheduler bool m_isShuttingDown; MSqlQueryInfo dbConn; - QDateTime fsInfoCacheFillTime; QMap<QString, FileSystemInfo> fsInfoCache; int error; @@ -284,6 +284,8 @@ class Scheduler : public MThread, public MythScheduler QDateTime livetvTime; QDateTime lastPrepareTime; + // Delay shutdown util this time (ms since epoch); + int64_t m_delayShutdownTime {0}; OpenEndType m_openEnd; diff --git a/mythtv/programs/mythbackend/services/content.cpp b/mythtv/programs/mythbackend/services/content.cpp index 3fddaed467..cb3afc320c 100644 --- a/mythtv/programs/mythbackend/services/content.cpp +++ b/mythtv/programs/mythbackend/services/content.cpp @@ -36,7 +36,7 @@ #include "storagegroup.h" #include "programinfo.h" #include "previewgenerator.h" -#include "backendutil.h" +#include "requesthandler/fileserverutil.h" #include "httprequest.h" #include "serviceUtil.h" #include "mythdate.h" diff --git a/mythtv/programs/mythbackend/services/dvr.cpp b/mythtv/programs/mythbackend/services/dvr.cpp index 6866f9aead..7f0094671a 100644 --- a/mythtv/programs/mythbackend/services/dvr.cpp +++ b/mythtv/programs/mythbackend/services/dvr.cpp @@ -473,13 +473,21 @@ long Dvr::GetSavedBookmark( int RecordedId, uint64_t offset; bool isend=true; uint64_t position = ri.QueryBookmark(); + // if no bookmark return 0 + if (position == 0) + return 0; if (offsettype.toLower() == "position"){ - ri.QueryKeyFramePosition(&offset, position, isend); - return offset; + // if bookmark cannot be converted to a keyframe we will + // just return the actual frame saved as the bookmark + if (ri.QueryKeyFramePosition(&offset, position, isend)) + return offset; } - else if (offsettype.toLower() == "duration"){ - ri.QueryKeyFrameDuration(&offset, position, isend); - return offset; + if (offsettype.toLower() == "duration"){ + if (ri.QueryKeyFrameDuration(&offset, position, isend)) + return offset; + else + // If bookmark cannot be converted to a duration return -1 + return -1; } else return position; diff --git a/mythtv/programs/mythbackend/services/myth.cpp b/mythtv/programs/mythbackend/services/myth.cpp index 733db2ceb6..093849a20e 100644 --- a/mythtv/programs/mythbackend/services/myth.cpp +++ b/mythtv/programs/mythbackend/services/myth.cpp @@ -46,6 +46,7 @@ #include "mythdate.h" #include "mythversion.h" #include "serviceUtil.h" +#include "scheduler.h" ///////////////////////////////////////////////////////////////////////////// // @@ -941,6 +942,14 @@ bool Myth::CheckDatabase( bool repair ) return bResult; } +bool Myth::DelayShutdown( void ) +{ + Scheduler *scheduler = dynamic_cast<Scheduler*>(gCoreContext->GetScheduler()); + scheduler->DelayShutdown(); + LOG(VB_GENERAL, LOG_NOTICE, "Shutdown delayed 5 minutes for external application."); + return true; +} + ///////////////////////////////////////////////////////////////////////////// // ///////////////////////////////////////////////////////////////////////////// diff --git a/mythtv/programs/mythbackend/services/myth.h b/mythtv/programs/mythbackend/services/myth.h index e22b14bfb9..7e704ade5b 100644 --- a/mythtv/programs/mythbackend/services/myth.h +++ b/mythtv/programs/mythbackend/services/myth.h @@ -129,6 +129,8 @@ class Myth : public MythServices bool CheckDatabase ( bool Repair ) override; // MythServices + bool DelayShutdown ( void ) override; // MythServices + bool ProfileSubmit ( void ) override; // MythServices bool ProfileDelete ( void ) override; // MythServices @@ -363,6 +365,13 @@ class ScriptableMyth : public QObject ) } + bool DelayShutdown( void ) + { + SCRIPT_CATCH_EXCEPTION( false, + return m_obj.DelayShutdown(); + ) + } + bool ProfileSubmit( void ) { SCRIPT_CATCH_EXCEPTION( false, diff --git a/mythtv/programs/mythexternrecorder/MythExternRecApp.cpp b/mythtv/programs/mythexternrecorder/MythExternRecApp.cpp index bc7a67cbb9..f4970d62ba 100644 --- a/mythtv/programs/mythexternrecorder/MythExternRecApp.cpp +++ b/mythtv/programs/mythexternrecorder/MythExternRecApp.cpp @@ -31,7 +31,8 @@ MythExternRecApp::MythExternRecApp(const QString & command, const QString & conf_file, - const QString & log_file) + const QString & log_file, + const QString & logging) : QObject() , m_fatal(false) , m_run(true) @@ -43,6 +44,7 @@ MythExternRecApp::MythExternRecApp(const QString & command, , m_lock_timeout(0) , m_scan_timeout(120000) , m_log_file(log_file) + , m_logging(logging) , m_config_ini(conf_file) , m_tuned(false) , m_chan_settings(nullptr) @@ -146,7 +148,8 @@ bool MythExternRecApp::Open(void) qRegisterMetaType<QProcess::ExitStatus>("QProcess::ExitStatus"); QObject::connect(&m_proc, - static_cast<void (QProcess::*)(int,QProcess::ExitStatus exitStatus)> + static_cast<void (QProcess::*) + (int,QProcess::ExitStatus exitStatus)> (&QProcess::finished), this, &MythExternRecApp::ProcFinished); @@ -391,7 +394,24 @@ Q_SLOT void MythExternRecApp::TuneChannel(const QString & serial, { m_command.replace("%URL%", url); LOG(VB_CHANNEL, LOG_DEBUG, LOC + - QString(": '%URL%' replaced in cmd: '%1'").arg(m_command)); + QString(": '%URL%' replaced with '%1' in cmd: '%2'") + .arg(url).arg(m_command)); + } + + if (!m_log_file.isEmpty() && m_command.indexOf("%LOGFILE%") >= 0) + { + m_command.replace("%LOGFILE%", m_log_file); + LOG(VB_RECORD, LOG_DEBUG, LOC + + QString(": '%LOGFILE%' replaced with '%1' in cmd: '%2'") + .arg(m_log_file).arg(m_command)); + } + + if (!m_logging.isEmpty() && m_command.indexOf("%LOGGING%") >= 0) + { + m_command.replace("%LOGGING%", m_logging); + LOG(VB_RECORD, LOG_DEBUG, LOC + + QString(": '%LOGGING%' replaced with '%1' in cmd: '%2'") + .arg(m_logging).arg(m_command)); } m_desc = m_rec_desc; @@ -498,7 +518,7 @@ Q_SLOT void MythExternRecApp::StopStreaming(const QString & serial, bool silent) if (m_proc.state() == QProcess::Running) { m_proc.terminate(); - m_proc.waitForFinished(); + m_proc.waitForFinished(3000); m_proc.kill(); LOG(VB_RECORD, LOG_INFO, LOC + ": External application terminated."); diff --git a/mythtv/programs/mythexternrecorder/MythExternRecApp.h b/mythtv/programs/mythexternrecorder/MythExternRecApp.h index 175a30b933..e1115122fd 100644 --- a/mythtv/programs/mythexternrecorder/MythExternRecApp.h +++ b/mythtv/programs/mythexternrecorder/MythExternRecApp.h @@ -35,7 +35,7 @@ class MythExternRecApp : public QObject public: MythExternRecApp(const QString & command, const QString & conf_file, - const QString & log_file); + const QString & log_file, const QString & logging); ~MythExternRecApp(void); bool Open(void); @@ -108,6 +108,7 @@ class MythExternRecApp : public QObject uint m_scan_timeout; QString m_log_file; + QString m_logging; QString m_config_ini; QString m_desc; diff --git a/mythtv/programs/mythexternrecorder/external-ffmpeg.conf b/mythtv/programs/mythexternrecorder/external-ffmpeg.conf index 934cc4459a..3804c1301b 100644 --- a/mythtv/programs/mythexternrecorder/external-ffmpeg.conf +++ b/mythtv/programs/mythexternrecorder/external-ffmpeg.conf @@ -2,6 +2,9 @@ # The recorder command to execute. %URL% is optional, and # will be replaced with the channel's "URL" as defined in the # [TUNER/channels] (channel conf) configuration file +# +# %LOGGING% will be replaced with mythtv logging params. For example: +# --verbose general,channel,record --logpath /var/log/mythtv --loglevel info --quiet command=/opt/ffmpeg/bin/ffmpeg -hide_banner -nostats -loglevel panic -re -i \"%URL%\" -c:v copy -c:a copy -f mpegts - # Used in logging events diff --git a/mythtv/programs/mythexternrecorder/external-twitch.conf b/mythtv/programs/mythexternrecorder/external-twitch.conf index ed251fa6f9..d35bd188c0 100644 --- a/mythtv/programs/mythexternrecorder/external-twitch.conf +++ b/mythtv/programs/mythexternrecorder/external-twitch.conf @@ -2,6 +2,9 @@ # The recorder command to execute. %URL% is optional, and # will be replaced with the channel's "URL" as defined in the # [TUNER/channels] (channel conf) configuration file +# +# %LOGGING% will be replaced with mythtv logging params. For example: +# --verbose general,channel,record --logpath /var/log/mythtv --loglevel info --quiet command="/usr/bin/youtube-dl --hls-use-mpegts --ffmpeg-location /opt/ffmpeg/bin --external-downloader-args \"-hide_banner -nostats -loglevel panic -re\" -o - \"%URL%\"" diff --git a/mythtv/programs/mythexternrecorder/external-vlc.conf b/mythtv/programs/mythexternrecorder/external-vlc.conf index 843f848585..73ad30db02 100644 --- a/mythtv/programs/mythexternrecorder/external-vlc.conf +++ b/mythtv/programs/mythexternrecorder/external-vlc.conf @@ -2,6 +2,9 @@ # The recorder command to execute. %URL% is optional, and # will be replaced with the channel's "URL" as defined in the # [TUNER/channels] (channel conf) configuration file +# +# %LOGGING% will be replaced with mythtv logging params. For example: +# --verbose general,channel,record --logpath /var/log/mythtv --loglevel info --quiet command="cvlc \"%URL%\" --sout \"#std{mux=ts,access=file,dst=-}\"" # Used in logging events, %ARG% are replaced from the channel info diff --git a/mythtv/programs/mythexternrecorder/main.cpp b/mythtv/programs/mythexternrecorder/main.cpp index 77ba6fc16e..11a97d1dda 100644 --- a/mythtv/programs/mythexternrecorder/main.cpp +++ b/mythtv/programs/mythexternrecorder/main.cpp @@ -63,6 +63,7 @@ int main(int argc, char *argv[]) if ((retval = cmdline.ConfigureLogging()) != GENERIC_EXIT_OK) return retval; QString logfile = cmdline.GetLogFilePath(); + QString logging = logPropagateArgs; MythExternControl *control = new MythExternControl(); MythExternRecApp *process = nullptr; @@ -70,12 +71,12 @@ int main(int argc, char *argv[]) QString conf_file = cmdline.toString("conf"); if (!conf_file.isEmpty()) { - process = new MythExternRecApp("", conf_file, logfile); + process = new MythExternRecApp("", conf_file, logfile, logging); } else if (!cmdline.toString("exec").isEmpty()) { QString command = cmdline.toString("exec"); - process = new MythExternRecApp(command, "", logfile); + process = new MythExternRecApp(command, "", logfile, logging); } else if (!cmdline.toString("infile").isEmpty()) { @@ -83,7 +84,7 @@ int main(int argc, char *argv[]) QString command = QString("ffmpeg -re -i \"%1\" " "-c:v copy -c:a copy -f mpegts -") .arg(filename); - process = new MythExternRecApp(command, "", logfile); + process = new MythExternRecApp(command, "", logfile, logging); } QObject::connect(process, &MythExternRecApp::Opened, diff --git a/mythtv/programs/mythfrontend/prevreclist.cpp b/mythtv/programs/mythfrontend/prevreclist.cpp index d084efff92..33288df9af 100644 --- a/mythtv/programs/mythfrontend/prevreclist.cpp +++ b/mythtv/programs/mythfrontend/prevreclist.cpp @@ -245,7 +245,9 @@ bool PrevRecordedList::LoadTitles(void) bool PrevRecordedList::LoadDates(void) { - QString querystr = "SELECT DISTINCT YEAR(starttime), MONTH(starttime) " + QString querystr = "SELECT DISTINCT " + "YEAR(CONVERT_TZ(starttime,'UTC','SYSTEM')), " + "MONTH(CONVERT_TZ(starttime,'UTC','SYSTEM')) " "FROM oldrecorded " "WHERE oldrecorded.future = 0 " + m_where; @@ -412,8 +414,11 @@ void PrevRecordedList::LoadShowsByTitle(void) { MSqlBindings bindings; QString sql = " AND oldrecorded.title = :TITLE " + m_where; - int selected = m_titleList->GetCurrentPos(); - bindings[":TITLE"] = m_titleData[selected]->GetTitle(); + uint selected = m_titleList->GetCurrentPos(); + if (selected < m_titleData.size()) + bindings[":TITLE"] = m_titleData[selected]->GetTitle(); + else + bindings[":TITLE"] = ""; if (!m_title.isEmpty()) bindings[":MTITLE"] = m_title; m_showData.clear(); diff --git a/mythtv/programs/mythfrontend/progdetails.cpp b/mythtv/programs/mythfrontend/progdetails.cpp index 9265292c35..4a9673017c 100644 --- a/mythtv/programs/mythfrontend/progdetails.cpp +++ b/mythtv/programs/mythfrontend/progdetails.cpp @@ -46,7 +46,7 @@ QString ProgDetails::getRatings(bool recorded, uint chanid, QDateTime startts) { QString table = (recorded) ? "recordedrating" : "programrating"; QString sel = QString( - "SELECT system, rating FROM %1 " + "SELECT `system`, rating FROM %1 " "WHERE chanid = :CHANID " "AND starttime = :STARTTIME").arg(table); diff --git a/mythtv/programs/mythwelcome/main.cpp b/mythtv/programs/mythwelcome/main.cpp index 8459b04a8a..4c1dbe9061 100644 --- a/mythtv/programs/mythwelcome/main.cpp +++ b/mythtv/programs/mythwelcome/main.cpp @@ -88,6 +88,8 @@ int main(int argc, char **argv) #endif gContext = new MythContext(MYTH_BINARY_VERSION, true); + + cmdline.ApplySettingsOverride(); if (!gContext->Init()) { LOG(VB_GENERAL, LOG_ERR, @@ -96,6 +98,8 @@ int main(int argc, char **argv) return GENERIC_EXIT_NO_MYTHCONTEXT; } + cmdline.ApplySettingsOverride(); + if (!MSqlQuery::testDBConnection()) { LOG(VB_GENERAL, LOG_ERR, diff --git a/mythtv/programs/scripts/hardwareprofile/smolt.py b/mythtv/programs/scripts/hardwareprofile/smolt.py index d867772099..40a421e2b1 100644 --- a/mythtv/programs/scripts/hardwareprofile/smolt.py +++ b/mythtv/programs/scripts/hardwareprofile/smolt.py @@ -1176,6 +1176,8 @@ def read_cpuinfo(): def read_memory(): un = os.uname() kernel = un[2] + if kernel[:2] == "5.": + return read_memory_2_6() if kernel[:2] == "4.": return read_memory_2_6() if kernel[:2] == "3.": diff --git a/mythtv/programs/scripts/hardwareprofile/software.py b/mythtv/programs/scripts/hardwareprofile/software.py index b90384943c..b89ad58a1c 100644 --- a/mythtv/programs/scripts/hardwareprofile/software.py +++ b/mythtv/programs/scripts/hardwareprofile/software.py @@ -33,7 +33,7 @@ def read_lsb_release(): initdefault_re = re.compile(r':(\d+):initdefault:') def read_runlevel(): - defaultRunlevel = 'Unknown' + defaultRunlevel = '9' try: inittab = file('/etc/inittab').read() match = initdefault_re.search(inittab) diff --git a/mythtv/programs/scripts/metadata/Movie/tmdb3.py b/mythtv/programs/scripts/metadata/Movie/tmdb3.py index 3dd893d8b7..9739ecf320 100755 --- a/mythtv/programs/scripts/metadata/Movie/tmdb3.py +++ b/mythtv/programs/scripts/metadata/Movie/tmdb3.py @@ -29,6 +29,10 @@ __version__ = "0.3.7" from optparse import OptionParser import sys +import signal + +def timeouthandler(signal, frame): + raise RuntimeError("Timed out") def buildSingle(inetref, opts): from MythTV.tmdb3.tmdb_exceptions import TMDBRequestInvalid @@ -275,6 +279,9 @@ def main(): opts, args = parser.parse_args() + signal.signal(signal.SIGALRM, timeouthandler) + signal.alarm(30) + if opts.version: buildVersion() @@ -312,14 +319,18 @@ def main(): sys.stdout.write('ERROR: tmdb3.py requires exactly one non-empty argument') sys.exit(1) - if opts.movielist: - buildList(args[0], opts) + try: + if opts.movielist: + buildList(args[0], opts) - if opts.moviedata: - buildSingle(args[0], opts) + if opts.moviedata: + buildSingle(args[0], opts) - if opts.collectiondata: - buildCollection(args[0], opts) + if opts.collectiondata: + buildCollection(args[0], opts) + except RuntimeError, exc: + sys.stdout.write('ERROR: ' + str(exc) + ' exception') + sys.exit(1) if __name__ == '__main__': main() diff --git a/mythtv/version.sh b/mythtv/version.sh index fd2c0be875..d412cc0505 100755 --- a/mythtv/version.sh +++ b/mythtv/version.sh @@ -21,44 +21,64 @@ GITREPOPATH="exported" cd ${GITTREEDIR} -git status > /dev/null 2>&1 -SOURCE_VERSION=$(git describe --dirty || git describe || echo Unknown) +# if we have a mythtv/DESCRIBE file use that to get the branch and version +if test -e $GITTREEDIR/DESCRIBE ; then + echo "Using $GITTREEDIR/DESCRIBE" + . $GITTREEDIR/DESCRIBE + echo "BRANCH: $BRANCH" + echo "SOURCE_VERSION: $SOURCE_VERSION" +else + # get the branch and version from git or fall back to EXPORTED_VERSION then VERSION as last resort + git status > /dev/null 2>&1 + SOURCE_VERSION=$(git describe --dirty || git describe || echo Unknown) + echo "SOURCE_VERSION: $SOURCE_VERSION" -case "${SOURCE_VERSION}" in - exported|Unknown) - if ! grep -q Format $GITTREEDIR/EXPORTED_VERSION; then - . $GITTREEDIR/EXPORTED_VERSION - # This file has SOURCE_VERSION and BRANCH - # example SOURCE_VERSION="30d8a96" - # BRANCH examples from github - # BRANCH=" (HEAD -> master)" - # BRANCH=" (fixes/0.28)" - # BRANCH=" (tag: v0.28.1)" - # From a checkout they can be as follows: - # " (origin/fixes/0.28, fixes/0.28)" - # " (HEAD -> master, origin/master, origin/HEAD)" - # " (tag: v0.28.1)" - hash="$SOURCE_VERSION" - # This extracts after the last comma inside the parens: - BRANCH=$(echo "${BRANCH}" | sed -e 's/ (\(.*, \)\{0,1\}\(.*\))/\2/' -e 's,origin/,,') - # Create a suitable version (hash is no good) - SOURCE_VERSION="$BRANCH" - SOURCE_VERSION=`echo "$SOURCE_VERSION" | sed "s/tag: *//"` - if ! echo "$SOURCE_VERSION" | grep "^v[0-9]" ; then + case "${SOURCE_VERSION}" in + exported|Unknown) + if ! grep -q Format $GITTREEDIR/EXPORTED_VERSION; then + . $GITTREEDIR/EXPORTED_VERSION + echo "Using $GITTREEDIR/EXPORTED_VERSION" + echo "BRANCH: $BRANCH" + echo "SOURCE_VERSION: $SOURCE_VERSION" + # This file has SOURCE_VERSION and BRANCH + # example SOURCE_VERSION="30d8a96" + # BRANCH examples from github + # BRANCH=" (HEAD -> master)" + # BRANCH=" (fixes/0.28)" + # BRANCH=" (tag: v0.28.1)" + # From a checkout they can be as follows: + # " (origin/fixes/0.28, fixes/0.28)" + # " (HEAD -> master, origin/master, origin/HEAD)" + # " (tag: v0.28.1)" + hash="$SOURCE_VERSION" + # This extracts after the last comma inside the parens: + BRANCH=$(echo "${BRANCH}" | sed -e 's/ (\(.*, \)\{0,1\}\(.*\))/\2/' -e 's,origin/,,') + # Create a suitable version (hash is no good) + SOURCE_VERSION="$BRANCH" + SOURCE_VERSION=`echo "$SOURCE_VERSION" | sed "s/tag: *//"` + if ! echo "$SOURCE_VERSION" | grep "^v[0-9]" ; then + . $GITTREEDIR/VERSION + fi + SOURCE_VERSION="${SOURCE_VERSION}-${hash}" + echo "Source Version created as $SOURCE_VERSION" + echo "Branch created as $BRANCH" + elif test -e $GITTREEDIR/VERSION ; then + echo "Using $GITTREEDIR/VERSION" . $GITTREEDIR/VERSION + echo "BRANCH: $BRANCH" + echo "SOURCE_VERSION: $SOURCE_VERSION" + fi + ;; + *) + if [ -z "${BRANCH}" ]; then + BRANCH=$(git branch --no-color | sed -e '/^[^\*]/d' -e 's/^\* //' -e 's/(no branch)/exported/') + echo "Using git to get branch and version" + echo "BRANCH: $BRANCH" + echo "SOURCE_VERSION: $SOURCE_VERSION" fi - SOURCE_VERSION="${SOURCE_VERSION}-${hash}" - echo "Source Version created as $SOURCE_VERSION" - elif test -e $GITTREEDIR/VERSION ; then - . $GITTREEDIR/VERSION - fi - ;; - *) - if [ -z "${BRANCH}" ]; then - BRANCH=$(git branch --no-color | sed -e '/^[^\*]/d' -e 's/^\* //' -e 's/(no branch)/exported/') - fi - ;; -esac + ;; + esac +fi if ! echo "${SOURCE_VERSION}" | egrep -i "v[0-9]+.*" ; then # Invalid version - use VERSION file