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:
parent
54cf10588d
commit
5d39daa13c
@ -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
|
||||||
|
3
HISTORY
3
HISTORY
@ -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).
|
||||||
|
162
pat.c
162
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 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,41 +423,58 @@ 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 (sectionSyncer.Sync(pat.getVersionNumber(), pat.getSectionNumber(), pat.getLastSectionNumber())) {
|
||||||
|
DBGLOG("PAT %d %d -> %d %d/%d", Transponder(), patVersion, pat.getVersionNumber(), pat.getSectionNumber(), pat.getLastSectionNumber());
|
||||||
if (pat.getVersionNumber() != patVersion) {
|
if (pat.getVersionNumber() != patVersion) {
|
||||||
DBGLOG("PAT %d %d -> %d", Transponder(), patVersion, pat.getVersionNumber());
|
if (pat.getLastSectionNumber() > 0)
|
||||||
if (pmtIndex >= 0) {
|
DBGLOG(" PAT %d: %d sections", Transponder(), pat.getLastSectionNumber() + 1);
|
||||||
Del(GetPmtPid(pmtIndex), SI::TableIdPMT);
|
if (activePmt) {
|
||||||
pmtIndex = -1;
|
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;
|
||||||
|
for (pPid = pmtPidList.First(); pPid && pPid->Pid() != PmtPid; pPid = pmtPidList.Next(pPid))
|
||||||
|
PidIndex++;
|
||||||
|
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()) {
|
if (sid == assoc.getServiceId()) {
|
||||||
pmtIndex = numPmtEntries;
|
activePmt = pPid;
|
||||||
DBGLOG("sid = %d pmtIndex = %d", sid, pmtIndex);
|
DBGLOG("sid = %d pidIndex = %d", sid, PidIndex);
|
||||||
}
|
|
||||||
numPmtEntries++;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (numPmtEntries > 0 && pmtIndex < 0)
|
}
|
||||||
pmtIndex = 0;
|
if (sectionSyncer.Complete()) { // all PAT sections done
|
||||||
if (pmtIndex >= 0)
|
if (pmtPidList.Count() != pmtSidList.Count())
|
||||||
Add(GetPmtPid(pmtIndex), SI::TableIdPMT);
|
DBGLOG(" PAT %d: shared PMT PIDs", Transponder());
|
||||||
patVersion = pat.getVersionNumber();
|
if (pmtSidList.Count() && !activePmt)
|
||||||
|
activePmt = pmtPidList.First();
|
||||||
|
if (activePmt)
|
||||||
|
Add(activePmt->Pid(), SI::TableIdPMT);
|
||||||
timer.Set(PMT_SCAN_TIMEOUT);
|
timer.Set(PMT_SCAN_TIMEOUT);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
else if (Tid == SI::TableIdPMT && Source() && Transponder()) {
|
else if (Tid == SI::TableIdPMT && Source() && Transponder()) {
|
||||||
timer.Set(PMT_SCAN_TIMEOUT);
|
timer.Set(PMT_SCAN_TIMEOUT);
|
||||||
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)) {
|
||||||
|
if (activePmt && activePmt->Complete())
|
||||||
SwitchToNextPmtPid();
|
SwitchToNextPmtPid();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -393,7 +483,7 @@ 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) {
|
||||||
@ -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
17
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 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:
|
||||||
|
Loading…
Reference in New Issue
Block a user