1
0
mirror of https://github.com/VDR4Arch/vdr.git synced 2023-10-10 13:36:52 +02:00

Improved PAT/PMT scanning to speed up initial tuning to encrypted channels on transponders with many PAT entries

This commit is contained in:
Klaus Schmidinger 2014-02-18 13:12:39 +01:00
parent 0238234c52
commit 0de69c3899
6 changed files with 102 additions and 66 deletions

View File

@ -3262,6 +3262,8 @@ Christian Paulick <cpaulick@xeatre.tv>
Mariusz Bialonczyk <manio@skyboo.net> Mariusz Bialonczyk <manio@skyboo.net>
for reporting a problem with live streaming of encrypted channels, when there are no for reporting a problem with live streaming of encrypted channels, when there are no
CA descriptors, yet, on initial tuning 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 <h@realh.co.uk> Tony Houghton <h@realh.co.uk>
for suggesting to add LinkageTypePremiere to libsi/si.h and eit.c to avoid a compiler for suggesting to add LinkageTypePremiere to libsi/si.h and eit.c to avoid a compiler

View File

@ -8170,7 +8170,7 @@ Video Disk Recorder Revision History
- Fixed a superfluous call to the skin's SetRecording() function after renaming a - Fixed a superfluous call to the skin's SetRecording() function after renaming a
recording (reported by Christoph Haubrich). 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 - 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 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 - Replaced the NULL pointer assignment in ~cReceiver() to force a segfault with
a call to abort() (suggested by Tony Houghten). a call to abort() (suggested by Tony Houghten).
- Fixed learning keyboard remote control codes (thanks to Lars Hanisch). - 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).

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * 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" #include "device.h"
@ -794,6 +794,7 @@ eSetChannelResult cDevice::SetChannel(const cChannel *Channel, bool LiveView)
if (SetChannelDevice(Channel, LiveView)) { if (SetChannelDevice(Channel, LiveView)) {
// Start section handling: // Start section handling:
if (sectionHandler) { if (sectionHandler) {
patFilter->Trigger(Channel->Sid());
sectionHandler->SetChannel(Channel); sectionHandler->SetChannel(Channel);
sectionHandler->SetStatus(true); sectionHandler->SetStatus(true);
} }

133
pat.c
View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * 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" #include "pat.h"
@ -12,9 +12,8 @@
#include "channels.h" #include "channels.h"
#include "libsi/section.h" #include "libsi/section.h"
#include "libsi/descriptor.h" #include "libsi/descriptor.h"
#include "thread.h"
#define PMT_SCAN_TIMEOUT 10 // seconds #define PMT_SCAN_TIMEOUT 1000 // ms
// --- cCaDescriptor --------------------------------------------------------- // --- cCaDescriptor ---------------------------------------------------------
@ -273,94 +272,115 @@ int GetCaPids(int Source, int Transponder, int ServiceId, const int *CaSystemIds
// --- cPatFilter ------------------------------------------------------------ // --- 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) cPatFilter::cPatFilter(void)
{ {
pmtIndex = 0; Trigger(0);
pmtPid = 0;
pmtSid = 0;
lastPmtScan = 0;
numPmtEntries = 0;
Set(0x00, 0x00); // PAT Set(0x00, 0x00); // PAT
} }
void cPatFilter::SetStatus(bool On) void cPatFilter::SetStatus(bool On)
{ {
cMutexLock MutexLock(&mutex);
DBGLOG("PAT filter set status %d", On);
cFilter::SetStatus(On); cFilter::SetStatus(On);
pmtIndex = 0; Trigger();
pmtPid = 0;
pmtSid = 0;
lastPmtScan = 0;
numPmtEntries = 0;
} }
void cPatFilter::Trigger(void) void cPatFilter::Trigger(int Sid)
{ {
cMutexLock MutexLock(&mutex);
patVersion = -1;
pmtIndex = -1;
numPmtEntries = 0; 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; int Id = MakePmtId(PmtPid, Sid);
v <<= 32;
uint64_t id = (PmtPid | (Sid << 16)) & 0x00000000FFFFFFFFLL;
for (int i = 0; i < numPmtEntries; i++) { for (int i = 0; i < numPmtEntries; i++) {
if ((pmtVersion[i] & 0x00000000FFFFFFFFLL) == id) { if (pmtId[i] == Id) {
bool Changed = (pmtVersion[i] & 0x000000FF00000000LL) != v; if (pmtVersion[i] != Version) {
if (Changed) if (SetNewVersion)
pmtVersion[i] = id | v; pmtVersion[i] = Version;
return Changed; else
DBGLOG("PMT %d %2d %5d %2d -> %2d", Transponder(), i, PmtPid, pmtVersion[i], Version);
return true;
}
break;
} }
} }
if (numPmtEntries < MAXPMTENTRIES) return false;
pmtVersion[numPmtEntries++] = id | v; }
return true;
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) void cPatFilter::Process(u_short Pid, u_char Tid, const u_char *Data, int Length)
{ {
cMutexLock MutexLock(&mutex);
if (Pid == 0x00) { if (Pid == 0x00) {
if (Tid == 0x00) { if (Tid == SI::TableIdPAT) {
if (pmtPid && time(NULL) - lastPmtScan > PMT_SCAN_TIMEOUT) { SI::PAT pat(Data, false);
Del(pmtPid, 0x02); if (!pat.CheckCRCAndParse())
pmtPid = 0; return;
pmtIndex++; if (pat.getVersionNumber() != patVersion) {
lastPmtScan = time(NULL); DBGLOG("PAT %d/%d %d %d -> %d", pat.getSectionNumber(), pat.getLastSectionNumber(), Transponder(), patVersion, pat.getVersionNumber());
} if (pmtIndex >= 0) {
if (!pmtPid) { Del(GetPmtPid(pmtIndex), SI::TableIdPMT);
SI::PAT pat(Data, false); pmtIndex = -1;
if (!pat.CheckCRCAndParse()) }
return; numPmtEntries = 0;
SI::PAT::Association assoc; SI::PAT::Association assoc;
int Index = 0;
for (SI::Loop::Iterator it; pat.associationLoop.getNext(assoc, it); ) { for (SI::Loop::Iterator it; pat.associationLoop.getNext(assoc, it); ) {
if (!assoc.isNITPid()) { if (!assoc.isNITPid() && numPmtEntries < MAXPMTENTRIES) {
if (Index++ >= pmtIndex && Channels.GetByServiceID(Source(), Transponder(), assoc.getServiceId())) { DBGLOG(" PMT pid %2d %5d SID %5d", numPmtEntries, assoc.getPid(), assoc.getServiceId());
pmtPid = assoc.getPid(); pmtId[numPmtEntries] = MakePmtId(assoc.getPid(), assoc.getServiceId());
pmtSid = assoc.getServiceId(); pmtVersion[numPmtEntries] = -1;
Add(pmtPid, 0x02); if (sid == assoc.getServiceId()) {
break; pmtIndex = numPmtEntries;
DBGLOG("sid = %d pmtIndex = %d", sid, pmtIndex);
} }
numPmtEntries++;
} }
} }
if (!pmtPid) if (numPmtEntries > 0 && pmtIndex < 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); SI::PMT pmt(Data, false);
if (!pmt.CheckCRCAndParse()) if (!pmt.CheckCRCAndParse())
return; return;
if (pmt.getServiceId() != pmtSid) if (!PmtVersionChanged(Pid, pmt.getTableIdExtension(), pmt.getVersionNumber())) {
return; // skip broken PMT records SwitchToNextPmtPid();
if (!PmtVersionChanged(pmtPid, pmt.getTableIdExtension(), pmt.getVersionNumber())) {
lastPmtScan = 0; // this triggers the next scan
return; return;
} }
if (!Channels.Lock(true, 10)) { if (!Channels.Lock(true, 10))
numPmtEntries = 0; // to make sure we try again
return; return;
} PmtVersionChanged(Pid, pmt.getTableIdExtension(), pmt.getVersionNumber(), true);
SwitchToNextPmtPid();
cChannel *Channel = Channels.GetByServiceID(Source(), Transponder(), pmt.getServiceId()); cChannel *Channel = Channels.GetByServiceID(Source(), Transponder(), pmt.getServiceId());
if (Channel) { if (Channel) {
SI::CaDescriptor *d; 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)); Channel->SetCaDescriptors(CaDescriptorHandler.AddCaDescriptors(CaDescriptors));
} }
lastPmtScan = 0; // this triggers the next scan
Channels.Unlock(); Channels.Unlock();
} }
if (timer.TimedOut()) {
if (pmtIndex >= 0)
DBGLOG("PMT timeout %d", pmtIndex);
SwitchToNextPmtPid();
timer.Set(PMT_SCAN_TIMEOUT);
}
} }

20
pat.h
View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * 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 #ifndef __PAT_H
@ -12,24 +12,30 @@
#include <stdint.h> #include <stdint.h>
#include "filter.h" #include "filter.h"
#include "thread.h"
#define MAXPMTENTRIES 64 #define MAXPMTENTRIES 64
class cPatFilter : public cFilter { class cPatFilter : public cFilter {
private: private:
time_t lastPmtScan; cMutex mutex;
cTimeMs timer;
int patVersion;
int pmtIndex; int pmtIndex;
int pmtPid; int pmtId[MAXPMTENTRIES];
int pmtSid; int pmtVersion[MAXPMTENTRIES];
uint64_t pmtVersion[MAXPMTENTRIES];
int numPmtEntries; 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: protected:
virtual void Process(u_short Pid, u_char Tid, const u_char *Data, int Length); virtual void Process(u_short Pid, u_char Tid, const u_char *Data, int Length);
public: public:
cPatFilter(void); cPatFilter(void);
virtual void SetStatus(bool On); 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); int GetCaDescriptors(int Source, int Transponder, int ServiceId, const int *CaSystemIds, int BufSize, uchar *Data, int EsPid);

6
sdt.c
View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * 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" #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) { else if (*pn && Setup.UpdateChannels >= 4) {
channel = Channels.NewChannel(Channel(), pn, ps, pp, sdt.getOriginalNetworkId(), sdt.getTransportStreamId(), SiSdtService.getServiceId()); channel = Channels.NewChannel(Channel(), pn, ps, pp, sdt.getOriginalNetworkId(), sdt.getTransportStreamId(), SiSdtService.getServiceId());
patFilter->Trigger(); patFilter->Trigger(SiSdtService.getServiceId());
} }
} }
default: ; 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())); cChannel *link = Channels.GetByChannelID(tChannelID(Source(), Service.getOriginalNetworkId(), Service.getTransportStream(), Service.getServiceId()));
if (!link && Setup.UpdateChannels >= 4) { if (!link && Setup.UpdateChannels >= 4) {
link = Channels.NewChannel(Channel(), "NVOD", "", "", Service.getOriginalNetworkId(), Service.getTransportStream(), Service.getServiceId()); link = Channels.NewChannel(Channel(), "NVOD", "", "", Service.getOriginalNetworkId(), Service.getTransportStream(), Service.getServiceId());
patFilter->Trigger(); patFilter->Trigger(Service.getServiceId());
} }
if (link) { if (link) {
if (!LinkChannels) if (!LinkChannels)