vdr  2.7.6
remux.c
Go to the documentation of this file.
1 /*
2  * remux.c: Tools for detecting frames and handling PAT/PMT
3  *
4  * See the main source file 'vdr.c' for copyright information and
5  * how to reach the author.
6  *
7  * $Id: remux.c 5.19 2025/03/02 11:03:35 kls Exp $
8  */
9 
10 #include "remux.h"
11 #include "device.h"
12 #include "libsi/si.h"
13 #include "libsi/section.h"
14 #include "libsi/descriptor.h"
15 #include "recording.h"
16 #include "shutdown.h"
17 #include "tools.h"
18 
19 // Set these to 'true' for debug output:
20 static bool DebugPatPmt = false;
21 static bool DebugFrames = false;
22 
23 #define dbgpatpmt(a...) if (DebugPatPmt) fprintf(stderr, a)
24 #define dbgframes(a...) if (DebugFrames) fprintf(stderr, a)
25 
26 #define MAX_TS_PACKETS_FOR_VIDEO_FRAME_DETECTION 6
27 #define WRN_TS_PACKETS_FOR_VIDEO_FRAME_DETECTION (MAX_TS_PACKETS_FOR_VIDEO_FRAME_DETECTION / 2)
28 #define WRN_TS_PACKETS_FOR_FRAME_DETECTOR (MIN_TS_PACKETS_FOR_FRAME_DETECTOR / 2)
29 
30 #define EMPTY_SCANNER (0xFFFFFFFF)
31 
32 ePesHeader AnalyzePesHeader(const uchar *Data, int Count, int &PesPayloadOffset, bool *ContinuationHeader)
33 {
34  if (Count < 7)
35  return phNeedMoreData; // too short
36 
37  if ((Data[6] & 0xC0) == 0x80) { // MPEG 2
38  if (Count < 9)
39  return phNeedMoreData; // too short
40 
41  PesPayloadOffset = 6 + 3 + Data[8];
42  if (Count < PesPayloadOffset)
43  return phNeedMoreData; // too short
44 
45  if (ContinuationHeader)
46  *ContinuationHeader = ((Data[6] == 0x80) && !Data[7] && !Data[8]);
47 
48  return phMPEG2; // MPEG 2
49  }
50 
51  // check for MPEG 1 ...
52  PesPayloadOffset = 6;
53 
54  // skip up to 16 stuffing bytes
55  for (int i = 0; i < 16; i++) {
56  if (Data[PesPayloadOffset] != 0xFF)
57  break;
58 
59  if (Count <= ++PesPayloadOffset)
60  return phNeedMoreData; // too short
61  }
62 
63  // skip STD_buffer_scale/size
64  if ((Data[PesPayloadOffset] & 0xC0) == 0x40) {
65  PesPayloadOffset += 2;
66 
67  if (Count <= PesPayloadOffset)
68  return phNeedMoreData; // too short
69  }
70 
71  if (ContinuationHeader)
72  *ContinuationHeader = false;
73 
74  if ((Data[PesPayloadOffset] & 0xF0) == 0x20) {
75  // skip PTS only
76  PesPayloadOffset += 5;
77  }
78  else if ((Data[PesPayloadOffset] & 0xF0) == 0x30) {
79  // skip PTS and DTS
80  PesPayloadOffset += 10;
81  }
82  else if (Data[PesPayloadOffset] == 0x0F) {
83  // continuation header
85 
86  if (ContinuationHeader)
87  *ContinuationHeader = true;
88  }
89  else
90  return phInvalid; // unknown
91 
92  if (Count < PesPayloadOffset)
93  return phNeedMoreData; // too short
94 
95  return phMPEG1; // MPEG 1
96 }
97 
98 #define VIDEO_STREAM_S 0xE0
99 
100 // --- cRemux ----------------------------------------------------------------
101 
102 void cRemux::SetBrokenLink(uchar *Data, int Length)
103 {
104  int PesPayloadOffset = 0;
105  if (AnalyzePesHeader(Data, Length, PesPayloadOffset) >= phMPEG1 && (Data[3] & 0xF0) == VIDEO_STREAM_S) {
106  for (int i = PesPayloadOffset; i < Length - 7; i++) {
107  if (Data[i] == 0 && Data[i + 1] == 0 && Data[i + 2] == 1 && Data[i + 3] == 0xB8) {
108  if (!(Data[i + 7] & 0x40)) // set flag only if GOP is not closed
109  Data[i + 7] |= 0x20;
110  return;
111  }
112  }
113  dsyslog("SetBrokenLink: no GOP header found in video packet");
114  }
115  else
116  dsyslog("SetBrokenLink: no video packet in frame");
117 }
118 
119 // --- Some TS handling tools ------------------------------------------------
120 
122 {
123  p[1] &= ~TS_PAYLOAD_START;
124  p[3] |= TS_ADAPT_FIELD_EXISTS;
125  p[3] &= ~TS_PAYLOAD_EXISTS;
126  p[4] = TS_SIZE - 5;
127  p[5] = 0x00;
128  memset(p + 6, 0xFF, TS_SIZE - 6);
129 }
130 
131 void TsSetPcr(uchar *p, int64_t Pcr)
132 {
133  if (TsHasAdaptationField(p)) {
134  if (p[4] >= 7 && (p[5] & TS_ADAPT_PCR)) {
135  int64_t b = Pcr / PCRFACTOR;
136  int e = Pcr % PCRFACTOR;
137  p[ 6] = b >> 25;
138  p[ 7] = b >> 17;
139  p[ 8] = b >> 9;
140  p[ 9] = b >> 1;
141  p[10] = (b << 7) | (p[10] & 0x7E) | ((e >> 8) & 0x01);
142  p[11] = e;
143  }
144  }
145 }
146 
147 int TsSync(const uchar *Data, int Length, const char *File, const char *Function, int Line)
148 {
149  int Skipped = 0;
150  while (Length > 0 && (*Data != TS_SYNC_BYTE || Length > TS_SIZE && Data[TS_SIZE] != TS_SYNC_BYTE)) {
151  Data++;
152  Length--;
153  Skipped++;
154  }
155  if (Skipped && File && Function && Line)
156  esyslog("ERROR: skipped %d bytes to sync on start of TS packet at %s/%s(%d)", Skipped, File, Function, Line);
157  return Skipped;
158 }
159 
160 int64_t TsGetPts(const uchar *p, int l)
161 {
162  // Find the first packet with a PTS and use it:
163  while (l > 0) {
164  const uchar *d = p;
165  if (TsPayloadStart(d) && TsGetPayload(&d) && PesHasPts(d))
166  return PesGetPts(d);
167  p += TS_SIZE;
168  l -= TS_SIZE;
169  }
170  return -1;
171 }
172 
173 int64_t TsGetDts(const uchar *p, int l)
174 {
175  // Find the first packet with a DTS and use it:
176  while (l > 0) {
177  const uchar *d = p;
178  if (TsPayloadStart(d) && TsGetPayload(&d) && PesHasDts(d))
179  return PesGetDts(d);
180  p += TS_SIZE;
181  l -= TS_SIZE;
182  }
183  return -1;
184 }
185 
186 void TsSetPts(uchar *p, int l, int64_t Pts)
187 {
188  // Find the first packet with a PTS and use it:
189  while (l > 0) {
190  const uchar *d = p;
191  if (TsPayloadStart(d) && TsGetPayload(&d) && PesHasPts(d)) {
192  PesSetPts(const_cast<uchar *>(d), Pts);
193  return;
194  }
195  p += TS_SIZE;
196  l -= TS_SIZE;
197  }
198 }
199 
200 void TsSetDts(uchar *p, int l, int64_t Dts)
201 {
202  // Find the first packet with a DTS and use it:
203  while (l > 0) {
204  const uchar *d = p;
205  if (TsPayloadStart(d) && TsGetPayload(&d) && PesHasDts(d)) {
206  PesSetDts(const_cast<uchar *>(d), Dts);
207  return;
208  }
209  p += TS_SIZE;
210  l -= TS_SIZE;
211  }
212 }
213 
214 // --- Some PES handling tools -----------------------------------------------
215 
216 void PesSetPts(uchar *p, int64_t Pts)
217 {
218  p[ 9] = ((Pts >> 29) & 0x0E) | (p[9] & 0xF1);
219  p[10] = Pts >> 22;
220  p[11] = ((Pts >> 14) & 0xFE) | 0x01;
221  p[12] = Pts >> 7;
222  p[13] = ((Pts << 1) & 0xFE) | 0x01;
223 }
224 
225 void PesSetDts(uchar *p, int64_t Dts)
226 {
227  p[14] = ((Dts >> 29) & 0x0E) | (p[14] & 0xF1);
228  p[15] = Dts >> 22;
229  p[16] = ((Dts >> 14) & 0xFE) | 0x01;
230  p[17] = Dts >> 7;
231  p[18] = ((Dts << 1) & 0xFE) | 0x01;
232 }
233 
234 int64_t PtsDiff(int64_t Pts1, int64_t Pts2)
235 {
236  int64_t d = Pts2 - Pts1;
237  if (d > MAX33BIT / 2)
238  return d - (MAX33BIT + 1);
239  if (d < -MAX33BIT / 2)
240  return d + (MAX33BIT + 1);
241  return d;
242 }
243 
244 // --- cTsPayload ------------------------------------------------------------
245 
247 {
248  data = NULL;
249  length = 0;
250  pid = -1;
251  Reset();
252 }
253 
254 cTsPayload::cTsPayload(uchar *Data, int Length, int Pid)
255 {
256  Setup(Data, Length, Pid);
257 }
258 
260 {
261  length = index; // triggers EOF
262  return 0x00;
263 }
264 
266 {
267  index = 0;
268  numPacketsPid = 0;
269  numPacketsOther = 0;
270 }
271 
272 void cTsPayload::Setup(uchar *Data, int Length, int Pid)
273 {
274  data = Data;
275  length = Length;
276  pid = Pid >= 0 ? Pid : TsPid(Data);
277  Reset();
278 }
279 
281 {
282  if (!Eof()) {
283  if (index % TS_SIZE == 0) { // encountered the next TS header
284  for (;; index += TS_SIZE) {
285  if (data[index] == TS_SYNC_BYTE && index + TS_SIZE <= length) { // to make sure we are at a TS header start and drop incomplete TS packets at the end
286  uchar *p = data + index;
287  if (TsPid(p) == pid) { // only handle TS packets for the initial PID
289  return SetEof();
290  if (TsError(p))
291  return SetEof(); // don't parse TS packets with errors
292  if (TsHasPayload(p)) {
293  if (index > 0 && TsPayloadStart(p)) // checking index to not skip the very first TS packet
294  return SetEof();
295  index += TsPayloadOffset(p);
296  break;
297  }
298  }
299  else if (TsPid(p) == PATPID)
300  return SetEof(); // caller must see PAT packets in case of index regeneration
301  else
302  numPacketsOther++;
303  }
304  else
305  return SetEof();
306  }
307  }
308  return data[index++];
309  }
310  return 0x00;
311 }
312 
313 bool cTsPayload::SkipBytes(int Bytes)
314 {
315  while (Bytes-- > 0)
316  GetByte();
317  return !Eof();
318 }
319 
321 {
323 }
324 
326 {
327  return index - 1;
328 }
329 
330 void cTsPayload::SetByte(uchar Byte, int Index)
331 {
332  if (Index >= 0 && Index < length)
333  data[Index] = Byte;
334 }
335 
336 bool cTsPayload::Find(uint32_t Code)
337 {
338  int OldIndex = index;
339  int OldNumPacketsPid = numPacketsPid;
340  int OldNumPacketsOther = numPacketsOther;
341  uint32_t Scanner = EMPTY_SCANNER;
342  while (!Eof()) {
343  Scanner = (Scanner << 8) | GetByte();
344  if (Scanner == Code)
345  return true;
346  }
347  index = OldIndex;
348  numPacketsPid = OldNumPacketsPid;
349  numPacketsOther = OldNumPacketsOther;
350  return false;
351 }
352 
353 void cTsPayload::Statistics(void) const
354 {
356  dsyslog("WARNING: required (%d+%d) TS packets to determine frame type", numPacketsOther, numPacketsPid);
358  dsyslog("WARNING: required %d video TS packets to determine frame type", numPacketsPid);
359 }
360 
361 // --- cPatPmtGenerator ------------------------------------------------------
362 
364 {
365  numPmtPackets = 0;
366  patCounter = pmtCounter = 0;
367  patVersion = pmtVersion = 0;
368  pmtPid = 0;
369  esInfoLength = NULL;
370  SetChannel(Channel);
371 }
372 
373 void cPatPmtGenerator::IncCounter(int &Counter, uchar *TsPacket)
374 {
375  TsPacket[3] = (TsPacket[3] & 0xF0) | Counter;
376  if (++Counter > 0x0F)
377  Counter = 0x00;
378 }
379 
381 {
382  if (++Version > 0x1F)
383  Version = 0x00;
384 }
385 
387 {
388  if (esInfoLength) {
389  Length += ((*esInfoLength & 0x0F) << 8) | *(esInfoLength + 1);
390  *esInfoLength = 0xF0 | (Length >> 8);
391  *(esInfoLength + 1) = Length;
392  }
393 }
394 
395 int cPatPmtGenerator::MakeStream(uchar *Target, uchar Type, int Pid)
396 {
397  int i = 0;
398  Target[i++] = Type; // stream type
399  Target[i++] = 0xE0 | (Pid >> 8); // dummy (3), pid hi (5)
400  Target[i++] = Pid; // pid lo
401  esInfoLength = &Target[i];
402  Target[i++] = 0xF0; // dummy (4), ES info length hi
403  Target[i++] = 0x00; // ES info length lo
404  return i;
405 }
406 
408 {
409  int i = 0;
410  Target[i++] = Type;
411  Target[i++] = 0x01; // length
412  Target[i++] = 0x00;
413  IncEsInfoLength(i);
414  return i;
415 }
416 
417 int cPatPmtGenerator::MakeSubtitlingDescriptor(uchar *Target, const char *Language, uchar SubtitlingType, uint16_t CompositionPageId, uint16_t AncillaryPageId)
418 {
419  int i = 0;
420  Target[i++] = SI::SubtitlingDescriptorTag;
421  Target[i++] = 0x08; // length
422  Target[i++] = *Language++;
423  Target[i++] = *Language++;
424  Target[i++] = *Language++;
425  Target[i++] = SubtitlingType;
426  Target[i++] = CompositionPageId >> 8;
427  Target[i++] = CompositionPageId & 0xFF;
428  Target[i++] = AncillaryPageId >> 8;
429  Target[i++] = AncillaryPageId & 0xFF;
430  IncEsInfoLength(i);
431  return i;
432 }
433 
434 int cPatPmtGenerator::MakeLanguageDescriptor(uchar *Target, const char *Language)
435 {
436  int i = 0;
437  Target[i++] = SI::ISO639LanguageDescriptorTag;
438  int Length = i++;
439  Target[Length] = 0x00; // length
440  for (const char *End = Language + strlen(Language); Language < End; ) {
441  Target[i++] = *Language++;
442  Target[i++] = *Language++;
443  Target[i++] = *Language++;
444  Target[i++] = 0x00; // audio type
445  Target[Length] += 0x04; // length
446  if (*Language == '+')
447  Language++;
448  }
449  IncEsInfoLength(i);
450  return i;
451 }
452 
453 int cPatPmtGenerator::MakeCRC(uchar *Target, const uchar *Data, int Length)
454 {
455  int crc = SI::CRC32::crc32((const char *)Data, Length, 0xFFFFFFFF);
456  int i = 0;
457  Target[i++] = crc >> 24;
458  Target[i++] = crc >> 16;
459  Target[i++] = crc >> 8;
460  Target[i++] = crc;
461  return i;
462 }
463 
464 #define P_TSID 0x8008 // pseudo TS ID
465 #define P_PMT_PID 0x0084 // pseudo PMT pid
466 #define MAXPID 0x2000 // the maximum possible number of pids
467 
469 {
470  bool Used[MAXPID] = { false };
471 #define SETPID(p) { if ((p) >= 0 && (p) < MAXPID) Used[p] = true; }
472 #define SETPIDS(l) { const int *p = l; while (*p) { SETPID(*p); p++; } }
473  SETPID(Channel->Vpid());
474  SETPID(Channel->Ppid());
475  SETPID(Channel->Tpid());
476  SETPIDS(Channel->Apids());
477  SETPIDS(Channel->Dpids());
478  SETPIDS(Channel->Spids());
479  for (pmtPid = P_PMT_PID; Used[pmtPid]; pmtPid++)
480  ;
481 }
482 
484 {
485  memset(pat, 0xFF, sizeof(pat));
486  uchar *p = pat;
487  int i = 0;
488  p[i++] = TS_SYNC_BYTE; // TS indicator
489  p[i++] = TS_PAYLOAD_START | (PATPID >> 8); // flags (3), pid hi (5)
490  p[i++] = PATPID & 0xFF; // pid lo
491  p[i++] = 0x10; // flags (4), continuity counter (4)
492  p[i++] = 0x00; // pointer field (payload unit start indicator is set)
493  int PayloadStart = i;
494  p[i++] = 0x00; // table id
495  p[i++] = 0xB0; // section syntax indicator (1), dummy (3), section length hi (4)
496  int SectionLength = i;
497  p[i++] = 0x00; // section length lo (filled in later)
498  p[i++] = P_TSID >> 8; // TS id hi
499  p[i++] = P_TSID & 0xFF; // TS id lo
500  p[i++] = 0xC1 | (patVersion << 1); // dummy (2), version number (5), current/next indicator (1)
501  p[i++] = 0x00; // section number
502  p[i++] = 0x00; // last section number
503  p[i++] = pmtPid >> 8; // program number hi
504  p[i++] = pmtPid & 0xFF; // program number lo
505  p[i++] = 0xE0 | (pmtPid >> 8); // dummy (3), PMT pid hi (5)
506  p[i++] = pmtPid & 0xFF; // PMT pid lo
507  pat[SectionLength] = i - SectionLength - 1 + 4; // -1 = SectionLength storage, +4 = length of CRC
508  MakeCRC(pat + i, pat + PayloadStart, i - PayloadStart);
510 }
511 
513 {
514  // generate the complete PMT section:
515  uchar buf[MAX_SECTION_SIZE];
516  memset(buf, 0xFF, sizeof(buf));
517  numPmtPackets = 0;
518  if (Channel) {
519  int Vpid = Channel->Vpid();
520  int Ppid = Channel->Ppid();
521  uchar *p = buf;
522  int i = 0;
523  p[i++] = 0x02; // table id
524  int SectionLength = i;
525  p[i++] = 0xB0; // section syntax indicator (1), dummy (3), section length hi (4)
526  p[i++] = 0x00; // section length lo (filled in later)
527  p[i++] = pmtPid >> 8; // program number hi
528  p[i++] = pmtPid & 0xFF; // program number lo
529  p[i++] = 0xC1 | (pmtVersion << 1); // dummy (2), version number (5), current/next indicator (1)
530  p[i++] = 0x00; // section number
531  p[i++] = 0x00; // last section number
532  p[i++] = 0xE0 | (Ppid >> 8); // dummy (3), PCR pid hi (5)
533  p[i++] = Ppid; // PCR pid lo
534  p[i++] = 0xF0; // dummy (4), program info length hi (4)
535  p[i++] = 0x00; // program info length lo
536 
537  if (Vpid)
538  i += MakeStream(buf + i, Channel->Vtype(), Vpid);
539  for (int n = 0; Channel->Apid(n); n++) {
540  i += MakeStream(buf + i, Channel->Atype(n), Channel->Apid(n));
541  const char *Alang = Channel->Alang(n);
542  i += MakeLanguageDescriptor(buf + i, Alang);
543  }
544  for (int n = 0; Channel->Dpid(n); n++) {
545  i += MakeStream(buf + i, 0x06, Channel->Dpid(n));
546  i += MakeAC3Descriptor(buf + i, Channel->Dtype(n));
547  i += MakeLanguageDescriptor(buf + i, Channel->Dlang(n));
548  }
549  for (int n = 0; Channel->Spid(n); n++) {
550  i += MakeStream(buf + i, 0x06, Channel->Spid(n));
551  i += MakeSubtitlingDescriptor(buf + i, Channel->Slang(n), Channel->SubtitlingType(n), Channel->CompositionPageId(n), Channel->AncillaryPageId(n));
552  }
553 
554  int sl = i - SectionLength - 2 + 4; // -2 = SectionLength storage, +4 = length of CRC
555  buf[SectionLength] |= (sl >> 8) & 0x0F;
556  buf[SectionLength + 1] = sl;
557  MakeCRC(buf + i, buf, i);
558  // split the PMT section into several TS packets:
559  uchar *q = buf;
560  bool pusi = true;
561  while (i > 0) {
562  uchar *p = pmt[numPmtPackets++];
563  int j = 0;
564  p[j++] = TS_SYNC_BYTE; // TS indicator
565  p[j++] = (pusi ? TS_PAYLOAD_START : 0x00) | (pmtPid >> 8); // flags (3), pid hi (5)
566  p[j++] = pmtPid & 0xFF; // pid lo
567  p[j++] = 0x10; // flags (4), continuity counter (4)
568  if (pusi) {
569  p[j++] = 0x00; // pointer field (payload unit start indicator is set)
570  pusi = false;
571  }
572  int l = TS_SIZE - j;
573  memcpy(p + j, q, l);
574  q += l;
575  i -= l;
576  }
578  }
579 }
580 
581 void cPatPmtGenerator::SetVersions(int PatVersion, int PmtVersion)
582 {
583  patVersion = PatVersion & 0x1F;
584  pmtVersion = PmtVersion & 0x1F;
585 }
586 
588 {
589  if (Channel) {
590  GeneratePmtPid(Channel);
591  GeneratePat();
592  GeneratePmt(Channel);
593  }
594 }
595 
597 {
599  return pat;
600 }
601 
603 {
604  if (Index < numPmtPackets) {
605  IncCounter(pmtCounter, pmt[Index]);
606  return pmt[Index++];
607  }
608  return NULL;
609 }
610 
611 // --- cPatPmtParser ---------------------------------------------------------
612 
613 cPatPmtParser::cPatPmtParser(bool UpdatePrimaryDevice)
614 {
615  updatePrimaryDevice = UpdatePrimaryDevice;
616  Reset();
617 }
618 
620 {
621  completed = false;
622  pmtSize = 0;
623  patVersion = pmtVersion = -1;
624  pmtPids[0] = 0;
625  vpid = vtype = 0;
626  ppid = 0;
627 }
628 
629 void cPatPmtParser::ParsePat(const uchar *Data, int Length)
630 {
631  // Unpack the TS packet:
632  int PayloadOffset = TsPayloadOffset(Data);
633  Data += PayloadOffset;
634  Length -= PayloadOffset;
635  // The PAT is always assumed to fit into a single TS packet
636  if ((Length -= Data[0] + 1) <= 0)
637  return;
638  Data += Data[0] + 1; // process pointer_field
639  SI::PAT Pat(Data, false);
640  if (Pat.CheckCRCAndParse()) {
641  dbgpatpmt("PAT: TSid = %d, c/n = %d, v = %d, s = %d, ls = %d\n", Pat.getTransportStreamId(), Pat.getCurrentNextIndicator(), Pat.getVersionNumber(), Pat.getSectionNumber(), Pat.getLastSectionNumber());
642  if (patVersion == Pat.getVersionNumber())
643  return;
644  int NumPmtPids = 0;
645  SI::PAT::Association assoc;
646  for (SI::Loop::Iterator it; Pat.associationLoop.getNext(assoc, it); ) {
647  dbgpatpmt(" isNITPid = %d\n", assoc.isNITPid());
648  if (!assoc.isNITPid()) {
649  if (NumPmtPids <= MAX_PMT_PIDS)
650  pmtPids[NumPmtPids++] = assoc.getPid();
651  dbgpatpmt(" service id = %d, pid = %d\n", assoc.getServiceId(), assoc.getPid());
652  }
653  }
654  pmtPids[NumPmtPids] = 0;
656  }
657  else
658  esyslog("ERROR: can't parse PAT");
659 }
660 
661 void cPatPmtParser::ParsePmt(const uchar *Data, int Length)
662 {
663  // Unpack the TS packet:
664  bool PayloadStart = TsPayloadStart(Data);
665  int PayloadOffset = TsPayloadOffset(Data);
666  Data += PayloadOffset;
667  Length -= PayloadOffset;
668  // The PMT may extend over several TS packets, so we need to assemble them
669  if (PayloadStart) {
670  pmtSize = 0;
671  if ((Length -= Data[0] + 1) <= 0)
672  return;
673  Data += Data[0] + 1; // this is the first packet
674  if (SectionLength(Data, Length) > Length) {
675  if (Length <= int(sizeof(pmt))) {
676  memcpy(pmt, Data, Length);
677  pmtSize = Length;
678  }
679  else
680  esyslog("ERROR: PMT packet length too big (%d byte)!", Length);
681  return;
682  }
683  // the packet contains the entire PMT section, so we run into the actual parsing
684  }
685  else if (pmtSize > 0) {
686  // this is a following packet, so we add it to the pmt storage
687  if (Length <= int(sizeof(pmt)) - pmtSize) {
688  memcpy(pmt + pmtSize, Data, Length);
689  pmtSize += Length;
690  }
691  else {
692  esyslog("ERROR: PMT section length too big (%d byte)!", pmtSize + Length);
693  pmtSize = 0;
694  }
696  return; // more packets to come
697  // the PMT section is now complete, so we run into the actual parsing
698  Data = pmt;
699  }
700  else
701  return; // fragment of broken packet - ignore
702  SI::PMT Pmt(Data, false);
703  if (Pmt.CheckCRCAndParse()) {
704  dbgpatpmt("PMT: sid = %d, c/n = %d, v = %d, s = %d, ls = %d\n", Pmt.getServiceId(), Pmt.getCurrentNextIndicator(), Pmt.getVersionNumber(), Pmt.getSectionNumber(), Pmt.getLastSectionNumber());
705  dbgpatpmt(" pcr = %d\n", Pmt.getPCRPid());
706  if (pmtVersion == Pmt.getVersionNumber())
707  return;
710  int NumApids = 0;
711  int NumDpids = 0;
712  int NumSpids = 0;
713  vpid = vtype = 0;
714  ppid = 0;
715  apids[0] = 0;
716  dpids[0] = 0;
717  spids[0] = 0;
718  atypes[0] = 0;
719  dtypes[0] = 0;
720  SI::PMT::Stream stream;
721  for (SI::Loop::Iterator it; Pmt.streamLoop.getNext(stream, it); ) {
722  dbgpatpmt(" stream type = %02X, pid = %d", stream.getStreamType(), stream.getPid());
723  switch (stream.getStreamType()) {
724  case 0x01: // STREAMTYPE_11172_VIDEO
725  case 0x02: // STREAMTYPE_13818_VIDEO
726  case 0x1B: // H.264
727  case 0x24: // H.265
728  vpid = stream.getPid();
729  vtype = stream.getStreamType();
730  ppid = Pmt.getPCRPid();
731  break;
732  case 0x03: // STREAMTYPE_11172_AUDIO
733  case 0x04: // STREAMTYPE_13818_AUDIO
734  case 0x0F: // ISO/IEC 13818-7 Audio with ADTS transport syntax
735  case 0x11: // ISO/IEC 14496-3 Audio with LATM transport syntax
736  {
737  if (NumApids < MAXAPIDS) {
738  apids[NumApids] = stream.getPid();
739  atypes[NumApids] = stream.getStreamType();
740  *alangs[NumApids] = 0;
741  SI::Descriptor *d;
742  for (SI::Loop::Iterator it; (d = stream.streamDescriptors.getNext(it)); ) {
743  switch (d->getDescriptorTag()) {
747  char *s = alangs[NumApids];
748  int n = 0;
749  for (SI::Loop::Iterator it; ld->languageLoop.getNext(l, it); ) {
750  if (*ld->languageCode != '-') { // some use "---" to indicate "none"
751  dbgpatpmt(" '%s'", l.languageCode);
752  if (n > 0)
753  *s++ = '+';
755  s += strlen(s);
756  if (n++ > 1)
757  break;
758  }
759  }
760  }
761  break;
762  default: ;
763  }
764  delete d;
765  }
767  cDevice::PrimaryDevice()->SetAvailableTrack(ttAudio, NumApids, apids[NumApids], alangs[NumApids]);
768  NumApids++;
769  apids[NumApids] = 0;
770  }
771  }
772  break;
773  case 0x06: // STREAMTYPE_13818_PES_PRIVATE
774  {
775  int dpid = 0;
776  int dtype = 0;
777  char lang[MAXLANGCODE1] = "";
778  SI::Descriptor *d;
779  for (SI::Loop::Iterator it; (d = stream.streamDescriptors.getNext(it)); ) {
780  switch (d->getDescriptorTag()) {
783  dbgpatpmt(" AC3");
784  dpid = stream.getPid();
785  dtype = d->getDescriptorTag();
786  break;
788  dbgpatpmt(" subtitling");
789  if (NumSpids < MAXSPIDS) {
790  spids[NumSpids] = stream.getPid();
791  *slangs[NumSpids] = 0;
792  subtitlingTypes[NumSpids] = 0;
793  compositionPageIds[NumSpids] = 0;
794  ancillaryPageIds[NumSpids] = 0;
797  char *s = slangs[NumSpids];
798  int n = 0;
799  for (SI::Loop::Iterator it; sd->subtitlingLoop.getNext(sub, it); ) {
800  if (sub.languageCode[0]) {
801  dbgpatpmt(" '%s'", sub.languageCode);
802  subtitlingTypes[NumSpids] = sub.getSubtitlingType();
803  compositionPageIds[NumSpids] = sub.getCompositionPageId();
804  ancillaryPageIds[NumSpids] = sub.getAncillaryPageId();
805  if (n > 0)
806  *s++ = '+';
808  s += strlen(s);
809  if (n++ > 1)
810  break;
811  }
812  }
814  cDevice::PrimaryDevice()->SetAvailableTrack(ttSubtitle, NumSpids, spids[NumSpids], slangs[NumSpids]);
815  NumSpids++;
816  spids[NumSpids] = 0;
817  }
818  break;
821  dbgpatpmt(" '%s'", ld->languageCode);
823  }
824  break;
825  default: ;
826  }
827  delete d;
828  }
829  if (dpid) {
830  if (NumDpids < MAXDPIDS) {
831  dpids[NumDpids] = dpid;
832  dtypes[NumDpids] = dtype;
833  strn0cpy(dlangs[NumDpids], lang, sizeof(dlangs[NumDpids]));
835  cDevice::PrimaryDevice()->SetAvailableTrack(ttDolby, NumDpids, dpid, lang);
836  NumDpids++;
837  dpids[NumDpids] = 0;
838  }
839  }
840  }
841  break;
842  case 0x81: // STREAMTYPE_USER_PRIVATE - AC3 audio for ATSC and BD
843  case 0x82: // STREAMTYPE_USER_PRIVATE - DTS audio for BD
844  case 0x87: // eac3
845  {
846  dbgpatpmt(" %s",
847  stream.getStreamType() == 0x81 ? "AC3" :
848  stream.getStreamType() == 0x87 ? "AC3" :
849  stream.getStreamType() == 0x82 ? "DTS" : "");
850  char lang[MAXLANGCODE1] = { 0 };
851  SI::Descriptor *d;
852  for (SI::Loop::Iterator it; (d = stream.streamDescriptors.getNext(it)); ) {
853  switch (d->getDescriptorTag()) {
856  dbgpatpmt(" '%s'", ld->languageCode);
858  }
859  break;
860  default: ;
861  }
862  delete d;
863  }
864  if (NumDpids < MAXDPIDS) {
865  dpids[NumDpids] = stream.getPid();
866  dtypes[NumDpids] = SI::AC3DescriptorTag;
867  strn0cpy(dlangs[NumDpids], lang, sizeof(dlangs[NumDpids]));
869  cDevice::PrimaryDevice()->SetAvailableTrack(ttDolby, NumDpids, stream.getPid(), lang);
870  NumDpids++;
871  dpids[NumDpids] = 0;
872  }
873  }
874  break;
875  case 0x90: // PGS subtitles for BD
876  {
877  dbgpatpmt(" subtitling");
878  char lang[MAXLANGCODE1] = { 0 };
879  SI::Descriptor *d;
880  for (SI::Loop::Iterator it; (d = stream.streamDescriptors.getNext(it)); ) {
881  switch (d->getDescriptorTag()) {
884  dbgpatpmt(" '%s'", ld->languageCode);
886  if (NumSpids < MAXSPIDS) {
887  spids[NumSpids] = stream.getPid();
888  *slangs[NumSpids] = 0;
889  subtitlingTypes[NumSpids] = 0;
890  compositionPageIds[NumSpids] = 0;
891  ancillaryPageIds[NumSpids] = 0;
893  cDevice::PrimaryDevice()->SetAvailableTrack(ttSubtitle, NumSpids, stream.getPid(), lang);
894  NumSpids++;
895  spids[NumSpids] = 0;
896  }
897  }
898  break;
899  default: ;
900  }
901  delete d;
902  }
903  }
904  break;
905  default: ;
906  }
907  dbgpatpmt("\n");
908  if (updatePrimaryDevice) {
911  }
912  }
914  completed = true;
915  }
916  else
917  esyslog("ERROR: can't parse PMT");
918  pmtSize = 0;
919 }
920 
921 bool cPatPmtParser::ParsePatPmt(const uchar *Data, int Length)
922 {
923  while (Length >= TS_SIZE) {
924  if (*Data != TS_SYNC_BYTE)
925  break; // just for safety
926  int Pid = TsPid(Data);
927  if (Pid == PATPID)
928  ParsePat(Data, TS_SIZE);
929  else if (IsPmtPid(Pid)) {
930  ParsePmt(Data, TS_SIZE);
931  if (patVersion >= 0 && pmtVersion >= 0)
932  return true;
933  }
934  Data += TS_SIZE;
935  Length -= TS_SIZE;
936  }
937  return false;
938 }
939 
940 bool cPatPmtParser::GetVersions(int &PatVersion, int &PmtVersion) const
941 {
942  PatVersion = patVersion;
943  PmtVersion = pmtVersion;
944  return patVersion >= 0 && pmtVersion >= 0;
945 }
946 
947 // --- cEitGenerator ---------------------------------------------------------
948 
950 {
951  counter = 0;
952  version = 0;
953  if (Sid)
954  Generate(Sid);
955 }
956 
957 uint16_t cEitGenerator::YMDtoMJD(int Y, int M, int D)
958 {
959  int L = (M < 3) ? 1 : 0;
960  return 14956 + D + int((Y - L) * 365.25) + int((M + 1 + L * 12) * 30.6001);
961 }
962 
964 {
966  *p++ = 0x04; // descriptor length
967  *p++ = '9'; // country code "902" ("All countries") -> EN 300 468 / 6.2.28; www.dvbservices.com/country_codes/index.php
968  *p++ = '0';
969  *p++ = '2';
970  *p++ = ParentalRating;
971  return p;
972 }
973 
975 {
976  uchar *PayloadStart;
977  uchar *SectionStart;
978  uchar *DescriptorsStart;
979  memset(eit, 0xFF, sizeof(eit));
980  struct tm tm_r;
981  time_t t = time(NULL) - 3600; // let's have the event start one hour in the past
982  tm *tm = localtime_r(&t, &tm_r);
983  uint16_t MJD = YMDtoMJD(tm->tm_year, tm->tm_mon + 1, tm->tm_mday);
984  uchar *p = eit;
985  // TS header:
986  *p++ = TS_SYNC_BYTE;
987  *p++ = TS_PAYLOAD_START;
988  *p++ = EITPID;
989  *p++ = 0x10 | (counter++ & 0x0F); // continuity counter
990  *p++ = 0x00; // pointer field (payload unit start indicator is set)
991  // payload:
992  PayloadStart = p;
993  *p++ = 0x4E; // TID present/following event on this transponder
994  *p++ = 0xF0;
995  *p++ = 0x00; // section length
996  SectionStart = p;
997  *p++ = Sid >> 8;
998  *p++ = Sid & 0xFF;
999  *p++ = 0xC1 | (version << 1);
1000  *p++ = 0x00; // section number
1001  *p++ = 0x00; // last section number
1002  *p++ = 0x00; // transport stream id
1003  *p++ = 0x00; // ...
1004  *p++ = 0x00; // original network id
1005  *p++ = 0x00; // ...
1006  *p++ = 0x00; // segment last section number
1007  *p++ = 0x4E; // last table id
1008  *p++ = 0x00; // event id
1009  *p++ = 0x01; // ...
1010  *p++ = MJD >> 8; // start time
1011  *p++ = MJD & 0xFF; // ...
1012  *p++ = tm->tm_hour; // ...
1013  *p++ = tm->tm_min; // ...
1014  *p++ = tm->tm_sec; // ...
1015  *p++ = 0x24; // duration (one day, should cover everything)
1016  *p++ = 0x00; // ...
1017  *p++ = 0x00; // ...
1018  *p++ = 0x90; // running status, free/CA mode
1019  *p++ = 0x00; // descriptors loop length
1020  DescriptorsStart = p;
1022  // fill in lengths:
1023  *(SectionStart - 1) = p - SectionStart + 4; // +4 = length of CRC
1024  *(DescriptorsStart - 1) = p - DescriptorsStart;
1025  // checksum
1026  int crc = SI::CRC32::crc32((char *)PayloadStart, p - PayloadStart, 0xFFFFFFFF);
1027  *p++ = crc >> 24;
1028  *p++ = crc >> 16;
1029  *p++ = crc >> 8;
1030  *p++ = crc;
1031  return eit;
1032 }
1033 
1034 // --- cTsToPes --------------------------------------------------------------
1035 
1037 {
1038  data = NULL;
1039  size = 0;
1040  Reset();
1041 }
1042 
1044 {
1045  free(data);
1046 }
1047 
1048 void cTsToPes::PutTs(const uchar *Data, int Length)
1049 {
1050  if (TsError(Data)) {
1051  Reset();
1052  return; // ignore packets with TEI set, and drop any PES data collected so far
1053  }
1054  if (TsPayloadStart(Data))
1055  Reset();
1056  else if (!size)
1057  return; // skip everything before the first payload start
1058  Length = TsGetPayload(&Data);
1059  if (length + Length > size) {
1060  int NewSize = max(KILOBYTE(2), length + Length);
1061  if (uchar *NewData = (uchar *)realloc(data, NewSize)) {
1062  data = NewData;
1063  size = NewSize;
1064  }
1065  else {
1066  esyslog("ERROR: out of memory");
1067  Reset();
1068  return;
1069  }
1070  }
1071  memcpy(data + length, Data, Length);
1072  length += Length;
1073 }
1074 
1075 #define MAXPESLENGTH 0xFFF0
1076 
1077 const uchar *cTsToPes::GetPes(int &Length)
1078 {
1079  if (repeatLast) {
1080  repeatLast = false;
1081  Length = lastLength;
1082  return lastData;
1083  }
1084  if (offset < length && PesLongEnough(length)) {
1085  if (!PesHasLength(data)) // this is a video PES packet with undefined length
1086  offset = 6; // trigger setting PES length for initial slice
1087  if (offset) {
1088  uchar *p = data + offset - 6;
1089  if (p != data) {
1090  p -= 3;
1091  if (p < data) {
1092  Reset();
1093  return NULL;
1094  }
1095  memmove(p, data, 4);
1096  }
1097  int l = min(length - offset, MAXPESLENGTH);
1098  offset += l;
1099  if (p != data) {
1100  l += 3;
1101  p[6] = 0x80;
1102  p[7] = 0x00;
1103  p[8] = 0x00;
1104  }
1105  p[4] = l / 256;
1106  p[5] = l & 0xFF;
1107  Length = l + 6;
1108  lastLength = Length;
1109  lastData = p;
1110  return p;
1111  }
1112  else {
1113  Length = PesLength(data);
1114  if (Length <= length) {
1115  offset = Length; // to make sure we break out in case of garbage data
1116  lastLength = Length;
1117  lastData = data;
1118  return data;
1119  }
1120  }
1121  }
1122  return NULL;
1123 }
1124 
1126 {
1127  repeatLast = true;
1128 }
1129 
1131 {
1132  length = offset = 0;
1133  lastData = NULL;
1134  lastLength = 0;
1135  repeatLast = false;
1136 }
1137 
1138 // --- Some helper functions for debugging -----------------------------------
1139 
1140 void BlockDump(const char *Name, const u_char *Data, int Length)
1141 {
1142  printf("--- %s\n", Name);
1143  for (int i = 0; i < Length; i++) {
1144  if (i && (i % 16) == 0)
1145  printf("\n");
1146  printf(" %02X", Data[i]);
1147  }
1148  printf("\n");
1149 }
1150 
1151 void TsDump(const char *Name, const u_char *Data, int Length)
1152 {
1153  printf("%s: %04X", Name, Length);
1154  int n = min(Length, 20);
1155  for (int i = 0; i < n; i++)
1156  printf(" %02X", Data[i]);
1157  if (n < Length) {
1158  printf(" ...");
1159  n = max(n, Length - 10);
1160  for (n = max(n, Length - 10); n < Length; n++)
1161  printf(" %02X", Data[n]);
1162  }
1163  printf("\n");
1164 }
1165 
1166 void PesDump(const char *Name, const u_char *Data, int Length)
1167 {
1168  TsDump(Name, Data, Length);
1169 }
1170 
1171 // --- cFrameParser ----------------------------------------------------------
1172 
1174 protected:
1175  bool debug;
1176  bool newFrame;
1179  uint16_t frameWidth;
1180  uint16_t frameHeight;
1184 public:
1185  cFrameParser(void);
1186  virtual ~cFrameParser() {};
1187  virtual int Parse(const uchar *Data, int Length, int Pid) = 0;
1194  void SetDebug(bool Debug) { debug = Debug; }
1195  bool NewFrame(void) { return newFrame; }
1196  bool IndependentFrame(void) { return independentFrame; }
1198  uint16_t FrameWidth(void) { return frameWidth; }
1199  uint16_t FrameHeight(void) { return frameHeight; }
1200  double FramesPerSecond(void) { return framesPerSecond; }
1201  eScanType ScanType(void) { return scanType; }
1203  };
1204 
1206 {
1207  debug = true;
1208  newFrame = false;
1209  independentFrame = false;
1211  frameWidth = 0;
1212  frameHeight = 0;
1213  framesPerSecond = 0.0;
1214  scanType = stUnknown;
1216 }
1217 
1218 // --- cAudioParser ----------------------------------------------------------
1219 
1220 class cAudioParser : public cFrameParser {
1221 public:
1222  cAudioParser(void);
1223  virtual int Parse(const uchar *Data, int Length, int Pid) override;
1224  };
1225 
1227 {
1228 }
1229 
1230 int cAudioParser::Parse(const uchar *Data, int Length, int Pid)
1231 {
1232  if (TsPayloadStart(Data)) {
1233  newFrame = independentFrame = true;
1234  if (debug)
1235  dbgframes("/");
1236  }
1237  else
1238  newFrame = independentFrame = false;
1239  return TS_SIZE;
1240 }
1241 
1242 // --- cMpeg2Parser ----------------------------------------------------------
1243 
1244 class cMpeg2Parser : public cFrameParser {
1245 private:
1246  uint32_t scanner;
1250  const double frame_rate_table[9] = {
1251  0, // 0 forbidden
1252  24000./1001., // 1 23.976...
1253  24., // 2 24
1254  25., // 3 25
1255  30000./1001., // 4 29.97...
1256  30., // 5 30
1257  50., // 6 50
1258  60000./1001., // 7 59.94...
1259  60. // 8 60
1260  };
1261 public:
1262  cMpeg2Parser(void);
1263  virtual int Parse(const uchar *Data, int Length, int Pid) override;
1264  };
1265 
1267 {
1269  seenIndependentFrame = false;
1270  lastIFrameTemporalReference = -1; // invalid
1271  seenScanType = false;
1272 }
1273 
1274 int cMpeg2Parser::Parse(const uchar *Data, int Length, int Pid)
1275 {
1276  newFrame = independentFrame = false;
1277  bool SeenPayloadStart = false;
1278  cTsPayload tsPayload(const_cast<uchar *>(Data), Length, Pid);
1279  if (TsPayloadStart(Data)) {
1280  SeenPayloadStart = true;
1281  tsPayload.SkipPesHeader();
1283  if (debug && seenIndependentFrame)
1284  dbgframes("/");
1285  }
1286  uint32_t OldScanner = scanner; // need to remember it in case of multiple frames per payload
1287  for (;;) {
1288  if (!SeenPayloadStart && tsPayload.AtTsStart())
1289  OldScanner = scanner;
1290  scanner = (scanner << 8) | tsPayload.GetByte();
1291  if (scanner == 0x00000100) { // Picture Start Code
1292  if (!SeenPayloadStart && tsPayload.GetLastIndex() > TS_SIZE) {
1293  scanner = OldScanner;
1294  return tsPayload.Used() - TS_SIZE;
1295  }
1296  uchar b1 = tsPayload.GetByte();
1297  uchar b2 = tsPayload.GetByte();
1298  int TemporalReference = (b1 << 2 ) + ((b2 & 0xC0) >> 6);
1299  uchar FrameType = (b2 >> 3) & 0x07;
1300  if (tsPayload.Find(0x000001B5)) { // Extension start code
1301  if (((tsPayload.GetByte() & 0xF0) >> 4) == 0x08) { // Picture coding extension
1302  tsPayload.GetByte();
1303  uchar PictureStructure = tsPayload.GetByte() & 0x03;
1304  if (PictureStructure == 0x02) // bottom field
1305  break;
1306  }
1307  }
1308  newFrame = true;
1309  independentFrame = FrameType == 1; // I-Frame
1310  if (independentFrame) {
1311  if (lastIFrameTemporalReference >= 0)
1313  lastIFrameTemporalReference = TemporalReference;
1314  }
1315  if (debug) {
1317  if (seenIndependentFrame) {
1318  static const char FrameTypes[] = "?IPBD???";
1319  dbgframes("%c", FrameTypes[FrameType]);
1320  }
1321  }
1322  tsPayload.Statistics();
1323  break;
1324  }
1325  else if (frameWidth == 0 && scanner == 0x000001B3) { // Sequence header code
1326  frameWidth = tsPayload.GetByte() << 4;
1327  uchar b = tsPayload.GetByte(); // ignoring two MSB of width and height in sequence extension
1328  frameWidth |= b >> 4; // as 12 Bit = max 4095 should be sufficient for all available MPEG2 streams
1329  frameHeight = (b & 0x0F) << 8 | tsPayload.GetByte();
1330  b = tsPayload.GetByte(); // hi: aspect ratio info, lo: frame rate code
1331  switch (b >> 4) {
1332  case 1: aspectRatio = ar_1_1; break;
1333  case 2: aspectRatio = ar_4_3; break;
1334  case 3: aspectRatio = ar_16_9; break;
1335  case 4: aspectRatio = ar_2_21_1; break;
1336  default: aspectRatio = arUnknown;
1337  }
1338  uchar frame_rate_value = b & 0x0F;
1339  if (frame_rate_value > 0 && frame_rate_value <= 8)
1340  framesPerSecond = frame_rate_table[frame_rate_value];
1341  }
1342  else if (!seenScanType && scanner == 0x000001B5) { // Extension start code
1343  if ((tsPayload.GetByte() & 0xF0) == 0x10) { // Sequence Extension
1344  scanType = (tsPayload.GetByte() & 0x40) ? stProgressive : stInterlaced;
1345  seenScanType = true;
1346  if (debug) {
1348  dsyslog("%s", *s);
1349  dbgframes("\n%s", *s);
1350  }
1351  }
1352  }
1353  if (tsPayload.AtPayloadStart() // stop at a new payload start to have the buffer refilled if necessary
1354  || tsPayload.Eof()) // or if we're out of data
1355  break;
1356  }
1357  return tsPayload.Used();
1358 }
1359 
1360 // --- cH264Parser -----------------------------------------------------------
1361 
1362 class cH264Parser : public cFrameParser {
1363 private:
1369  };
1370  uchar byte; // holds the current byte value in case of bitwise access
1371  int bit; // the bit index into the current byte (-1 if we're not in bit reading mode)
1372  int zeroBytes; // the number of consecutive zero bytes (to detect 0x000003)
1373  // Identifiers written in '_' notation as in "ITU-T H.264":
1377 protected:
1379  uint32_t scanner;
1382  uchar GetByte(bool Raw = false);
1386  uchar GetBit(void);
1387  uint32_t GetBits(int Bits);
1388  uint32_t GetGolombUe(void);
1389  int32_t GetGolombSe(void);
1390  void ParseAccessUnitDelimiter(void);
1391  void ParseSequenceParameterSet(void);
1392  void ParseSliceHeader(void);
1393 public:
1394  cH264Parser(void);
1398  virtual int Parse(const uchar *Data, int Length, int Pid) override;
1399  };
1400 
1402 {
1403  byte = 0;
1404  bit = -1;
1405  zeroBytes = 0;
1408  log2_max_frame_num = 0;
1409  frame_mbs_only_flag = false;
1410  gotAccessUnitDelimiter = false;
1411  gotSequenceParameterSet = false;
1412 }
1413 
1415 {
1416  uchar b = tsPayload.GetByte();
1417  if (!Raw) {
1418  // If we encounter the byte sequence 0x000003, we need to skip the 0x03:
1419  if (b == 0x00)
1420  zeroBytes++;
1421  else {
1422  if (b == 0x03 && zeroBytes >= 2)
1423  b = tsPayload.GetByte();
1424  zeroBytes = b ? 0 : 1;
1425  }
1426  }
1427  else
1428  zeroBytes = 0;
1429  bit = -1;
1430  return b;
1431 }
1432 
1434 {
1435  if (bit < 0) {
1436  byte = GetByte();
1437  bit = 7;
1438  }
1439  return (byte & (1 << bit--)) ? 1 : 0;
1440 }
1441 
1442 uint32_t cH264Parser::GetBits(int Bits)
1443 {
1444  uint32_t b = 0;
1445  while (Bits--)
1446  b |= GetBit() << Bits;
1447  return b;
1448 }
1449 
1451 {
1452  int z = -1;
1453  for (int b = 0; !b && z < 32; z++) // limiting z to no get stuck if GetBit() always returns 0
1454  b = GetBit();
1455  return (1 << z) - 1 + GetBits(z);
1456 }
1457 
1459 {
1460  uint32_t v = GetGolombUe();
1461  if (v) {
1462  if ((v & 0x01) != 0)
1463  return (v + 1) / 2; // fails for v == 0xFFFFFFFF, but that will probably never happen
1464  else
1465  return -int32_t(v / 2);
1466  }
1467  return v;
1468 }
1469 
1470 int cH264Parser::Parse(const uchar *Data, int Length, int Pid)
1471 {
1472  newFrame = independentFrame = false;
1473  tsPayload.Setup(const_cast<uchar *>(Data), Length, Pid);
1474  if (TsPayloadStart(Data)) {
1477  if (debug && gotSequenceParameterSet) {
1478  dbgframes("/");
1479  }
1480  }
1481  for (;;) {
1482  scanner = (scanner << 8) | GetByte(true);
1483  if ((scanner & 0xFFFFFF00) == 0x00000100) { // NAL unit start
1484  uchar NalUnitType = scanner & 0x1F;
1485  switch (NalUnitType) {
1487  gotAccessUnitDelimiter = true;
1488  break;
1491  gotSequenceParameterSet = true;
1492  }
1493  break;
1494  case nutCodedSliceNonIdr:
1496  ParseSliceHeader();
1497  gotAccessUnitDelimiter = false;
1498  if (newFrame)
1500  return tsPayload.Used();
1501  }
1502  break;
1503  default: ;
1504  }
1505  }
1506  if (tsPayload.AtPayloadStart() // stop at a new payload start to have the buffer refilled if necessary
1507  || tsPayload.Eof()) // or if we're out of data
1508  break;
1509  }
1510  return tsPayload.Used();
1511 }
1512 
1514 {
1516  dbgframes("A");
1517  GetByte(); // primary_pic_type
1518 }
1519 
1521 {
1522  int chroma_format_idc = 0;
1523  int bitDepth = 0;
1524  uchar profile_idc = GetByte(); // profile_idc
1525  GetByte(); // constraint_set[0-5]_flags, reserved_zero_2bits
1526  GetByte(); // level_idc
1527  GetGolombUe(); // seq_parameter_set_id
1528  if (profile_idc == 100 || profile_idc == 110 || profile_idc == 122 || profile_idc == 244 || profile_idc == 44 || profile_idc == 83 || profile_idc == 86 || profile_idc ==118 || profile_idc == 128) {
1529  chroma_format_idc = GetGolombUe(); // chroma_format_idc
1530  if (chroma_format_idc == 3)
1532  bitDepth = 8 + GetGolombUe(); // bit_depth_luma_minus8
1533  GetGolombUe(); // bit_depth_chroma_minus8
1534  GetBit(); // qpprime_y_zero_transform_bypass_flag
1535  if (GetBit()) { // seq_scaling_matrix_present_flag
1536  for (int i = 0; i < ((chroma_format_idc != 3) ? 8 : 12); i++) {
1537  if (GetBit()) { // seq_scaling_list_present_flag
1538  int SizeOfScalingList = (i < 6) ? 16 : 64;
1539  int LastScale = 8;
1540  int NextScale = 8;
1541  for (int j = 0; j < SizeOfScalingList; j++) {
1542  if (NextScale)
1543  NextScale = (LastScale + GetGolombSe() + 256) % 256; // delta_scale
1544  if (NextScale)
1545  LastScale = NextScale;
1546  }
1547  }
1548  }
1549  }
1550  }
1551  log2_max_frame_num = GetGolombUe() + 4; // log2_max_frame_num_minus4
1552  int pic_order_cnt_type = GetGolombUe(); // pic_order_cnt_type
1553  if (pic_order_cnt_type == 0)
1554  GetGolombUe(); // log2_max_pic_order_cnt_lsb_minus4
1555  else if (pic_order_cnt_type == 1) {
1556  GetBit(); // delta_pic_order_always_zero_flag
1557  GetGolombSe(); // offset_for_non_ref_pic
1558  GetGolombSe(); // offset_for_top_to_bottom_field
1559  for (int i = GetGolombUe(); i--; ) // num_ref_frames_in_pic_order_cnt_cycle
1560  GetGolombSe(); // offset_for_ref_frame
1561  }
1562  GetGolombUe(); // max_num_ref_frames
1563  GetBit(); // gaps_in_frame_num_value_allowed_flag
1564  uint16_t frame_Width = 16 * (1 + GetGolombUe()); // pic_width_in_mbs_minus1
1565  uint16_t frame_Height = 16 * (1 + GetGolombUe()); // pic_height_in_map_units_minus1
1566  frame_mbs_only_flag = GetBit(); // frame_mbs_only_flag
1567  if (frameWidth == 0) {
1569  if (!frame_mbs_only_flag) {
1570  GetBit(); // mb_adaptive_frame_field_flag
1571  frame_Height *= 2;
1572  }
1573  GetBit(); // direct_8x8_inference_flag
1574  bool frame_cropping_flag = GetBit(); // frame_cropping_flag
1575  if (frame_cropping_flag) {
1576  uint16_t frame_crop_left_offset = GetGolombUe(); // frame_crop_left_offset
1577  uint16_t frame_crop_right_offset = GetGolombUe(); // frame_crop_right_offset
1578  uint16_t frame_crop_top_offset = GetGolombUe(); // frame_crop_top_offset
1579  uint16_t frame_crop_bottom_offset = GetGolombUe(); // frame_crop_bottom_offset
1580  uint16_t CropUnitX = 1;
1581  uint16_t CropUnitY = frame_mbs_only_flag ? 1 : 2;
1582  if (!separate_colour_plane_flag && chroma_format_idc > 0) {
1583  if (chroma_format_idc == 1) {
1584  CropUnitX = 2;
1585  CropUnitY *= 2;
1586  }
1587  else if (chroma_format_idc == 2)
1588  CropUnitX = 2;
1589  }
1590  frame_Width -= CropUnitX * (frame_crop_left_offset + frame_crop_right_offset);
1591  frame_Height -= CropUnitY * (frame_crop_top_offset + frame_crop_bottom_offset);
1592  if (frame_Height > 1080 && frame_Height <= 1090) // workaround for channels with wrong crop parameters
1593  frame_Height = 1080;
1594  }
1595  frameWidth = frame_Width;
1596  frameHeight = frame_Height;
1597  // VUI parameters
1598  if (GetBit()) { // vui_parameters_present_flag
1599  if (GetBit()) { // aspect_ratio_info_present
1600  int aspect_ratio_idc = GetBits(8); // aspect_ratio_idc
1601  if (aspect_ratio_idc == 255) // EXTENDED_SAR
1602  GetBits(32); // sar_width, sar_height
1603  else if (frameHeight >= 720 && (aspect_ratio_idc == 1 || aspect_ratio_idc == 14 || aspect_ratio_idc == 15 || aspect_ratio_idc == 16))
1604  aspectRatio = ar_16_9;
1605  // implement decoding of other aspect_ratio_idc values when they are required
1606  }
1607  if (GetBit()) // overscan_info_present_flag
1608  GetBit(); // overscan_approriate_flag
1609  if (GetBit()) { // video_signal_type_present_flag
1610  GetBits(4); // video_format, video_full_range_flag
1611  if (GetBit()) // colour_description_present_flag
1612  GetBits(24); // colour_primaries, transfer_characteristics, matrix_coefficients
1613  }
1614  if (GetBit()) { // chroma_loc_info_present_flag
1615  GetGolombUe(); // chroma_sample_loc_type_top_field
1616  GetGolombUe(); // chroma_sample_loc_type_bottom_field
1617  }
1618  if (GetBit()) { // timing_info_present_flag
1619  uint32_t num_units_in_tick = GetBits(32); // num_units_in_tick
1620  uint32_t time_scale = GetBits(32); // time_scale
1621  if (num_units_in_tick > 0)
1622  framesPerSecond = double(time_scale) / (num_units_in_tick << 1);
1623  }
1624  }
1625  if (debug) {
1626  cString s = cString::sprintf("H.264: %d x %d%c %.2f fps %d Bit %s", frameWidth, frameHeight, ScanTypeChars[scanType], framesPerSecond, bitDepth, AspectRatioTexts[aspectRatio]);
1627  dsyslog("%s", *s);
1628  dbgframes("\n%s", *s);
1629  }
1630  }
1631  if (debug) {
1633  dbgframes("A"); // just for completeness
1634  dbgframes(frame_mbs_only_flag ? "S" : "s");
1635  }
1636 }
1637 
1639 {
1640  newFrame = true;
1641  GetGolombUe(); // first_mb_in_slice
1642  int slice_type = GetGolombUe(); // slice_type, 0 = P, 1 = B, 2 = I, 3 = SP, 4 = SI
1643  independentFrame = (slice_type % 5) == 2;
1644  if (debug) {
1645  static const char SliceTypes[] = "PBIpi";
1646  dbgframes("%c", SliceTypes[slice_type % 5]);
1647  }
1648  if (frame_mbs_only_flag)
1649  return; // don't need the rest - a frame is complete
1650  GetGolombUe(); // pic_parameter_set_id
1652  GetBits(2); // colour_plane_id
1653  GetBits(log2_max_frame_num); // frame_num
1654  if (!frame_mbs_only_flag) {
1655  if (GetBit()) // field_pic_flag
1656  newFrame = !GetBit(); // bottom_field_flag
1657  if (debug)
1658  dbgframes(newFrame ? "t" : "b");
1659  }
1660 }
1661 
1662 // --- cH265Parser -----------------------------------------------------------
1663 
1664 class cH265Parser : public cH264Parser {
1665 private:
1696  };
1697  void ParseSequenceParameterSet(void);
1698 public:
1699  cH265Parser(void);
1700  virtual int Parse(const uchar *Data, int Length, int Pid) override;
1701  };
1702 
1704 :cH264Parser()
1705 {
1706 }
1707 
1708 int cH265Parser::Parse(const uchar *Data, int Length, int Pid)
1709 {
1710  newFrame = independentFrame = false;
1711  tsPayload.Setup(const_cast<uchar *>(Data), Length, Pid);
1712  if (TsPayloadStart(Data)) {
1715  }
1716  for (;;) {
1717  scanner = (scanner << 8) | GetByte(true);
1718  if ((scanner & 0xFFFFFF00) == 0x00000100) { // NAL unit start
1719  uchar NalUnitType = (scanner >> 1) & 0x3F;
1720  GetByte(); // nuh_layer_id + nuh_temporal_id_plus1
1721  if (NalUnitType <= nutSliceSegmentRASLR || (NalUnitType >= nutSliceSegmentBLAWLP && NalUnitType <= nutSliceSegmentCRANUT)) {
1722  if (NalUnitType == nutSliceSegmentIDRWRADL || NalUnitType == nutSliceSegmentIDRNLP || NalUnitType == nutSliceSegmentCRANUT)
1723  independentFrame = true;
1724  if (GetBit()) { // first_slice_segment_in_pic_flag
1725  newFrame = true;
1727  }
1728  break;
1729  }
1730  else if (frameWidth == 0 && NalUnitType == nutSequenceParameterSet) {
1732  gotSequenceParameterSet = true;
1733  }
1734  }
1735  if (tsPayload.AtPayloadStart() // stop at a new payload start to have the buffer refilled if necessary
1736  || tsPayload.Eof()) // or if we're out of data
1737  break;
1738  }
1739  return tsPayload.Used();
1740 }
1741 
1743 {
1745  uint8_t sub_layer_profile_present_flag[8];
1746  uint8_t sub_layer_level_present_flag[8];
1747  GetBits(4); // sps_video_parameter_set_id
1748  int sps_max_sub_layers_minus1 = GetBits(3) & 7; // sps_max_sub_layers_minus1 ("& 7" to silence a compiler warning with gcc 14.1.0)
1749  GetBit(); // sps_temporal_id_nesting_flag
1750  // begin profile_tier_level(1, sps_max_sub_layers_minus1)
1751  GetByte();
1752  GetByte();
1753  GetByte();
1754  GetByte();
1755  GetByte();
1756  bool general_progressive_source_flag = GetBit(); // general_progressive_source_flag
1757  scanType = general_progressive_source_flag ? stProgressive : stInterlaced;
1758  GetBit(); // general_interlaced_source_flag
1759  GetBits(6);
1760  GetByte();
1761  GetByte();
1762  GetByte();
1763  GetByte();
1764  GetByte();
1765  GetByte(); // general_level_idc
1766  for (int i = 0; i < sps_max_sub_layers_minus1; i++ ) {
1767  sub_layer_profile_present_flag[i] = GetBit(); // sub_layer_profile_present_flag[i]
1768  sub_layer_level_present_flag[i] = GetBit(); // sub_layer_level_present_flag[i]
1769  }
1770  if (sps_max_sub_layers_minus1 > 0) {
1771  for (int i = sps_max_sub_layers_minus1; i < 8; i++ )
1772  GetBits(2); // reserved_zero_2bits[i]
1773  }
1774  for (int i = 0; i < sps_max_sub_layers_minus1; i++ ) {
1775  if (sub_layer_profile_present_flag[i] )
1776  GetBits(88);
1777  if (sub_layer_level_present_flag[i])
1778  GetBits(8);
1779  }
1780  // end profile_tier_level
1781  GetGolombUe(); // sps_seq_parameter_set_id
1782  int chroma_format_idc = GetGolombUe(); // chroma_format_idc
1783  if (chroma_format_idc == 3)
1784  separate_colour_plane_flag = GetBit(); // separate_colour_plane_flag
1785  frameWidth = GetGolombUe(); // pic_width_in_luma_samples
1786  frameHeight = GetGolombUe(); // pic_height_in_luma_samples
1787  bool conformance_window_flag = GetBit(); // conformance_window_flag
1788  if (conformance_window_flag) {
1789  int conf_win_left_offset = GetGolombUe(); // conf_win_left_offset
1790  int conf_win_right_offset = GetGolombUe(); // conf_win_right_offset
1791  int conf_win_top_offset = GetGolombUe(); // conf_win_top_offset
1792  int conf_win_bottom_offset = GetGolombUe(); // conf_win_bottom_offset
1793  uint16_t SubWidthC = 1;
1794  uint16_t SubHeightC = 1;
1795  if (!separate_colour_plane_flag && chroma_format_idc > 0) {
1796  if (chroma_format_idc == 1) {
1797  SubWidthC = 2;
1798  SubHeightC = 2;
1799  }
1800  else if (chroma_format_idc == 2)
1801  SubWidthC = 2;
1802  }
1803  frameWidth -= SubWidthC * (conf_win_left_offset + conf_win_right_offset);
1804  frameHeight -= SubHeightC * (conf_win_top_offset + conf_win_bottom_offset);
1805  }
1806  int bitDepth = 8 + GetGolombUe(); // bit_depth_luma_minus8
1807  GetGolombUe(); // bit_depth_chroma_minus8
1808  int log2_max_pic_order_cnt_lsb_minus4 = GetGolombUe(); // log2_max_pic_order_cnt_lsb_minus4
1809  int sps_sub_layer_ordering_info_present_flag = GetBit(); // sps_sub_layer_ordering_info_present_flag
1810  for (int i = sps_sub_layer_ordering_info_present_flag ? 0 : sps_max_sub_layers_minus1; i <= sps_max_sub_layers_minus1; ++i) {
1811  GetGolombUe(); // sps_max_dec_pic_buffering_minus1[i]
1812  GetGolombUe(); // sps_max_num_reorder_pics[i]
1813  GetGolombUe(); // sps_max_latency_increase_plus1[i]
1814  }
1815  GetGolombUe(); // log2_min_luma_coding_block_size_minus3
1816  GetGolombUe(); // log2_diff_max_min_luma_coding_block_size
1817  GetGolombUe(); // log2_min_luma_transform_block_size_minus2
1818  GetGolombUe(); // log2_diff_max_min_luma_transform_block_size
1819  GetGolombUe(); // max_transform_hierarchy_depth_inter
1820  GetGolombUe(); // max_transform_hierarchy_depth_intra
1821  if (GetBit()) { // scaling_list_enabled_flag
1822  if (GetBit()) { // sps_scaling_list_data_present_flag
1823  // begin scaling_list_data
1824  for (int sizeId = 0; sizeId < 4; ++sizeId) {
1825  for (int matrixId = 0; matrixId < 6; matrixId += (sizeId == 3) ? 3 : 1) {
1826  if (!GetBit()) // scaling_list_pred_mode_flag[sizeId][matrixId]
1827  GetGolombUe(); // scaling_list_pred_matrix_id_delta[sizeId][matrixId]
1828  else {
1829  int coefNum = min(64, (1 << (4 + (sizeId << 1))));
1830  if (sizeId > 1)
1831  GetGolombSe(); // scaling_list_dc_coef_minus8[sizeId−2][matrixId]
1832  for (int i = 0; i < coefNum; ++i)
1833  GetGolombSe(); // scaling_list_delta_coef
1834  }
1835  }
1836  }
1837  }
1838  // end scaling_list_data
1839  }
1840  GetBits(2); // amp_enabled_flag, sample_adaptive_offset_enabled_flag
1841  if (GetBit()) { // pcm_enabled_flag
1842  GetBits(8); // pcm_sample_bit_depth_luma_minus1, pcm_sample_bit_depth_chroma_minus1
1843  GetGolombUe(); // log2_min_pcm_luma_coding_block_size_minus3
1844  GetGolombUe(); // log2_diff_max_min_pcm_luma_coding_block_size
1845  GetBit(); // pcm_loop_filter_disabled_flag
1846  }
1847  uint32_t num_short_term_ref_pic_sets = GetGolombUe(); // num_short_term_ref_pic_sets
1848  uint32_t NumDeltaPocs[num_short_term_ref_pic_sets];
1849  for (uint32_t stRpsIdx = 0; stRpsIdx < num_short_term_ref_pic_sets; ++stRpsIdx) {
1850  // start of st_ref_pic_set(stRpsIdx)
1851  bool inter_ref_pic_set_prediction_flag = false;
1852  if (stRpsIdx != 0)
1853  inter_ref_pic_set_prediction_flag = GetBit(); // inter_ref_pic_set_prediction_flag
1854  if (inter_ref_pic_set_prediction_flag) {
1855  uint32_t RefRpsIdx, delta_idx_minus1 = 0;
1856  if (stRpsIdx == num_short_term_ref_pic_sets)
1857  delta_idx_minus1 = GetGolombUe(); // delta_idx_minus1
1858  GetBit(); // delta_rps_sign
1859  GetGolombUe(); // abs_delta_rps_minus1
1860  RefRpsIdx = stRpsIdx - (delta_idx_minus1 + 1);
1861  NumDeltaPocs[stRpsIdx] = 0;
1862  for (uint32_t j = 0; j <= NumDeltaPocs[RefRpsIdx]; ++j) {
1863  if (!GetBit()) { // used_by_curr_pic_flag[j]
1864  if (GetBit()) // use_delta_flag[j]
1865  NumDeltaPocs[stRpsIdx]++;
1866  }
1867  else
1868  NumDeltaPocs[stRpsIdx]++;
1869  }
1870  }
1871  else {
1872  uint32_t num_negative_pics = GetGolombUe(); // num_negative_pics
1873  uint32_t num_positive_pics = GetGolombUe(); // num_positive_pics
1874  for (uint32_t j = 0; j < num_negative_pics; ++j) {
1875  GetGolombUe(); // delta_poc_s0_minus1[i]
1876  GetBit(); // used_by_curr_pic_s0_flag[i]
1877  }
1878  for (uint32_t j = 0; j < num_positive_pics; ++j) {
1879  GetGolombUe(); // delta_poc_s1_minus1[i]
1880  GetBit(); // delta_poc_s1_minus1[i]
1881  }
1882  NumDeltaPocs[stRpsIdx] = num_negative_pics + num_positive_pics;
1883  }
1884  // end of st_ref_pic_set(stRpsIdx)
1885  }
1886  if (GetBit()) { // long_term_ref_pics_present_flag
1887  uint32_t num_long_term_ref_pics_sps = GetGolombUe(); // num_long_term_ref_pics_sps
1888  for (uint32_t i = 0; i < num_long_term_ref_pics_sps; ++i) {
1889  GetBits(log2_max_pic_order_cnt_lsb_minus4 + 4); // lt_ref_pic_poc_lsb_sps[i]
1890  GetBit(); // used_by_curr_pic_lt_sps_flag[i]
1891  }
1892  }
1893  GetBits(2); // sps_temporal_mvp_enabled_flag, strong_intra_smoothing_enabled_flag
1894  if (GetBit()) { // vui_parameters_present_flag
1895  // begin of vui_parameters()
1896  if (GetBit()) { // aspect_ratio_info_present_flag
1897  int aspect_ratio_idc = GetBits(8); // aspect_ratio_idc
1898  if (aspect_ratio_idc == 255) // EXTENDED_SAR
1899  GetBits(32); // sar_width, sar_height
1900  else if (aspect_ratio_idc == 1 || aspect_ratio_idc == 14)
1901  aspectRatio = ar_16_9;
1902  // implement decoding of other aspect_ratio_idc values when they are required
1903  }
1904  if (GetBit()) // overscan_info_present_flag
1905  GetBit(); // overscan_appropriate_flag
1906  if (GetBit()) { // video_signal_type_present_flag
1907  GetBits(4); // video_format, video_full_range_flag
1908  if (GetBit()) // colour_description_present_flag
1909  GetBits(24); // colour_primaries, transfer_characteristics, matrix_coeffs
1910  }
1911  if (GetBit()) { // chroma_loc_info_present_flag
1912  GetGolombUe(); // chroma_sample_loc_type_top_field
1913  GetGolombUe(); // chroma_sample_loc_type_bottom_field
1914  }
1915  GetBits(3); // neutral_chroma_indication_flag, field_seq_flag, frame_field_info_present_flag
1916  if (GetBit()) { // default_display_window_flag
1917  GetGolombUe(); // def_disp_win_left_offset
1918  GetGolombUe(); // def_disp_win_right_offset
1919  GetGolombUe(); // def_disp_win_top_offset
1920  GetGolombUe(); // def_disp_win_bottom_offset
1921  }
1922  if (GetBit()) { // vui_timing_info_present_flag
1923  uint32_t vui_num_units_in_tick = GetBits(32); // vui_num_units_in_tick
1924  uint32_t vui_time_scale = GetBits(32); // vui_time_scale
1925  if (vui_num_units_in_tick > 0)
1926  framesPerSecond = (double)vui_time_scale / vui_num_units_in_tick;
1927  }
1928  }
1929  if (debug) {
1930  cString s = cString::sprintf("H.265: %d x %d%c %.2f fps %d Bit %s", frameWidth, frameHeight, ScanTypeChars[scanType], framesPerSecond, bitDepth, AspectRatioTexts[aspectRatio]);
1931  dsyslog("%s", *s);
1932  dbgframes("\n%s", *s);
1933  }
1934 }
1935 
1936 static bool DebugChecks = false;
1937 
1938 // cTsChecker and cFrameChecker are used to detect errors in the recorded data stream.
1939 // While cTsChecker checks the continuity counter of the incoming TS packets, cFrameChecker
1940 // works on entire frames, checking their PTS (Presentation Time Stamps) to see whether
1941 // all expected frames arrive. The resulting number of errors is not a precise value.
1942 // If it is zero, the recording can be safely considered error free. The higher the value,
1943 // the more damaged the recording is.
1944 
1945 // --- cTsChecker ------------------------------------------------------------
1946 
1947 #define TS_CC_UNKNOWN 0xFF
1948 
1949 class cTsChecker {
1950 private:
1952  int errors;
1953  void Report(int Pid, const char *Message);
1954 public:
1955  cTsChecker(void);
1956  void CheckTs(const uchar *Data, int Length);
1957  int Errors(void) { return errors; }
1958  void Clear(void) { errors = 0; }
1959  };
1960 
1962 {
1963  memset(counter, TS_CC_UNKNOWN, sizeof(counter));
1964  errors = 0;
1965 }
1966 
1967 void cTsChecker::Report(int Pid, const char *Message)
1968 {
1969  errors++;
1970  if (DebugChecks)
1971  fprintf(stderr, "%s: TS error #%d on PID %d (%s)\n", *TimeToString(time(NULL)), errors, Pid, Message);
1972 }
1973 
1974 void cTsChecker::CheckTs(const uchar *Data, int Length)
1975 {
1976  while (Length >= TS_SIZE) {
1977  int Pid = TsPid(Data);
1978  uchar Cc = TsContinuityCounter(Data);
1979  if (TsHasPayload(Data)) {
1980  if (TsError(Data))
1981  Report(Pid, "tei");
1982  else if (TsIsScrambled(Data))
1983  Report(Pid, "scrambled");
1984  else {
1985  uchar OldCc = counter[Pid];
1986  if (OldCc != TS_CC_UNKNOWN) {
1987  uchar NewCc = (OldCc + 1) & TS_CONT_CNT_MASK;
1988  if (Cc != NewCc)
1989  Report(Pid, "continuity");
1990  }
1991  }
1992  }
1993  counter[Pid] = Cc;
1994  Data += TS_SIZE;
1995  Length -= TS_SIZE;
1996  }
1997 }
1998 
1999 // --- cFrameChecker ---------------------------------------------------------
2000 
2001 #define MAX_BACK_REFS 32
2002 
2004 private:
2007  int64_t lastPts;
2008  uint32_t backRefs;
2010  int errors;
2013  void Report(const char *Message, int NumErrors = 1);
2014 public:
2015  cFrameChecker(void);
2016  void SetMissing(void) { missingFrames++; }
2017  void SetFrameDelta(int FrameDelta) { frameDelta = FrameDelta; }
2018  void CheckTs(const uchar *Data, int Length);
2019  void CheckFrame(const uchar *Data, int Length, bool IndependentFrame);
2020  int PreviousErrors(void) { return previousErrors; }
2021  int MissingFrames(void) { return missingFrames; }
2022  };
2023 
2025 {
2027  lastPts = -1;
2028  backRefs = 0;
2029  lastFwdRef = 0;
2030  errors = 0;
2031  previousErrors = 0;
2032  missingFrames = 0;
2033 }
2034 
2035 void cFrameChecker::Report(const char *Message, int NumErrors)
2036 {
2037  errors += NumErrors;
2038  if (DebugChecks)
2039  fprintf(stderr, "%s: frame error #%d (%s)\n", *TimeToString(time(NULL)), errors, Message);
2040 }
2041 
2042 void cFrameChecker::CheckTs(const uchar *Data, int Length)
2043 {
2044  tsChecker.CheckTs(Data, Length);
2045 }
2046 
2047 void cFrameChecker::CheckFrame(const uchar *Data, int Length, bool IndependentFrame)
2048 {
2051  errors = 0;
2052  tsChecker.Clear();
2053  int64_t Pts = TsGetPts(Data, Length);
2054  if (Pts >= 0) {
2055  if (lastPts >= 0) {
2056  int Diff = int(round((PtsDiff(lastPts, Pts) / double(frameDelta))));
2057  if (Diff > 0) {
2058  if (Diff <= MAX_BACK_REFS) {
2059  if (lastFwdRef > 1) {
2060  if (backRefs != uint32_t((1 << (lastFwdRef - 1)) - 1))
2061  Report("missing backref");
2062  }
2063  }
2064  else
2065  Report("missed", Diff);
2066  backRefs = 0;
2067  lastFwdRef = Diff;
2068  lastPts = Pts;
2069  }
2070  else if (Diff < 0) {
2071  Diff = -Diff;
2072  if (Diff <= MAX_BACK_REFS) {
2073  int b = 1 << (Diff - 1);
2074  if ((backRefs & b) != 0)
2075  Report("duplicate backref");
2076  backRefs |= b;
2077  }
2078  else {
2079  Report("rev diff too big");
2080  lastPts = Pts;
2081  }
2082  }
2083  else
2084  Report("zero diff");
2085  }
2086  else if (IndependentFrame)
2087  lastPts = Pts;
2088  }
2089  else
2090  Report("no PTS");
2091 }
2092 
2093 // --- cFrameDetector --------------------------------------------------------
2094 
2095 const char *ScanTypeChars = "-pi"; // index is eScanType
2096 const char *AspectRatioTexts[] = { // index is eAspectRatio
2097  "-",
2098  "1:1",
2099  "4:3",
2100  "16:9",
2101  "2.21:1",
2102  NULL
2103  };
2104 
2106 {
2107  parser = NULL;
2108  SetPid(Pid, Type);
2109  synced = false;
2110  newFrame = independentFrame = false;
2111  numPtsValues = 0;
2112  numIFrames = 0;
2113  framesPerSecond = 0;
2114  frameWidth = 0;
2115  frameHeight = 0;
2116  scanType = stUnknown;
2119  scanning = false;
2120  firstIframeSeen = false;
2122 }
2123 
2125 {
2126  delete frameChecker;
2127 }
2128 
2129 static int CmpUint32(const void *p1, const void *p2)
2130 {
2131  if (*(uint32_t *)p1 < *(uint32_t *)p2) return -1;
2132  if (*(uint32_t *)p1 > *(uint32_t *)p2) return 1;
2133  return 0;
2134 }
2135 
2136 void cFrameDetector::SetPid(int Pid, int Type)
2137 {
2138  pid = Pid;
2139  type = Type;
2140  isVideo = type == 0x01 || type == 0x02 || type == 0x1B || type == 0x24; // MPEG 1, 2, H.264 or H.265
2141  delete parser;
2142  parser = NULL;
2143  if (type == 0x01 || type == 0x02)
2144  parser = new cMpeg2Parser;
2145  else if (type == 0x1B)
2146  parser = new cH264Parser;
2147  else if (type == 0x24)
2148  parser = new cH265Parser;
2149  else if (type == 0x03 || type == 0x04 || type == 0x06) // MPEG audio or AC3 audio
2150  parser = new cAudioParser;
2151  else if (type != 0)
2152  esyslog("ERROR: unknown stream type %d (PID %d) in frame detector", type, pid);
2153 }
2154 
2156 {
2158 }
2159 
2160 bool cFrameDetector::NewFrame(int *PreviousErrors, int *MissingFrames)
2161 {
2162  if (newFrame) {
2163  if (PreviousErrors)
2164  *PreviousErrors = frameChecker->PreviousErrors();
2165  if (MissingFrames)
2166  *MissingFrames = frameChecker->MissingFrames();
2167  }
2168  return newFrame;
2169 }
2170 
2171 int cFrameDetector::Analyze(const uchar *Data, int Length, bool ErrorCheck)
2172 {
2173  if (!parser)
2174  return 0;
2175  int Processed = 0;
2176  newFrame = independentFrame = false;
2177  while (Length >= MIN_TS_PACKETS_FOR_FRAME_DETECTOR * TS_SIZE) { // makes sure we are looking at enough data, in case the frame type is not stored in the first TS packet
2178  // Sync on TS packet borders:
2179  if (int Skipped = TS_SYNC(Data, Length))
2180  return Processed + Skipped;
2181  // Handle one TS packet:
2182  int Handled = TS_SIZE;
2183  if (TsHasPayload(Data) && !TsIsScrambled(Data)) {
2184  int Pid = TsPid(Data);
2185  if (Pid == pid) {
2186  if (Processed)
2187  return Processed;
2188  if (TsPayloadStart(Data))
2189  scanning = true;
2190  if (scanning) {
2191  // Detect the beginning of a new frame:
2192  if (TsPayloadStart(Data)) {
2193  if (!framesPerPayloadUnit)
2195  }
2196  int n = parser->Parse(Data, Length, pid);
2197  if (n > 0) {
2198  if (parser->NewFrame()) {
2199  newFrame = true;
2202  if (synced) {
2203  if (ErrorCheck)
2205  if (framesPerPayloadUnit <= 1)
2206  scanning = false;
2207  }
2208  else {
2209  if (parser->FramesPerSecond() > 0.0) {
2213  scanType = parser->ScanType();
2216  synced = true;
2217  parser->SetDebug(false);
2218  }
2220  if (independentFrame)
2221  numIFrames++;
2222  }
2223  }
2224  Handled = n;
2225  }
2226  }
2227  if (TsPayloadStart(Data)) {
2228  // Determine the frame rate from the PTS values in the PES headers:
2229  if (framesPerSecond <= 0.0) {
2230  // frame rate unknown, so collect a sequence of PTS values:
2231  if (numPtsValues < 2 || numPtsValues < MaxPtsValues && numIFrames < 2) { // collect a sequence containing at least two I-frames
2232  if (newFrame) { // only take PTS values at the beginning of a frame (in case of fields!)
2233  const uchar *Pes = Data + TsPayloadOffset(Data);
2234  if (numIFrames && PesHasPts(Pes)) {
2236  // check for rollover:
2237  if (numPtsValues && ptsValues[numPtsValues - 1] > 0xF0000000 && ptsValues[numPtsValues] < 0x10000000) {
2238  dbgframes("#");
2239  numPtsValues = 0;
2240  numIFrames = 0;
2241  }
2242  else
2243  numPtsValues++;
2244  }
2245  }
2246  }
2247  if (numPtsValues >= 2 && numIFrames >= 2) {
2248  // find the smallest PTS delta:
2249  qsort(ptsValues, numPtsValues, sizeof(uint32_t), CmpUint32);
2250  numPtsValues--;
2251  for (int i = 0; i < numPtsValues; i++)
2252  ptsValues[i] = ptsValues[i + 1] - ptsValues[i];
2253  qsort(ptsValues, numPtsValues, sizeof(uint32_t), CmpUint32);
2254  int Div = framesPerPayloadUnit;
2255  if (framesPerPayloadUnit > 1)
2257  if (Div <= 0)
2258  Div = 1;
2259  int Delta = ptsValues[0] / Div;
2260  // determine frame info:
2261  if (isVideo) {
2262  if (Delta == 3753)
2263  framesPerSecond = 24.0 / 1.001;
2264  else if (abs(Delta - 3600) <= 1)
2265  framesPerSecond = 25.0;
2266  else if (Delta % 3003 == 0)
2267  framesPerSecond = 30.0 / 1.001;
2268  else if (abs(Delta - 1800) <= 1)
2269  framesPerSecond = 50.0;
2270  else if (Delta == 1501)
2271  framesPerSecond = 60.0 / 1.001;
2272  else {
2274  dsyslog("unknown frame delta (%d), assuming %5.2f fps", Delta, framesPerSecond);
2275  }
2276  }
2277  else // audio
2278  framesPerSecond = double(PTSTICKS) / Delta; // PTS of audio frames is always increasing
2280  dbgframes("\nDelta = %d FPS = %5.2f FPPU = %d NF = %d TRO = %d\n", Delta, framesPerSecond, framesPerPayloadUnit, numPtsValues + 1, parser->IFrameTemporalReferenceOffset());
2281  synced = true;
2282  parser->SetDebug(false);
2283  }
2284  }
2285  }
2286  }
2287  else if (Pid == PATPID && synced && Processed)
2288  return Processed; // allow the caller to see any PAT packets
2289  }
2290  if (firstIframeSeen && ErrorCheck)
2291  frameChecker->CheckTs(Data, Handled);
2292  Data += Handled;
2293  Length -= Handled;
2294  Processed += Handled;
2295  if (newFrame)
2296  break;
2297  }
2298  return Processed;
2299 }
#define MAXDPIDS
Definition: channels.h:32
#define MAXAPIDS
Definition: channels.h:31
#define MAXSPIDS
Definition: channels.h:33
#define MAXLANGCODE1
Definition: channels.h:36
static u_int32_t crc32(const char *d, int len, u_int32_t CRCvalue)
Definition: util.c:267
bool CheckCRCAndParse()
Definition: si.c:65
Descriptor * getNext(Iterator &it)
Definition: si.c:112
DescriptorTag getDescriptorTag() const
Definition: si.c:100
StructureLoop< Language > languageLoop
Definition: descriptor.h:490
bool getCurrentNextIndicator() const
Definition: si.c:80
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
int getTransportStreamId() const
Definition: section.c:26
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
StructureLoop< Subtitling > subtitlingLoop
Definition: descriptor.h:332
virtual int Parse(const uchar *Data, int Length, int Pid) override
Parses the given Data, which is a sequence of Length bytes of TS packets.
Definition: remux.c:1230
cAudioParser(void)
Definition: remux.c:1226
const int * Dpids(void) const
Definition: channels.h:160
uint16_t AncillaryPageId(int i) const
Definition: channels.h:172
const char * Alang(int i) const
Definition: channels.h:165
uint16_t CompositionPageId(int i) const
Definition: channels.h:171
int Tpid(void) const
Definition: channels.h:173
int Vpid(void) const
Definition: channels.h:156
int Atype(int i) const
Definition: channels.h:168
int Dtype(int i) const
Definition: channels.h:169
int Dpid(int i) const
Definition: channels.h:163
int Vtype(void) const
Definition: channels.h:158
int Apid(int i) const
Definition: channels.h:162
int Ppid(void) const
Definition: channels.h:157
uchar SubtitlingType(int i) const
Definition: channels.h:170
int Spid(int i) const
Definition: channels.h:164
const int * Spids(void) const
Definition: channels.h:161
const int * Apids(void) const
Definition: channels.h:159
const char * Slang(int i) const
Definition: channels.h:167
const char * Dlang(int i) const
Definition: channels.h:166
void EnsureAudioTrack(bool Force=false)
Makes sure an audio track is selected that is actually available.
Definition: device.c:1227
void ClrAvailableTracks(bool DescriptionsOnly=false, bool IdsOnly=false)
Clears the list of currently available tracks.
Definition: device.c:1091
void EnsureSubtitleTrack(void)
Makes sure one of the preferred language subtitle tracks is selected.
Definition: device.c:1260
static cDevice * PrimaryDevice(void)
Returns the primary device.
Definition: device.h:148
bool SetAvailableTrack(eTrackType Type, int Index, uint16_t Id, const char *Language=NULL, const char *Description=NULL)
Sets the track of the given Type and Index to the given values.
Definition: device.c:1114
uchar eit[TS_SIZE]
Definition: remux.h:434
cEitGenerator(int Sid=0)
Definition: remux.c:949
int counter
Definition: remux.h:435
uchar * AddParentalRatingDescriptor(uchar *p, uchar ParentalRating=0)
Definition: remux.c:963
uint16_t YMDtoMJD(int Y, int M, int D)
Definition: remux.c:957
uchar * Generate(int Sid)
Definition: remux.c:974
int version
Definition: remux.h:436
uint32_t backRefs
Definition: remux.c:2008
int missingFrames
Definition: remux.c:2012
cTsChecker tsChecker
Definition: remux.c:2005
int MissingFrames(void)
Definition: remux.c:2021
int frameDelta
Definition: remux.c:2006
void Report(const char *Message, int NumErrors=1)
Definition: remux.c:2035
cFrameChecker(void)
Definition: remux.c:2024
void SetFrameDelta(int FrameDelta)
Definition: remux.c:2017
void CheckTs(const uchar *Data, int Length)
Definition: remux.c:2042
int previousErrors
Definition: remux.c:2011
int errors
Definition: remux.c:2010
int PreviousErrors(void)
Definition: remux.c:2020
int lastFwdRef
Definition: remux.c:2009
void SetMissing(void)
Definition: remux.c:2016
int64_t lastPts
Definition: remux.c:2007
void CheckFrame(const uchar *Data, int Length, bool IndependentFrame)
Definition: remux.c:2047
@ MaxPtsValues
Definition: remux.h:530
uint32_t ptsValues[MaxPtsValues]
Definition: remux.h:536
bool synced
Definition: remux.h:533
uint16_t frameHeight
Definition: remux.h:542
cFrameChecker * frameChecker
Definition: remux.h:552
uint16_t frameWidth
Definition: remux.h:541
bool scanning
Definition: remux.h:548
int framesPerPayloadUnit
Definition: remux.h:546
bool NewFrame(int *PreviousErrors=NULL, int *MissingFrames=NULL)
Returns true if the data given to the last call to Analyze() started a new frame.
Definition: remux.c:2160
~cFrameDetector()
Definition: remux.c:2124
bool firstIframeSeen
Definition: remux.h:549
int Analyze(const uchar *Data, int Length, bool ErrorCheck=true)
Analyzes the TS packets pointed to by Data.
Definition: remux.c:2171
double framesPerSecond
Definition: remux.h:540
int framesInPayloadUnit
Definition: remux.h:545
int numIFrames
Definition: remux.h:538
bool independentFrame
Definition: remux.h:535
cFrameDetector(int Pid=0, int Type=0)
Sets up a frame detector for the given Pid and stream Type.
Definition: remux.c:2105
eScanType scanType
Definition: remux.h:543
void SetMissing(void)
Call if this is a resumed recording, which has missing frames.
Definition: remux.c:2155
bool newFrame
Definition: remux.h:534
cFrameParser * parser
Definition: remux.h:550
int numPtsValues
Definition: remux.h:537
bool isVideo
Definition: remux.h:539
void SetPid(int Pid, int Type)
Sets the Pid and stream Type to detect frames for.
Definition: remux.c:2136
eAspectRatio aspectRatio
Definition: remux.h:544
uint16_t FrameWidth(void)
Definition: remux.c:1198
void SetDebug(bool Debug)
Definition: remux.c:1194
bool NewFrame(void)
Definition: remux.c:1195
eAspectRatio aspectRatio
Definition: remux.c:1183
double FramesPerSecond(void)
Definition: remux.c:1200
bool IndependentFrame(void)
Definition: remux.c:1196
bool newFrame
Definition: remux.c:1176
int iFrameTemporalReferenceOffset
Definition: remux.c:1178
double framesPerSecond
Definition: remux.c:1181
eScanType ScanType(void)
Definition: remux.c:1201
bool independentFrame
Definition: remux.c:1177
virtual ~cFrameParser()
Definition: remux.c:1186
uint16_t frameHeight
Definition: remux.c:1180
bool debug
Definition: remux.c:1175
virtual int Parse(const uchar *Data, int Length, int Pid)=0
Parses the given Data, which is a sequence of Length bytes of TS packets.
eAspectRatio AspectRatio(void)
Definition: remux.c:1202
eScanType scanType
Definition: remux.c:1182
uint16_t FrameHeight(void)
Definition: remux.c:1199
int IFrameTemporalReferenceOffset(void)
Definition: remux.c:1197
uint16_t frameWidth
Definition: remux.c:1179
cFrameParser(void)
Definition: remux.c:1205
uint32_t GetBits(int Bits)
Definition: remux.c:1442
cTsPayload tsPayload
Definition: remux.c:1378
void ParseAccessUnitDelimiter(void)
Definition: remux.c:1513
@ nutSequenceParameterSet
Definition: remux.c:1367
@ nutCodedSliceNonIdr
Definition: remux.c:1365
@ nutAccessUnitDelimiter
Definition: remux.c:1368
@ nutCodedSliceIdr
Definition: remux.c:1366
bool separate_colour_plane_flag
Definition: remux.c:1374
bool gotAccessUnitDelimiter
Definition: remux.c:1380
int zeroBytes
Definition: remux.c:1372
bool frame_mbs_only_flag
Definition: remux.c:1376
int bit
Definition: remux.c:1371
int log2_max_frame_num
Definition: remux.c:1375
virtual int Parse(const uchar *Data, int Length, int Pid) override
Parses the given Data, which is a sequence of Length bytes of TS packets.
Definition: remux.c:1470
uint32_t GetGolombUe(void)
Definition: remux.c:1450
uchar GetByte(bool Raw=false)
Gets the next data byte.
Definition: remux.c:1414
void ParseSliceHeader(void)
Definition: remux.c:1638
void ParseSequenceParameterSet(void)
Definition: remux.c:1520
uchar byte
Definition: remux.c:1370
uint32_t scanner
Definition: remux.c:1379
bool gotSequenceParameterSet
Definition: remux.c:1381
int32_t GetGolombSe(void)
Definition: remux.c:1458
cH264Parser(void)
Sets up a new H.264 parser.
Definition: remux.c:1401
uchar GetBit(void)
Definition: remux.c:1433
virtual int Parse(const uchar *Data, int Length, int Pid) override
Parses the given Data, which is a sequence of Length bytes of TS packets.
Definition: remux.c:1708
cH265Parser(void)
Definition: remux.c:1703
@ nutSliceSegmentIDRWRADL
Definition: remux.c:1680
@ nutUnspecified0
Definition: remux.c:1694
@ nutSliceSegmentSTSAN
Definition: remux.c:1671
@ nutSliceSegmentRADLN
Definition: remux.c:1673
@ nutSliceSegmentIDRNLP
Definition: remux.c:1681
@ nutPrefixSEI
Definition: remux.c:1690
@ nutAccessUnitDelimiter
Definition: remux.c:1686
@ nutUnspecified7
Definition: remux.c:1695
@ nutSliceSegmentBLAWRADL
Definition: remux.c:1678
@ nutSliceSegmentTSAR
Definition: remux.c:1670
@ nutSliceSegmentRADLR
Definition: remux.c:1674
@ nutSliceSegmentTrailingR
Definition: remux.c:1668
@ nutVideoParameterSet
Definition: remux.c:1683
@ nutSequenceParameterSet
Definition: remux.c:1684
@ nutSliceSegmentTSAN
Definition: remux.c:1669
@ nutSliceSegmentRASLN
Definition: remux.c:1675
@ nutSuffixSEI
Definition: remux.c:1691
@ nutSliceSegmentBLAWLP
Definition: remux.c:1677
@ nutEndOfBitstream
Definition: remux.c:1688
@ nutSliceSegmentBLANLP
Definition: remux.c:1679
@ nutSliceSegmentRASLR
Definition: remux.c:1676
@ nutPictureParameterSet
Definition: remux.c:1685
@ nutNonVCLRes3
Definition: remux.c:1693
@ nutSliceSegmentCRANUT
Definition: remux.c:1682
@ nutSliceSegmentTrailingN
Definition: remux.c:1667
@ nutNonVCLRes0
Definition: remux.c:1692
@ nutFillerData
Definition: remux.c:1689
@ nutSliceSegmentSTSAR
Definition: remux.c:1672
@ nutEndOfSequence
Definition: remux.c:1687
void ParseSequenceParameterSet(void)
Definition: remux.c:1742
bool seenIndependentFrame
Definition: remux.c:1247
cMpeg2Parser(void)
Definition: remux.c:1266
bool seenScanType
Definition: remux.c:1249
int lastIFrameTemporalReference
Definition: remux.c:1248
uint32_t scanner
Definition: remux.c:1246
const double frame_rate_table[9]
Definition: remux.c:1250
virtual int Parse(const uchar *Data, int Length, int Pid) override
Parses the given Data, which is a sequence of Length bytes of TS packets.
Definition: remux.c:1274
int pmtVersion
Definition: remux.h:306
int pmtCounter
Definition: remux.h:304
int MakeCRC(uchar *Target, const uchar *Data, int Length)
Definition: remux.c:453
uchar * GetPmt(int &Index)
Returns a pointer to the Index'th TS packet of the PMT section.
Definition: remux.c:602
void SetChannel(const cChannel *Channel)
Sets the Channel for which the PAT/PMT shall be generated.
Definition: remux.c:587
void IncEsInfoLength(int Length)
Definition: remux.c:386
void IncCounter(int &Counter, uchar *TsPacket)
Definition: remux.c:373
cPatPmtGenerator(const cChannel *Channel=NULL)
Definition: remux.c:363
void SetVersions(int PatVersion, int PmtVersion)
Sets the version numbers for the generated PAT and PMT, in case this generator is used to,...
Definition: remux.c:581
int numPmtPackets
Definition: remux.h:302
uchar * esInfoLength
Definition: remux.h:308
uchar pat[TS_SIZE]
Definition: remux.h:300
int MakeAC3Descriptor(uchar *Target, uchar Type)
Definition: remux.c:407
void GeneratePat(void)
Generates a PAT section for later use with GetPat().
Definition: remux.c:483
uchar * GetPat(void)
Returns a pointer to the PAT section, which consists of exactly one TS packet.
Definition: remux.c:596
int patVersion
Definition: remux.h:305
uchar pmt[MAX_PMT_TS][TS_SIZE]
Definition: remux.h:301
int MakeLanguageDescriptor(uchar *Target, const char *Language)
Definition: remux.c:434
void GeneratePmt(const cChannel *Channel)
Generates a PMT section for the given Channel, for later use with GetPmt().
Definition: remux.c:512
void GeneratePmtPid(const cChannel *Channel)
Generates a PMT pid that doesn't collide with any of the actual pids of the Channel.
Definition: remux.c:468
int patCounter
Definition: remux.h:303
int MakeStream(uchar *Target, uchar Type, int Pid)
Definition: remux.c:395
int MakeSubtitlingDescriptor(uchar *Target, const char *Language, uchar SubtitlingType, uint16_t CompositionPageId, uint16_t AncillaryPageId)
Definition: remux.c:417
void IncVersion(int &Version)
Definition: remux.c:380
int ppid
Definition: remux.h:361
bool GetVersions(int &PatVersion, int &PmtVersion) const
Returns true if a valid PAT/PMT has been parsed and stores the current version numbers in the given v...
Definition: remux.c:940
int dpids[MAXDPIDS+1]
Definition: remux.h:366
uchar pmt[MAX_SECTION_SIZE]
Definition: remux.h:355
int apids[MAXAPIDS+1]
Definition: remux.h:363
int vpid
Definition: remux.h:360
cPatPmtParser(bool UpdatePrimaryDevice=false)
Definition: remux.c:613
void Reset(void)
Resets the parser.
Definition: remux.c:619
void ParsePat(const uchar *Data, int Length)
Parses the PAT data from the single TS packet in Data.
Definition: remux.c:629
int vtype
Definition: remux.h:362
int pmtSize
Definition: remux.h:356
char dlangs[MAXDPIDS][MAXLANGCODE2]
Definition: remux.h:368
bool ParsePatPmt(const uchar *Data, int Length)
Parses the given Data (which may consist of several TS packets, typically an entire frame) and extrac...
Definition: remux.c:921
int patVersion
Definition: remux.h:357
int pmtPids[MAX_PMT_PIDS+1]
Definition: remux.h:359
uchar subtitlingTypes[MAXSPIDS]
Definition: remux.h:371
int dtypes[MAXDPIDS+1]
Definition: remux.h:367
uint16_t ancillaryPageIds[MAXSPIDS]
Definition: remux.h:373
int SectionLength(const uchar *Data, int Length)
Definition: remux.h:377
void ParsePmt(const uchar *Data, int Length)
Parses the PMT data from the single TS packet in Data.
Definition: remux.c:661
bool completed
Definition: remux.h:375
bool IsPmtPid(int Pid) const
Returns true if Pid the one of the PMT pids as defined by the current PAT.
Definition: remux.h:400
uint16_t compositionPageIds[MAXSPIDS]
Definition: remux.h:372
char alangs[MAXAPIDS][MAXLANGCODE2]
Definition: remux.h:365
int spids[MAXSPIDS+1]
Definition: remux.h:369
int pmtVersion
Definition: remux.h:358
bool updatePrimaryDevice
Definition: remux.h:374
char slangs[MAXSPIDS][MAXLANGCODE2]
Definition: remux.h:370
int atypes[MAXAPIDS+1]
Definition: remux.h:364
static void SetBrokenLink(uchar *Data, int Length)
Definition: remux.c:102
int UseDolbyDigital
Definition: config.h:336
Definition: tools.h:178
static cString sprintf(const char *fmt,...) __attribute__((format(printf
Definition: tools.c:1195
uchar counter[MAXPID]
Definition: remux.c:1951
cTsChecker(void)
Definition: remux.c:1961
void CheckTs(const uchar *Data, int Length)
Definition: remux.c:1974
int errors
Definition: remux.c:1952
int Errors(void)
Definition: remux.c:1957
void Report(int Pid, const char *Message)
Definition: remux.c:1967
void Clear(void)
Definition: remux.c:1958
int numPacketsPid
Definition: remux.h:232
int pid
Definition: remux.h:230
cTsPayload(void)
Definition: remux.c:246
bool AtPayloadStart(void)
Returns true if this payload handler is currently pointing to the first byte of a TS packet that star...
Definition: remux.h:252
int Used(void)
Returns the number of raw bytes that have already been used (e.g.
Definition: remux.h:258
bool Eof(void) const
Returns true if all available bytes of the TS payload have been processed.
Definition: remux.h:262
void SetByte(uchar Byte, int Index)
Sets the TS data byte at the given Index to the value Byte.
Definition: remux.c:330
uchar GetByte(void)
Gets the next byte of the TS payload, skipping any intermediate TS header data.
Definition: remux.c:280
bool AtTsStart(void)
Returns true if this payload handler is currently pointing to first byte of a TS packet.
Definition: remux.h:249
int GetLastIndex(void)
Returns the index into the TS data of the payload byte that has most recently been read.
Definition: remux.c:325
void Setup(uchar *Data, int Length, int Pid=-1)
Sets up this TS payload handler with the given Data, which points to a sequence of Length bytes of co...
Definition: remux.c:272
bool SkipPesHeader(void)
Skips all bytes belonging to the PES header of the payload.
Definition: remux.c:320
int index
Definition: remux.h:231
int numPacketsOther
Definition: remux.h:233
void Statistics(void) const
May be called after a new frame has been detected, and will log a warning if the number of TS packets...
Definition: remux.c:353
uchar SetEof(void)
Definition: remux.c:259
int length
Definition: remux.h:229
bool Find(uint32_t Code)
Searches for the four byte sequence given in Code and returns true if it was found within the payload...
Definition: remux.c:336
void Reset(void)
Definition: remux.c:265
uchar * data
Definition: remux.h:228
bool SkipBytes(int Bytes)
Skips the given number of bytes in the payload and returns true if there is still data left to read.
Definition: remux.c:313
int lastLength
Definition: remux.h:457
bool repeatLast
Definition: remux.h:458
uchar * lastData
Definition: remux.h:456
uchar * data
Definition: remux.h:452
void PutTs(const uchar *Data, int Length)
Puts the payload data of the single TS packet at Data into the converter.
Definition: remux.c:1048
void SetRepeatLast(void)
Makes the next call to GetPes() return exactly the same data as the last one (provided there was no c...
Definition: remux.c:1125
const uchar * GetPes(int &Length)
Gets a pointer to the complete PES packet, or NULL if the packet is not complete yet.
Definition: remux.c:1077
cTsToPes(void)
Definition: remux.c:1036
int length
Definition: remux.h:454
~cTsToPes()
Definition: remux.c:1043
void Reset(void)
Resets the converter.
Definition: remux.c:1130
int offset
Definition: remux.h:455
int size
Definition: remux.h:453
cSetup Setup
Definition: config.c:372
@ ttSubtitle
Definition: device.h:70
@ ttDolby
Definition: device.h:67
@ ttAudio
Definition: device.h:64
const char * I18nNormalizeLanguageCode(const char *Code)
Returns a 3 letter language code that may not be zero terminated.
Definition: i18n.c:286
@ EnhancedAC3DescriptorTag
Definition: si.h:136
@ SubtitlingDescriptorTag
Definition: si.h:102
@ ISO639LanguageDescriptorTag
Definition: si.h:60
@ ParentalRatingDescriptorTag
Definition: si.h:98
@ AC3DescriptorTag
Definition: si.h:119
unsigned char u_char
Definition: headers.h:24
#define DEFAULTFRAMESPERSECOND
Definition: recording.h:378
void TsSetPcr(uchar *p, int64_t Pcr)
Definition: remux.c:131
const char * AspectRatioTexts[]
Definition: remux.c:2096
#define WRN_TS_PACKETS_FOR_VIDEO_FRAME_DETECTION
Definition: remux.c:27
#define dbgframes(a...)
Definition: remux.c:24
#define WRN_TS_PACKETS_FOR_FRAME_DETECTOR
Definition: remux.c:28
#define SETPID(p)
void PesDump(const char *Name, const u_char *Data, int Length)
Definition: remux.c:1166
static bool DebugFrames
Definition: remux.c:21
int64_t PtsDiff(int64_t Pts1, int64_t Pts2)
Returns the difference between two PTS values.
Definition: remux.c:234
const char * ScanTypeChars
Definition: remux.c:2095
#define MAXPESLENGTH
Definition: remux.c:1075
#define P_PMT_PID
Definition: remux.c:465
void TsHidePayload(uchar *p)
Definition: remux.c:121
static int CmpUint32(const void *p1, const void *p2)
Definition: remux.c:2129
#define MAXPID
Definition: remux.c:466
void PesSetDts(uchar *p, int64_t Dts)
Definition: remux.c:225
#define EMPTY_SCANNER
Definition: remux.c:30
static bool DebugPatPmt
Definition: remux.c:20
static bool DebugChecks
Definition: remux.c:1936
int64_t TsGetDts(const uchar *p, int l)
Definition: remux.c:173
#define TS_CC_UNKNOWN
Definition: remux.c:1947
void TsSetDts(uchar *p, int l, int64_t Dts)
Definition: remux.c:200
void TsSetPts(uchar *p, int l, int64_t Pts)
Definition: remux.c:186
ePesHeader AnalyzePesHeader(const uchar *Data, int Count, int &PesPayloadOffset, bool *ContinuationHeader)
Definition: remux.c:32
#define dbgpatpmt(a...)
Definition: remux.c:23
#define VIDEO_STREAM_S
Definition: remux.c:98
void PesSetPts(uchar *p, int64_t Pts)
Definition: remux.c:216
int64_t TsGetPts(const uchar *p, int l)
Definition: remux.c:160
void BlockDump(const char *Name, const u_char *Data, int Length)
Definition: remux.c:1140
int TsSync(const uchar *Data, int Length, const char *File, const char *Function, int Line)
Definition: remux.c:147
#define MAX_BACK_REFS
Definition: remux.c:2001
#define SETPIDS(l)
#define P_TSID
Definition: remux.c:464
void TsDump(const char *Name, const u_char *Data, int Length)
Definition: remux.c:1151
#define MAX_TS_PACKETS_FOR_VIDEO_FRAME_DETECTION
Definition: remux.c:26
bool TsError(const uchar *p)
Definition: remux.h:77
#define TS_ADAPT_PCR
Definition: remux.h:46
int TsPid(const uchar *p)
Definition: remux.h:82
bool TsHasPayload(const uchar *p)
Definition: remux.h:62
#define MAX33BIT
Definition: remux.h:59
#define MAX_PMT_PIDS
Definition: remux.h:351
int PesPayloadOffset(const uchar *p)
Definition: remux.h:178
#define PATPID
Definition: remux.h:52
bool TsIsScrambled(const uchar *p)
Definition: remux.h:93
uchar TsContinuityCounter(const uchar *p)
Definition: remux.h:98
int TsGetPayload(const uchar **p)
Definition: remux.h:114
#define TS_PAYLOAD_EXISTS
Definition: remux.h:41
bool PesHasPts(const uchar *p)
Definition: remux.h:183
bool PesLongEnough(int Length)
Definition: remux.h:163
#define TS_SIZE
Definition: remux.h:34
eAspectRatio
Definition: remux.h:514
@ ar_16_9
Definition: remux.h:518
@ ar_1_1
Definition: remux.h:516
@ arUnknown
Definition: remux.h:515
@ ar_4_3
Definition: remux.h:517
@ ar_2_21_1
Definition: remux.h:519
eScanType
Definition: remux.h:507
@ stInterlaced
Definition: remux.h:510
@ stProgressive
Definition: remux.h:509
@ stUnknown
Definition: remux.h:508
#define MAX_SECTION_SIZE
Definition: remux.h:295
int64_t PesGetDts(const uchar *p)
Definition: remux.h:202
#define TS_ADAPT_FIELD_EXISTS
Definition: remux.h:40
int64_t PesGetPts(const uchar *p)
Definition: remux.h:193
bool TsPayloadStart(const uchar *p)
Definition: remux.h:72
#define TS_SYNC(Data, Length)
Definition: remux.h:149
int TsPayloadOffset(const uchar *p)
Definition: remux.h:108
bool PesHasDts(const uchar *p)
Definition: remux.h:188
#define PCRFACTOR
Definition: remux.h:58
#define TS_SYNC_BYTE
Definition: remux.h:33
bool PesHasLength(const uchar *p)
Definition: remux.h:168
bool TsHasAdaptationField(const uchar *p)
Definition: remux.h:67
#define PTSTICKS
Definition: remux.h:57
#define MIN_TS_PACKETS_FOR_FRAME_DETECTOR
Definition: remux.h:503
int PesLength(const uchar *p)
Definition: remux.h:173
ePesHeader
Definition: remux.h:16
@ phMPEG2
Definition: remux.h:20
@ phNeedMoreData
Definition: remux.h:17
@ phInvalid
Definition: remux.h:18
@ phMPEG1
Definition: remux.h:19
#define EITPID
Definition: remux.h:54
#define TS_CONT_CNT_MASK
Definition: remux.h:42
#define TS_PAYLOAD_START
Definition: remux.h:36
cString TimeToString(time_t t)
Converts the given time to a string of the form "www mmm dd hh:mm:ss yyyy".
Definition: tools.c:1271
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
T min(T a, T b)
Definition: tools.h:63
T max(T a, T b)
Definition: tools.h:64
#define esyslog(a...)
Definition: tools.h:35
#define KILOBYTE(n)
Definition: tools.h:44