vdr  2.6.1
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.2 2022/01/18 14:24:33 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 (TsHasPayload(p)) {
291  if (index > 0 && TsPayloadStart(p)) // checking index to not skip the very first TS packet
292  return SetEof();
293  index += TsPayloadOffset(p);
294  break;
295  }
296  }
297  else if (TsPid(p) == PATPID)
298  return SetEof(); // caller must see PAT packets in case of index regeneration
299  else
300  numPacketsOther++;
301  }
302  else
303  return SetEof();
304  }
305  }
306  return data[index++];
307  }
308  return 0x00;
309 }
310 
311 bool cTsPayload::SkipBytes(int Bytes)
312 {
313  while (Bytes-- > 0)
314  GetByte();
315  return !Eof();
316 }
317 
319 {
321 }
322 
324 {
325  return index - 1;
326 }
327 
328 void cTsPayload::SetByte(uchar Byte, int Index)
329 {
330  if (Index >= 0 && Index < length)
331  data[Index] = Byte;
332 }
333 
334 bool cTsPayload::Find(uint32_t Code)
335 {
336  int OldIndex = index;
337  int OldNumPacketsPid = numPacketsPid;
338  int OldNumPacketsOther = numPacketsOther;
339  uint32_t Scanner = EMPTY_SCANNER;
340  while (!Eof()) {
341  Scanner = (Scanner << 8) | GetByte();
342  if (Scanner == Code)
343  return true;
344  }
345  index = OldIndex;
346  numPacketsPid = OldNumPacketsPid;
347  numPacketsOther = OldNumPacketsOther;
348  return false;
349 }
350 
351 void cTsPayload::Statistics(void) const
352 {
354  dsyslog("WARNING: required (%d+%d) TS packets to determine frame type", numPacketsOther, numPacketsPid);
356  dsyslog("WARNING: required %d video TS packets to determine frame type", numPacketsPid);
357 }
358 
359 // --- cPatPmtGenerator ------------------------------------------------------
360 
362 {
363  numPmtPackets = 0;
364  patCounter = pmtCounter = 0;
365  patVersion = pmtVersion = 0;
366  pmtPid = 0;
367  esInfoLength = NULL;
368  SetChannel(Channel);
369 }
370 
371 void cPatPmtGenerator::IncCounter(int &Counter, uchar *TsPacket)
372 {
373  TsPacket[3] = (TsPacket[3] & 0xF0) | Counter;
374  if (++Counter > 0x0F)
375  Counter = 0x00;
376 }
377 
379 {
380  if (++Version > 0x1F)
381  Version = 0x00;
382 }
383 
385 {
386  if (esInfoLength) {
387  Length += ((*esInfoLength & 0x0F) << 8) | *(esInfoLength + 1);
388  *esInfoLength = 0xF0 | (Length >> 8);
389  *(esInfoLength + 1) = Length;
390  }
391 }
392 
393 int cPatPmtGenerator::MakeStream(uchar *Target, uchar Type, int Pid)
394 {
395  int i = 0;
396  Target[i++] = Type; // stream type
397  Target[i++] = 0xE0 | (Pid >> 8); // dummy (3), pid hi (5)
398  Target[i++] = Pid; // pid lo
399  esInfoLength = &Target[i];
400  Target[i++] = 0xF0; // dummy (4), ES info length hi
401  Target[i++] = 0x00; // ES info length lo
402  return i;
403 }
404 
406 {
407  int i = 0;
408  Target[i++] = Type;
409  Target[i++] = 0x01; // length
410  Target[i++] = 0x00;
411  IncEsInfoLength(i);
412  return i;
413 }
414 
415 int cPatPmtGenerator::MakeSubtitlingDescriptor(uchar *Target, const char *Language, uchar SubtitlingType, uint16_t CompositionPageId, uint16_t AncillaryPageId)
416 {
417  int i = 0;
418  Target[i++] = SI::SubtitlingDescriptorTag;
419  Target[i++] = 0x08; // length
420  Target[i++] = *Language++;
421  Target[i++] = *Language++;
422  Target[i++] = *Language++;
423  Target[i++] = SubtitlingType;
424  Target[i++] = CompositionPageId >> 8;
425  Target[i++] = CompositionPageId & 0xFF;
426  Target[i++] = AncillaryPageId >> 8;
427  Target[i++] = AncillaryPageId & 0xFF;
428  IncEsInfoLength(i);
429  return i;
430 }
431 
432 int cPatPmtGenerator::MakeLanguageDescriptor(uchar *Target, const char *Language)
433 {
434  int i = 0;
435  Target[i++] = SI::ISO639LanguageDescriptorTag;
436  int Length = i++;
437  Target[Length] = 0x00; // length
438  for (const char *End = Language + strlen(Language); Language < End; ) {
439  Target[i++] = *Language++;
440  Target[i++] = *Language++;
441  Target[i++] = *Language++;
442  Target[i++] = 0x00; // audio type
443  Target[Length] += 0x04; // length
444  if (*Language == '+')
445  Language++;
446  }
447  IncEsInfoLength(i);
448  return i;
449 }
450 
451 int cPatPmtGenerator::MakeCRC(uchar *Target, const uchar *Data, int Length)
452 {
453  int crc = SI::CRC32::crc32((const char *)Data, Length, 0xFFFFFFFF);
454  int i = 0;
455  Target[i++] = crc >> 24;
456  Target[i++] = crc >> 16;
457  Target[i++] = crc >> 8;
458  Target[i++] = crc;
459  return i;
460 }
461 
462 #define P_TSID 0x8008 // pseudo TS ID
463 #define P_PMT_PID 0x0084 // pseudo PMT pid
464 #define MAXPID 0x2000 // the maximum possible number of pids
465 
467 {
468  bool Used[MAXPID] = { false };
469 #define SETPID(p) { if ((p) >= 0 && (p) < MAXPID) Used[p] = true; }
470 #define SETPIDS(l) { const int *p = l; while (*p) { SETPID(*p); p++; } }
471  SETPID(Channel->Vpid());
472  SETPID(Channel->Ppid());
473  SETPID(Channel->Tpid());
474  SETPIDS(Channel->Apids());
475  SETPIDS(Channel->Dpids());
476  SETPIDS(Channel->Spids());
477  for (pmtPid = P_PMT_PID; Used[pmtPid]; pmtPid++)
478  ;
479 }
480 
482 {
483  memset(pat, 0xFF, sizeof(pat));
484  uchar *p = pat;
485  int i = 0;
486  p[i++] = TS_SYNC_BYTE; // TS indicator
487  p[i++] = TS_PAYLOAD_START | (PATPID >> 8); // flags (3), pid hi (5)
488  p[i++] = PATPID & 0xFF; // pid lo
489  p[i++] = 0x10; // flags (4), continuity counter (4)
490  p[i++] = 0x00; // pointer field (payload unit start indicator is set)
491  int PayloadStart = i;
492  p[i++] = 0x00; // table id
493  p[i++] = 0xB0; // section syntax indicator (1), dummy (3), section length hi (4)
494  int SectionLength = i;
495  p[i++] = 0x00; // section length lo (filled in later)
496  p[i++] = P_TSID >> 8; // TS id hi
497  p[i++] = P_TSID & 0xFF; // TS id lo
498  p[i++] = 0xC1 | (patVersion << 1); // dummy (2), version number (5), current/next indicator (1)
499  p[i++] = 0x00; // section number
500  p[i++] = 0x00; // last section number
501  p[i++] = pmtPid >> 8; // program number hi
502  p[i++] = pmtPid & 0xFF; // program number lo
503  p[i++] = 0xE0 | (pmtPid >> 8); // dummy (3), PMT pid hi (5)
504  p[i++] = pmtPid & 0xFF; // PMT pid lo
505  pat[SectionLength] = i - SectionLength - 1 + 4; // -1 = SectionLength storage, +4 = length of CRC
506  MakeCRC(pat + i, pat + PayloadStart, i - PayloadStart);
508 }
509 
511 {
512  // generate the complete PMT section:
513  uchar buf[MAX_SECTION_SIZE];
514  memset(buf, 0xFF, sizeof(buf));
515  numPmtPackets = 0;
516  if (Channel) {
517  int Vpid = Channel->Vpid();
518  int Ppid = Channel->Ppid();
519  uchar *p = buf;
520  int i = 0;
521  p[i++] = 0x02; // table id
522  int SectionLength = i;
523  p[i++] = 0xB0; // section syntax indicator (1), dummy (3), section length hi (4)
524  p[i++] = 0x00; // section length lo (filled in later)
525  p[i++] = pmtPid >> 8; // program number hi
526  p[i++] = pmtPid & 0xFF; // program number lo
527  p[i++] = 0xC1 | (pmtVersion << 1); // dummy (2), version number (5), current/next indicator (1)
528  p[i++] = 0x00; // section number
529  p[i++] = 0x00; // last section number
530  p[i++] = 0xE0 | (Ppid >> 8); // dummy (3), PCR pid hi (5)
531  p[i++] = Ppid; // PCR pid lo
532  p[i++] = 0xF0; // dummy (4), program info length hi (4)
533  p[i++] = 0x00; // program info length lo
534 
535  if (Vpid)
536  i += MakeStream(buf + i, Channel->Vtype(), Vpid);
537  for (int n = 0; Channel->Apid(n); n++) {
538  i += MakeStream(buf + i, Channel->Atype(n), Channel->Apid(n));
539  const char *Alang = Channel->Alang(n);
540  i += MakeLanguageDescriptor(buf + i, Alang);
541  }
542  for (int n = 0; Channel->Dpid(n); n++) {
543  i += MakeStream(buf + i, 0x06, Channel->Dpid(n));
544  i += MakeAC3Descriptor(buf + i, Channel->Dtype(n));
545  i += MakeLanguageDescriptor(buf + i, Channel->Dlang(n));
546  }
547  for (int n = 0; Channel->Spid(n); n++) {
548  i += MakeStream(buf + i, 0x06, Channel->Spid(n));
549  i += MakeSubtitlingDescriptor(buf + i, Channel->Slang(n), Channel->SubtitlingType(n), Channel->CompositionPageId(n), Channel->AncillaryPageId(n));
550  }
551 
552  int sl = i - SectionLength - 2 + 4; // -2 = SectionLength storage, +4 = length of CRC
553  buf[SectionLength] |= (sl >> 8) & 0x0F;
554  buf[SectionLength + 1] = sl;
555  MakeCRC(buf + i, buf, i);
556  // split the PMT section into several TS packets:
557  uchar *q = buf;
558  bool pusi = true;
559  while (i > 0) {
560  uchar *p = pmt[numPmtPackets++];
561  int j = 0;
562  p[j++] = TS_SYNC_BYTE; // TS indicator
563  p[j++] = (pusi ? TS_PAYLOAD_START : 0x00) | (pmtPid >> 8); // flags (3), pid hi (5)
564  p[j++] = pmtPid & 0xFF; // pid lo
565  p[j++] = 0x10; // flags (4), continuity counter (4)
566  if (pusi) {
567  p[j++] = 0x00; // pointer field (payload unit start indicator is set)
568  pusi = false;
569  }
570  int l = TS_SIZE - j;
571  memcpy(p + j, q, l);
572  q += l;
573  i -= l;
574  }
576  }
577 }
578 
579 void cPatPmtGenerator::SetVersions(int PatVersion, int PmtVersion)
580 {
581  patVersion = PatVersion & 0x1F;
582  pmtVersion = PmtVersion & 0x1F;
583 }
584 
586 {
587  if (Channel) {
588  GeneratePmtPid(Channel);
589  GeneratePat();
590  GeneratePmt(Channel);
591  }
592 }
593 
595 {
597  return pat;
598 }
599 
601 {
602  if (Index < numPmtPackets) {
603  IncCounter(pmtCounter, pmt[Index]);
604  return pmt[Index++];
605  }
606  return NULL;
607 }
608 
609 // --- cPatPmtParser ---------------------------------------------------------
610 
611 cPatPmtParser::cPatPmtParser(bool UpdatePrimaryDevice)
612 {
613  updatePrimaryDevice = UpdatePrimaryDevice;
614  Reset();
615 }
616 
618 {
619  completed = false;
620  pmtSize = 0;
621  patVersion = pmtVersion = -1;
622  pmtPids[0] = 0;
623  vpid = vtype = 0;
624  ppid = 0;
625 }
626 
627 void cPatPmtParser::ParsePat(const uchar *Data, int Length)
628 {
629  // Unpack the TS packet:
630  int PayloadOffset = TsPayloadOffset(Data);
631  Data += PayloadOffset;
632  Length -= PayloadOffset;
633  // The PAT is always assumed to fit into a single TS packet
634  if ((Length -= Data[0] + 1) <= 0)
635  return;
636  Data += Data[0] + 1; // process pointer_field
637  SI::PAT Pat(Data, false);
638  if (Pat.CheckCRCAndParse()) {
639  dbgpatpmt("PAT: TSid = %d, c/n = %d, v = %d, s = %d, ls = %d\n", Pat.getTransportStreamId(), Pat.getCurrentNextIndicator(), Pat.getVersionNumber(), Pat.getSectionNumber(), Pat.getLastSectionNumber());
640  if (patVersion == Pat.getVersionNumber())
641  return;
642  int NumPmtPids = 0;
643  SI::PAT::Association assoc;
644  for (SI::Loop::Iterator it; Pat.associationLoop.getNext(assoc, it); ) {
645  dbgpatpmt(" isNITPid = %d\n", assoc.isNITPid());
646  if (!assoc.isNITPid()) {
647  if (NumPmtPids <= MAX_PMT_PIDS)
648  pmtPids[NumPmtPids++] = assoc.getPid();
649  dbgpatpmt(" service id = %d, pid = %d\n", assoc.getServiceId(), assoc.getPid());
650  }
651  }
652  pmtPids[NumPmtPids] = 0;
654  }
655  else
656  esyslog("ERROR: can't parse PAT");
657 }
658 
659 void cPatPmtParser::ParsePmt(const uchar *Data, int Length)
660 {
661  // Unpack the TS packet:
662  bool PayloadStart = TsPayloadStart(Data);
663  int PayloadOffset = TsPayloadOffset(Data);
664  Data += PayloadOffset;
665  Length -= PayloadOffset;
666  // The PMT may extend over several TS packets, so we need to assemble them
667  if (PayloadStart) {
668  pmtSize = 0;
669  if ((Length -= Data[0] + 1) <= 0)
670  return;
671  Data += Data[0] + 1; // this is the first packet
672  if (SectionLength(Data, Length) > Length) {
673  if (Length <= int(sizeof(pmt))) {
674  memcpy(pmt, Data, Length);
675  pmtSize = Length;
676  }
677  else
678  esyslog("ERROR: PMT packet length too big (%d byte)!", Length);
679  return;
680  }
681  // the packet contains the entire PMT section, so we run into the actual parsing
682  }
683  else if (pmtSize > 0) {
684  // this is a following packet, so we add it to the pmt storage
685  if (Length <= int(sizeof(pmt)) - pmtSize) {
686  memcpy(pmt + pmtSize, Data, Length);
687  pmtSize += Length;
688  }
689  else {
690  esyslog("ERROR: PMT section length too big (%d byte)!", pmtSize + Length);
691  pmtSize = 0;
692  }
694  return; // more packets to come
695  // the PMT section is now complete, so we run into the actual parsing
696  Data = pmt;
697  }
698  else
699  return; // fragment of broken packet - ignore
700  SI::PMT Pmt(Data, false);
701  if (Pmt.CheckCRCAndParse()) {
702  dbgpatpmt("PMT: sid = %d, c/n = %d, v = %d, s = %d, ls = %d\n", Pmt.getServiceId(), Pmt.getCurrentNextIndicator(), Pmt.getVersionNumber(), Pmt.getSectionNumber(), Pmt.getLastSectionNumber());
703  dbgpatpmt(" pcr = %d\n", Pmt.getPCRPid());
704  if (pmtVersion == Pmt.getVersionNumber())
705  return;
708  int NumApids = 0;
709  int NumDpids = 0;
710  int NumSpids = 0;
711  vpid = vtype = 0;
712  ppid = 0;
713  apids[0] = 0;
714  dpids[0] = 0;
715  spids[0] = 0;
716  atypes[0] = 0;
717  dtypes[0] = 0;
718  SI::PMT::Stream stream;
719  for (SI::Loop::Iterator it; Pmt.streamLoop.getNext(stream, it); ) {
720  dbgpatpmt(" stream type = %02X, pid = %d", stream.getStreamType(), stream.getPid());
721  switch (stream.getStreamType()) {
722  case 0x01: // STREAMTYPE_11172_VIDEO
723  case 0x02: // STREAMTYPE_13818_VIDEO
724  case 0x1B: // H.264
725  case 0x24: // H.265
726  vpid = stream.getPid();
727  vtype = stream.getStreamType();
728  ppid = Pmt.getPCRPid();
729  break;
730  case 0x03: // STREAMTYPE_11172_AUDIO
731  case 0x04: // STREAMTYPE_13818_AUDIO
732  case 0x0F: // ISO/IEC 13818-7 Audio with ADTS transport syntax
733  case 0x11: // ISO/IEC 14496-3 Audio with LATM transport syntax
734  {
735  if (NumApids < MAXAPIDS) {
736  apids[NumApids] = stream.getPid();
737  atypes[NumApids] = stream.getStreamType();
738  *alangs[NumApids] = 0;
739  SI::Descriptor *d;
740  for (SI::Loop::Iterator it; (d = stream.streamDescriptors.getNext(it)); ) {
741  switch (d->getDescriptorTag()) {
745  char *s = alangs[NumApids];
746  int n = 0;
747  for (SI::Loop::Iterator it; ld->languageLoop.getNext(l, it); ) {
748  if (*ld->languageCode != '-') { // some use "---" to indicate "none"
749  dbgpatpmt(" '%s'", l.languageCode);
750  if (n > 0)
751  *s++ = '+';
753  s += strlen(s);
754  if (n++ > 1)
755  break;
756  }
757  }
758  }
759  break;
760  default: ;
761  }
762  delete d;
763  }
765  cDevice::PrimaryDevice()->SetAvailableTrack(ttAudio, NumApids, apids[NumApids], alangs[NumApids]);
766  NumApids++;
767  apids[NumApids] = 0;
768  }
769  }
770  break;
771  case 0x06: // STREAMTYPE_13818_PES_PRIVATE
772  {
773  int dpid = 0;
774  int dtype = 0;
775  char lang[MAXLANGCODE1] = "";
776  SI::Descriptor *d;
777  for (SI::Loop::Iterator it; (d = stream.streamDescriptors.getNext(it)); ) {
778  switch (d->getDescriptorTag()) {
781  dbgpatpmt(" AC3");
782  dpid = stream.getPid();
783  dtype = d->getDescriptorTag();
784  break;
786  dbgpatpmt(" subtitling");
787  if (NumSpids < MAXSPIDS) {
788  spids[NumSpids] = stream.getPid();
789  *slangs[NumSpids] = 0;
790  subtitlingTypes[NumSpids] = 0;
791  compositionPageIds[NumSpids] = 0;
792  ancillaryPageIds[NumSpids] = 0;
795  char *s = slangs[NumSpids];
796  int n = 0;
797  for (SI::Loop::Iterator it; sd->subtitlingLoop.getNext(sub, it); ) {
798  if (sub.languageCode[0]) {
799  dbgpatpmt(" '%s'", sub.languageCode);
800  subtitlingTypes[NumSpids] = sub.getSubtitlingType();
801  compositionPageIds[NumSpids] = sub.getCompositionPageId();
802  ancillaryPageIds[NumSpids] = sub.getAncillaryPageId();
803  if (n > 0)
804  *s++ = '+';
806  s += strlen(s);
807  if (n++ > 1)
808  break;
809  }
810  }
812  cDevice::PrimaryDevice()->SetAvailableTrack(ttSubtitle, NumSpids, spids[NumSpids], slangs[NumSpids]);
813  NumSpids++;
814  spids[NumSpids] = 0;
815  }
816  break;
819  dbgpatpmt(" '%s'", ld->languageCode);
821  }
822  break;
823  default: ;
824  }
825  delete d;
826  }
827  if (dpid) {
828  if (NumDpids < MAXDPIDS) {
829  dpids[NumDpids] = dpid;
830  dtypes[NumDpids] = dtype;
831  strn0cpy(dlangs[NumDpids], lang, sizeof(dlangs[NumDpids]));
833  cDevice::PrimaryDevice()->SetAvailableTrack(ttDolby, NumDpids, dpid, lang);
834  NumDpids++;
835  dpids[NumDpids] = 0;
836  }
837  }
838  }
839  break;
840  case 0x81: // STREAMTYPE_USER_PRIVATE - AC3 audio for ATSC and BD
841  case 0x82: // STREAMTYPE_USER_PRIVATE - DTS audio for BD
842  case 0x87: // eac3
843  {
844  dbgpatpmt(" %s",
845  stream.getStreamType() == 0x81 ? "AC3" :
846  stream.getStreamType() == 0x87 ? "AC3" :
847  stream.getStreamType() == 0x82 ? "DTS" : "");
848  char lang[MAXLANGCODE1] = { 0 };
849  SI::Descriptor *d;
850  for (SI::Loop::Iterator it; (d = stream.streamDescriptors.getNext(it)); ) {
851  switch (d->getDescriptorTag()) {
854  dbgpatpmt(" '%s'", ld->languageCode);
856  }
857  break;
858  default: ;
859  }
860  delete d;
861  }
862  if (NumDpids < MAXDPIDS) {
863  dpids[NumDpids] = stream.getPid();
864  dtypes[NumDpids] = SI::AC3DescriptorTag;
865  strn0cpy(dlangs[NumDpids], lang, sizeof(dlangs[NumDpids]));
867  cDevice::PrimaryDevice()->SetAvailableTrack(ttDolby, NumDpids, stream.getPid(), lang);
868  NumDpids++;
869  dpids[NumDpids] = 0;
870  }
871  }
872  break;
873  case 0x90: // PGS subtitles for BD
874  {
875  dbgpatpmt(" subtitling");
876  char lang[MAXLANGCODE1] = { 0 };
877  SI::Descriptor *d;
878  for (SI::Loop::Iterator it; (d = stream.streamDescriptors.getNext(it)); ) {
879  switch (d->getDescriptorTag()) {
882  dbgpatpmt(" '%s'", ld->languageCode);
884  if (NumSpids < MAXSPIDS) {
885  spids[NumSpids] = stream.getPid();
886  *slangs[NumSpids] = 0;
887  subtitlingTypes[NumSpids] = 0;
888  compositionPageIds[NumSpids] = 0;
889  ancillaryPageIds[NumSpids] = 0;
891  cDevice::PrimaryDevice()->SetAvailableTrack(ttSubtitle, NumSpids, stream.getPid(), lang);
892  NumSpids++;
893  spids[NumSpids] = 0;
894  }
895  }
896  break;
897  default: ;
898  }
899  delete d;
900  }
901  }
902  break;
903  default: ;
904  }
905  dbgpatpmt("\n");
906  if (updatePrimaryDevice) {
909  }
910  }
912  completed = true;
913  }
914  else
915  esyslog("ERROR: can't parse PMT");
916  pmtSize = 0;
917 }
918 
919 bool cPatPmtParser::ParsePatPmt(const uchar *Data, int Length)
920 {
921  while (Length >= TS_SIZE) {
922  if (*Data != TS_SYNC_BYTE)
923  break; // just for safety
924  int Pid = TsPid(Data);
925  if (Pid == PATPID)
926  ParsePat(Data, TS_SIZE);
927  else if (IsPmtPid(Pid)) {
928  ParsePmt(Data, TS_SIZE);
929  if (patVersion >= 0 && pmtVersion >= 0)
930  return true;
931  }
932  Data += TS_SIZE;
933  Length -= TS_SIZE;
934  }
935  return false;
936 }
937 
938 bool cPatPmtParser::GetVersions(int &PatVersion, int &PmtVersion) const
939 {
940  PatVersion = patVersion;
941  PmtVersion = pmtVersion;
942  return patVersion >= 0 && pmtVersion >= 0;
943 }
944 
945 // --- cEitGenerator ---------------------------------------------------------
946 
948 {
949  counter = 0;
950  version = 0;
951  if (Sid)
952  Generate(Sid);
953 }
954 
955 uint16_t cEitGenerator::YMDtoMJD(int Y, int M, int D)
956 {
957  int L = (M < 3) ? 1 : 0;
958  return 14956 + D + int((Y - L) * 365.25) + int((M + 1 + L * 12) * 30.6001);
959 }
960 
962 {
964  *p++ = 0x04; // descriptor length
965  *p++ = '9'; // country code "902" ("All countries") -> EN 300 468 / 6.2.28; www.dvbservices.com/country_codes/index.php
966  *p++ = '0';
967  *p++ = '2';
968  *p++ = ParentalRating;
969  return p;
970 }
971 
973 {
974  uchar *PayloadStart;
975  uchar *SectionStart;
976  uchar *DescriptorsStart;
977  memset(eit, 0xFF, sizeof(eit));
978  struct tm tm_r;
979  time_t t = time(NULL) - 3600; // let's have the event start one hour in the past
980  tm *tm = localtime_r(&t, &tm_r);
981  uint16_t MJD = YMDtoMJD(tm->tm_year, tm->tm_mon + 1, tm->tm_mday);
982  uchar *p = eit;
983  // TS header:
984  *p++ = TS_SYNC_BYTE;
985  *p++ = TS_PAYLOAD_START;
986  *p++ = EITPID;
987  *p++ = 0x10 | (counter++ & 0x0F); // continuity counter
988  *p++ = 0x00; // pointer field (payload unit start indicator is set)
989  // payload:
990  PayloadStart = p;
991  *p++ = 0x4E; // TID present/following event on this transponder
992  *p++ = 0xF0;
993  *p++ = 0x00; // section length
994  SectionStart = p;
995  *p++ = Sid >> 8;
996  *p++ = Sid & 0xFF;
997  *p++ = 0xC1 | (version << 1);
998  *p++ = 0x00; // section number
999  *p++ = 0x00; // last section number
1000  *p++ = 0x00; // transport stream id
1001  *p++ = 0x00; // ...
1002  *p++ = 0x00; // original network id
1003  *p++ = 0x00; // ...
1004  *p++ = 0x00; // segment last section number
1005  *p++ = 0x4E; // last table id
1006  *p++ = 0x00; // event id
1007  *p++ = 0x01; // ...
1008  *p++ = MJD >> 8; // start time
1009  *p++ = MJD & 0xFF; // ...
1010  *p++ = tm->tm_hour; // ...
1011  *p++ = tm->tm_min; // ...
1012  *p++ = tm->tm_sec; // ...
1013  *p++ = 0x24; // duration (one day, should cover everything)
1014  *p++ = 0x00; // ...
1015  *p++ = 0x00; // ...
1016  *p++ = 0x90; // running status, free/CA mode
1017  *p++ = 0x00; // descriptors loop length
1018  DescriptorsStart = p;
1020  // fill in lengths:
1021  *(SectionStart - 1) = p - SectionStart + 4; // +4 = length of CRC
1022  *(DescriptorsStart - 1) = p - DescriptorsStart;
1023  // checksum
1024  int crc = SI::CRC32::crc32((char *)PayloadStart, p - PayloadStart, 0xFFFFFFFF);
1025  *p++ = crc >> 24;
1026  *p++ = crc >> 16;
1027  *p++ = crc >> 8;
1028  *p++ = crc;
1029  return eit;
1030 }
1031 
1032 // --- cTsToPes --------------------------------------------------------------
1033 
1035 {
1036  data = NULL;
1037  size = 0;
1038  Reset();
1039 }
1040 
1042 {
1043  free(data);
1044 }
1045 
1046 void cTsToPes::PutTs(const uchar *Data, int Length)
1047 {
1048  if (TsError(Data)) {
1049  Reset();
1050  return; // ignore packets with TEI set, and drop any PES data collected so far
1051  }
1052  if (TsPayloadStart(Data))
1053  Reset();
1054  else if (!size)
1055  return; // skip everything before the first payload start
1056  Length = TsGetPayload(&Data);
1057  if (length + Length > size) {
1058  int NewSize = max(KILOBYTE(2), length + Length);
1059  if (uchar *NewData = (uchar *)realloc(data, NewSize)) {
1060  data = NewData;
1061  size = NewSize;
1062  }
1063  else {
1064  esyslog("ERROR: out of memory");
1065  Reset();
1066  return;
1067  }
1068  }
1069  memcpy(data + length, Data, Length);
1070  length += Length;
1071 }
1072 
1073 #define MAXPESLENGTH 0xFFF0
1074 
1075 const uchar *cTsToPes::GetPes(int &Length)
1076 {
1077  if (repeatLast) {
1078  repeatLast = false;
1079  Length = lastLength;
1080  return lastData;
1081  }
1082  if (offset < length && PesLongEnough(length)) {
1083  if (!PesHasLength(data)) // this is a video PES packet with undefined length
1084  offset = 6; // trigger setting PES length for initial slice
1085  if (offset) {
1086  uchar *p = data + offset - 6;
1087  if (p != data) {
1088  p -= 3;
1089  if (p < data) {
1090  Reset();
1091  return NULL;
1092  }
1093  memmove(p, data, 4);
1094  }
1095  int l = min(length - offset, MAXPESLENGTH);
1096  offset += l;
1097  if (p != data) {
1098  l += 3;
1099  p[6] = 0x80;
1100  p[7] = 0x00;
1101  p[8] = 0x00;
1102  }
1103  p[4] = l / 256;
1104  p[5] = l & 0xFF;
1105  Length = l + 6;
1106  lastLength = Length;
1107  lastData = p;
1108  return p;
1109  }
1110  else {
1111  Length = PesLength(data);
1112  if (Length <= length) {
1113  offset = Length; // to make sure we break out in case of garbage data
1114  lastLength = Length;
1115  lastData = data;
1116  return data;
1117  }
1118  }
1119  }
1120  return NULL;
1121 }
1122 
1124 {
1125  repeatLast = true;
1126 }
1127 
1129 {
1130  length = offset = 0;
1131  lastData = NULL;
1132  lastLength = 0;
1133  repeatLast = false;
1134 }
1135 
1136 // --- Some helper functions for debugging -----------------------------------
1137 
1138 void BlockDump(const char *Name, const u_char *Data, int Length)
1139 {
1140  printf("--- %s\n", Name);
1141  for (int i = 0; i < Length; i++) {
1142  if (i && (i % 16) == 0)
1143  printf("\n");
1144  printf(" %02X", Data[i]);
1145  }
1146  printf("\n");
1147 }
1148 
1149 void TsDump(const char *Name, const u_char *Data, int Length)
1150 {
1151  printf("%s: %04X", Name, Length);
1152  int n = min(Length, 20);
1153  for (int i = 0; i < n; i++)
1154  printf(" %02X", Data[i]);
1155  if (n < Length) {
1156  printf(" ...");
1157  n = max(n, Length - 10);
1158  for (n = max(n, Length - 10); n < Length; n++)
1159  printf(" %02X", Data[n]);
1160  }
1161  printf("\n");
1162 }
1163 
1164 void PesDump(const char *Name, const u_char *Data, int Length)
1165 {
1166  TsDump(Name, Data, Length);
1167 }
1168 
1169 // --- cFrameParser ----------------------------------------------------------
1170 
1172 protected:
1173  bool debug;
1174  bool newFrame;
1177 public:
1178  cFrameParser(void);
1179  virtual ~cFrameParser() {};
1180  virtual int Parse(const uchar *Data, int Length, int Pid) = 0;
1187  void SetDebug(bool Debug) { debug = Debug; }
1188  bool NewFrame(void) { return newFrame; }
1189  bool IndependentFrame(void) { return independentFrame; }
1191  };
1192 
1194 {
1195  debug = true;
1196  newFrame = false;
1197  independentFrame = false;
1199 }
1200 
1201 // --- cAudioParser ----------------------------------------------------------
1202 
1203 class cAudioParser : public cFrameParser {
1204 public:
1205  cAudioParser(void);
1206  virtual int Parse(const uchar *Data, int Length, int Pid);
1207  };
1208 
1210 {
1211 }
1212 
1213 int cAudioParser::Parse(const uchar *Data, int Length, int Pid)
1214 {
1215  if (TsPayloadStart(Data)) {
1216  newFrame = independentFrame = true;
1217  if (debug)
1218  dbgframes("/");
1219  }
1220  else
1221  newFrame = independentFrame = false;
1222  return TS_SIZE;
1223 }
1224 
1225 // --- cMpeg2Parser ----------------------------------------------------------
1226 
1227 class cMpeg2Parser : public cFrameParser {
1228 private:
1229  uint32_t scanner;
1232 public:
1233  cMpeg2Parser(void);
1234  virtual int Parse(const uchar *Data, int Length, int Pid);
1235  };
1236 
1238 {
1240  seenIndependentFrame = false;
1241  lastIFrameTemporalReference = -1; // invalid
1242 }
1243 
1244 int cMpeg2Parser::Parse(const uchar *Data, int Length, int Pid)
1245 {
1246  newFrame = independentFrame = false;
1247  bool SeenPayloadStart = false;
1248  cTsPayload tsPayload(const_cast<uchar *>(Data), Length, Pid);
1249  if (TsPayloadStart(Data)) {
1250  SeenPayloadStart = true;
1251  tsPayload.SkipPesHeader();
1253  if (debug && seenIndependentFrame)
1254  dbgframes("/");
1255  }
1256  uint32_t OldScanner = scanner; // need to remember it in case of multiple frames per payload
1257  for (;;) {
1258  if (!SeenPayloadStart && tsPayload.AtTsStart())
1259  OldScanner = scanner;
1260  scanner = (scanner << 8) | tsPayload.GetByte();
1261  if (scanner == 0x00000100) { // Picture Start Code
1262  if (!SeenPayloadStart && tsPayload.GetLastIndex() > TS_SIZE) {
1263  scanner = OldScanner;
1264  return tsPayload.Used() - TS_SIZE;
1265  }
1266  uchar b1 = tsPayload.GetByte();
1267  uchar b2 = tsPayload.GetByte();
1268  int TemporalReference = (b1 << 2 ) + ((b2 & 0xC0) >> 6);
1269  uchar FrameType = (b2 >> 3) & 0x07;
1270  if (tsPayload.Find(0x000001B5)) { // Extension start code
1271  if (((tsPayload.GetByte() & 0xF0) >> 4) == 0x08) { // Picture coding extension
1272  tsPayload.GetByte();
1273  uchar PictureStructure = tsPayload.GetByte() & 0x03;
1274  if (PictureStructure == 0x02) // bottom field
1275  break;
1276  }
1277  }
1278  newFrame = true;
1279  independentFrame = FrameType == 1; // I-Frame
1280  if (independentFrame) {
1281  if (lastIFrameTemporalReference >= 0)
1283  lastIFrameTemporalReference = TemporalReference;
1284  }
1285  if (debug) {
1287  if (seenIndependentFrame) {
1288  static const char FrameTypes[] = "?IPBD???";
1289  dbgframes("%c", FrameTypes[FrameType]);
1290  }
1291  }
1292  tsPayload.Statistics();
1293  break;
1294  }
1295  if (tsPayload.AtPayloadStart() // stop at a new payload start to have the buffer refilled if necessary
1296  || tsPayload.Eof()) // or if we're out of data
1297  break;
1298  }
1299  return tsPayload.Used();
1300 }
1301 
1302 // --- cH264Parser -----------------------------------------------------------
1303 
1304 class cH264Parser : public cFrameParser {
1305 private:
1311  };
1312  uchar byte; // holds the current byte value in case of bitwise access
1313  int bit; // the bit index into the current byte (-1 if we're not in bit reading mode)
1314  int zeroBytes; // the number of consecutive zero bytes (to detect 0x000003)
1315  // Identifiers written in '_' notation as in "ITU-T H.264":
1319 protected:
1321  uint32_t scanner;
1324  uchar GetByte(bool Raw = false);
1328  uchar GetBit(void);
1329  uint32_t GetBits(int Bits);
1330  uint32_t GetGolombUe(void);
1331  int32_t GetGolombSe(void);
1332  void ParseAccessUnitDelimiter(void);
1333  void ParseSequenceParameterSet(void);
1334  void ParseSliceHeader(void);
1335 public:
1336  cH264Parser(void);
1340  virtual int Parse(const uchar *Data, int Length, int Pid);
1341  };
1342 
1344 {
1345  byte = 0;
1346  bit = -1;
1347  zeroBytes = 0;
1350  log2_max_frame_num = 0;
1351  frame_mbs_only_flag = false;
1352  gotAccessUnitDelimiter = false;
1353  gotSequenceParameterSet = false;
1354 }
1355 
1357 {
1358  uchar b = tsPayload.GetByte();
1359  if (!Raw) {
1360  // If we encounter the byte sequence 0x000003, we need to skip the 0x03:
1361  if (b == 0x00)
1362  zeroBytes++;
1363  else {
1364  if (b == 0x03 && zeroBytes >= 2)
1365  b = tsPayload.GetByte();
1366  zeroBytes = b ? 0 : 1;
1367  }
1368  }
1369  else
1370  zeroBytes = 0;
1371  bit = -1;
1372  return b;
1373 }
1374 
1376 {
1377  if (bit < 0) {
1378  byte = GetByte();
1379  bit = 7;
1380  }
1381  return (byte & (1 << bit--)) ? 1 : 0;
1382 }
1383 
1384 uint32_t cH264Parser::GetBits(int Bits)
1385 {
1386  uint32_t b = 0;
1387  while (Bits--)
1388  b |= GetBit() << Bits;
1389  return b;
1390 }
1391 
1393 {
1394  int z = -1;
1395  for (int b = 0; !b && z < 32; z++) // limiting z to no get stuck if GetBit() always returns 0
1396  b = GetBit();
1397  return (1 << z) - 1 + GetBits(z);
1398 }
1399 
1401 {
1402  uint32_t v = GetGolombUe();
1403  if (v) {
1404  if ((v & 0x01) != 0)
1405  return (v + 1) / 2; // fails for v == 0xFFFFFFFF, but that will probably never happen
1406  else
1407  return -int32_t(v / 2);
1408  }
1409  return v;
1410 }
1411 
1412 int cH264Parser::Parse(const uchar *Data, int Length, int Pid)
1413 {
1414  newFrame = independentFrame = false;
1415  tsPayload.Setup(const_cast<uchar *>(Data), Length, Pid);
1416  if (TsPayloadStart(Data)) {
1419  if (debug && gotSequenceParameterSet) {
1420  dbgframes("/");
1421  }
1422  }
1423  for (;;) {
1424  scanner = (scanner << 8) | GetByte(true);
1425  if ((scanner & 0xFFFFFF00) == 0x00000100) { // NAL unit start
1426  uchar NalUnitType = scanner & 0x1F;
1427  switch (NalUnitType) {
1429  gotAccessUnitDelimiter = true;
1430  break;
1433  gotSequenceParameterSet = true;
1434  }
1435  break;
1436  case nutCodedSliceNonIdr:
1438  ParseSliceHeader();
1439  gotAccessUnitDelimiter = false;
1440  if (newFrame)
1442  return tsPayload.Used();
1443  }
1444  break;
1445  default: ;
1446  }
1447  }
1448  if (tsPayload.AtPayloadStart() // stop at a new payload start to have the buffer refilled if necessary
1449  || tsPayload.Eof()) // or if we're out of data
1450  break;
1451  }
1452  return tsPayload.Used();
1453 }
1454 
1456 {
1458  dbgframes("A");
1459  GetByte(); // primary_pic_type
1460 }
1461 
1463 {
1464  uchar profile_idc = GetByte(); // profile_idc
1465  GetByte(); // constraint_set[0-5]_flags, reserved_zero_2bits
1466  GetByte(); // level_idc
1467  GetGolombUe(); // seq_parameter_set_id
1468  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) {
1469  int chroma_format_idc = GetGolombUe(); // chroma_format_idc
1470  if (chroma_format_idc == 3)
1472  GetGolombUe(); // bit_depth_luma_minus8
1473  GetGolombUe(); // bit_depth_chroma_minus8
1474  GetBit(); // qpprime_y_zero_transform_bypass_flag
1475  if (GetBit()) { // seq_scaling_matrix_present_flag
1476  for (int i = 0; i < ((chroma_format_idc != 3) ? 8 : 12); i++) {
1477  if (GetBit()) { // seq_scaling_list_present_flag
1478  int SizeOfScalingList = (i < 6) ? 16 : 64;
1479  int LastScale = 8;
1480  int NextScale = 8;
1481  for (int j = 0; j < SizeOfScalingList; j++) {
1482  if (NextScale)
1483  NextScale = (LastScale + GetGolombSe() + 256) % 256; // delta_scale
1484  if (NextScale)
1485  LastScale = NextScale;
1486  }
1487  }
1488  }
1489  }
1490  }
1491  log2_max_frame_num = GetGolombUe() + 4; // log2_max_frame_num_minus4
1492  int pic_order_cnt_type = GetGolombUe(); // pic_order_cnt_type
1493  if (pic_order_cnt_type == 0)
1494  GetGolombUe(); // log2_max_pic_order_cnt_lsb_minus4
1495  else if (pic_order_cnt_type == 1) {
1496  GetBit(); // delta_pic_order_always_zero_flag
1497  GetGolombSe(); // offset_for_non_ref_pic
1498  GetGolombSe(); // offset_for_top_to_bottom_field
1499  for (int i = GetGolombUe(); i--; ) // num_ref_frames_in_pic_order_cnt_cycle
1500  GetGolombSe(); // offset_for_ref_frame
1501  }
1502  GetGolombUe(); // max_num_ref_frames
1503  GetBit(); // gaps_in_frame_num_value_allowed_flag
1504  GetGolombUe(); // pic_width_in_mbs_minus1
1505  GetGolombUe(); // pic_height_in_map_units_minus1
1506  frame_mbs_only_flag = GetBit(); // frame_mbs_only_flag
1507  if (debug) {
1509  dbgframes("A"); // just for completeness
1510  dbgframes(frame_mbs_only_flag ? "S" : "s");
1511  }
1512 }
1513 
1515 {
1516  newFrame = true;
1517  GetGolombUe(); // first_mb_in_slice
1518  int slice_type = GetGolombUe(); // slice_type, 0 = P, 1 = B, 2 = I, 3 = SP, 4 = SI
1519  independentFrame = (slice_type % 5) == 2;
1520  if (debug) {
1521  static const char SliceTypes[] = "PBIpi";
1522  dbgframes("%c", SliceTypes[slice_type % 5]);
1523  }
1524  if (frame_mbs_only_flag)
1525  return; // don't need the rest - a frame is complete
1526  GetGolombUe(); // pic_parameter_set_id
1528  GetBits(2); // colour_plane_id
1529  GetBits(log2_max_frame_num); // frame_num
1530  if (!frame_mbs_only_flag) {
1531  if (GetBit()) // field_pic_flag
1532  newFrame = !GetBit(); // bottom_field_flag
1533  if (debug)
1534  dbgframes(newFrame ? "t" : "b");
1535  }
1536 }
1537 
1538 // --- cH265Parser -----------------------------------------------------------
1539 
1540 class cH265Parser : public cH264Parser {
1541 private:
1572  };
1573 public:
1574  cH265Parser(void);
1575  virtual int Parse(const uchar *Data, int Length, int Pid);
1576  };
1577 
1579 :cH264Parser()
1580 {
1581 }
1582 
1583 int cH265Parser::Parse(const uchar *Data, int Length, int Pid)
1584 {
1585  newFrame = independentFrame = false;
1586  tsPayload.Setup(const_cast<uchar *>(Data), Length, Pid);
1587  if (TsPayloadStart(Data)) {
1590  }
1591  for (;;) {
1592  scanner = (scanner << 8) | GetByte(true);
1593  if ((scanner & 0xFFFFFF00) == 0x00000100) { // NAL unit start
1594  uchar NalUnitType = (scanner >> 1) & 0x3F;
1595  GetByte(); // nuh_layer_id + nuh_temporal_id_plus1
1596  if (NalUnitType <= nutSliceSegmentRASLR || (NalUnitType >= nutSliceSegmentBLAWLP && NalUnitType <= nutSliceSegmentCRANUT)) {
1597  if (NalUnitType == nutSliceSegmentIDRWRADL || NalUnitType == nutSliceSegmentIDRNLP || NalUnitType == nutSliceSegmentCRANUT)
1598  independentFrame = true;
1599  if (GetBit()) { // first_slice_segment_in_pic_flag
1600  newFrame = true;
1602  }
1603  break;
1604  }
1605  }
1606  if (tsPayload.AtPayloadStart() // stop at a new payload start to have the buffer refilled if necessary
1607  || tsPayload.Eof()) // or if we're out of data
1608  break;
1609  }
1610  return tsPayload.Used();
1611 }
1612 
1613 // --- cFrameDetector --------------------------------------------------------
1614 
1616 {
1617  parser = NULL;
1618  SetPid(Pid, Type);
1619  synced = false;
1620  newFrame = independentFrame = false;
1621  numPtsValues = 0;
1622  numIFrames = 0;
1623  framesPerSecond = 0;
1625  scanning = false;
1626 }
1627 
1628 static int CmpUint32(const void *p1, const void *p2)
1629 {
1630  if (*(uint32_t *)p1 < *(uint32_t *)p2) return -1;
1631  if (*(uint32_t *)p1 > *(uint32_t *)p2) return 1;
1632  return 0;
1633 }
1634 
1635 void cFrameDetector::SetPid(int Pid, int Type)
1636 {
1637  pid = Pid;
1638  type = Type;
1639  isVideo = type == 0x01 || type == 0x02 || type == 0x1B || type == 0x24; // MPEG 1, 2, H.264 or H.265
1640  delete parser;
1641  parser = NULL;
1642  if (type == 0x01 || type == 0x02)
1643  parser = new cMpeg2Parser;
1644  else if (type == 0x1B)
1645  parser = new cH264Parser;
1646  else if (type == 0x24)
1647  parser = new cH265Parser;
1648  else if (type == 0x03 || type == 0x04 || type == 0x06) // MPEG audio or AC3 audio
1649  parser = new cAudioParser;
1650  else if (type != 0)
1651  esyslog("ERROR: unknown stream type %d (PID %d) in frame detector", type, pid);
1652 }
1653 
1654 int cFrameDetector::Analyze(const uchar *Data, int Length)
1655 {
1656  if (!parser)
1657  return 0;
1658  int Processed = 0;
1659  newFrame = independentFrame = false;
1660  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
1661  // Sync on TS packet borders:
1662  if (int Skipped = TS_SYNC(Data, Length))
1663  return Processed + Skipped;
1664  // Handle one TS packet:
1665  int Handled = TS_SIZE;
1666  if (TsHasPayload(Data) && !TsIsScrambled(Data)) {
1667  int Pid = TsPid(Data);
1668  if (Pid == pid) {
1669  if (Processed)
1670  return Processed;
1671  if (TsPayloadStart(Data))
1672  scanning = true;
1673  if (scanning) {
1674  // Detect the beginning of a new frame:
1675  if (TsPayloadStart(Data)) {
1676  if (!framesPerPayloadUnit)
1678  }
1679  int n = parser->Parse(Data, Length, pid);
1680  if (n > 0) {
1681  if (parser->NewFrame()) {
1682  newFrame = true;
1684  if (synced) {
1685  if (framesPerPayloadUnit <= 1)
1686  scanning = false;
1687  }
1688  else {
1690  if (independentFrame)
1691  numIFrames++;
1692  }
1693  }
1694  Handled = n;
1695  }
1696  }
1697  if (TsPayloadStart(Data)) {
1698  // Determine the frame rate from the PTS values in the PES headers:
1699  if (framesPerSecond <= 0.0) {
1700  // frame rate unknown, so collect a sequence of PTS values:
1701  if (numPtsValues < 2 || numPtsValues < MaxPtsValues && numIFrames < 2) { // collect a sequence containing at least two I-frames
1702  if (newFrame) { // only take PTS values at the beginning of a frame (in case if fields!)
1703  const uchar *Pes = Data + TsPayloadOffset(Data);
1704  if (numIFrames && PesHasPts(Pes)) {
1706  // check for rollover:
1707  if (numPtsValues && ptsValues[numPtsValues - 1] > 0xF0000000 && ptsValues[numPtsValues] < 0x10000000) {
1708  dbgframes("#");
1709  numPtsValues = 0;
1710  numIFrames = 0;
1711  }
1712  else
1713  numPtsValues++;
1714  }
1715  }
1716  }
1717  if (numPtsValues >= 2 && numIFrames >= 2) {
1718  // find the smallest PTS delta:
1719  qsort(ptsValues, numPtsValues, sizeof(uint32_t), CmpUint32);
1720  numPtsValues--;
1721  for (int i = 0; i < numPtsValues; i++)
1722  ptsValues[i] = ptsValues[i + 1] - ptsValues[i];
1723  qsort(ptsValues, numPtsValues, sizeof(uint32_t), CmpUint32);
1724  int Div = framesPerPayloadUnit;
1725  if (framesPerPayloadUnit > 1)
1727  if (Div <= 0)
1728  Div = 1;
1729  int Delta = ptsValues[0] / Div;
1730  // determine frame info:
1731  if (isVideo) {
1732  if (Delta == 3753)
1733  framesPerSecond = 24.0 / 1.001;
1734  else if (abs(Delta - 3600) <= 1)
1735  framesPerSecond = 25.0;
1736  else if (Delta % 3003 == 0)
1737  framesPerSecond = 30.0 / 1.001;
1738  else if (abs(Delta - 1800) <= 1)
1739  framesPerSecond = 50.0;
1740  else if (Delta == 1501)
1741  framesPerSecond = 60.0 / 1.001;
1742  else {
1744  dsyslog("unknown frame delta (%d), assuming %5.2f fps", Delta, DEFAULTFRAMESPERSECOND);
1745  }
1746  }
1747  else // audio
1748  framesPerSecond = double(PTSTICKS) / Delta; // PTS of audio frames is always increasing
1749  dbgframes("\nDelta = %d FPS = %5.2f FPPU = %d NF = %d TRO = %d\n", Delta, framesPerSecond, framesPerPayloadUnit, numPtsValues + 1, parser->IFrameTemporalReferenceOffset());
1750  synced = true;
1751  parser->SetDebug(false);
1752  }
1753  }
1754  }
1755  }
1756  else if (Pid == PATPID && synced && Processed)
1757  return Processed; // allow the caller to see any PAT packets
1758  }
1759  Data += Handled;
1760  Length -= Handled;
1761  Processed += Handled;
1762  if (newFrame)
1763  break;
1764  }
1765  return Processed;
1766 }
#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)
Parses the given Data, which is a sequence of Length bytes of TS packets.
Definition: remux.c:1213
cAudioParser(void)
Definition: remux.c:1209
const int * Dpids(void) const
Definition: channels.h:157
uint16_t AncillaryPageId(int i) const
Definition: channels.h:169
const char * Alang(int i) const
Definition: channels.h:162
uint16_t CompositionPageId(int i) const
Definition: channels.h:168
int Tpid(void) const
Definition: channels.h:170
int Vpid(void) const
Definition: channels.h:153
int Atype(int i) const
Definition: channels.h:165
int Dtype(int i) const
Definition: channels.h:166
int Dpid(int i) const
Definition: channels.h:160
int Vtype(void) const
Definition: channels.h:155
int Apid(int i) const
Definition: channels.h:159
int Ppid(void) const
Definition: channels.h:154
uchar SubtitlingType(int i) const
Definition: channels.h:167
int Spid(int i) const
Definition: channels.h:161
const int * Spids(void) const
Definition: channels.h:158
const int * Apids(void) const
Definition: channels.h:156
const char * Slang(int i) const
Definition: channels.h:164
const char * Dlang(int i) const
Definition: channels.h:163
void EnsureAudioTrack(bool Force=false)
Makes sure an audio track is selected that is actually available.
Definition: device.c:1179
void ClrAvailableTracks(bool DescriptionsOnly=false, bool IdsOnly=false)
Clears the list of currently available tracks.
Definition: device.c:1056
void EnsureSubtitleTrack(void)
Makes sure one of the preferred language subtitle tracks is selected.
Definition: device.c:1212
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:1079
uchar eit[TS_SIZE]
Definition: remux.h:434
cEitGenerator(int Sid=0)
Definition: remux.c:947
int counter
Definition: remux.h:435
uchar * AddParentalRatingDescriptor(uchar *p, uchar ParentalRating=0)
Definition: remux.c:961
uint16_t YMDtoMJD(int Y, int M, int D)
Definition: remux.c:955
uchar * Generate(int Sid)
Definition: remux.c:972
int version
Definition: remux.h:436
@ MaxPtsValues
Definition: remux.h:509
uint32_t ptsValues[MaxPtsValues]
Definition: remux.h:515
bool synced
Definition: remux.h:512
bool scanning
Definition: remux.h:523
int framesPerPayloadUnit
Definition: remux.h:521
double framesPerSecond
Definition: remux.h:519
int framesInPayloadUnit
Definition: remux.h:520
int numIFrames
Definition: remux.h:517
bool independentFrame
Definition: remux.h:514
cFrameDetector(int Pid=0, int Type=0)
Sets up a frame detector for the given Pid and stream Type.
Definition: remux.c:1615
bool newFrame
Definition: remux.h:513
cFrameParser * parser
Definition: remux.h:524
int numPtsValues
Definition: remux.h:516
int Analyze(const uchar *Data, int Length)
Analyzes the TS packets pointed to by Data.
Definition: remux.c:1654
bool isVideo
Definition: remux.h:518
void SetPid(int Pid, int Type)
Sets the Pid and stream Type to detect frames for.
Definition: remux.c:1635
void SetDebug(bool Debug)
Definition: remux.c:1187
bool NewFrame(void)
Definition: remux.c:1188
bool IndependentFrame(void)
Definition: remux.c:1189
bool newFrame
Definition: remux.c:1174
int iFrameTemporalReferenceOffset
Definition: remux.c:1176
bool independentFrame
Definition: remux.c:1175
virtual ~cFrameParser()
Definition: remux.c:1179
bool debug
Definition: remux.c:1173
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.
int IFrameTemporalReferenceOffset(void)
Definition: remux.c:1190
cFrameParser(void)
Definition: remux.c:1193
uint32_t GetBits(int Bits)
Definition: remux.c:1384
cTsPayload tsPayload
Definition: remux.c:1320
void ParseAccessUnitDelimiter(void)
Definition: remux.c:1455
@ nutSequenceParameterSet
Definition: remux.c:1309
@ nutCodedSliceNonIdr
Definition: remux.c:1307
@ nutAccessUnitDelimiter
Definition: remux.c:1310
@ nutCodedSliceIdr
Definition: remux.c:1308
bool separate_colour_plane_flag
Definition: remux.c:1316
bool gotAccessUnitDelimiter
Definition: remux.c:1322
int zeroBytes
Definition: remux.c:1314
bool frame_mbs_only_flag
Definition: remux.c:1318
virtual int Parse(const uchar *Data, int Length, int Pid)
Parses the given Data, which is a sequence of Length bytes of TS packets.
Definition: remux.c:1412
int bit
Definition: remux.c:1313
int log2_max_frame_num
Definition: remux.c:1317
uint32_t GetGolombUe(void)
Definition: remux.c:1392
uchar GetByte(bool Raw=false)
Gets the next data byte.
Definition: remux.c:1356
void ParseSliceHeader(void)
Definition: remux.c:1514
void ParseSequenceParameterSet(void)
Definition: remux.c:1462
uchar byte
Definition: remux.c:1312
uint32_t scanner
Definition: remux.c:1321
bool gotSequenceParameterSet
Definition: remux.c:1323
int32_t GetGolombSe(void)
Definition: remux.c:1400
cH264Parser(void)
Sets up a new H.264 parser.
Definition: remux.c:1343
uchar GetBit(void)
Definition: remux.c:1375
virtual int Parse(const uchar *Data, int Length, int Pid)
Parses the given Data, which is a sequence of Length bytes of TS packets.
Definition: remux.c:1583
cH265Parser(void)
Definition: remux.c:1578
@ nutSliceSegmentIDRWRADL
Definition: remux.c:1556
@ nutUnspecified0
Definition: remux.c:1570
@ nutSliceSegmentSTSAN
Definition: remux.c:1547
@ nutSliceSegmentRADLN
Definition: remux.c:1549
@ nutSliceSegmentIDRNLP
Definition: remux.c:1557
@ nutPrefixSEI
Definition: remux.c:1566
@ nutAccessUnitDelimiter
Definition: remux.c:1562
@ nutUnspecified7
Definition: remux.c:1571
@ nutSliceSegmentBLAWRADL
Definition: remux.c:1554
@ nutSliceSegmentTSAR
Definition: remux.c:1546
@ nutSliceSegmentRADLR
Definition: remux.c:1550
@ nutSliceSegmentTrailingR
Definition: remux.c:1544
@ nutVideoParameterSet
Definition: remux.c:1559
@ nutSequenceParameterSet
Definition: remux.c:1560
@ nutSliceSegmentTSAN
Definition: remux.c:1545
@ nutSliceSegmentRASLN
Definition: remux.c:1551
@ nutSuffixSEI
Definition: remux.c:1567
@ nutSliceSegmentBLAWLP
Definition: remux.c:1553
@ nutEndOfBitstream
Definition: remux.c:1564
@ nutSliceSegmentBLANLP
Definition: remux.c:1555
@ nutSliceSegmentRASLR
Definition: remux.c:1552
@ nutPictureParameterSet
Definition: remux.c:1561
@ nutNonVCLRes3
Definition: remux.c:1569
@ nutSliceSegmentCRANUT
Definition: remux.c:1558
@ nutSliceSegmentTrailingN
Definition: remux.c:1543
@ nutNonVCLRes0
Definition: remux.c:1568
@ nutFillerData
Definition: remux.c:1565
@ nutSliceSegmentSTSAR
Definition: remux.c:1548
@ nutEndOfSequence
Definition: remux.c:1563
bool seenIndependentFrame
Definition: remux.c:1230
cMpeg2Parser(void)
Definition: remux.c:1237
int lastIFrameTemporalReference
Definition: remux.c:1231
uint32_t scanner
Definition: remux.c:1229
virtual int Parse(const uchar *Data, int Length, int Pid)
Parses the given Data, which is a sequence of Length bytes of TS packets.
Definition: remux.c:1244
int pmtVersion
Definition: remux.h:306
int pmtCounter
Definition: remux.h:304
int MakeCRC(uchar *Target, const uchar *Data, int Length)
Definition: remux.c:451
uchar * GetPmt(int &Index)
Returns a pointer to the Index'th TS packet of the PMT section.
Definition: remux.c:600
void SetChannel(const cChannel *Channel)
Sets the Channel for which the PAT/PMT shall be generated.
Definition: remux.c:585
void IncEsInfoLength(int Length)
Definition: remux.c:384
void IncCounter(int &Counter, uchar *TsPacket)
Definition: remux.c:371
cPatPmtGenerator(const cChannel *Channel=NULL)
Definition: remux.c:361
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:579
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:405
void GeneratePat(void)
Generates a PAT section for later use with GetPat().
Definition: remux.c:481
uchar * GetPat(void)
Returns a pointer to the PAT section, which consists of exactly one TS packet.
Definition: remux.c:594
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:432
void GeneratePmt(const cChannel *Channel)
Generates a PMT section for the given Channel, for later use with GetPmt().
Definition: remux.c:510
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:466
int patCounter
Definition: remux.h:303
int MakeStream(uchar *Target, uchar Type, int Pid)
Definition: remux.c:393
int MakeSubtitlingDescriptor(uchar *Target, const char *Language, uchar SubtitlingType, uint16_t CompositionPageId, uint16_t AncillaryPageId)
Definition: remux.c:415
void IncVersion(int &Version)
Definition: remux.c:378
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:938
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:611
void Reset(void)
Resets the parser.
Definition: remux.c:617
void ParsePat(const uchar *Data, int Length)
Parses the PAT data from the single TS packet in Data.
Definition: remux.c:627
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:919
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:659
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:326
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:328
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:323
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:318
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:351
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:334
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:311
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:1046
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:1123
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:1075
cTsToPes(void)
Definition: remux.c:1034
int length
Definition: remux.h:454
~cTsToPes()
Definition: remux.c:1041
void Reset(void)
Resets the converter.
Definition: remux.c:1128
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:285
@ EnhancedAC3DescriptorTag
Definition: si.h:137
@ SubtitlingDescriptorTag
Definition: si.h:103
@ ISO639LanguageDescriptorTag
Definition: si.h:61
@ ParentalRatingDescriptorTag
Definition: si.h:99
@ AC3DescriptorTag
Definition: si.h:120
unsigned char u_char
Definition: headers.h:24
#define DEFAULTFRAMESPERSECOND
Definition: recording.h:352
void TsSetPcr(uchar *p, int64_t Pcr)
Definition: remux.c:131
#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:1164
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
#define MAXPESLENGTH
Definition: remux.c:1073
#define P_PMT_PID
Definition: remux.c:463
void TsHidePayload(uchar *p)
Definition: remux.c:121
static int CmpUint32(const void *p1, const void *p2)
Definition: remux.c:1628
#define MAXPID
Definition: remux.c:464
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
int64_t TsGetDts(const uchar *p, int l)
Definition: remux.c:173
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:1138
int TsSync(const uchar *Data, int Length, const char *File, const char *Function, int Line)
Definition: remux.c:147
#define SETPIDS(l)
#define P_TSID
Definition: remux.c:462
void TsDump(const char *Name, const u_char *Data, int Length)
Definition: remux.c:1149
#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
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
#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_PAYLOAD_START
Definition: remux.h:36
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