rendered paste bodyIndex: libs/libmythtv/dvbrecorder.cpp===================================================================--- libs/libmythtv/dvbrecorder.cpp (revision 9417)+++ libs/libmythtv/dvbrecorder.cpp (working copy)@@ -703,7 +703,7 @@ PIDInfo *info = _pid_infos[pid]; if (!info) info = _pid_infos[pid] = new PIDInfo();-+/* // track scrambled pids if (tspacket.ScramplingControl()) {@@ -721,7 +721,7 @@ QString("PID 0x%1 is no longer encrypted").arg(pid,0,16)); info->isEncrypted = false; }-+*/ // Check continuity counter if (tspacket.HasPayload()) {Index: libs/libmythtv/dbcheck.cpp===================================================================--- libs/libmythtv/dbcheck.cpp (revision 9417)+++ libs/libmythtv/dbcheck.cpp (working copy)@@ -12,11 +12,18 @@ /// This is the DB schema version expected by the running MythTV instance. const QString currentDatabaseVersion = "1132"; +/// This is the DB schema minor version used by supplementary patches +const QString currentDatabaseVersionMinor = "2";+ static bool UpdateDBVersionNumber(const QString &newnumber);+static bool UpdateDBVersionMinor( const QString &newminor); static bool performActualUpdate(const QString updates[], QString version, QString &dbver);+static bool performMinorUpdate(const QString updates[], QString minor,+ QString &dbminor); static bool InitializeDatabase(void); static bool doUpgradeTVDatabaseSchema(void);+static bool dbMinorUpdate(void); /** \defgroup db_schema MythTV Database Schema @@ -352,6 +359,48 @@ return true; } +static bool UpdateDBVersionMinor(const QString &newminor)+{+ // delete old schema version+ MSqlQuery query(MSqlQuery::InitCon()); + + QString thequery = "DELETE FROM settings WHERE value='DBSchemaVerMinor';";+ query.prepare(thequery);+ query.exec();+ + if (query.lastError().type() != QSqlError::None)+ {+ QString msg =+ QString("DB Error (Deleting old DB minor version number): \n"+ "Query was: %1 \nError was: %2 \nnew version: %3")+ .arg(thequery)+ .arg(MythContext::DBErrorMessage(query.lastError()))+ .arg(newminor);+ VERBOSE(VB_IMPORTANT, msg);+ return false;+ }++ // set new schema minor+ thequery = QString("INSERT INTO settings (value, data, hostname) "+ "VALUES ('DBSchemaVerMinor', %1, NULL);").arg(newminor);+ query.prepare(thequery);+ query.exec();++ if (query.lastError().type() != QSqlError::None)+ {+ QString msg =+ QString("DB Error (Setting new DB minor version number): \n"+ "Query was: %1 \nError was: %2 \nnew minor version: %3")+ .arg(thequery)+ .arg(MythContext::DBErrorMessage(query.lastError()))+ .arg(newminor);+ VERBOSE(VB_IMPORTANT, msg);+ return false;+ }++ return true;+}+ /** \fn performActualUpdate(const QString updates[], QString, QString&) * \brief Runs a number of SQL commands, and updates the schema version. *@@ -399,6 +448,44 @@ return true; } +static bool performMinorUpdate(const QString updates[], QString minor,+ QString &dbminor)+{+ MSqlQuery query(MSqlQuery::InitCon());++ VERBOSE(VB_IMPORTANT, QString("Upgrading to schema minor ") + minor);++ int counter = 0;+ QString thequery = updates[counter];++ while (thequery != "")+ {+ query.prepare(thequery);+ query.exec();++ if (query.lastError().type() != QSqlError::None)+ {+ QString msg =+ QString("DB Error (Performing database upgrade): \n"+ "Query was: %1 \nError was: %2 \nnew minor: %3")+ .arg(thequery)+ .arg(MythContext::DBErrorMessage(query.lastError()))+ .arg(minor);+ VERBOSE(VB_IMPORTANT, msg);+ return false;+ }++ counter++;+ thequery = updates[counter];+ }++ if (!UpdateDBVersionMinor(minor))+ return false;++ dbminor = minor;+ return true; +}+ /** \fn UpgradeTVDatabaseSchema(void) * \brief This is the function called from outside dbcheck.cpp to update the schema. *@@ -416,17 +503,22 @@ { QString dbver = gContext->GetSetting("DBSchemaVer"); - VERBOSE(VB_IMPORTANT, QString("Current Schema Version: %1").arg(dbver));+ QString dbminor = gContext->GetSetting("DBSchemaVerMinor"); - if (dbver == currentDatabaseVersion)+ VERBOSE(VB_IMPORTANT, QString("Current Schema Version: %1.%2").arg(dbver)+ .arg(dbminor));++ if ((dbver == currentDatabaseVersion) &&+ (dbminor == currentDatabaseVersionMinor)) return true; MSqlQuery chartype(MSqlQuery::InitCon()); chartype.prepare("ALTER DATABASE mythconverg DEFAULT CHARACTER SET latin1;"); chartype.exec(); - VERBOSE(VB_IMPORTANT, QString("Newest Schema Version : %1")- .arg(currentDatabaseVersion));+ VERBOSE(VB_IMPORTANT, QString("Newest Schema Version : %1.%2")+ .arg(currentDatabaseVersion)+ .arg(currentDatabaseVersionMinor)); MSqlQuery lockquery(MSqlQuery::InitCon()); @@ -458,7 +550,15 @@ bool ret = doUpgradeTVDatabaseSchema(); + // Database version minor updates if (ret)+ ret = dbMinorUpdate();++ VERBOSE(VB_IMPORTANT, QString("Newest Schema Version : %1.%2")+ .arg(currentDatabaseVersion)+ .arg(currentDatabaseVersionMinor));++ if (ret) VERBOSE(VB_IMPORTANT, "Database Schema upgrade complete, unlocking."); else VERBOSE(VB_IMPORTANT, "Database Schema upgrade FAILED, unlocking.");@@ -2148,8 +2248,51 @@ return true; } +static bool dbMinorUpdate(void)+{+ QString dbminor = gContext->GetSetting("DBSchemaVerMinor");+ if (dbminor == currentDatabaseVersionMinor)+ return true;+ if ((dbminor == "") || (dbminor == "0"))+ {+ const QString updates[] = {+// Dish Network+"INSERT INTO dtv_privatetypes (sitype, networkid, private_type, private_value)"+" VALUES('dvb', 4102, 'force_guide_present', 'yes');",+"INSERT INTO dtv_privatetypes (sitype, networkid, private_type, private_value)"+" VALUES('dvb', 4102, 'extended_guide_tid', '229');",+// Bell ExpressVu+"INSERT INTO dtv_privatetypes (sitype, networkid, private_type, private_value)"+" VALUES('dvb', 256, 'force_guide_present', 'yes');",+"INSERT INTO dtv_privatetypes (sitype, networkid, private_type, private_value)"+" VALUES('dvb', 256, 'guide_on_single_tid', 'yes');",+"INSERT INTO dtv_privatetypes (sitype, networkid, private_type, private_value)"+" VALUES('dvb', 257, 'force_guide_present', 'yes');",+"INSERT INTO dtv_privatetypes (sitype, networkid, private_type, private_value)"+" VALUES('dvb', 257, 'guide_on_single_tid', 'yes');",+""+ };+ if (!performMinorUpdate(updates, "1", dbminor))+ return false;+ } + if ((dbminor == "1"))+ {+ const QString updates[] = {+// Bell ExpressVu+"INSERT INTO dtv_privatetypes (sitype, networkid, private_type, private_value)"+" VALUES('dvb', 256, 'standard_guide_tid', '4');",+"INSERT INTO dtv_privatetypes (sitype, networkid, private_type, private_value)"+" VALUES('dvb', 257, 'standard_guide_tid', '102');",+""+ };+ if (!performMinorUpdate(updates, "2", dbminor))+ return false;+ } + return true;+}+ bool InitializeDatabase(void) { MSqlQuery query(MSqlQuery::InitCon());Index: libs/libmythtv/dvbcam.h===================================================================--- libs/libmythtv/dvbcam.h (revision 9417)+++ libs/libmythtv/dvbcam.h (working copy)@@ -47,6 +47,13 @@ bool pmt_sent; bool pmt_updated; bool pmt_added;+ bool exitSkThread;+ bool skThreadRunning;+ pthread_t externSoftkeyThread;+ int external_cam_fd;+ void sendExternalCam(const ProgramMapTable *pmt);+ bool useExternalCam();+ void stopExternalCam(); }; #endif // DVBCAM_HIndex: libs/libmythtv/dvbcam.cpp===================================================================--- libs/libmythtv/dvbcam.cpp (revision 9417)+++ libs/libmythtv/dvbcam.cpp (working copy)@@ -35,7 +35,7 @@ #include <qdatetime.h> #include <qvariant.h>-+#include <qdir.h> #include <iostream> #include <vector> #include <map>@@ -85,6 +85,8 @@ bool DVBCam::Start() {+ if(useExternalCam())+ return true; if (numslots == 0) return false; @@ -116,6 +118,7 @@ bool DVBCam::Stop() { + stopExternalCam(); if (ciThreadRunning) { exitCiThread = true;@@ -262,7 +265,7 @@ void DVBCam::SetPMT(const ProgramMapTable *pmt) { VERBOSE(VB_CHANNEL, LOC + "SetPMT() program num #"<<pmt->ProgramNumber());-+ sendExternalCam(pmt); QMutexLocker locker(&pmt_lock); PMTList.clear(); PMTList.push_back(*pmt);@@ -376,3 +379,147 @@ } return capmt; }++bool DVBCam::useExternalCam()+{+ skThreadRunning = false;+ exitSkThread = false;+ external_cam_fd = -1;+ QString extCam = QDir::homeDirPath() ++ QString("/.mythtv/externcam_%1").arg(cardnum);+ if (QFileInfo(extCam).isDir())+ {+ QString cmd = gContext->GetSetting("ExternalCamApp","");+ if(cmd == "") {+ ERROR("CAM - No external app set in SQL db.");+ return false;+ }+ cmd += " --dir " + extCam + QString(" --card %1").arg(cardnum);++ QString keyFifo = QDir::homeDirPath() + + QString("/.mythtv/externcam_%1/keyfifo").arg(cardnum);+ unlink(keyFifo.ascii());+ bool spawn_thread = false;+ if(numslots==0 || QFileInfo(extCam + "/force_sw").isFile()) {+ cmd += " --writekey " + keyFifo;+ mkfifo(keyFifo.ascii(), 0600);+ spawn_thread = true;+ }+ + int tmppid[2];+ if (pipe(tmppid) < 0)+ {+ perror("Failed to create pipe\n");+ return false;+ }+ + int child = fork();+ if (child < 0)+ {+ perror("Failed to fork\n");+ return false;+ }+ if (child == 0)+ {+ dup2(tmppid[0],fileno(stdin));+ for(int i = 3; i < sysconf(_SC_OPEN_MAX) - 1; ++i)+ close(i);+ execl("/bin/sh", "sh", "-c", cmd.ascii(), NULL);+ perror("exec");+ _exit(1);+ }+ close(tmppid[0]);+ external_cam_fd=tmppid[1];+ //we need to fake ciThreadRunning in oreder to get PMTs+ ciThreadRunning = true;+ return true;+ }+ return false;+}+void DVBCam::sendExternalCam(const ProgramMapTable *pmt)+{+ if (external_cam_fd < 0)+ return;++ unsigned char newpmt[512];+ int hdr[34]; //Allow for up to 16 PIDs+ int pmtlen=0, hdrlen = 0;+ hdr[hdrlen++]=pmt->ProgramNumber();+ hdr[hdrlen++]=1; //Place holder for transportID (future)++ desc_list_t gdesc = MPEGDescriptor::ParseOnlyInclude(+ pmt->ProgramInfo(), pmt->ProgramInfoLength(),+ DescriptorID::conditional_access);++ for (desc_list_t::const_iterator it = gdesc.begin(); it != gdesc.end(); ++it)+ {+ ConditionalAccessDescriptor cad(*it);+ newpmt[pmtlen++] = 0x09;+ newpmt[pmtlen++] = cad.DataSize() + 4;+ newpmt[pmtlen++] = (cad.SystemID()) >> 8;+ newpmt[pmtlen++] = (cad.SystemID()) & 0xff;+ newpmt[pmtlen++] = (cad.PID()) >> 8;+ newpmt[pmtlen++] = (cad.PID()) & 0xff;+ const unsigned char* p_data = cad.Data();+ for (int x = 0; x < cad.DataSize(); x++)+ newpmt[pmtlen++] = p_data[x];+ }+ for (uint i = 0; i < pmt->StreamCount(); i++)+ {+ int type;+ if (StreamID::IsVideo(pmt->StreamType(i)))+ type = 0;+ else if (StreamID::IsAudio(pmt->StreamType(i)))+ type = 1;+ else+ type = 5;++ hdr[hdrlen++] = pmt->StreamPID(i); //pid+ hdr[hdrlen++] = type; //stream type++ desc_list_t gdesc = MPEGDescriptor::ParseOnlyInclude(+ pmt->StreamInfo(i), pmt->StreamInfoLength(i),+ DescriptorID::conditional_access);++ for (desc_list_t::const_iterator it = gdesc.begin(); it != gdesc.end(); ++it)+ {+ ConditionalAccessDescriptor cad(*it);+ newpmt[pmtlen++] = 0x09;+ newpmt[pmtlen++] = cad.DataSize() + 4;+ newpmt[pmtlen++] = (cad.SystemID()) >> 8;+ newpmt[pmtlen++] = (cad.SystemID()) & 0xff;+ newpmt[pmtlen++] = (cad.PID()) >> 8;+ newpmt[pmtlen++] = (cad.PID()) & 0xff;+ const unsigned char* p_data = cad.Data();+ for (int x = 0; x < cad.DataSize(); x++)+ newpmt[pmtlen++] = p_data[x];+ }+ }+ if (pmtlen) {+ QString temp = QString("SID: %1 TID: %2").arg(hdr[0]).arg(hdr[1]);+ for (int x = 2; x < hdrlen; x += 2)+ temp += QString(" (%1 %2)").arg(hdr[x]).arg(hdr[x + 1]);+ GENERAL(temp);+ temp = QString("Found CA Descriptors: (%1)").arg(pmtlen);+ for (int x = 0; x < pmtlen; x++)+ temp += QString(" %1").arg(newpmt[x],2,16);+ GENERAL(temp);+ write(external_cam_fd, &hdrlen, sizeof(hdrlen));+ write(external_cam_fd, &hdr, hdrlen * sizeof(int));+ write(external_cam_fd, &pmtlen, sizeof(pmtlen));+ write(external_cam_fd, &newpmt, pmtlen);+ }+}++void DVBCam::stopExternalCam()+{+ if(external_cam_fd != -1) {+ close(external_cam_fd);+ ciThreadRunning = false;+ if (skThreadRunning)+ {+ exitSkThread = true;+ pthread_join(externSoftkeyThread, NULL);+ }+ }+}Index: libs/libmythtv/eitscanner.h===================================================================--- libs/libmythtv/eitscanner.h (revision 9417)+++ libs/libmythtv/eitscanner.h (working copy)@@ -28,7 +28,7 @@ void StopPassiveScan(void); void StartActiveScan(TVRec*, uint max_seconds_per_source,- bool ignore_source);+ bool ignore_source, bool limit_transport=false); void StopActiveScan(void); Index: libs/libmythtv/tv_rec.cpp===================================================================--- libs/libmythtv/tv_rec.cpp (revision 9417)+++ libs/libmythtv/tv_rec.cpp (working copy)@@ -78,9 +78,6 @@ #define LOC QString("TVRec(%1): ").arg(cardid) #define LOC_ERR QString("TVRec(%1) Error: ").arg(cardid) -/// How many seconds after entering kState_None should we start EIT Scanner-const uint TVRec::kEITScanStartTimeout = 60; /* 1 minute */- /// How many milliseconds the signal monitor should wait between checks const uint TVRec::kSignalMonitoringRate = 50; /* msec */ @@ -768,7 +765,8 @@ { // Add some randomness to avoid all cards starting // EIT scanning at nearly the same time.- uint timeout = kEITScanStartTimeout + random() % 59;+ uint idle_start = gContext->GetNumSetting("EITCrawIdleStart", 1);+ uint timeout = (idle_start * 60) + random() % 59; eitScanStartTime = eitScanStartTime.addSecs(timeout); } else@@ -1207,7 +1205,8 @@ // Add some randomness to avoid all cards starting // EIT scanning at nearly the same time.- uint timeout = kEITScanStartTimeout + random() % 59;+ uint idle_start = gContext->GetNumSetting("EITCrawIdleStart", 1);+ uint timeout = (idle_start * 60) + random() % 59; eitScanStartTime = QDateTime::currentDateTime().addSecs(timeout); while (HasFlags(kFlagRunMainLoop))@@ -1342,8 +1341,11 @@ else { uint ttMin = gContext->GetNumSetting("EITTransportTimeout", 5);+ + uint tid_limit = gContext->GetNumSetting("EITCrawLimitTransports", 0); uint ignore = gContext->GetNumSetting("EITIgnoresSource", 0);- scanner->StartActiveScan(this, ttMin * 60, ignore);+ scanner->StartActiveScan(this, ttMin * 60, ignore, (tid_limit ? true : false));+ SetFlags(kFlagEITScannerRunning); eitScanStartTime = QDateTime::currentDateTime().addYears(1); }Index: libs/libmythtv/eitscanner.cpp===================================================================--- libs/libmythtv/eitscanner.cpp (revision 9417)+++ libs/libmythtv/eitscanner.cpp (working copy)@@ -183,7 +183,7 @@ } void EITScanner::StartActiveScan(TVRec *_rec, uint max_seconds_per_source,- bool _ignore_source)+ bool _ignore_source, bool limit_transports) { rec = _rec; ignore_source = _ignore_source;@@ -191,17 +191,42 @@ if (!activeScanChannels.size()) { MSqlQuery query(MSqlQuery::InitCon());- query.prepare(- "SELECT channum, mplexid "- "FROM channel, cardinput, capturecard, videosource "- "WHERE cardinput.sourceid = channel.sourceid AND "- " videosource.sourceid = channel.sourceid AND "- " capturecard.cardid = cardinput.cardid AND "- " channel.mplexid IS NOT NULL AND "- " useonairguide = 1 AND "- " useeit = 1 AND "- " cardinput.cardid = :CARDID "- "ORDER BY cardinput.sourceid, atscsrcid");++ if (limit_transports)+ query.prepare(+ "SELECT MIN(channum), channel.mplexid "+ "FROM channel, dtv_multiplex, dtv_privatetypes, videosource, "+ "cardinput, capturecard "+ "WHERE dtv_multiplex.networkid = dtv_privatetypes.networkid "+ "AND videosource.sourceid = channel.sourceid "+ "AND cardinput.sourceid = channel.sourceid "+ "AND capturecard.cardid = cardinput.cardid "+ "AND (private_type = 'extended_guide_tid' "+ "OR private_type = 'standard_guide_tid') "+ "AND private_value = transportid "+ "AND channel.mplexid = dtv_multiplex.mplexid "+ "AND useonairguide = 1 "+ "AND useeit = 1 "+ "AND cardinput.cardid = :CARDID "+ "GROUP BY transportid");+ else+ query.prepare(+ "SELECT MIN(channum), channel.mplexid "+ "FROM channel,videosource,cardinput,capturecard,dtv_multiplex "+ "LEFT JOIN dtv_privatetypes "+ "ON dtv_multiplex.networkid = dtv_privatetypes.networkid "+ "AND (private_type = 'extended_guide_tid' "+ "OR private_type = 'standard_guide_tid') "+ "AND private_value = transportid "+ "WHERE videosource.sourceid = channel.sourceid "+ "AND cardinput.sourceid = channel.sourceid "+ "AND capturecard.cardid = cardinput.cardid "+ "AND channel.mplexid = dtv_multiplex.mplexid "+ "AND useonairguide = 1 "+ "AND useeit = 1 "+ "AND cardinput.cardid = :CARDID "+ "GROUP BY transportid");+ query.bindValue(":CARDID", rec->GetCaptureCardNum()); if (!query.exec() || !query.isActive())Index: libs/libmythtv/dtvsignalmonitor.cpp===================================================================--- libs/libmythtv/dtvsignalmonitor.cpp (revision 9417)+++ libs/libmythtv/dtvsignalmonitor.cpp (working copy)@@ -234,9 +234,9 @@ if (pmt->ProgramNumber() != (uint)programNumber) {- VERBOSE(VB_IMPORTANT, LOC_ERR +- QString("Wrong PMT; pmt->pn(%1) desired(%2)")- .arg(pmt->ProgramNumber()).arg(programNumber));+// VERBOSE(VB_IMPORTANT, LOC_ERR ++// QString("Wrong PMT; pmt->pn(%1) desired(%2)")+// .arg(pmt->ProgramNumber()).arg(programNumber)); return; // Not the PMT we are looking for... } Index: libs/libmythtv/tv_rec.h===================================================================--- libs/libmythtv/tv_rec.h (revision 9417)+++ libs/libmythtv/tv_rec.h (working copy)@@ -372,7 +372,6 @@ QString rbFileExt; public:- static const uint kEITScanStartTimeout; static const uint kSignalMonitoringRate; // General State flagsIndex: setup/backendsettings.cpp===================================================================--- setup/backendsettings.cpp (revision 9417)+++ setup/backendsettings.cpp (working copy)@@ -73,6 +73,15 @@ return gc; }; +static GlobalLineEdit *ExternalCamApp()+{+ GlobalLineEdit *gc = new GlobalLineEdit("ExternalCamApp");+ gc->setLabel(QObject::tr("External Cam App"));+ gc->setValue("sasc");+ gc->setHelpText(QObject::tr("External Application for CAMless cards."));+ return gc;+};+ static GlobalComboBox *TVFormat() { GlobalComboBox *gc = new GlobalComboBox("TVFormat");@@ -214,6 +223,30 @@ return gc; }; +static GlobalSpinBox *EITCrawIdleStart()+{+ GlobalSpinBox *gc = new GlobalSpinBox("EITCrawIdleStart", 1, 120, 1);+ gc->setLabel(QObject::tr("Backend Idle Before EIT Craw (mins)"));+ gc->setValue(1);+ QString helpText = QObject::tr(+ "The amount of time to wait after the backend becomes idle for a given "+ "capture card before the EIT craw starts.");+ gc->setHelpText(helpText);+ return gc;+}++static GlobalCheckBox *EITCrawLimitTransports()+{+ GlobalCheckBox *gc = new GlobalCheckBox("EITCrawLimitTransports");+ gc->setLabel(QObject::tr("EIT Craw Limits Transports"));+ gc->setValue(false);+ gc->setHelpText(QObject::tr("If set, EIT craw will scan only "+ "those transports which have either "+ "standard_guide_tid or extended_guide_tid "+ "entries defined in dtv_privatetypes."));+ return gc;+};+ static GlobalSpinBox *EITTransportTimeout() { GlobalSpinBox *gc = new GlobalSpinBox("EITTransportTimeout", 1, 15, 1);@@ -654,6 +687,7 @@ VerticalConfigurationGroup* group1 = new VerticalConfigurationGroup(false); group1->setLabel(QObject::tr("Host-specific Backend Setup")); group1->addChild(RecordFilePrefix());+ group1->addChild(ExternalCamApp()); addChild(group1); VerticalConfigurationGroup* group2 = new VerticalConfigurationGroup(false);@@ -669,6 +703,8 @@ VerticalConfigurationGroup* group2a1 = new VerticalConfigurationGroup(false); group2a1->setLabel(QObject::tr("EIT Scanner Options")); group2a1->addChild(EITTransportTimeout());+ group2a1->addChild(EITCrawIdleStart());+ group2a1->addChild(EITCrawLimitTransports()); group2a1->addChild(EITIgnoresSource()); addChild(group2a1);