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

Added handling shared PMT pids and multiple PMT sections

This commit is contained in:
Klaus Schmidinger 2020-06-19 12:19:15 +02:00
parent 54cf10588d
commit 5d39daa13c
4 changed files with 142 additions and 49 deletions

View File

@ -3601,6 +3601,7 @@ Helmut Binder <cco@aon.at>
for adding cMtdHandler::StopDecrypting() for adding cMtdHandler::StopDecrypting()
for adding support for detecting new channels broadcast in HEVC for adding support for detecting new channels broadcast in HEVC
for adding support for detecting 'advanced codec digital radio sound service' for adding support for detecting 'advanced codec digital radio sound service'
for adding handling shared PMT pids and multiple PMT sections
Ulrich Eckhardt <uli@uli-eckhardt.de> Ulrich Eckhardt <uli@uli-eckhardt.de>
for reporting a problem with shutdown after user inactivity in case a plugin is for reporting a problem with shutdown after user inactivity in case a plugin is

View File

@ -9453,7 +9453,7 @@ Video Disk Recorder Revision History
The version numbers (both VDRVERSNUM and APIVERSNUM) have been bumped to 2.4.2, so The version numbers (both VDRVERSNUM and APIVERSNUM) have been bumped to 2.4.2, so
that plugins can detect the presence of the new cControl::Control(). that plugins can detect the presence of the new cControl::Control().
2020-06-16: Version 2.4.3 2020-06-19: Version 2.4.3
- Added a missing '-D' to the 'plugins' target of the Makefile (thanks to Johann - Added a missing '-D' to the 'plugins' target of the Makefile (thanks to Johann
Friedrichs). Friedrichs).
@ -9474,3 +9474,4 @@ Video Disk Recorder Revision History
- Added support for detecting new channels broadcast in HEVC (thanks to Helmut Binder). - Added support for detecting new channels broadcast in HEVC (thanks to Helmut Binder).
- Added support for detecting 'advanced codec digital radio sound service' (thanks to - Added support for detecting 'advanced codec digital radio sound service' (thanks to
Helmut Binder). Helmut Binder).
- Added handling shared PMT pids and multiple PMT sections (thanks to Helmut Binder).

170
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 4.5 2019/03/15 10:14:35 kls Exp $ * $Id: pat.c 4.6 2020/06/19 12:19:15 kls Exp $
*/ */
#include "pat.h" #include "pat.h"
@ -280,6 +280,54 @@ int GetPmtPid(int Source, int Transponder, int ServiceId)
return CaDescriptorHandler.GetPmtPid(Source, Transponder, ServiceId); return CaDescriptorHandler.GetPmtPid(Source, Transponder, ServiceId);
} }
// --- cPmtPidEntry ----------------------------------------------------------
class cPmtPidEntry : public cListObject {
private:
int pid;
bool complete;
public:
cPmtPidEntry(int Pid);
int Pid(void) { return pid; }
int Complete(void) { return complete; }
void SetComplete(bool State) { complete = State; }
};
cPmtPidEntry::cPmtPidEntry(int Pid)
{
pid = Pid;
complete = false;
}
// --- cPmtSidEntry ----------------------------------------------------------
class cPmtSidEntry : public cListObject {
private:
int sid;
int pid;
cPmtPidEntry *pidEntry;
int version;
bool received;
public:
cPmtSidEntry(int Sid, int Pid, cPmtPidEntry *PidEntry);
int Sid(void) { return sid; }
int Pid(void) { return pid; }
cPmtPidEntry *PidEntry(void) { return pidEntry; }
int Version(void) { return version; }
int Received(void) { return received; }
void SetVersion(int Version) { version = Version; }
void SetReceived(bool State) { received = State; }
};
cPmtSidEntry::cPmtSidEntry(int Sid, int Pid, cPmtPidEntry *PidEntry)
{
sid = Sid;
pid = Pid;
pidEntry = PidEntry;
version = -1;
received = false;
}
// --- cPatFilter ------------------------------------------------------------ // --- cPatFilter ------------------------------------------------------------
//#define DEBUG_PAT_PMT //#define DEBUG_PAT_PMT
@ -307,24 +355,47 @@ void cPatFilter::Trigger(int Sid)
{ {
cMutexLock MutexLock(&mutex); cMutexLock MutexLock(&mutex);
patVersion = -1; patVersion = -1;
pmtIndex = -1; sectionSyncer.Reset();
numPmtEntries = 0; if (Sid != 0 && activePmt)
Del(activePmt->Pid(), SI::TableIdPMT);
activePmt = NULL;
if (Sid >= 0) { if (Sid >= 0) {
sid = Sid; sid = Sid;
DBGLOG("PAT filter trigger SID %d", Sid); DBGLOG("PAT filter trigger SID %d", Sid);
} }
} }
bool cPatFilter::PmtPidComplete(int PmtPid)
{
for (cPmtSidEntry *se = pmtSidList.First(); se; se = pmtSidList.Next(se)) {
if (se->Pid() == PmtPid && !se->Received())
return false;
}
return true;
}
void cPatFilter::PmtPidReset(int PmtPid)
{
for (cPmtSidEntry *se = pmtSidList.First(); se; se = pmtSidList.Next(se)) {
if (se->Pid() == PmtPid)
se->SetReceived(false);
}
}
bool cPatFilter::PmtVersionChanged(int PmtPid, int Sid, int Version, bool SetNewVersion) bool cPatFilter::PmtVersionChanged(int PmtPid, int Sid, int Version, bool SetNewVersion)
{ {
int Id = MakePmtId(PmtPid, Sid); int i = 0;
for (int i = 0; i < numPmtEntries; i++) { for (cPmtSidEntry *se = pmtSidList.First(); se; se = pmtSidList.Next(se), i++) {
if (pmtId[i] == Id) { if (se->Sid() == Sid && se->Pid() == PmtPid) {
if (pmtVersion[i] != Version) { if (!se->Received()) {
se->SetReceived(true);
if (PmtPidComplete(PmtPid))
se->PidEntry()->SetComplete(true);
}
if (se->Version() != Version) {
DBGLOG("PMT %d %2d %5d/%d %2d -> %2d", Transponder(), i, PmtPid, Sid, se->Version(), Version);
if (SetNewVersion) if (SetNewVersion)
pmtVersion[i] = Version; se->SetVersion(Version);
else
DBGLOG("PMT %d %2d %5d %2d -> %2d", Transponder(), i, PmtPid, pmtVersion[i], Version);
return true; return true;
} }
break; break;
@ -335,10 +406,12 @@ bool cPatFilter::PmtVersionChanged(int PmtPid, int Sid, int Version, bool SetNew
void cPatFilter::SwitchToNextPmtPid(void) void cPatFilter::SwitchToNextPmtPid(void)
{ {
if (pmtIndex >= 0) { if (activePmt) {
Del(GetPmtPid(pmtIndex), SI::TableIdPMT); Del(activePmt->Pid(), SI::TableIdPMT);
pmtIndex = (pmtIndex + 1) % numPmtEntries; if (!(activePmt = pmtPidList.Next(activePmt)))
Add(GetPmtPid(pmtIndex), SI::TableIdPMT); activePmt = pmtPidList.First();
PmtPidReset(activePmt->Pid());
Add(activePmt->Pid(), SI::TableIdPMT);
} }
} }
@ -350,32 +423,48 @@ void cPatFilter::Process(u_short Pid, u_char Tid, const u_char *Data, int Length
SI::PAT pat(Data, false); SI::PAT pat(Data, false);
if (!pat.CheckCRCAndParse()) if (!pat.CheckCRCAndParse())
return; return;
if (pat.getVersionNumber() != patVersion) { if (sectionSyncer.Sync(pat.getVersionNumber(), pat.getSectionNumber(), pat.getLastSectionNumber())) {
DBGLOG("PAT %d %d -> %d", Transponder(), patVersion, pat.getVersionNumber()); DBGLOG("PAT %d %d -> %d %d/%d", Transponder(), patVersion, pat.getVersionNumber(), pat.getSectionNumber(), pat.getLastSectionNumber());
if (pmtIndex >= 0) { if (pat.getVersionNumber() != patVersion) {
Del(GetPmtPid(pmtIndex), SI::TableIdPMT); if (pat.getLastSectionNumber() > 0)
pmtIndex = -1; DBGLOG(" PAT %d: %d sections", Transponder(), pat.getLastSectionNumber() + 1);
if (activePmt) {
Del(activePmt->Pid(), SI::TableIdPMT);
activePmt = NULL;
}
pmtSidList.Clear();
pmtPidList.Clear();
patVersion = pat.getVersionNumber();
} }
numPmtEntries = 0;
SI::PAT::Association assoc; SI::PAT::Association assoc;
for (SI::Loop::Iterator it; pat.associationLoop.getNext(assoc, it); ) { for (SI::Loop::Iterator it; pat.associationLoop.getNext(assoc, it); ) {
if (!assoc.isNITPid() && numPmtEntries < MAXPMTENTRIES) { if (!assoc.isNITPid()) {
DBGLOG(" PMT pid %2d %5d SID %5d", numPmtEntries, assoc.getPid(), assoc.getServiceId()); int PmtPid = assoc.getPid();
pmtId[numPmtEntries] = MakePmtId(assoc.getPid(), assoc.getServiceId()); cPmtPidEntry *pPid = NULL;
pmtVersion[numPmtEntries] = -1; int PidIndex = 0;
if (sid == assoc.getServiceId()) { for (pPid = pmtPidList.First(); pPid && pPid->Pid() != PmtPid; pPid = pmtPidList.Next(pPid))
pmtIndex = numPmtEntries; PidIndex++;
DBGLOG("sid = %d pmtIndex = %d", sid, pmtIndex); if (!pPid) { // new PMT Pid
pPid = new cPmtPidEntry(PmtPid);
pmtPidList.Add(pPid);
}
pmtSidList.Add(new cPmtSidEntry(assoc.getServiceId(), PmtPid, pPid));
DBGLOG(" PMT pid %2d/%2d %5d SID %5d", PidIndex, pmtSidList.Count() - 1, PmtPid, assoc.getServiceId());
if (sid == assoc.getServiceId()) {
activePmt = pPid;
DBGLOG("sid = %d pidIndex = %d", sid, PidIndex);
} }
numPmtEntries++;
} }
} }
if (numPmtEntries > 0 && pmtIndex < 0) if (sectionSyncer.Complete()) { // all PAT sections done
pmtIndex = 0; if (pmtPidList.Count() != pmtSidList.Count())
if (pmtIndex >= 0) DBGLOG(" PAT %d: shared PMT PIDs", Transponder());
Add(GetPmtPid(pmtIndex), SI::TableIdPMT); if (pmtSidList.Count() && !activePmt)
patVersion = pat.getVersionNumber(); activePmt = pmtPidList.First();
timer.Set(PMT_SCAN_TIMEOUT); if (activePmt)
Add(activePmt->Pid(), SI::TableIdPMT);
timer.Set(PMT_SCAN_TIMEOUT);
}
} }
} }
} }
@ -384,8 +473,9 @@ void cPatFilter::Process(u_short Pid, u_char Tid, const u_char *Data, int Length
SI::PMT pmt(Data, false); SI::PMT pmt(Data, false);
if (!pmt.CheckCRCAndParse()) if (!pmt.CheckCRCAndParse())
return; return;
if (!PmtVersionChanged(Pid, pmt.getTableIdExtension(), pmt.getVersionNumber())) { if (!PmtVersionChanged(Pid, pmt.getTableIdExtension(), pmt.getVersionNumber(), true)) {
SwitchToNextPmtPid(); if (activePmt && activePmt->Complete())
SwitchToNextPmtPid();
return; return;
} }
cStateKey StateKey; cStateKey StateKey;
@ -393,8 +483,8 @@ void cPatFilter::Process(u_short Pid, u_char Tid, const u_char *Data, int Length
if (!Channels) if (!Channels)
return; return;
bool ChannelsModified = false; bool ChannelsModified = false;
PmtVersionChanged(Pid, pmt.getTableIdExtension(), pmt.getVersionNumber(), true); if (activePmt && activePmt->Complete())
SwitchToNextPmtPid(); 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;
@ -636,8 +726,8 @@ void cPatFilter::Process(u_short Pid, u_char Tid, const u_char *Data, int Length
StateKey.Remove(ChannelsModified); StateKey.Remove(ChannelsModified);
} }
if (timer.TimedOut()) { if (timer.TimedOut()) {
if (pmtIndex >= 0) if (activePmt)
DBGLOG("PMT timeout %d", pmtIndex); DBGLOG("PMT timeout Pid %d", activePmt->Pid());
SwitchToNextPmtPid(); SwitchToNextPmtPid();
timer.Set(PMT_SCAN_TIMEOUT); timer.Set(PMT_SCAN_TIMEOUT);
} }

17
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 4.1 2016/12/23 14:03:24 kls Exp $ * $Id: pat.h 4.2 2020/06/19 12:19:15 kls Exp $
*/ */
#ifndef __PAT_H #ifndef __PAT_H
@ -14,20 +14,21 @@
#include "filter.h" #include "filter.h"
#include "thread.h" #include "thread.h"
#define MAXPMTENTRIES 64 class cPmtPidEntry;
class cPmtSidEntry;
class cPatFilter : public cFilter { class cPatFilter : public cFilter {
private: private:
cMutex mutex; cMutex mutex;
cTimeMs timer; cTimeMs timer;
int patVersion; int patVersion;
int pmtIndex;
int pmtId[MAXPMTENTRIES];
int pmtVersion[MAXPMTENTRIES];
int numPmtEntries;
int sid; int sid;
int GetPmtPid(int Index) { return pmtId[Index] & 0x0000FFFF; } cPmtPidEntry *activePmt;
int MakePmtId(int PmtPid, int Sid) { return PmtPid | (Sid << 16); } cList<cPmtPidEntry> pmtPidList;
cList<cPmtSidEntry> pmtSidList;
cSectionSyncer sectionSyncer;
bool PmtPidComplete(int PmtPid);
void PmtPidReset(int PmtPid);
bool PmtVersionChanged(int PmtPid, int Sid, int Version, bool SetNewVersion = false); bool PmtVersionChanged(int PmtPid, int Sid, int Version, bool SetNewVersion = false);
void SwitchToNextPmtPid(void); void SwitchToNextPmtPid(void);
protected: protected: