vdr  2.6.1
pat.c
Go to the documentation of this file.
1 /*
2  * pat.c: PAT section filter
3  *
4  * See the main source file 'vdr.c' for copyright information and
5  * how to reach the author.
6  *
7  * $Id: pat.c 5.4 2021/06/21 20:13:55 kls Exp $
8  */
9 
10 #include "pat.h"
11 #include <malloc.h>
12 #include "channels.h"
13 #include "libsi/section.h"
14 #include "libsi/descriptor.h"
15 
16 #define PMT_SCAN_TIMEOUT 1000 // ms
17 
18 // --- cCaDescriptor ---------------------------------------------------------
19 
20 class cCaDescriptor : public cListObject {
21 private:
22  int caSystem;
23  int caPid;
24  int esPid;
25  int length;
27 public:
28  cCaDescriptor(int CaSystem, int CaPid, int EsPid, int Length, const uchar *Data);
29  virtual ~cCaDescriptor();
30  bool operator== (const cCaDescriptor &arg) const;
31  int CaSystem(void) { return caSystem; }
32  int CaPid(void) { return caPid; }
33  int EsPid(void) { return esPid; }
34  int Length(void) const { return length; }
35  const uchar *Data(void) const { return data; }
36  };
37 
38 cCaDescriptor::cCaDescriptor(int CaSystem, int CaPid, int EsPid, int Length, const uchar *Data)
39 {
41  caPid = CaPid;
42  esPid = EsPid;
43  length = Length + 6;
44  data = MALLOC(uchar, length);
46  data[1] = length - 2;
47  data[2] = (caSystem >> 8) & 0xFF;
48  data[3] = caSystem & 0xFF;
49  data[4] = ((CaPid >> 8) & 0x1F) | 0xE0;
50  data[5] = CaPid & 0xFF;
51  if (Length)
52  memcpy(&data[6], Data, Length);
53 }
54 
56 {
57  free(data);
58 }
59 
61 {
62  return esPid == arg.esPid && length == arg.length && memcmp(data, arg.data, length) == 0;
63 }
64 
65 // --- cCaDescriptors --------------------------------------------------------
66 
67 class cCaDescriptors : public cListObject {
68 private:
69  int source;
71  int serviceId;
72  int pmtPid; // needed for OctopusNet - otherwise irrelevant!
73  int numCaIds;
74  int caIds[MAXCAIDS + 1];
76  void AddCaId(int CaId);
77 public:
78  cCaDescriptors(int Source, int Transponder, int ServiceId, int PmtPid);
79  bool operator== (const cCaDescriptors &arg) const;
80  bool Is(int Source, int Transponder, int ServiceId);
81  bool Is(cCaDescriptors * CaDescriptors);
82  bool Empty(void) { return caDescriptors.Count() == 0; }
83  void AddCaDescriptor(SI::CaDescriptor *d, int EsPid);
84  void GetCaDescriptors(const int *CaSystemIds, cDynamicBuffer &Buffer, int EsPid);
85  int GetCaPids(const int *CaSystemIds, int BufSize, int *Pids);
86  const int GetPmtPid(void) { return pmtPid; };
87  const int *CaIds(void) { return caIds; }
88  };
89 
90 cCaDescriptors::cCaDescriptors(int Source, int Transponder, int ServiceId, int PmtPid)
91 {
92  source = Source;
93  transponder = Transponder;
94  serviceId = ServiceId;
95  pmtPid = PmtPid;
96  numCaIds = 0;
97  caIds[0] = 0;
98 }
99 
101 {
102  const cCaDescriptor *ca1 = caDescriptors.First();
103  const cCaDescriptor *ca2 = arg.caDescriptors.First();
104  while (ca1 && ca2) {
105  if (!(*ca1 == *ca2))
106  return false;
107  ca1 = caDescriptors.Next(ca1);
108  ca2 = arg.caDescriptors.Next(ca2);
109  }
110  return !ca1 && !ca2;
111 }
112 
113 bool cCaDescriptors::Is(int Source, int Transponder, int ServiceId)
114 {
115  return source == Source && transponder == Transponder && serviceId == ServiceId;
116 }
117 
118 bool cCaDescriptors::Is(cCaDescriptors *CaDescriptors)
119 {
120  return Is(CaDescriptors->source, CaDescriptors->transponder, CaDescriptors->serviceId);
121 }
122 
124 {
125  if (numCaIds < MAXCAIDS) {
126  for (int i = 0; i < numCaIds; i++) {
127  if (caIds[i] == CaId)
128  return;
129  }
130  caIds[numCaIds++] = CaId;
131  caIds[numCaIds] = 0;
132  }
133 }
134 
136 {
137  cCaDescriptor *nca = new cCaDescriptor(d->getCaType(), d->getCaPid(), EsPid, d->privateData.getLength(), d->privateData.getData());
138  for (cCaDescriptor *ca = caDescriptors.First(); ca; ca = caDescriptors.Next(ca)) {
139  if (*ca == *nca) {
140  delete nca;
141  return;
142  }
143  }
144  AddCaId(nca->CaSystem());
145  caDescriptors.Add(nca);
146 //#define DEBUG_CA_DESCRIPTORS 1
147 #ifdef DEBUG_CA_DESCRIPTORS
148  char buffer[1024];
149  char *q = buffer;
150  q += sprintf(q, "CAM: %04X %5d %5d %04X %04X -", source, transponder, serviceId, d->getCaType(), EsPid);
151  for (int i = 0; i < nca->Length(); i++)
152  q += sprintf(q, " %02X", nca->Data()[i]);
153  dsyslog("%s", buffer);
154 #endif
155 }
156 
157 // EsPid is to select the "type" of CaDescriptor to be returned
158 // >0 - CaDescriptor for the particular esPid
159 // =0 - common CaDescriptor
160 // <0 - all CaDescriptors regardless of type (old default)
161 
162 void cCaDescriptors::GetCaDescriptors(const int *CaSystemIds, cDynamicBuffer &Buffer, int EsPid)
163 {
164  Buffer.Clear();
165  if (!CaSystemIds || !*CaSystemIds)
166  return;
167  for (cCaDescriptor *d = caDescriptors.First(); d; d = caDescriptors.Next(d)) {
168  if (EsPid < 0 || d->EsPid() == EsPid) {
169  const int *caids = CaSystemIds;
170  do {
171  if (*caids == 0xFFFF || d->CaSystem() == *caids)
172  Buffer.Append(d->Data(), d->Length());
173  } while (*++caids);
174  }
175  }
176 }
177 
178 int cCaDescriptors::GetCaPids(const int *CaSystemIds, int BufSize, int *Pids)
179 {
180  if (!CaSystemIds || !*CaSystemIds)
181  return 0;
182  if (BufSize > 0 && Pids) {
183  int numPids = 0;
184  for (cCaDescriptor *d = caDescriptors.First(); d; d = caDescriptors.Next(d)) {
185  const int *caids = CaSystemIds;
186  do {
187  if (*caids == 0xFFFF || d->CaSystem() == *caids) {
188  if (numPids + 1 < BufSize) {
189  Pids[numPids++] = d->CaPid();
190  Pids[numPids] = 0;
191  }
192  else
193  return -1;
194  }
195  } while (*++caids);
196  }
197  return numPids;
198  }
199  return -1;
200 }
201 
202 // --- cCaDescriptorHandler --------------------------------------------------
203 
204 class cCaDescriptorHandler : public cList<cCaDescriptors> {
205 private:
207 public:
208  int AddCaDescriptors(cCaDescriptors *CaDescriptors);
209  // Returns 0 if this is an already known descriptor,
210  // 1 if it is an all new descriptor with actual contents,
211  // and 2 if an existing descriptor was changed.
212  void GetCaDescriptors(int Source, int Transponder, int ServiceId, const int *CaSystemIds, cDynamicBuffer &Buffer, int EsPid);
213  int GetCaPids(int Source, int Transponder, int ServiceId, const int *CaSystemIds, int BufSize, int *Pids);
214  int GetPmtPid(int Source, int Transponder, int ServiceId);
215  };
216 
218 {
219  cMutexLock MutexLock(&mutex);
220  for (cCaDescriptors *ca = First(); ca; ca = Next(ca)) {
221  if (ca->Is(CaDescriptors)) {
222  if (*ca == *CaDescriptors) {
223  delete CaDescriptors;
224  return 0;
225  }
226  Del(ca);
227  Add(CaDescriptors);
228  return 2;
229  }
230  }
231  Add(CaDescriptors);
232  return CaDescriptors->Empty() ? 0 : 1;
233 }
234 
235 void cCaDescriptorHandler::GetCaDescriptors(int Source, int Transponder, int ServiceId, const int *CaSystemIds, cDynamicBuffer &Buffer, int EsPid)
236 {
237  cMutexLock MutexLock(&mutex);
238  for (cCaDescriptors *ca = First(); ca; ca = Next(ca)) {
239  if (ca->Is(Source, Transponder, ServiceId)) {
240  ca->GetCaDescriptors(CaSystemIds, Buffer, EsPid);
241  break;
242  }
243  }
244 }
245 
246 int cCaDescriptorHandler::GetCaPids(int Source, int Transponder, int ServiceId, const int *CaSystemIds, int BufSize, int *Pids)
247 {
248  cMutexLock MutexLock(&mutex);
249  for (cCaDescriptors *ca = First(); ca; ca = Next(ca)) {
250  if (ca->Is(Source, Transponder, ServiceId))
251  return ca->GetCaPids(CaSystemIds, BufSize, Pids);
252  }
253  return 0;
254 }
255 
256 int cCaDescriptorHandler::GetPmtPid(int Source, int Transponder, int ServiceId)
257 {
258  cMutexLock MutexLock(&mutex);
259  for (cCaDescriptors *ca = First(); ca; ca = Next(ca)) {
260  if (ca->Is(Source, Transponder, ServiceId))
261  return ca->GetPmtPid();
262  }
263  return 0;
264 }
265 
267 
268 void GetCaDescriptors(int Source, int Transponder, int ServiceId, const int *CaSystemIds, cDynamicBuffer &Buffer, int EsPid)
269 {
270  CaDescriptorHandler.GetCaDescriptors(Source, Transponder, ServiceId, CaSystemIds, Buffer, EsPid);
271 }
272 
273 int GetCaPids(int Source, int Transponder, int ServiceId, const int *CaSystemIds, int BufSize, int *Pids)
274 {
275  return CaDescriptorHandler.GetCaPids(Source, Transponder, ServiceId, CaSystemIds, BufSize, Pids);
276 }
277 
278 int GetPmtPid(int Source, int Transponder, int ServiceId)
279 {
280  return CaDescriptorHandler.GetPmtPid(Source, Transponder, ServiceId);
281 }
282 
283 // --- cPmtPidEntry ----------------------------------------------------------
284 
285 class cPmtPidEntry : public cListObject {
286 private:
287  int pid;
288  int count; // the number of SIDs currently requested from this PID
289  int state; // adding/deleting PIDs to/from the filter may only be done from within the Process() function,
290  // otherwise there could be a deadlock between cPatFilter::mutex and cSectionHandler::mutex;
291  // this member tells whether this PID needs to be added to (>0) or deleted from (<0) the filter
292  bool complete; // true if all SIDs on this PID have been received
293 public:
294  cPmtPidEntry(int Pid);
295  int Pid(void) { return pid; }
296  int Count(void) { return count; }
297  int State(void) { int s = state; state = 0; return s; } // returns the current state and resets it
298  void SetState(int State) { state = State; } // 1 = add the PID, -1 = delete the PID, 0 = do nothing
299  void Inc(void) { if (++count == 1) state = 1; }
300  void Dec(void) { if (--count == 0) state = -1; }
301  int Complete(void) { return complete; }
302  void SetComplete(bool State) { complete = State; }
303  };
304 
306 {
307  pid = Pid;
308  count = 0;
309  state = 0;
310  complete = false;
311 }
312 
313 // --- cPmtSidEntry ----------------------------------------------------------
314 
315 class cPmtSidEntry : public cListObject {
316 private:
317  int sid;
318  int pid;
320  int version;
321  bool received;
322 public:
324  int Sid(void) { return sid; }
325  int Pid(void) { return pid; }
326  cPmtPidEntry *PidEntry(void) { return pidEntry; }
327  int Version(void) { return version; }
328  int Received(void) { return received; }
330  void SetReceived(bool State) { received = State; }
331  };
332 
334 {
335  sid = Sid;
336  pid = PidEntry->Pid();
337  pidEntry = PidEntry;
338  version = -1;
339  received = false;
340 }
341 
342 // --- cPmtSidRequest --------------------------------------------------------
343 
344 class cPmtSidRequest : public cListObject {
345 private:
346  int sid;
347  int count; // the number of requests for this SID
348 public:
349  cPmtSidRequest(int Sid) { sid = Sid; count = 1; }
350  int Sid(void) { return sid; }
351  int Count(void) { return count; }
352  void Inc(void) { count++; }
353  void Dec(void) { count--; }
354  };
355 
356 // --- cPatFilter ------------------------------------------------------------
357 
358 //#define DEBUG_PAT_PMT
359 #ifdef DEBUG_PAT_PMT
360 #define DBGLOG(a...) { cString s = cString::sprintf(a); fprintf(stderr, "%s\n", *s); dsyslog("%s", *s); }
361 #else
362 #define DBGLOG(a...) void()
363 #endif
364 
366 {
367  patVersion = -1;
368  activePmt = NULL;
369  transponder = 0;
370  source = 0;
371  Set(0x00, 0x00); // PAT
372 }
373 
375 {
376  cMutexLock MutexLock(&mutex);
377  if (On) { // restart all requested PMT Pids
378  for (cPmtPidEntry *pPid = pmtPidList.First(); pPid; pPid = pmtPidList.Next(pPid))
379  pPid->SetState(pPid->Count() > 0);
380  if (activePmt && activePmt->Count() == 0) {
381  activePmt->SetState(1);
383  }
384  }
385  DBGLOG("PAT filter set status %d", On);
386  cFilter::SetStatus(On);
387 }
388 
390 {
391  if (source != Source() || transponder != Transponder()) {
392  DBGLOG("PAT filter transponder changed from %d/%d to %d/%d", source, transponder, Source(), Transponder());
393  source = Source();
395  return true;
396  }
397  return false;
398 }
399 
401 {
402  cMutexLock MutexLock(&mutex);
403  DBGLOG("PAT filter trigger");
404  patVersion = -1;
406 }
407 
408 void cPatFilter::Request(int Sid)
409 {
410  cMutexLock MutexLock(&mutex);
411  DBGLOG("PAT filter request SID %d", Sid);
412  for (cPmtSidRequest *sr = pmtSidRequestList.First(); sr; sr = pmtSidRequestList.Next(sr)) {
413  if (sr->Sid() == Sid) {
414  sr->Inc();
415  DBGLOG("PAT filter add SID request %d (%d)", Sid, sr->Count());
416  return;
417  }
418  }
419  DBGLOG("PAT filter new SID request %d", Sid);
421  for (cPmtSidEntry *se = pmtSidList.First(); se; se = pmtSidList.Next(se)) {
422  if (se->Sid() == Sid) {
423  cPmtPidEntry *pPid = se->PidEntry();
424  pPid->Inc();
425  DBGLOG(" PMT pid %5d SID %5d (%d)", pPid->Pid(), se->Sid(), pPid->Count());
426  break;
427  }
428  }
429 }
430 
431 void cPatFilter::Release(int Sid)
432 {
433  cMutexLock MutexLock(&mutex);
434  DBGLOG("PAT filter release SID %d", Sid);
435  for (cPmtSidRequest *sr = pmtSidRequestList.First(); sr; sr = pmtSidRequestList.Next(sr)) {
436  if (sr->Sid() == Sid) {
437  sr->Dec();
438  DBGLOG("PAT filter del SID request %d (%d)", Sid, sr->Count());
439  if (sr->Count() == 0) {
441  for (cPmtSidEntry *se = pmtSidList.First(); se; se = pmtSidList.Next(se)) {
442  if (se->Sid() == Sid) {
443  cPmtPidEntry *pPid = se->PidEntry();
444  pPid->Dec();
445  DBGLOG(" PMT pid %5d SID %5d (%d)", pPid->Pid(), se->Sid(), pPid->Count());
446  break;
447  }
448  }
449  }
450  break;
451  }
452  }
453 }
454 
456 {
457  for (cPmtSidRequest *sr = pmtSidRequestList.First(); sr; sr = pmtSidRequestList.Next(sr)) {
458  if (sr->Sid() == Sid)
459  return sr->Count();
460  }
461  return 0;
462 }
463 
465 {
466  for (cPmtSidEntry *se = pmtSidList.First(); se; se = pmtSidList.Next(se)) {
467  if (se->Pid() == PmtPid && !se->Received())
468  return false;
469  }
470  return true;
471 }
472 
473 void cPatFilter::PmtPidReset(int PmtPid)
474 {
475  for (cPmtSidEntry *se = pmtSidList.First(); se; se = pmtSidList.Next(se)) {
476  if (se->Pid() == PmtPid) {
477  se->SetReceived(false);
478  se->PidEntry()->SetComplete(false);
479  }
480  }
481 }
482 
483 bool cPatFilter::PmtVersionChanged(int PmtPid, int Sid, int Version, bool SetNewVersion)
484 {
485  for (cPmtSidEntry *se = pmtSidList.First(); se; se = pmtSidList.Next(se)) {
486  if (se->Sid() == Sid && se->Pid() == PmtPid) {
487  if (!se->Received()) {
488  se->SetReceived(true);
489  se->PidEntry()->SetComplete(PmtPidComplete(PmtPid));
490  }
491  if (se->Version() != Version) {
492  if (SetNewVersion)
493  se->SetVersion(Version);
494  else
495  DBGLOG("PMT %d %5d/%5d %2d -> %2d %d", Transponder(), PmtPid, Sid, se->Version(), Version, NumSidRequests(Sid));
496  return true;
497  }
498  break;
499  }
500  }
501  return false;
502 }
503 
505 {
506  if (activePmt) {
507  if (activePmt->Count() == 0)
509  for (;;) {
511  if (!activePmt || activePmt->Count() == 0)
512  break;
513  }
514  if (activePmt) {
518  }
519  }
520 }
521 
522 void cPatFilter::Process(u_short Pid, u_char Tid, const u_char *Data, int Length)
523 {
524  cMutexLock MutexLock(&mutex);
525  if (TransponderChanged()) {
526  patVersion = -1;
528  }
529  if (patVersion >= 0) {
530  for (cPmtPidEntry *pPid = pmtPidList.First(); pPid; pPid = pmtPidList.Next(pPid)) {
531  int State = pPid->State();
532  if (State > 0)
533  Add(pPid->Pid(), SI::TableIdPMT);
534  else if (State < 0)
535  Del(pPid->Pid(), SI::TableIdPMT);
536  }
537  }
538  else if (Pid != 0x00)
539  return;
540  if (Pid == 0x00) {
541  if (Tid == SI::TableIdPAT) {
542  SI::PAT pat(Data, false);
543  if (!pat.CheckCRCAndParse())
544  return;
546  DBGLOG("PAT %d %d -> %d %d/%d", Transponder(), patVersion, pat.getVersionNumber(), pat.getSectionNumber(), pat.getLastSectionNumber());
547  bool NeedsSetStatus = patVersion >= 0;
548  if (pat.getVersionNumber() != patVersion) {
549  if (NeedsSetStatus)
550  SetStatus(false); // deletes all PIDs from the filter
551  activePmt = NULL;
552  pmtSidList.Clear();
553  pmtPidList.Clear();
555  }
556  SI::PAT::Association assoc;
557  for (SI::Loop::Iterator it; pat.associationLoop.getNext(assoc, it); ) {
558  if (!assoc.isNITPid()) {
559  int PmtPid = assoc.getPid();
560  int PmtSid = assoc.getServiceId();
561  cPmtPidEntry *pPid = NULL;
562  for (pPid = pmtPidList.First(); pPid; pPid = pmtPidList.Next(pPid)) {
563  if (pPid->Pid() == PmtPid)
564  break;
565  }
566  int SidRequest = NumSidRequests(PmtSid);
567  DBGLOG(" PMT pid %5d SID %5d%s%s", PmtPid, PmtSid, SidRequest ? " R" : "", pPid ? " S" : "");
568  if (!pPid) { // new PMT Pid
569  pPid = new cPmtPidEntry(PmtPid);
570  pmtPidList.Add(pPid);
571  }
572  pmtSidList.Add(new cPmtSidEntry(PmtSid, pPid));
573  if (SidRequest > 0)
574  pPid->Inc();
575  }
576  }
577  if (sectionSyncer.Processed(pat.getSectionNumber(), pat.getLastSectionNumber())) { // all PAT sections done
578  for (cPmtPidEntry *pPid = pmtPidList.First(); pPid; pPid = pmtPidList.Next(pPid)) {
579  if (pPid->Count() == 0) {
580  pPid->SetState(1);
581  activePmt = pPid;
583  break;
584  }
585  }
586  if (NeedsSetStatus)
587  SetStatus(true);
588  }
589  }
590  }
591  }
592  else if (Tid == SI::TableIdPMT && Source() && Transponder()) {
593  SI::PMT pmt(Data, false);
594  if (!pmt.CheckCRCAndParse())
595  return;
596  if (!PmtVersionChanged(Pid, pmt.getTableIdExtension(), pmt.getVersionNumber(), false)) {
597  if (activePmt && activePmt->Complete())
599  return;
600  }
601  cStateKey StateKey;
602  cChannels *Channels = cChannels::GetChannelsWrite(StateKey, 10);
603  if (!Channels)
604  return;
605  PmtVersionChanged(Pid, pmt.getTableIdExtension(), pmt.getVersionNumber(), true);
606  bool ChannelsModified = false;
607  if (activePmt && activePmt->Complete())
609  cChannel *Channel = Channels->GetByServiceID(Source(), Transponder(), pmt.getServiceId());
610  if (Channel) {
611  Channel->SetSeen();
612  SI::CaDescriptor *d;
613  cCaDescriptors *CaDescriptors = new cCaDescriptors(Channel->Source(), Channel->Transponder(), Channel->Sid(), Pid);
614  // Scan the common loop:
616  CaDescriptors->AddCaDescriptor(d, 0);
617  delete d;
618  }
619  // Scan the stream-specific loop:
620  SI::PMT::Stream stream;
621  int Vpid = 0;
622  int Ppid = 0;
623  int Vtype = 0;
624  int Apids[MAXAPIDS + 1] = { 0 }; // these lists are zero-terminated
625  int Atypes[MAXAPIDS + 1] = { 0 };
626  int Dpids[MAXDPIDS + 1] = { 0 };
627  int Dtypes[MAXDPIDS + 1] = { 0 };
628  int Spids[MAXSPIDS + 1] = { 0 };
629  uchar SubtitlingTypes[MAXSPIDS + 1] = { 0 };
630  uint16_t CompositionPageIds[MAXSPIDS + 1] = { 0 };
631  uint16_t AncillaryPageIds[MAXSPIDS + 1] = { 0 };
632  char ALangs[MAXAPIDS][MAXLANGCODE2] = { "" };
633  char DLangs[MAXDPIDS][MAXLANGCODE2] = { "" };
634  char SLangs[MAXSPIDS][MAXLANGCODE2] = { "" };
635  int Tpid = 0;
636  int NumApids = 0;
637  int NumDpids = 0;
638  int NumSpids = 0;
639  for (SI::Loop::Iterator it; pmt.streamLoop.getNext(stream, it); ) {
640  bool ProcessCaDescriptors = false;
641  int esPid = stream.getPid();
642  switch (stream.getStreamType()) {
643  case 1: // STREAMTYPE_11172_VIDEO
644  case 2: // STREAMTYPE_13818_VIDEO
645  case 0x1B: // H.264
646  case 0x24: // H.265
647  Vpid = esPid;
648  Ppid = pmt.getPCRPid();
649  Vtype = stream.getStreamType();
650  ProcessCaDescriptors = true;
651  break;
652  case 3: // STREAMTYPE_11172_AUDIO
653  case 4: // STREAMTYPE_13818_AUDIO
654  case 0x0F: // ISO/IEC 13818-7 Audio with ADTS transport syntax
655  case 0x11: // ISO/IEC 14496-3 Audio with LATM transport syntax
656  {
657  if (NumApids < MAXAPIDS) {
658  Apids[NumApids] = esPid;
659  Atypes[NumApids] = stream.getStreamType();
660  SI::Descriptor *d;
661  for (SI::Loop::Iterator it; (d = stream.streamDescriptors.getNext(it)); ) {
662  switch (d->getDescriptorTag()) {
666  char *s = ALangs[NumApids];
667  int n = 0;
668  for (SI::Loop::Iterator it; ld->languageLoop.getNext(l, it); ) {
669  if (*ld->languageCode != '-') { // some use "---" to indicate "none"
670  if (n > 0)
671  *s++ = '+';
673  s += strlen(s);
674  if (n++ > 1)
675  break;
676  }
677  }
678  }
679  break;
680  default: ;
681  }
682  delete d;
683  }
684  NumApids++;
685  }
686  ProcessCaDescriptors = true;
687  }
688  break;
689  case 5: // STREAMTYPE_13818_PRIVATE
690  case 6: // STREAMTYPE_13818_PES_PRIVATE
691  //XXX case 8: // STREAMTYPE_13818_DSMCC
692  {
693  int dpid = 0;
694  int dtype = 0;
695  char lang[MAXLANGCODE1] = { 0 };
696  SI::Descriptor *d;
697  for (SI::Loop::Iterator it; (d = stream.streamDescriptors.getNext(it)); ) {
698  switch (d->getDescriptorTag()) {
701  dpid = esPid;
702  dtype = d->getDescriptorTag();
703  ProcessCaDescriptors = true;
704  break;
706  if (NumSpids < MAXSPIDS) {
707  Spids[NumSpids] = esPid;
710  char *s = SLangs[NumSpids];
711  int n = 0;
712  for (SI::Loop::Iterator it; sd->subtitlingLoop.getNext(sub, it); ) {
713  if (sub.languageCode[0]) {
714  SubtitlingTypes[NumSpids] = sub.getSubtitlingType();
715  CompositionPageIds[NumSpids] = sub.getCompositionPageId();
716  AncillaryPageIds[NumSpids] = sub.getAncillaryPageId();
717  if (n > 0)
718  *s++ = '+';
720  s += strlen(s);
721  if (n++ > 1)
722  break;
723  }
724  }
725  NumSpids++;
726  }
727  break;
729  Tpid = esPid;
730  break;
734  }
735  break;
736  default: ;
737  }
738  delete d;
739  }
740  if (dpid) {
741  if (NumDpids < MAXDPIDS) {
742  Dpids[NumDpids] = dpid;
743  Dtypes[NumDpids] = dtype;
744  strn0cpy(DLangs[NumDpids], lang, MAXLANGCODE1);
745  NumDpids++;
746  }
747  }
748  }
749  break;
750  case 0x80: // STREAMTYPE_USER_PRIVATE
751  if (Setup.StandardCompliance == STANDARD_ANSISCTE) { // DigiCipher II VIDEO (ANSI/SCTE 57)
752  Vpid = esPid;
753  Ppid = pmt.getPCRPid();
754  Vtype = 0x02; // compression based upon MPEG-2
755  ProcessCaDescriptors = true;
756  break;
757  }
758  // fall through
759  case 0x81: // STREAMTYPE_USER_PRIVATE
760  case 0x87: // eac3
761  if (Setup.StandardCompliance == STANDARD_ANSISCTE) { // ATSC A/53 AUDIO (ANSI/SCTE 57)
762  char lang[MAXLANGCODE1] = { 0 };
763  SI::Descriptor *d;
764  for (SI::Loop::Iterator it; (d = stream.streamDescriptors.getNext(it)); ) {
765  switch (d->getDescriptorTag()) {
769  }
770  break;
771  default: ;
772  }
773  delete d;
774  }
775  if (NumDpids < MAXDPIDS) {
776  Dpids[NumDpids] = esPid;
777  Dtypes[NumDpids] = SI::AC3DescriptorTag;
778  strn0cpy(DLangs[NumDpids], lang, MAXLANGCODE1);
779  NumDpids++;
780  }
781  ProcessCaDescriptors = true;
782  break;
783  }
784  // fall through
785  case 0x82: // STREAMTYPE_USER_PRIVATE
786  if (Setup.StandardCompliance == STANDARD_ANSISCTE) { // STANDARD SUBTITLE (ANSI/SCTE 27)
787  //TODO
788  break;
789  }
790  // fall through
791  case 0x83 ... 0x86: // STREAMTYPE_USER_PRIVATE
792  case 0x88 ... 0xFF: // STREAMTYPE_USER_PRIVATE
793  {
794  char lang[MAXLANGCODE1] = { 0 };
795  bool IsAc3 = false;
796  SI::Descriptor *d;
797  for (SI::Loop::Iterator it; (d = stream.streamDescriptors.getNext(it)); ) {
798  switch (d->getDescriptorTag()) {
801  // http://www.smpte-ra.org/mpegreg/mpegreg.html
802  switch (rd->getFormatIdentifier()) {
803  case 0x41432D33: // 'AC-3'
804  IsAc3 = true;
805  break;
806  default:
807  //printf("Format identifier: 0x%08X (pid: %d)\n", rd->getFormatIdentifier(), esPid);
808  break;
809  }
810  }
811  break;
815  }
816  break;
817  default: ;
818  }
819  delete d;
820  }
821  if (IsAc3) {
822  if (NumDpids < MAXDPIDS) {
823  Dpids[NumDpids] = esPid;
824  Dtypes[NumDpids] = SI::AC3DescriptorTag;
825  strn0cpy(DLangs[NumDpids], lang, MAXLANGCODE1);
826  NumDpids++;
827  }
828  ProcessCaDescriptors = true;
829  }
830  }
831  break;
832  default: ;//printf("PID: %5d %5d %2d %3d %3d\n", pmt.getServiceId(), stream.getPid(), stream.getStreamType(), pmt.getVersionNumber(), Channel->Number());
833  }
834  if (ProcessCaDescriptors) {
836  CaDescriptors->AddCaDescriptor(d, esPid);
837  delete d;
838  }
839  }
840  }
841  if (Setup.UpdateChannels == 1 || Setup.UpdateChannels >= 3)
842  ChannelsModified |= Channel->ClearObsoleteChannel();
843  if (Setup.UpdateChannels >= 2) {
844  ChannelsModified |= Channel->SetPids(Vpid, Ppid, Vtype, Apids, Atypes, ALangs, Dpids, Dtypes, DLangs, Spids, SLangs, Tpid);
845  ChannelsModified |= Channel->SetCaIds(CaDescriptors->CaIds());
846  ChannelsModified |= Channel->SetSubtitlingDescriptors(SubtitlingTypes, CompositionPageIds, AncillaryPageIds);
847  }
848  ChannelsModified |= Channel->SetCaDescriptors(CaDescriptorHandler.AddCaDescriptors(CaDescriptors));
849  }
850  StateKey.Remove(ChannelsModified);
851  }
852  if (timer.TimedOut()) {
853  if (activePmt)
854  DBGLOG("PMT timeout Pid %d", activePmt->Pid());
856  }
857 }
#define MAXLANGCODE2
Definition: channels.h:37
#define MAXDPIDS
Definition: channels.h:32
#define MAXAPIDS
Definition: channels.h:31
#define MAXSPIDS
Definition: channels.h:33
#define MAXCAIDS
Definition: channels.h:34
#define MAXLANGCODE1
Definition: channels.h:36
bool CheckCRCAndParse()
Definition: si.c:65
CharArray privateData
Definition: descriptor.h:147
int getCaPid() const
Definition: descriptor.c:355
int getCaType() const
Definition: descriptor.c:351
int getLength() const
Definition: util.h:58
const unsigned char * getData() const
Definition: util.h:51
Descriptor * getNext(Iterator &it)
Definition: si.c:112
DescriptorTag getDescriptorTag() const
Definition: si.c:100
StructureLoop< Language > languageLoop
Definition: descriptor.h:490
int getTableIdExtension() const
Definition: si.c:72
int getSectionNumber() const
Definition: si.c:88
int getLastSectionNumber() const
Definition: si.c:92
int getVersionNumber() const
Definition: si.c:84
int getPid() const
Definition: section.c:34
int getServiceId() const
Definition: section.c:30
bool isNITPid() const
Definition: section.h:31
StructureLoop< Association > associationLoop
Definition: section.h:39
DescriptorLoop streamDescriptors
Definition: section.h:63
int getPid() const
Definition: section.c:65
int getStreamType() const
Definition: section.c:69
int getServiceId() const
Definition: section.c:57
int getPCRPid() const
Definition: section.c:61
StructureLoop< Stream > streamLoop
Definition: section.h:71
DescriptorLoop commonDescriptors
Definition: section.h:70
int getFormatIdentifier() const
Definition: descriptor.c:1193
StructureLoop< Subtitling > subtitlingLoop
Definition: descriptor.h:332
int GetCaPids(int Source, int Transponder, int ServiceId, const int *CaSystemIds, int BufSize, int *Pids)
Definition: pat.c:246
int GetPmtPid(int Source, int Transponder, int ServiceId)
Definition: pat.c:256
void GetCaDescriptors(int Source, int Transponder, int ServiceId, const int *CaSystemIds, cDynamicBuffer &Buffer, int EsPid)
Definition: pat.c:235
int AddCaDescriptors(cCaDescriptors *CaDescriptors)
Definition: pat.c:217
cMutex mutex
Definition: pat.c:206
const uchar * Data(void) const
Definition: pat.c:35
virtual ~cCaDescriptor()
Definition: pat.c:55
cCaDescriptor(int CaSystem, int CaPid, int EsPid, int Length, const uchar *Data)
Definition: pat.c:38
int caSystem
Definition: pat.c:22
int CaPid(void)
Definition: pat.c:32
int CaSystem(void)
Definition: pat.c:31
uchar * data
Definition: pat.c:26
int EsPid(void)
Definition: pat.c:33
int caPid
Definition: pat.c:23
int length
Definition: pat.c:25
int Length(void) const
Definition: pat.c:34
int esPid
Definition: pat.c:24
bool operator==(const cCaDescriptor &arg) const
Definition: pat.c:60
cCaDescriptors(int Source, int Transponder, int ServiceId, int PmtPid)
Definition: pat.c:90
bool Empty(void)
Definition: pat.c:82
int pmtPid
Definition: pat.c:72
const int GetPmtPid(void)
Definition: pat.c:86
const int * CaIds(void)
Definition: pat.c:87
bool Is(int Source, int Transponder, int ServiceId)
Definition: pat.c:113
void AddCaId(int CaId)
Definition: pat.c:123
int caIds[MAXCAIDS+1]
Definition: pat.c:74
cList< cCaDescriptor > caDescriptors
Definition: pat.c:75
int source
Definition: pat.c:69
int serviceId
Definition: pat.c:71
void AddCaDescriptor(SI::CaDescriptor *d, int EsPid)
Definition: pat.c:135
int GetCaPids(const int *CaSystemIds, int BufSize, int *Pids)
Definition: pat.c:178
bool operator==(const cCaDescriptors &arg) const
Definition: pat.c:100
int numCaIds
Definition: pat.c:73
void GetCaDescriptors(const int *CaSystemIds, cDynamicBuffer &Buffer, int EsPid)
Definition: pat.c:162
int transponder
Definition: pat.c:70
bool SetCaIds(const int *CaIds)
Definition: channels.c:458
int Source(void) const
Definition: channels.h:151
bool SetPids(int Vpid, int Ppid, int Vtype, int *Apids, int *Atypes, char ALangs[][MAXLANGCODE2], int *Dpids, int *Dtypes, char DLangs[][MAXLANGCODE2], int *Spids, char SLangs[][MAXLANGCODE2], int Tpid)
Definition: channels.c:345
bool ClearObsoleteChannel(void)
Definition: channels.c:1157
void SetSeen(void)
Definition: channels.c:437
bool SetCaDescriptors(int Level)
Definition: channels.c:480
int Transponder(void) const
Returns the transponder frequency in MHz, plus the polarization in case of sat.
Definition: channels.c:146
int Sid(void) const
Definition: channels.h:175
bool SetSubtitlingDescriptors(uchar *SubtitlingTypes, uint16_t *CompositionPageIds, uint16_t *AncillaryPageIds)
Definition: channels.c:413
static cChannels * GetChannelsWrite(cStateKey &StateKey, int TimeoutMs=0)
Gets the list of channels for write access.
Definition: channels.c:860
const cChannel * GetByServiceID(int Source, int Transponder, unsigned short ServiceID) const
Definition: channels.c:997
void Append(const uchar *Data, int Length)
Definition: tools.c:2360
void Clear(void)
Definition: tools.h:888
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 Del(u_short Pid, u_char Tid, u_char Mask=0xFF)
Deletes the given filter data from this filter.
Definition: filter.c:224
void Add(u_short Pid, u_char Tid, u_char Mask=0xFF, bool Sticky=false)
Adds the given filter data to this filter.
Definition: filter.c:216
virtual void Clear(void)
Definition: tools.c:2261
void Del(cListObject *Object, bool DeleteObject=true)
Definition: tools.c:2216
int Count(void) const
Definition: tools.h:637
void Add(cListObject *Object, cListObject *After=NULL)
Definition: tools.c:2184
const T * Next(const T *Object) const
< Returns the element immediately before Object in this list, or NULL if Object is the first element ...
Definition: tools.h:660
const T * First(void) const
Returns the first element in this list, or NULL if the list is empty.
Definition: tools.h:653
Definition: thread.h:67
cList< cPmtSidEntry > pmtSidList
Definition: pat.h:28
int NumSidRequests(int Sid)
Definition: pat.c:455
void Trigger(int=0)
Definition: pat.c:400
void PmtPidReset(int PmtPid)
Definition: pat.c:473
bool PmtPidComplete(int PmtPid)
Definition: pat.c:464
void SwitchToNextPmtPid(void)
Definition: pat.c:504
virtual void SetStatus(bool On)
Turns this filter on or off, depending on the value of On.
Definition: pat.c:374
bool PmtVersionChanged(int PmtPid, int Sid, int Version, bool SetNewVersion=false)
Definition: pat.c:483
cList< cPmtPidEntry > pmtPidList
Definition: pat.h:27
int patVersion
Definition: pat.h:25
cPatFilter(void)
Definition: pat.c:365
int transponder
Definition: pat.h:31
void Request(int Sid)
Definition: pat.c:408
cTimeMs timer
Definition: pat.h:24
cMutex mutex
Definition: pat.h:23
cPmtPidEntry * activePmt
Definition: pat.h:26
cSectionSyncer sectionSyncer
Definition: pat.h:32
int source
Definition: pat.h:30
virtual void Process(u_short Pid, u_char Tid, const u_char *Data, int Length)
Processes the data delivered to this filter.
Definition: pat.c:522
bool TransponderChanged(void)
Definition: pat.c:389
void Release(int Sid)
Definition: pat.c:431
cList< cPmtSidRequest > pmtSidRequestList
Definition: pat.h:29
int Pid(void)
Definition: pat.c:295
int Complete(void)
Definition: pat.c:301
int count
Definition: pat.c:288
bool complete
Definition: pat.c:292
void Dec(void)
Definition: pat.c:300
int state
Definition: pat.c:289
int pid
Definition: pat.c:287
void Inc(void)
Definition: pat.c:299
void SetComplete(bool State)
Definition: pat.c:302
int State(void)
Definition: pat.c:297
void SetState(int State)
Definition: pat.c:298
cPmtPidEntry(int Pid)
Definition: pat.c:305
int Count(void)
Definition: pat.c:296
bool received
Definition: pat.c:321
int Sid(void)
Definition: pat.c:324
void SetReceived(bool State)
Definition: pat.c:330
cPmtSidEntry(int Sid, cPmtPidEntry *PidEntry)
Definition: pat.c:333
int Received(void)
Definition: pat.c:328
int Version(void)
Definition: pat.c:327
cPmtPidEntry * pidEntry
Definition: pat.c:319
int Pid(void)
Definition: pat.c:325
int version
Definition: pat.c:320
int sid
Definition: pat.c:317
void SetVersion(int Version)
Definition: pat.c:329
cPmtPidEntry * PidEntry(void)
Definition: pat.c:326
int pid
Definition: pat.c:318
int sid
Definition: pat.c:346
void Dec(void)
Definition: pat.c:353
int count
Definition: pat.c:347
void Inc(void)
Definition: pat.c:352
int Sid(void)
Definition: pat.c:350
cPmtSidRequest(int Sid)
Definition: pat.c:349
int Count(void)
Definition: pat.c:351
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 StandardCompliance
Definition: config.h:290
int UpdateChannels
Definition: config.h:325
void Remove(bool IncState=true)
Removes this key from the lock it was previously used with.
Definition: thread.c:859
void Set(int Ms=0)
Sets the timer.
Definition: tools.c:792
bool TimedOut(void) const
Definition: tools.c:797
cSetup Setup
Definition: config.c:372
#define STANDARD_ANSISCTE
Definition: config.h:78
const char * I18nNormalizeLanguageCode(const char *Code)
Returns a 3 letter language code that may not be zero terminated.
Definition: i18n.c:285
@ TableIdPAT
Definition: si.h:23
@ TableIdPMT
Definition: si.h:25
@ EnhancedAC3DescriptorTag
Definition: si.h:137
@ TeletextDescriptorTag
Definition: si.h:100
@ CaDescriptorTag
Definition: si.h:60
@ SubtitlingDescriptorTag
Definition: si.h:103
@ ISO639LanguageDescriptorTag
Definition: si.h:61
@ AC3DescriptorTag
Definition: si.h:120
@ RegistrationDescriptorTag
Definition: si.h:56
unsigned char u_char
Definition: headers.h:24
int GetCaPids(int Source, int Transponder, int ServiceId, const int *CaSystemIds, int BufSize, int *Pids)
Gets all CA pids for a given channel.
Definition: pat.c:273
#define DBGLOG(a...)
Definition: pat.c:362
int GetPmtPid(int Source, int Transponder, int ServiceId)
Gets the Pid of the PMT in which the CA descriptors for this channel are defined.
Definition: pat.c:278
void GetCaDescriptors(int Source, int Transponder, int ServiceId, const int *CaSystemIds, cDynamicBuffer &Buffer, int EsPid)
Gets all CA descriptors for a given channel.
Definition: pat.c:268
#define PMT_SCAN_TIMEOUT
Definition: pat.c:16
cCaDescriptorHandler CaDescriptorHandler
Definition: pat.c:266
char * strn0cpy(char *dest, const char *src, size_t n)
Definition: tools.c:131
unsigned char uchar
Definition: tools.h:31
#define dsyslog(a...)
Definition: tools.h:37
#define MALLOC(type, size)
Definition: tools.h:47