vdr 2.7.4
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:
17static bool DebugSdt = false;
18
19#define dbgsdt(a...) if (DebugSdt) fprintf(stderr, a)
20
21// --- cSdtFilter ------------------------------------------------------------
22
24{
28 lastNid = 0;
29 lastTid = 0;
30 patFilter = PatFilter;
32 Set(0x11, 0x42); // SDT actual TS
33}
34
36{
37 cMutexLock MutexLock(&mutex);
39 sectionSyncer.Reset();
40 if (!On)
43}
44
46{
47 cMutexLock MutexLock(&mutex);
48 source = Source;
49}
50
51void 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;
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:
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;
85 if (!sectionSyncer.Check(sdt.getVersionNumber(), sdt.getSectionNumber()))
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;
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();
207 if (sectionSyncer.Processed(sdt.getSectionNumber(), sdt.getLastSectionNumber())) {
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
static cChannels * GetChannelsWrite(cStateKey &StateKey, int TimeoutMs=0)
Gets the list of channels for write access.
Definition channels.c:861
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:1106
bool MarkObsoleteChannels(int Source, int Nid, int Tid)
Definition channels.c:1125
const cChannel * GetByChannelID(tChannelID ChannelID, bool TryWithoutRid=false, bool TryWithoutPolarization=false) const
Definition channels.c:1011
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:182
int Transponder(void)
Returns the transponder of the data delivered to this filter.
Definition filter.c:139
virtual void SetStatus(bool On)
Turns this filter on or off, depending on the value of On.
Definition filter.c:149
int Source(void)
Returns the source of the data delivered to this filter.
Definition filter.c:134
const cChannel * Channel(void)
Returns the channel of the data delivered to this filter.
Definition filter.c:144
void Add(cListObject *Object, cListObject *After=NULL)
Definition tools.c:2175
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
static cString ToString(int Code)
Definition sources.c:52
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:868
cSetup Setup
Definition config.c:372
@ NVODReferenceDescriptorTag
Definition si.h:88
@ ServiceDescriptorTag
Definition si.h:85
#define dbgsdt(a...)
Definition sdt.c:19
static bool DebugSdt
Definition sdt.c:17
char * compactspace(char *s)
Definition tools.c:239
#define dsyslog(a...)
Definition tools.h:37
char * skipspace(const char *s)
Definition tools.h:244
#define Utf8BufSize(s)
Definition tools.h:143