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:
parent
0238234c52
commit
0de69c3899
@ -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
|
||||||
|
4
HISTORY
4
HISTORY
@ -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).
|
||||||
|
3
device.c
3
device.c
@ -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
133
pat.c
@ -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
20
pat.h
@ -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
6
sdt.c
@ -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)
|
||||||
|
Loading…
Reference in New Issue
Block a user