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>
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 <h@realh.co.uk>
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
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).

View File

@ -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);
}

133
pat.c
View File

@ -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);
}
}

20
pat.h
View File

@ -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 <stdint.h>
#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);

6
sdt.c
View File

@ -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)