diff --git a/CONTRIBUTORS b/CONTRIBUTORS index 50068839..6e523173 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -3203,3 +3203,7 @@ Eike Sauer Christian Paulick for reporting a problem with frame detection in MPEG-2 streams that have "bottom fields" or varying GOP structures + +Mariusz Bialonczyk + for reporting that acquiring the CA descriptors takes way too long on transponders + with many PAT entries, and his help in debugging this diff --git a/HISTORY b/HISTORY index ff54aa51..93991f60 100644 --- a/HISTORY +++ b/HISTORY @@ -7892,3 +7892,5 @@ Video Disk Recorder Revision History - Fixed a possible crash in the OSD demo (reported by Christopher Reimer). - Fixed learning keyboard remote control codes (thanks to Lars Hanisch). - Fixed the replay progress display for very long recordings. +- Improved PAT/PMT scanning to speed up initial tuning to encrypted channels on + transponders with many PAT entries (reported by Mariusz Bialonczyk). diff --git a/device.c b/device.c index d07a552c..5e7d4751 100644 --- a/device.c +++ b/device.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: device.c 2.74.1.2 2013/08/22 10:35:30 kls Exp $ + * $Id: device.c 2.74.1.3 2014/02/18 14:12:08 kls Exp $ */ #include "device.h" @@ -785,6 +785,7 @@ eSetChannelResult cDevice::SetChannel(const cChannel *Channel, bool LiveView) if (SetChannelDevice(Channel, LiveView)) { // Start section handling: if (sectionHandler) { + patFilter->Trigger(Channel->Sid()); sectionHandler->SetChannel(Channel); sectionHandler->SetStatus(true); } diff --git a/pat.c b/pat.c index a7791e2a..1f6561cd 100644 --- a/pat.c +++ b/pat.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: pat.c 2.19 2012/11/25 14:12:21 kls Exp $ + * $Id: pat.c 2.19.1.1 2014/02/18 14:12:17 kls Exp $ */ #include "pat.h" @@ -12,9 +12,8 @@ #include "channels.h" #include "libsi/section.h" #include "libsi/descriptor.h" -#include "thread.h" -#define PMT_SCAN_TIMEOUT 10 // seconds +#define PMT_SCAN_TIMEOUT 1000 // ms // --- cCaDescriptor --------------------------------------------------------- @@ -229,94 +228,115 @@ int GetCaDescriptors(int Source, int Transponder, int ServiceId, const int *CaSy // --- cPatFilter ------------------------------------------------------------ +//#define DEBUG_PAT_PMT +#ifdef DEBUG_PAT_PMT +#define DBGLOG(a...) { cString s = cString::sprintf(a); fprintf(stderr, "%s\n", *s); dsyslog("%s", *s); } +#else +#define DBGLOG(a...) +#endif + cPatFilter::cPatFilter(void) { - pmtIndex = 0; - pmtPid = 0; - pmtSid = 0; - lastPmtScan = 0; - numPmtEntries = 0; + Trigger(0); Set(0x00, 0x00); // PAT } void cPatFilter::SetStatus(bool On) { + cMutexLock MutexLock(&mutex); + DBGLOG("PAT filter set status %d", On); cFilter::SetStatus(On); - pmtIndex = 0; - pmtPid = 0; - pmtSid = 0; - lastPmtScan = 0; - numPmtEntries = 0; + Trigger(); } -void cPatFilter::Trigger(void) +void cPatFilter::Trigger(int Sid) { + cMutexLock MutexLock(&mutex); + patVersion = -1; + pmtIndex = -1; numPmtEntries = 0; + if (Sid >= 0) { + sid = Sid; + DBGLOG("PAT filter trigger SID %d", Sid); + } } -bool cPatFilter::PmtVersionChanged(int PmtPid, int Sid, int Version) +bool cPatFilter::PmtVersionChanged(int PmtPid, int Sid, int Version, bool SetNewVersion) { - uint64_t v = Version; - v <<= 32; - uint64_t id = (PmtPid | (Sid << 16)) & 0x00000000FFFFFFFFLL; + int Id = MakePmtId(PmtPid, Sid); for (int i = 0; i < numPmtEntries; i++) { - if ((pmtVersion[i] & 0x00000000FFFFFFFFLL) == id) { - bool Changed = (pmtVersion[i] & 0x000000FF00000000LL) != v; - if (Changed) - pmtVersion[i] = id | v; - return Changed; + if (pmtId[i] == Id) { + if (pmtVersion[i] != Version) { + if (SetNewVersion) + pmtVersion[i] = Version; + else + DBGLOG("PMT %d %2d %5d %2d -> %2d", Transponder(), i, PmtPid, pmtVersion[i], Version); + return true; + } + break; } } - if (numPmtEntries < MAXPMTENTRIES) - pmtVersion[numPmtEntries++] = id | v; - return true; + return false; +} + +void cPatFilter::SwitchToNextPmtPid(void) +{ + if (pmtIndex >= 0) { + Del(GetPmtPid(pmtIndex), SI::TableIdPMT); + pmtIndex = (pmtIndex + 1) % numPmtEntries; + Add(GetPmtPid(pmtIndex), SI::TableIdPMT); + } } void cPatFilter::Process(u_short Pid, u_char Tid, const u_char *Data, int Length) { + cMutexLock MutexLock(&mutex); if (Pid == 0x00) { - if (Tid == 0x00) { - if (pmtPid && time(NULL) - lastPmtScan > PMT_SCAN_TIMEOUT) { - Del(pmtPid, 0x02); - pmtPid = 0; - pmtIndex++; - lastPmtScan = time(NULL); - } - if (!pmtPid) { - SI::PAT pat(Data, false); - if (!pat.CheckCRCAndParse()) - return; + if (Tid == SI::TableIdPAT) { + SI::PAT pat(Data, false); + if (!pat.CheckCRCAndParse()) + return; + if (pat.getVersionNumber() != patVersion) { + DBGLOG("PAT %d/%d %d %d -> %d", pat.getSectionNumber(), pat.getLastSectionNumber(), Transponder(), patVersion, pat.getVersionNumber()); + if (pmtIndex >= 0) { + Del(GetPmtPid(pmtIndex), SI::TableIdPMT); + pmtIndex = -1; + } + numPmtEntries = 0; SI::PAT::Association assoc; - int Index = 0; for (SI::Loop::Iterator it; pat.associationLoop.getNext(assoc, it); ) { - if (!assoc.isNITPid()) { - if (Index++ >= pmtIndex && Channels.GetByServiceID(Source(), Transponder(), assoc.getServiceId())) { - pmtPid = assoc.getPid(); - pmtSid = assoc.getServiceId(); - Add(pmtPid, 0x02); - break; + if (!assoc.isNITPid() && numPmtEntries < MAXPMTENTRIES) { + DBGLOG(" PMT pid %2d %5d SID %5d", numPmtEntries, assoc.getPid(), assoc.getServiceId()); + pmtId[numPmtEntries] = MakePmtId(assoc.getPid(), assoc.getServiceId()); + pmtVersion[numPmtEntries] = -1; + if (sid == assoc.getServiceId()) { + pmtIndex = numPmtEntries; + DBGLOG("sid = %d pmtIndex = %d", sid, pmtIndex); } + numPmtEntries++; } } - if (!pmtPid) + if (numPmtEntries > 0 && pmtIndex < 0) pmtIndex = 0; + Add(GetPmtPid(pmtIndex), SI::TableIdPMT); + patVersion = pat.getVersionNumber(); + timer.Set(PMT_SCAN_TIMEOUT); } } } - else if (Pid == pmtPid && Tid == SI::TableIdPMT && Source() && Transponder()) { + else if (Tid == SI::TableIdPMT && Source() && Transponder()) { + timer.Set(PMT_SCAN_TIMEOUT); SI::PMT pmt(Data, false); if (!pmt.CheckCRCAndParse()) return; - if (pmt.getServiceId() != pmtSid) - return; // skip broken PMT records - if (!PmtVersionChanged(pmtPid, pmt.getTableIdExtension(), pmt.getVersionNumber())) { - lastPmtScan = 0; // this triggers the next scan + if (!PmtVersionChanged(Pid, pmt.getTableIdExtension(), pmt.getVersionNumber())) { + SwitchToNextPmtPid(); return; } - if (!Channels.Lock(true, 10)) { - numPmtEntries = 0; // to make sure we try again + if (!Channels.Lock(true, 10)) return; - } + PmtVersionChanged(Pid, pmt.getTableIdExtension(), pmt.getVersionNumber(), true); + SwitchToNextPmtPid(); cChannel *Channel = Channels.GetByServiceID(Source(), Transponder(), pmt.getServiceId()); if (Channel) { SI::CaDescriptor *d; @@ -552,7 +572,12 @@ void cPatFilter::Process(u_short Pid, u_char Tid, const u_char *Data, int Length } Channel->SetCaDescriptors(CaDescriptorHandler.AddCaDescriptors(CaDescriptors)); } - lastPmtScan = 0; // this triggers the next scan Channels.Unlock(); } + if (timer.TimedOut()) { + if (pmtIndex >= 0) + DBGLOG("PMT timeout %d", pmtIndex); + SwitchToNextPmtPid(); + timer.Set(PMT_SCAN_TIMEOUT); + } } diff --git a/pat.h b/pat.h index 08da051f..dd8f08ce 100644 --- a/pat.h +++ b/pat.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: pat.h 2.3 2013/02/16 15:20:24 kls Exp $ + * $Id: pat.h 2.3.1.1 2014/02/18 14:12:24 kls Exp $ */ #ifndef __PAT_H @@ -12,24 +12,30 @@ #include #include "filter.h" +#include "thread.h" #define MAXPMTENTRIES 64 class cPatFilter : public cFilter { private: - time_t lastPmtScan; + cMutex mutex; + cTimeMs timer; + int patVersion; int pmtIndex; - int pmtPid; - int pmtSid; - uint64_t pmtVersion[MAXPMTENTRIES]; + int pmtId[MAXPMTENTRIES]; + int pmtVersion[MAXPMTENTRIES]; int numPmtEntries; - bool PmtVersionChanged(int PmtPid, int Sid, int Version); + int sid; + int GetPmtPid(int Index) { return pmtId[Index] & 0x0000FFFF; } + int MakePmtId(int PmtPid, int Sid) { return PmtPid | (Sid << 16); } + bool PmtVersionChanged(int PmtPid, int Sid, int Version, bool SetNewVersion = false); + void SwitchToNextPmtPid(void); protected: virtual void Process(u_short Pid, u_char Tid, const u_char *Data, int Length); public: cPatFilter(void); virtual void SetStatus(bool On); - void Trigger(void); + void Trigger(int Sid = -1); }; int GetCaDescriptors(int Source, int Transponder, int ServiceId, const int *CaSystemIds, int BufSize, uchar *Data, int EsPid); diff --git a/sdt.c b/sdt.c index 5f2502b0..8eeebc40 100644 --- a/sdt.c +++ b/sdt.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: sdt.c 2.5 2010/05/16 14:23:21 kls Exp $ + * $Id: sdt.c 2.5.1.1 2014/02/18 14:12:33 kls Exp $ */ #include "sdt.h" @@ -92,7 +92,7 @@ void cSdtFilter::Process(u_short Pid, u_char Tid, const u_char *Data, int Length } else if (*pn && Setup.UpdateChannels >= 4) { channel = Channels.NewChannel(Channel(), pn, ps, pp, sdt.getOriginalNetworkId(), sdt.getTransportStreamId(), SiSdtService.getServiceId()); - patFilter->Trigger(); + patFilter->Trigger(SiSdtService.getServiceId()); } } default: ; @@ -118,7 +118,7 @@ void cSdtFilter::Process(u_short Pid, u_char Tid, const u_char *Data, int Length cChannel *link = Channels.GetByChannelID(tChannelID(Source(), Service.getOriginalNetworkId(), Service.getTransportStream(), Service.getServiceId())); if (!link && Setup.UpdateChannels >= 4) { link = Channels.NewChannel(Channel(), "NVOD", "", "", Service.getOriginalNetworkId(), Service.getTransportStream(), Service.getServiceId()); - patFilter->Trigger(); + patFilter->Trigger(Service.getServiceId()); } if (link) { if (!LinkChannels)