From 0de69c389993ca0c78c726fe567ae4e155c9a1b9 Mon Sep 17 00:00:00 2001 From: Klaus Schmidinger Date: Tue, 18 Feb 2014 13:12:39 +0100 Subject: [PATCH] Improved PAT/PMT scanning to speed up initial tuning to encrypted channels on transponders with many PAT entries --- CONTRIBUTORS | 2 + HISTORY | 4 +- device.c | 3 +- pat.c | 133 ++++++++++++++++++++++++++++++--------------------- pat.h | 20 +++++--- sdt.c | 6 +-- 6 files changed, 102 insertions(+), 66 deletions(-) diff --git a/CONTRIBUTORS b/CONTRIBUTORS index 7ebbdb69..9721f831 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -3262,6 +3262,8 @@ Christian Paulick Mariusz Bialonczyk for reporting a problem with live streaming of encrypted channels, when there are no CA descriptors, yet, on initial tuning + for reporting that acquiring the CA descriptors takes way too long on transponders + with many PAT entries, and his help in debugging this Tony Houghton for suggesting to add LinkageTypePremiere to libsi/si.h and eit.c to avoid a compiler diff --git a/HISTORY b/HISTORY index b697a6a7..d39d0dc0 100644 --- a/HISTORY +++ b/HISTORY @@ -8170,7 +8170,7 @@ Video Disk Recorder Revision History - Fixed a superfluous call to the skin's SetRecording() function after renaming a recording (reported by Christoph Haubrich). -2014-02-15: Version 2.1.5 +2014-02-18: Version 2.1.5 - Now checking whether the primary device actually has a decoder before retuning the current channel after a change in its parameters. This fixes broken recordings on @@ -8197,3 +8197,5 @@ Video Disk Recorder Revision History - Replaced the NULL pointer assignment in ~cReceiver() to force a segfault with a call to abort() (suggested by Tony Houghten). - Fixed learning keyboard remote control codes (thanks to Lars Hanisch). +- 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 9da5e7ff..901fa2b3 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 3.11 2014/01/21 11:12:01 kls Exp $ + * $Id: device.c 3.12 2014/02/18 13:12:39 kls Exp $ */ #include "device.h" @@ -794,6 +794,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 5246e074..73dc32b6 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 3.2 2014/01/04 11:17:24 kls Exp $ + * $Id: pat.c 3.3 2014/02/18 13:03:19 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 --------------------------------------------------------- @@ -273,94 +272,115 @@ int GetCaPids(int Source, int Transponder, int ServiceId, const int *CaSystemIds // --- 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; @@ -596,7 +616,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 7f04575e..993a9b96 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 3.2 2014/01/04 11:16:48 kls Exp $ + * $Id: pat.h 3.3 2014/02/18 11:22:34 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 c6d0ce54..44c6c9d9 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 3.1 2014/01/04 15:02:31 kls Exp $ + * $Id: sdt.c 3.2 2014/02/18 10:37:50 kls Exp $ */ #include "sdt.h" @@ -94,7 +94,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: ; @@ -120,7 +120,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)