vdr  2.6.1
sdt.c
Go to the documentation of this file.
1 /*
2  * sdt.c: SDT section filter
3  *
4  * See the main source file 'vdr.c' for copyright information and
5  * how to reach the author.
6  *
7  * $Id: sdt.c 5.2 2021/06/21 20:13:55 kls Exp $
8  */
9 
10 #include "sdt.h"
11 #include "channels.h"
12 #include "config.h"
13 #include "libsi/section.h"
14 #include "libsi/descriptor.h"
15 
16 // Set to 'true' for debug output:
17 static bool DebugSdt = false;
18 
19 #define dbgsdt(a...) if (DebugSdt) fprintf(stderr, a)
20 
21 // --- cSdtFilter ------------------------------------------------------------
22 
24 {
27  lastTransponder = 0;
28  lastNid = 0;
29  lastTid = 0;
30  patFilter = PatFilter;
32  Set(0x11, 0x42); // SDT actual TS
33 }
34 
35 void cSdtFilter::SetStatus(bool On)
36 {
37  cMutexLock MutexLock(&mutex);
40  if (!On)
43 }
44 
45 void cSdtFilter::Trigger(int Source)
46 {
47  cMutexLock MutexLock(&mutex);
48  source = Source;
49 }
50 
51 void cSdtFilter::Process(u_short Pid, u_char Tid, const u_char *Data, int Length)
52 {
53  cMutexLock MutexLock(&mutex);
54  SI::SDT sdt(Data, false);
55  if (!sdt.CheckCRCAndParse())
56  return;
57  if (transponderState == tsUnknown) {
58  // The transponder can be verified with any section, no sync required:
59  int Nid = sdt.getOriginalNetworkId();
60  int Tid = sdt.getTransportStreamId();
62  // We expect a change in NID/TID:
63  if (Nid && Tid && Nid == lastNid && Tid == lastTid) {
65  dsyslog("SDT: channel %d NID/TID (%d/%d) not found, got %d/%d", Channel()->Number(), Channel()->Nid(), Channel()->Tid(), Nid, Tid);
66  return;
67  }
68  }
69  // NID/TID is acceptable:
70  lastSource = Source();
72  lastNid = Nid;
73  lastTid = Tid;
74  if (Nid == Channel()->Nid() && Tid == Channel()->Tid()) {
75  // NID/TID correspond with the channel data:
77  }
78  else {
79  // NID/TID differ from the channel data, but we accept it, since this *is* the data for this transponder:
81  }
82  }
83  if (!(source && Transponder()))
84  return;
86  return;
87  cStateKey StateKey;
88  cChannels *Channels = cChannels::GetChannelsWrite(StateKey, 10);
89  if (!Channels)
90  return;
91  dbgsdt("SDT: %2d %2d %2d %s %d\n", sdt.getVersionNumber(), sdt.getSectionNumber(), sdt.getLastSectionNumber(), *cSource::ToString(source), Transponder());
92  bool ChannelsModified = false;
93  bool TriggerPat = false;
94  SI::SDT::Service SiSdtService;
95  for (SI::Loop::Iterator it; sdt.serviceLoop.getNext(SiSdtService, it); ) {
97  if (!Channel)
98  Channel = Channels->GetByChannelID(tChannelID(source, 0, Transponder(), SiSdtService.getServiceId()));
99  if (Channel)
100  Channel->SetSeen();
101 
102  cLinkChannels *LinkChannels = NULL;
103  SI::Descriptor *d;
104  for (SI::Loop::Iterator it2; (d = SiSdtService.serviceDescriptors.getNext(it2)); ) {
105  switch (d->getDescriptorTag()) {
108  switch (sd->getServiceType()) {
109  case 0x01: // digital television service
110  case 0x02: // digital radio sound service
111  case 0x04: // NVOD reference service
112  case 0x05: // NVOD time-shifted service
113  case 0x0A: // advanced codec digital radio sound service
114  case 0x16: // digital SD television service
115  case 0x19: // digital HD television service
116  case 0x1F: // HEVC digital television service
117  case 0x20: // HEVC UHD digital television service
118  {
119  char NameBuf[Utf8BufSize(1024)];
120  char ShortNameBuf[Utf8BufSize(1024)];
121  char ProviderNameBuf[Utf8BufSize(1024)];
122  sd->serviceName.getText(NameBuf, ShortNameBuf, sizeof(NameBuf), sizeof(ShortNameBuf));
123  char *pn = compactspace(NameBuf);
124  char *ps = compactspace(ShortNameBuf);
125  if (!*ps && cSource::IsCable(source)) {
126  // Some cable providers don't mark short channel names according to the
127  // standard, but rather go their own way and use "name>short name":
128  char *p = strchr(pn, '>'); // fix for UPC Wien
129  if (p && p > pn) {
130  *p++ = 0;
131  strcpy(ShortNameBuf, skipspace(p));
132  }
133  }
134  // Avoid ',' in short name (would cause trouble in channels.conf):
135  for (char *p = ShortNameBuf; *p; p++) {
136  if (*p == ',')
137  *p = '.';
138  }
139  sd->providerName.getText(ProviderNameBuf, sizeof(ProviderNameBuf));
140  char *pp = compactspace(ProviderNameBuf);
141  if (Channel) {
142  ChannelsModified |= Channel->SetId(Channels, sdt.getOriginalNetworkId(), sdt.getTransportStreamId(), SiSdtService.getServiceId());
143  if (Setup.UpdateChannels == 1 || Setup.UpdateChannels >= 3)
144  ChannelsModified |= Channel->SetName(pn, ps, pp);
145  // Using SiSdtService.getFreeCaMode() is no good, because some
146  // tv stations set this flag even for non-encrypted channels :-(
147  // The special value 0xFFFF was supposed to mean "unknown encryption"
148  // and would have been overwritten with real CA values later:
149  // Channel->SetCa(SiSdtService.getFreeCaMode() ? 0xFFFF : 0);
150  }
151  else if (*pn && Setup.UpdateChannels >= 4) {
152  dbgsdt(" %5d %5d %5d %s/%s %d %s\n", sdt.getOriginalNetworkId(), sdt.getTransportStreamId(), SiSdtService.getServiceId(), *cSource::ToString(this->Channel()->Source()), *cSource::ToString(source), this->Channel()->Transponder(), pn);
153  Channel = Channels->NewChannel(this->Channel(), pn, ps, pp, sdt.getOriginalNetworkId(), sdt.getTransportStreamId(), SiSdtService.getServiceId());
154  Channel->SetSource(source); // in case this comes from a satellite with a slightly different position
155  ChannelsModified = true;
156  TriggerPat = true;
157  }
158  }
159  default: ;
160  }
161  }
162  break;
163  // Using the CaIdentifierDescriptor is no good, because some tv stations
164  // just don't use it. The actual CA values are collected in pat.c:
165  /*
166  case SI::CaIdentifierDescriptorTag: {
167  SI::CaIdentifierDescriptor *cid = (SI::CaIdentifierDescriptor *)d;
168  if (Channel) {
169  for (SI::Loop::Iterator it; cid->identifiers.hasNext(it); )
170  Channel->SetCa(Channels, cid->identifiers.getNext(it));
171  }
172  }
173  break;
174  */
178  for (SI::Loop::Iterator it; nrd->serviceLoop.getNext(Service, it); ) {
179  cChannel *link = Channels->GetByChannelID(tChannelID(source, Service.getOriginalNetworkId(), Service.getTransportStream(), Service.getServiceId()));
180  if (!link && Setup.UpdateChannels >= 4) {
181  link = Channels->NewChannel(this->Channel(), "NVOD", "", "", Service.getOriginalNetworkId(), Service.getTransportStream(), Service.getServiceId());
182  ChannelsModified = true;
183  TriggerPat = true;
184  }
185  if (link) {
186  if (!LinkChannels)
187  LinkChannels = new cLinkChannels;
188  LinkChannels->Add(new cLinkChannel(link));
189  ChannelsModified = true;
190  }
191  }
192  }
193  break;
194  default: ;
195  }
196  delete d;
197  }
198  if (LinkChannels) {
199  if (Channel)
200  ChannelsModified |= Channel->SetLinkChannels(LinkChannels);
201  else
202  delete LinkChannels;
203  }
204  }
205  if (TriggerPat)
206  patFilter->Trigger();
208  if (Setup.UpdateChannels == 1 || Setup.UpdateChannels >= 3) {
209  ChannelsModified |= Channels->MarkObsoleteChannels(source, sdt.getOriginalNetworkId(), sdt.getTransportStreamId());
210  if (source != Source())
211  ChannelsModified |= Channels->MarkObsoleteChannels(Source(), sdt.getOriginalNetworkId(), sdt.getTransportStreamId());
212  }
213  }
214  StateKey.Remove(ChannelsModified);
215 }
#define ISTRANSPONDER(f1, f2)
Definition: channels.h:18
bool CheckCRCAndParse()
Definition: si.c:65
Descriptor * getNext(Iterator &it)
Definition: si.c:112
DescriptorTag getDescriptorTag() const
Definition: si.c:100
StructureLoop< Service > serviceLoop
Definition: descriptor.h:281
int getSectionNumber() const
Definition: si.c:88
int getLastSectionNumber() const
Definition: si.c:92
int getVersionNumber() const
Definition: si.c:84
int getServiceId() const
Definition: section.c:132
DescriptorLoop serviceDescriptors
Definition: section.h:135
int getTransportStreamId() const
Definition: section.c:124
StructureLoop< Service > serviceLoop
Definition: section.h:143
int getOriginalNetworkId() const
Definition: section.c:128
int getServiceType() const
Definition: descriptor.c:526
char * getText()
Definition: si.c:222
bool SetName(const char *Name, const char *ShortName, const char *Provider)
Definition: channels.c:262
bool SetLinkChannels(cLinkChannels *LinkChannels)
Definition: channels.c:491
bool SetSource(int Source)
Definition: channels.c:218
void SetSeen(void)
Definition: channels.c:437
bool SetId(cChannels *Channels, int Nid, int Tid, int Sid, int Rid=0)
Definition: channels.c:231
static cChannels * GetChannelsWrite(cStateKey &StateKey, int TimeoutMs=0)
Gets the list of channels for write access.
Definition: channels.c:860
cChannel * NewChannel(const cChannel *Transponder, const char *Name, const char *ShortName, const char *Provider, int Nid, int Tid, int Sid, int Rid=0)
Definition: channels.c:1105
bool MarkObsoleteChannels(int Source, int Nid, int Tid)
Definition: channels.c:1124
const cChannel * GetByChannelID(tChannelID ChannelID, bool TryWithoutRid=false, bool TryWithoutPolarization=false) const
Definition: channels.c:1010
void Set(u_short Pid, u_char Tid, u_char Mask=0xFF)
Sets the given filter data by calling Add() with Sticky = true.
Definition: filter.c:211
int Transponder(void)
Returns the transponder of the data delivered to this filter.
Definition: filter.c:168
virtual void SetStatus(bool On)
Turns this filter on or off, depending on the value of On.
Definition: filter.c:178
int Source(void)
Returns the source of the data delivered to this filter.
Definition: filter.c:163
const cChannel * Channel(void)
Returns the channel of the data delivered to this filter.
Definition: filter.c:173
void Add(cListObject *Object, cListObject *After=NULL)
Definition: tools.c:2184
Definition: pat.h:21
void Trigger(int=0)
Definition: pat.c:400
cMutex mutex
Definition: sdt.h:19
virtual void SetStatus(bool On)
Turns this filter on or off, depending on the value of On.
Definition: sdt.c:35
void Trigger(int Source)
Definition: sdt.c:45
cPatFilter * patFilter
Definition: sdt.h:26
@ tsVerified
Definition: sdt.h:18
@ tsUnknown
Definition: sdt.h:18
@ tsAccepted
Definition: sdt.h:18
@ tsWrong
Definition: sdt.h:18
cSdtFilter(cPatFilter *PatFilter)
Definition: sdt.c:23
enum eTransponderState transponderState
Definition: sdt.h:27
virtual void Process(u_short Pid, u_char Tid, const u_char *Data, int Length)
Processes the data delivered to this filter.
Definition: sdt.c:51
int source
Definition: sdt.h:21
int lastTransponder
Definition: sdt.h:23
cSectionSyncer sectionSyncer
Definition: sdt.h:20
int lastSource
Definition: sdt.h:22
int lastNid
Definition: sdt.h:24
int lastTid
Definition: sdt.h:25
bool Check(uchar Version, int SectionNumber)
Returns true if Version is not the current version, or the given SectionNumber has not been marked as...
Definition: filter.c:31
bool Processed(int SectionNumber, int LastSectionNumber, int SegmentLastSectionNumber=-1)
Marks the given SectionNumber as processed.
Definition: filter.c:54
void Reset(void)
Definition: filter.c:21
int UpdateChannels
Definition: config.h:325
static cString ToString(int Code)
Definition: sources.c:55
static bool IsCable(int Code)
Definition: sources.h:56
@ stNone
Definition: sources.h:18
void Remove(bool IncState=true)
Removes this key from the lock it was previously used with.
Definition: thread.c:859
cSetup Setup
Definition: config.c:372
@ NVODReferenceDescriptorTag
Definition: si.h:89
@ ServiceDescriptorTag
Definition: si.h:86
unsigned char u_char
Definition: headers.h:24
#define dbgsdt(a...)
Definition: sdt.c:19
static bool DebugSdt
Definition: sdt.c:17
char * compactspace(char *s)
Definition: tools.c:231
char * skipspace(const char *s)
Definition: tools.h:241
#define dsyslog(a...)
Definition: tools.h:37
#define Utf8BufSize(s)
Definition: tools.h:143