vdr 2.7.5
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.5 2025/03/02 11:03:35 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
20class cCaDescriptor : public cListObject {
21private:
23 int caPid;
24 int esPid;
25 int length;
27public:
28 cCaDescriptor(int CaSystem, int CaPid, int EsPid, int Length, const uchar *Data);
29 virtual ~cCaDescriptor() override;
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
39{
41 caPid = CaPid;
42 esPid = EsPid;
43 length = Length + 6;
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
59
61{
62 return esPid == arg.esPid && length == arg.length && memcmp(data, arg.data, length) == 0;
63}
64
65// --- cCaDescriptors --------------------------------------------------------
66
68private:
69 int source;
72 int pmtPid; // needed for OctopusNet - otherwise irrelevant!
74 int caIds[MAXCAIDS + 1];
76 void AddCaId(int CaId);
77public:
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
90cCaDescriptors::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
113bool cCaDescriptors::Is(int Source, int Transponder, int ServiceId)
114{
115 return source == Source && transponder == Transponder && serviceId == ServiceId;
116}
117
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
162void 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
178int 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
204class cCaDescriptorHandler : public cList<cCaDescriptors> {
205private:
207public:
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
235void 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
246int 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
256int 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
268void 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
273int 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
278int GetPmtPid(int Source, int Transponder, int ServiceId)
279{
280 return CaDescriptorHandler.GetPmtPid(Source, Transponder, ServiceId);
281}
282
283// --- cPmtPidEntry ----------------------------------------------------------
284
285class cPmtPidEntry : public cListObject {
286private:
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
293public:
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
315class cPmtSidEntry : public cListObject {
316private:
317 int sid;
318 int pid;
322public:
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();
338 version = -1;
339 received = false;
340}
341
342// --- cPmtSidRequest --------------------------------------------------------
343
345private:
346 int sid;
347 int count; // the number of requests for this SID
348public:
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);
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;
405 sectionSyncer.Reset();
406}
407
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);
420 pmtSidRequestList.Add(new cPmtSidRequest(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
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) {
440 pmtSidRequestList.Del(sr);
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
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
483bool 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) {
515 PmtPidReset(activePmt->Pid());
518 }
519 }
520}
521
522void 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;
527 sectionSyncer.Reset();
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;
545 if (sectionSyncer.Check(pat.getVersionNumber(), pat.getSectionNumber())) {
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 }
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;
606 bool ChannelsModified = false;
607 if (activePmt && activePmt->Complete())
610 if (Channel) {
611 Channel->SetSeen();
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();
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 };
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 };
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;
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
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
cCaDescriptor(int CaSystem, int CaPid, int EsPid, int Length, const uchar *Data)
Definition pat.c:38
const uchar * Data(void) const
Definition pat.c:35
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
virtual ~cCaDescriptor() override
Definition pat.c:55
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
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
const int * CaIds(void)
Definition pat.c:87
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
static cChannels * GetChannelsWrite(cStateKey &StateKey, int TimeoutMs=0)
Gets the list of channels for write access.
Definition channels.c:861
const cChannel * GetByServiceID(int Source, int Transponder, unsigned short ServiceID) const
Definition channels.c:998
void Append(const uchar *Data, int Length)
Definition tools.c:2351
void Clear(void)
Definition tools.h:878
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 Del(u_short Pid, u_char Tid, u_char Mask=0xFF)
Deletes the given filter data from this filter.
Definition filter.c:195
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:187
void Del(cListObject *Object, bool DeleteObject=true)
Definition tools.c:2207
void Add(cListObject *Object, cListObject *After=NULL)
Definition tools.c:2175
cListObject(const cListObject &ListObject)
Definition tools.h:534
Definition tools.h:631
const T * First(void) const
Returns the first element in this list, or NULL if the list is empty.
Definition tools.h:643
cList(const char *NeedsLocking=NULL)
Definition tools.h:633
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:650
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
virtual void Process(u_short Pid, u_char Tid, const u_char *Data, int Length) override
Processes the data delivered to this filter.
Definition pat.c:522
bool PmtPidComplete(int PmtPid)
Definition pat.c:464
void SwitchToNextPmtPid(void)
Definition pat.c:504
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
virtual void SetStatus(bool On) override
Turns this filter on or off, depending on the value of On.
Definition pat.c:374
int source
Definition pat.h:30
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
cPmtPidEntry * PidEntry(void)
Definition pat.c:326
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
int pid
Definition pat.c:318
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
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
#define STANDARD_ANSISCTE
Definition config.h:80
const char * I18nNormalizeLanguageCode(const char *Code)
Returns a 3 letter language code that may not be zero terminated.
Definition i18n.c:286
@ TableIdPAT
Definition si.h:23
@ TableIdPMT
Definition si.h:25
@ EnhancedAC3DescriptorTag
Definition si.h:136
@ TeletextDescriptorTag
Definition si.h:99
@ CaDescriptorTag
Definition si.h:59
@ SubtitlingDescriptorTag
Definition si.h:102
@ ISO639LanguageDescriptorTag
Definition si.h:60
@ AC3DescriptorTag
Definition si.h:119
@ RegistrationDescriptorTag
Definition si.h:55
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