summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--HISTORY8
-rw-r--r--eit.c43
-rw-r--r--eit.h23
-rw-r--r--filter.c53
-rw-r--r--filter.h37
-rw-r--r--nit.c10
-rw-r--r--pat.c6
-rw-r--r--sdt.c10
8 files changed, 155 insertions, 35 deletions
diff --git a/HISTORY b/HISTORY
index c9adec0f..c1b1e5c9 100644
--- a/HISTORY
+++ b/HISTORY
@@ -9578,7 +9578,7 @@ Video Disk Recorder Revision History
given (reported by Manuel Reimer).
- Fixed handling $(PKG_CONFIG) in newplugin (thanks to Winfried Köhler).
-2021-01-19:
+2021-03-16:
- Fixed strreplace() to handle NULL strings (reported by Jürgen Schneider).
- Somewhere down the road the 'x' bit of Doxyfile.filter got lost, so the
@@ -9605,3 +9605,9 @@ Video Disk Recorder Revision History
Jürgen Schneider).
- Added some missing user command calls for copying, renaming and moving recordings
(thanks to Peter Bieringer).
+- Improved cSectionSyncer to make sure that no sections are missed, and to allow
+ handling partially used segments (as in the EIT) and processing sections in random
+ order. Segment syncing is now done with the two member functions Check() and
+ Processed(). The old functions Sync() and Repeat() are deprecated and may be
+ removed in a future version. See the comments in filter.h for a description on
+ how to use these new function.
diff --git a/eit.c b/eit.c
index 9c3f6f61..e1f52993 100644
--- a/eit.c
+++ b/eit.c
@@ -8,7 +8,7 @@
* Robert Schneider <Robert.Schneider@web.de> and Rolf Hakenes <hakenes@hippomi.de>.
* Adapted to 'libsi' for VDR 1.3.0 by Marcel Wiesweg <marcel.wiesweg@gmx.de>.
*
- * $Id: eit.c 4.11 2020/11/28 21:45:05 kls Exp $
+ * $Id: eit.c 5.1 2021/03/16 15:10:54 kls Exp $
*/
#include "eit.h"
@@ -22,6 +22,28 @@
#define DBGEIT 0
+// --- cEitTables ------------------------------------------------------------
+
+bool cEitTables::Check(uchar TableId, uchar Version, int SectionNumber)
+{
+ int ti = Index(TableId);
+ return sectionSyncer[ti].Check(Version, SectionNumber);
+}
+
+bool cEitTables::Processed(uchar TableId, uchar LastTableId, int SectionNumber, int LastSectionNumber, int SegmentLastSectionNumber)
+{
+ int ti = Index(TableId);
+ int LastIndex = Index(LastTableId);
+ if (sectionSyncer[ti].Processed(SectionNumber, LastSectionNumber, SegmentLastSectionNumber)) {
+ for (int i = 0; i <= LastIndex; i++) {
+ if (!sectionSyncer[i].Complete())
+ return false;
+ }
+ return true; // all tables have been processed
+ }
+ return false;
+}
+
// --- cEIT ------------------------------------------------------------------
class cEIT : public SI::EIT {
@@ -34,13 +56,13 @@ cEIT::cEIT(cSectionSyncerHash &SectionSyncerHash, int Source, u_char Tid, const
{
if (!CheckCRCAndParse())
return;
- int HashId = Tid + (getServiceId() << 8);
- cSectionSyncerEntry *SectionSyncerEntry = SectionSyncerHash.Get(HashId);
- if (!SectionSyncerEntry) {
- SectionSyncerEntry = new cSectionSyncerEntry;
- SectionSyncerHash.Add(SectionSyncerEntry, HashId);
+ int HashId = getServiceId();
+ cEitTables *EitTables = SectionSyncerHash.Get(HashId);
+ if (!EitTables) {
+ EitTables = new cEitTables;
+ SectionSyncerHash.Add(EitTables, HashId);
}
- bool Process = SectionSyncerEntry->Sync(getVersionNumber(), getSectionNumber(), getLastSectionNumber());
+ bool Process = EitTables->Check(Tid, getVersionNumber(), getSectionNumber());
if (Tid != 0x4E && !Process) // we need to set the 'seen' tag to watch the running status of the present/following event
return;
@@ -50,10 +72,8 @@ cEIT::cEIT(cSectionSyncerHash &SectionSyncerHash, int Source, u_char Tid, const
cStateKey ChannelsStateKey;
cChannels *Channels = cChannels::GetChannelsWrite(ChannelsStateKey, 10);
- if (!Channels) {
- SectionSyncerEntry->Repeat(); // let's not miss any section of the EIT
+ if (!Channels)
return;
- }
tChannelID channelID(Source, getOriginalNetworkId(), getTransportStreamId(), getServiceId());
cChannel *Channel = Channels->GetByChannelID(channelID, true);
if (!Channel || EpgHandlers.IgnoreChannel(Channel)) {
@@ -64,7 +84,6 @@ cEIT::cEIT(cSectionSyncerHash &SectionSyncerHash, int Source, u_char Tid, const
cStateKey SchedulesStateKey;
cSchedules *Schedules = cSchedules::GetSchedulesWrite(SchedulesStateKey, 10);
if (!Schedules) {
- SectionSyncerEntry->Repeat(); // let's not miss any section of the EIT
ChannelsStateKey.Remove(false);
return;
}
@@ -361,6 +380,8 @@ cEIT::cEIT(cSectionSyncerHash &SectionSyncerHash, int Source, u_char Tid, const
EpgHandlers.DropOutdated(pSchedule, SegmentStart, SegmentEnd, Tid, getVersionNumber());
pSchedule->SetModified();
}
+ if (Process)
+ EitTables->Processed(Tid, getLastTableId(), getSectionNumber(), getLastSectionNumber(), getSegmentLastSectionNumber());
SchedulesStateKey.Remove(Modified);
ChannelsStateKey.Remove(ChannelsModified);
EpgHandlers.EndSegmentTransfer(Modified);
diff --git a/eit.h b/eit.h
index c93aabc3..aedf0b56 100644
--- a/eit.h
+++ b/eit.h
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: eit.h 4.2 2017/05/08 21:10:29 kls Exp $
+ * $Id: eit.h 5.1 2021/03/16 15:10:54 kls Exp $
*/
#ifndef __EIT_H
@@ -13,9 +13,26 @@
#include "filter.h"
#include "tools.h"
-class cSectionSyncerEntry : public cListObject, public cSectionSyncer {};
+#define NUM_EIT_TABLES 17
-class cSectionSyncerHash : public cHash<cSectionSyncerEntry> {
+// Event information (or EPG) is broadcast in tables 0x4E and 0x4F for "present/following" events on
+// "this transponder" (0x4E) and "other transponders" (0x4F), as well as 0x50-0x5F ("all events on this
+// transponder) and 0x60-0x6F ("all events on other transponders). Since it's either "this" or "other",
+// we only use one section syncer for 0x4E/0x4F and 16 syncers for either 0x5X or 0x6X.
+
+class cEitTables : public cListObject {
+private:
+ cSectionSyncerRandom sectionSyncer[NUM_EIT_TABLES]; // for tables 0x4E/0x4F and 0x50-0x5F/0x60-0x6F
+ bool complete;
+ int Index(uchar TableId) { return (TableId < 0x50) ? 0 : (TableId & 0x0F) + 1; }
+public:
+ cEitTables(void) { complete = false; }
+ bool Check(uchar TableId, uchar Version, int SectionNumber);
+ bool Processed(uchar TableId, uchar LastTableId, int SectionNumber, int LastSectionNumber, int SegmentLastSectionNumber = -1);
+ bool Complete(void) { return complete; }
+ };
+
+class cSectionSyncerHash : public cHash<cEitTables> {
public:
cSectionSyncerHash(void) : cHash(HASHSIZE, true) {};
};
diff --git a/filter.c b/filter.c
index 742041a7..e1abd574 100644
--- a/filter.c
+++ b/filter.c
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: filter.c 4.3 2017/05/09 08:37:23 kls Exp $
+ * $Id: filter.c 5.1 2021/03/16 15:10:54 kls Exp $
*/
#include "filter.h"
@@ -12,8 +12,9 @@
// --- cSectionSyncer --------------------------------------------------------
-cSectionSyncer::cSectionSyncer(void)
+cSectionSyncer::cSectionSyncer(bool Random)
{
+ random = Random;
Reset();
}
@@ -23,9 +24,56 @@ void cSectionSyncer::Reset(void)
currentSection = -1;
synced = false;
complete = false;
+ segments = 0;
memset(sections, 0x00, sizeof(sections));
}
+bool cSectionSyncer::Check(uchar Version, int SectionNumber)
+{
+ if (Version != currentVersion) {
+ Reset();
+ currentVersion = Version;
+ }
+ if (complete)
+ return false;
+ if (!random) {
+ if (!synced) {
+ if (SectionNumber == 0) {
+ currentSection = 0;
+ synced = true;
+ }
+ else
+ return false;
+ }
+ if (SectionNumber != currentSection)
+ return false;
+ }
+ return !GetSectionFlag(SectionNumber);
+}
+
+bool cSectionSyncer::Processed(int SectionNumber, int LastSectionNumber, int SegmentLastSectionNumber)
+{
+ SetSectionFlag(SectionNumber, true); // the flag for this section
+ if (!random)
+ currentSection++; // expect the next section
+ int Index = SectionNumber / 8; // the segment (byte) in which this section lies
+ uchar b = 0xFF; // all sections in this segment
+ if (SegmentLastSectionNumber < 0 && Index == LastSectionNumber / 8)
+ SegmentLastSectionNumber = LastSectionNumber;
+ if (SegmentLastSectionNumber >= 0) {
+ b >>= 7 - (SegmentLastSectionNumber & 0x07); // limits them up to the last section in this segment
+ if (!random && SectionNumber == SegmentLastSectionNumber)
+ currentSection = (SectionNumber + 8) & ~0x07; // expect first section of next segment
+ }
+ if (sections[Index] == b) // all expected sections in this segment have been received
+ segments |= 1 << Index; // so we set the respective bit in the segments flags
+ uint32_t s = 0xFFFFFFFF; // all segments
+ s >>= 31 - (LastSectionNumber / 8); // limits them up to the last expected segment
+ complete = segments == s;
+ return complete;
+}
+
+#if DEPRECATED_SECTIONSYNCER_SYNC_REPEAT
void cSectionSyncer::Repeat(void)
{
SetSectionFlag(currentSection, false);
@@ -52,6 +100,7 @@ bool cSectionSyncer::Sync(uchar Version, int Number, int LastNumber)
complete = true;
return Result;
}
+#endif
// --- cFilterData -----------------------------------------------------------
diff --git a/filter.h b/filter.h
index b8198345..deb75162 100644
--- a/filter.h
+++ b/filter.h
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: filter.h 4.3 2017/05/09 08:37:23 kls Exp $
+ * $Id: filter.h 5.1 2021/03/16 15:10:54 kls Exp $
*/
#ifndef __FILTER_H
@@ -13,21 +13,52 @@
#include <sys/types.h>
#include "tools.h"
+#define DEPRECATED_SECTIONSYNCER_SYNC_REPEAT 1
+
class cSectionSyncer {
private:
int currentVersion;
int currentSection;
+ bool random;
bool synced;
bool complete;
+ uint32_t segments; // bit flags for the 32 segments
uchar sections[32]; // holds 32 * 8 = 256 bits, as flags for the sections
void SetSectionFlag(uchar Section, bool On) { if (On) sections[Section / 8] |= (1 << (Section % 8)); else sections[Section / 8] &= ~(1 << (Section % 8)); }
bool GetSectionFlag(uchar Section) { return sections[Section / 8] & (1 << (Section % 8)); }
public:
- cSectionSyncer(void);
+ cSectionSyncer(bool Random = false);
+ ///< Sets up a new section syncer.
+ ///< Call Check() to see whether a given section needs processing. Once the section
+ ///< has been processed, call Processed() to mark it as such. If, for any reason,
+ ///< processing is not completed after calling Check(), nothing special needs to be
+ ///< done. Just don't call Processed() and a later call to Check() with the same
+ ///< SectionNumber will return true again.
+ ///< If Random is true, sections can be processed in random order, not necessarily
+ ///< starting with section 0.
void Reset(void);
- void Repeat(void);
+ bool Check(uchar Version, int SectionNumber);
+ ///< Returns true if Version is not the current version, or the given SectionNumber has not
+ ///< been marked as processed, yet. Sections are handled in ascending order, starting at 0,
+ ///< unless Random is true in the constructor call.
+ bool Processed(int SectionNumber, int LastSectionNumber, int SegmentLastSectionNumber = -1);
+ ///< Marks the given SectionNumber as processed.
+ ///< LastSectionNumber is used to determine whether all sections have been processed.
+ ///< SegmentLastSectionNumber can be given to handle partially filled segments (like,
+ ///< for instance in the EIT).
+ ///< Returns true if all sections have been processed.
bool Complete(void) { return complete; }
+ ///< Returns true if all sections have been processed.
+#if DEPRECATED_SECTIONSYNCER_SYNC_REPEAT
+ void Repeat(void);
bool Sync(uchar Version, int Number, int LastNumber);
+#endif
+ };
+
+class cSectionSyncerRandom : public cSectionSyncer {
+ ///< Helper class for having an array of random section syncers.
+public:
+ cSectionSyncerRandom(void): cSectionSyncer(true) {}
};
class cFilterData : public cListObject {
diff --git a/nit.c b/nit.c
index 785aba52..980a3b2d 100644
--- a/nit.c
+++ b/nit.c
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: nit.c 4.9 2019/05/31 13:25:00 kls Exp $
+ * $Id: nit.c 5.1 2021/03/16 15:10:54 kls Exp $
*/
#include "nit.h"
@@ -43,7 +43,7 @@ void cNitFilter::Process(u_short Pid, u_char Tid, const u_char *Data, int Length
SI::NIT nit(Data, false);
if (!nit.CheckCRCAndParse())
return;
- if (!sectionSyncer.Sync(nit.getVersionNumber(), nit.getSectionNumber(), nit.getLastSectionNumber()))
+ if (!sectionSyncer.Check(nit.getVersionNumber(), nit.getSectionNumber()))
return;
if (DebugNit) {
char NetworkName[MAXNETWORKNAME] = "";
@@ -63,10 +63,8 @@ void cNitFilter::Process(u_short Pid, u_char Tid, const u_char *Data, int Length
}
cStateKey StateKey;
cChannels *Channels = cChannels::GetChannelsWrite(StateKey, 10);
- if (!Channels) {
- sectionSyncer.Repeat(); // let's not miss any section of the NIT
+ if (!Channels)
return;
- }
bool ChannelsModified = false;
SI::NIT::TransportStream ts;
for (SI::Loop::Iterator it; nit.transportStreamLoop.getNext(ts, it); ) {
@@ -371,7 +369,7 @@ void cNitFilter::Process(u_short Pid, u_char Tid, const u_char *Data, int Length
delete d;
}
}
- if (nit.getSectionNumber() == nit.getLastSectionNumber()) {
+ if (sectionSyncer.Processed(nit.getSectionNumber(), nit.getLastSectionNumber())) {
dbgnit(" trigger sdtFilter for current tp %d\n", Transponder());
sdtFilter->Trigger(Source());
}
diff --git a/pat.c b/pat.c
index 72164c49..39009b14 100644
--- a/pat.c
+++ b/pat.c
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: pat.c 4.9 2020/12/18 14:51:57 kls Exp $
+ * $Id: pat.c 5.1 2021/03/16 15:10:54 kls Exp $
*/
#include "pat.h"
@@ -424,7 +424,7 @@ void cPatFilter::Process(u_short Pid, u_char Tid, const u_char *Data, int Length
SI::PAT pat(Data, false);
if (!pat.CheckCRCAndParse())
return;
- if (sectionSyncer.Sync(pat.getVersionNumber(), pat.getSectionNumber(), pat.getLastSectionNumber())) {
+ if (sectionSyncer.Check(pat.getVersionNumber(), pat.getSectionNumber())) {
DBGLOG("PAT %d %d -> %d %d/%d", Transponder(), patVersion, pat.getVersionNumber(), pat.getSectionNumber(), pat.getLastSectionNumber());
if (pat.getVersionNumber() != patVersion) {
if (pat.getLastSectionNumber() > 0)
@@ -457,7 +457,7 @@ void cPatFilter::Process(u_short Pid, u_char Tid, const u_char *Data, int Length
}
}
}
- if (sectionSyncer.Complete()) { // all PAT sections done
+ if (sectionSyncer.Processed(pat.getSectionNumber(), pat.getLastSectionNumber())) { // all PAT sections done
if (pmtPidList.Count() != pmtSidList.Count())
DBGLOG(" PAT %d: shared PMT PIDs", Transponder());
if (pmtSidList.Count() && !activePmt)
diff --git a/sdt.c b/sdt.c
index e6a8f40f..7634761e 100644
--- a/sdt.c
+++ b/sdt.c
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: sdt.c 4.8 2020/06/16 14:50:07 kls Exp $
+ * $Id: sdt.c 5.1 2021/03/16 15:10:54 kls Exp $
*/
#include "sdt.h"
@@ -82,14 +82,12 @@ void cSdtFilter::Process(u_short Pid, u_char Tid, const u_char *Data, int Length
}
if (!(source && Transponder()))
return;
- if (!sectionSyncer.Sync(sdt.getVersionNumber(), sdt.getSectionNumber(), sdt.getLastSectionNumber()))
+ if (!sectionSyncer.Check(sdt.getVersionNumber(), sdt.getSectionNumber()))
return;
cStateKey StateKey;
cChannels *Channels = cChannels::GetChannelsWrite(StateKey, 10);
- if (!Channels) {
- sectionSyncer.Repeat(); // let's not miss any section of the SDT
+ if (!Channels)
return;
- }
dbgsdt("SDT: %2d %2d %2d %s %d\n", sdt.getVersionNumber(), sdt.getSectionNumber(), sdt.getLastSectionNumber(), *cSource::ToString(source), Transponder());
bool ChannelsModified = false;
SI::SDT::Service SiSdtService;
@@ -203,7 +201,7 @@ void cSdtFilter::Process(u_short Pid, u_char Tid, const u_char *Data, int Length
delete LinkChannels;
}
}
- if (sdt.getSectionNumber() == sdt.getLastSectionNumber()) {
+ if (sectionSyncer.Processed(sdt.getSectionNumber(), sdt.getLastSectionNumber())) {
if (Setup.UpdateChannels == 1 || Setup.UpdateChannels >= 3) {
ChannelsModified |= Channels->MarkObsoleteChannels(source, sdt.getOriginalNetworkId(), sdt.getTransportStreamId());
if (source != Source())