vdr  2.4.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 4.7.1.1 2019/03/15 13:13:40 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 void TsExtendAdaptionField(unsigned char *Packet, int ToLength)
360 {
361  // Hint: ExtenAdaptionField(p, TsPayloadOffset(p) - 4) is a null operation
362 
363  int Offset = TsPayloadOffset(Packet); // First byte after existing adaption field
364 
365  if (ToLength <= 0)
366  {
367  // Remove adaption field
368  Packet[3] = Packet[3] & ~TS_ADAPT_FIELD_EXISTS;
369  return;
370  }
371 
372  // Set adaption field present
373  Packet[3] = Packet[3] | TS_ADAPT_FIELD_EXISTS;
374 
375  // Set new length of adaption field:
376  Packet[4] = ToLength <= TS_SIZE-4 ? ToLength-1 : TS_SIZE-4-1;
377 
378  if (Packet[4] == TS_SIZE-4-1)
379  {
380  // No more payload, remove payload flag
381  Packet[3] = Packet[3] & ~TS_PAYLOAD_EXISTS;
382  }
383 
384  int NewPayload = TsPayloadOffset(Packet); // First byte after new adaption field
385 
386  // Fill new adaption field
387  if (Offset == 4 && Offset < NewPayload)
388  Offset++; // skip adaptation_field_length
389  if (Offset == 5 && Offset < NewPayload)
390  Packet[Offset++] = 0; // various flags set to 0
391  while (Offset < NewPayload)
392  Packet[Offset++] = 0xff; // stuffing byte
393 }
394 
395 // --- cPatPmtGenerator ------------------------------------------------------
396 
398 {
399  numPmtPackets = 0;
400  patCounter = pmtCounter = 0;
401  patVersion = pmtVersion = 0;
402  pmtPid = 0;
403  esInfoLength = NULL;
404  SetChannel(Channel);
405 }
406 
407 void cPatPmtGenerator::IncCounter(int &Counter, uchar *TsPacket)
408 {
409  TsPacket[3] = (TsPacket[3] & 0xF0) | Counter;
410  if (++Counter > 0x0F)
411  Counter = 0x00;
412 }
413 
415 {
416  if (++Version > 0x1F)
417  Version = 0x00;
418 }
419 
421 {
422  if (esInfoLength) {
423  Length += ((*esInfoLength & 0x0F) << 8) | *(esInfoLength + 1);
424  *esInfoLength = 0xF0 | (Length >> 8);
425  *(esInfoLength + 1) = Length;
426  }
427 }
428 
429 int cPatPmtGenerator::MakeStream(uchar *Target, uchar Type, int Pid)
430 {
431  int i = 0;
432  Target[i++] = Type; // stream type
433  Target[i++] = 0xE0 | (Pid >> 8); // dummy (3), pid hi (5)
434  Target[i++] = Pid; // pid lo
435  esInfoLength = &Target[i];
436  Target[i++] = 0xF0; // dummy (4), ES info length hi
437  Target[i++] = 0x00; // ES info length lo
438  return i;
439 }
440 
442 {
443  int i = 0;
444  Target[i++] = Type;
445  Target[i++] = 0x01; // length
446  Target[i++] = 0x00;
447  IncEsInfoLength(i);
448  return i;
449 }
450 
451 int cPatPmtGenerator::MakeSubtitlingDescriptor(uchar *Target, const char *Language, uchar SubtitlingType, uint16_t CompositionPageId, uint16_t AncillaryPageId)
452 {
453  int i = 0;
454  Target[i++] = SI::SubtitlingDescriptorTag;
455  Target[i++] = 0x08; // length
456  Target[i++] = *Language++;
457  Target[i++] = *Language++;
458  Target[i++] = *Language++;
459  Target[i++] = SubtitlingType;
460  Target[i++] = CompositionPageId >> 8;
461  Target[i++] = CompositionPageId & 0xFF;
462  Target[i++] = AncillaryPageId >> 8;
463  Target[i++] = AncillaryPageId & 0xFF;
464  IncEsInfoLength(i);
465  return i;
466 }
467 
468 int cPatPmtGenerator::MakeLanguageDescriptor(uchar *Target, const char *Language)
469 {
470  int i = 0;
471  Target[i++] = SI::ISO639LanguageDescriptorTag;
472  int Length = i++;
473  Target[Length] = 0x00; // length
474  for (const char *End = Language + strlen(Language); Language < End; ) {
475  Target[i++] = *Language++;
476  Target[i++] = *Language++;
477  Target[i++] = *Language++;
478  Target[i++] = 0x00; // audio type
479  Target[Length] += 0x04; // length
480  if (*Language == '+')
481  Language++;
482  }
483  IncEsInfoLength(i);
484  return i;
485 }
486 
487 int cPatPmtGenerator::MakeCRC(uchar *Target, const uchar *Data, int Length)
488 {
489  int crc = SI::CRC32::crc32((const char *)Data, Length, 0xFFFFFFFF);
490  int i = 0;
491  Target[i++] = crc >> 24;
492  Target[i++] = crc >> 16;
493  Target[i++] = crc >> 8;
494  Target[i++] = crc;
495  return i;
496 }
497 
498 #define P_TSID 0x8008 // pseudo TS ID
499 #define P_PMT_PID 0x0084 // pseudo PMT pid
500 #define MAXPID 0x2000 // the maximum possible number of pids
501 
503 {
504  bool Used[MAXPID] = { false };
505 #define SETPID(p) { if ((p) >= 0 && (p) < MAXPID) Used[p] = true; }
506 #define SETPIDS(l) { const int *p = l; while (*p) { SETPID(*p); p++; } }
507  SETPID(Channel->Vpid());
508  SETPID(Channel->Ppid());
509  SETPID(Channel->Tpid());
510  SETPIDS(Channel->Apids());
511  SETPIDS(Channel->Dpids());
512  SETPIDS(Channel->Spids());
513  for (pmtPid = P_PMT_PID; Used[pmtPid]; pmtPid++)
514  ;
515 }
516 
518 {
519  memset(pat, 0xFF, sizeof(pat));
520  uchar *p = pat;
521  int i = 0;
522  p[i++] = TS_SYNC_BYTE; // TS indicator
523  p[i++] = TS_PAYLOAD_START | (PATPID >> 8); // flags (3), pid hi (5)
524  p[i++] = PATPID & 0xFF; // pid lo
525  p[i++] = 0x10; // flags (4), continuity counter (4)
526  p[i++] = 0x00; // pointer field (payload unit start indicator is set)
527  int PayloadStart = i;
528  p[i++] = 0x00; // table id
529  p[i++] = 0xB0; // section syntax indicator (1), dummy (3), section length hi (4)
530  int SectionLength = i;
531  p[i++] = 0x00; // section length lo (filled in later)
532  p[i++] = P_TSID >> 8; // TS id hi
533  p[i++] = P_TSID & 0xFF; // TS id lo
534  p[i++] = 0xC1 | (patVersion << 1); // dummy (2), version number (5), current/next indicator (1)
535  p[i++] = 0x00; // section number
536  p[i++] = 0x00; // last section number
537  p[i++] = pmtPid >> 8; // program number hi
538  p[i++] = pmtPid & 0xFF; // program number lo
539  p[i++] = 0xE0 | (pmtPid >> 8); // dummy (3), PMT pid hi (5)
540  p[i++] = pmtPid & 0xFF; // PMT pid lo
541  pat[SectionLength] = i - SectionLength - 1 + 4; // -1 = SectionLength storage, +4 = length of CRC
542  MakeCRC(pat + i, pat + PayloadStart, i - PayloadStart);
544 }
545 
547 {
548  // generate the complete PMT section:
549  uchar buf[MAX_SECTION_SIZE];
550  memset(buf, 0xFF, sizeof(buf));
551  numPmtPackets = 0;
552  if (Channel) {
553  int Vpid = Channel->Vpid();
554  int Ppid = Channel->Ppid();
555  uchar *p = buf;
556  int i = 0;
557  p[i++] = 0x02; // table id
558  int SectionLength = i;
559  p[i++] = 0xB0; // section syntax indicator (1), dummy (3), section length hi (4)
560  p[i++] = 0x00; // section length lo (filled in later)
561  p[i++] = pmtPid >> 8; // program number hi
562  p[i++] = pmtPid & 0xFF; // program number lo
563  p[i++] = 0xC1 | (pmtVersion << 1); // dummy (2), version number (5), current/next indicator (1)
564  p[i++] = 0x00; // section number
565  p[i++] = 0x00; // last section number
566  p[i++] = 0xE0 | (Ppid >> 8); // dummy (3), PCR pid hi (5)
567  p[i++] = Ppid; // PCR pid lo
568  p[i++] = 0xF0; // dummy (4), program info length hi (4)
569  p[i++] = 0x00; // program info length lo
570 
571  if (Vpid)
572  i += MakeStream(buf + i, Channel->Vtype(), Vpid);
573  for (int n = 0; Channel->Apid(n); n++) {
574  i += MakeStream(buf + i, Channel->Atype(n), Channel->Apid(n));
575  const char *Alang = Channel->Alang(n);
576  i += MakeLanguageDescriptor(buf + i, Alang);
577  }
578  for (int n = 0; Channel->Dpid(n); n++) {
579  i += MakeStream(buf + i, 0x06, Channel->Dpid(n));
580  i += MakeAC3Descriptor(buf + i, Channel->Dtype(n));
581  i += MakeLanguageDescriptor(buf + i, Channel->Dlang(n));
582  }
583  for (int n = 0; Channel->Spid(n); n++) {
584  i += MakeStream(buf + i, 0x06, Channel->Spid(n));
585  i += MakeSubtitlingDescriptor(buf + i, Channel->Slang(n), Channel->SubtitlingType(n), Channel->CompositionPageId(n), Channel->AncillaryPageId(n));
586  }
587 
588  int sl = i - SectionLength - 2 + 4; // -2 = SectionLength storage, +4 = length of CRC
589  buf[SectionLength] |= (sl >> 8) & 0x0F;
590  buf[SectionLength + 1] = sl;
591  MakeCRC(buf + i, buf, i);
592  // split the PMT section into several TS packets:
593  uchar *q = buf;
594  bool pusi = true;
595  while (i > 0) {
596  uchar *p = pmt[numPmtPackets++];
597  int j = 0;
598  p[j++] = TS_SYNC_BYTE; // TS indicator
599  p[j++] = (pusi ? TS_PAYLOAD_START : 0x00) | (pmtPid >> 8); // flags (3), pid hi (5)
600  p[j++] = pmtPid & 0xFF; // pid lo
601  p[j++] = 0x10; // flags (4), continuity counter (4)
602  if (pusi) {
603  p[j++] = 0x00; // pointer field (payload unit start indicator is set)
604  pusi = false;
605  }
606  int l = TS_SIZE - j;
607  memcpy(p + j, q, l);
608  q += l;
609  i -= l;
610  }
612  }
613 }
614 
615 void cPatPmtGenerator::SetVersions(int PatVersion, int PmtVersion)
616 {
617  patVersion = PatVersion & 0x1F;
618  pmtVersion = PmtVersion & 0x1F;
619 }
620 
622 {
623  if (Channel) {
624  GeneratePmtPid(Channel);
625  GeneratePat();
626  GeneratePmt(Channel);
627  }
628 }
629 
631 {
633  return pat;
634 }
635 
637 {
638  if (Index < numPmtPackets) {
639  IncCounter(pmtCounter, pmt[Index]);
640  return pmt[Index++];
641  }
642  return NULL;
643 }
644 
645 // --- cPatPmtParser ---------------------------------------------------------
646 
647 cPatPmtParser::cPatPmtParser(bool UpdatePrimaryDevice)
648 {
649  updatePrimaryDevice = UpdatePrimaryDevice;
650  Reset();
651 }
652 
654 {
655  completed = false;
656  pmtSize = 0;
657  patVersion = pmtVersion = -1;
658  pmtPids[0] = 0;
659  vpid = vtype = 0;
660  ppid = 0;
661 }
662 
663 void cPatPmtParser::ParsePat(const uchar *Data, int Length)
664 {
665  // Unpack the TS packet:
666  int PayloadOffset = TsPayloadOffset(Data);
667  Data += PayloadOffset;
668  Length -= PayloadOffset;
669  // The PAT is always assumed to fit into a single TS packet
670  if ((Length -= Data[0] + 1) <= 0)
671  return;
672  Data += Data[0] + 1; // process pointer_field
673  SI::PAT Pat(Data, false);
674  if (Pat.CheckCRCAndParse()) {
675  dbgpatpmt("PAT: TSid = %d, c/n = %d, v = %d, s = %d, ls = %d\n", Pat.getTransportStreamId(), Pat.getCurrentNextIndicator(), Pat.getVersionNumber(), Pat.getSectionNumber(), Pat.getLastSectionNumber());
676  if (patVersion == Pat.getVersionNumber())
677  return;
678  int NumPmtPids = 0;
679  SI::PAT::Association assoc;
680  for (SI::Loop::Iterator it; Pat.associationLoop.getNext(assoc, it); ) {
681  dbgpatpmt(" isNITPid = %d\n", assoc.isNITPid());
682  if (!assoc.isNITPid()) {
683  if (NumPmtPids <= MAX_PMT_PIDS)
684  pmtPids[NumPmtPids++] = assoc.getPid();
685  dbgpatpmt(" service id = %d, pid = %d\n", assoc.getServiceId(), assoc.getPid());
686  }
687  }
688  pmtPids[NumPmtPids] = 0;
690  }
691  else
692  esyslog("ERROR: can't parse PAT");
693 }
694 
695 void cPatPmtParser::ParsePmt(const uchar *Data, int Length)
696 {
697  // Unpack the TS packet:
698  bool PayloadStart = TsPayloadStart(Data);
699  int PayloadOffset = TsPayloadOffset(Data);
700  Data += PayloadOffset;
701  Length -= PayloadOffset;
702  // The PMT may extend over several TS packets, so we need to assemble them
703  if (PayloadStart) {
704  pmtSize = 0;
705  if ((Length -= Data[0] + 1) <= 0)
706  return;
707  Data += Data[0] + 1; // this is the first packet
708  if (SectionLength(Data, Length) > Length) {
709  if (Length <= int(sizeof(pmt))) {
710  memcpy(pmt, Data, Length);
711  pmtSize = Length;
712  }
713  else
714  esyslog("ERROR: PMT packet length too big (%d byte)!", Length);
715  return;
716  }
717  // the packet contains the entire PMT section, so we run into the actual parsing
718  }
719  else if (pmtSize > 0) {
720  // this is a following packet, so we add it to the pmt storage
721  if (Length <= int(sizeof(pmt)) - pmtSize) {
722  memcpy(pmt + pmtSize, Data, Length);
723  pmtSize += Length;
724  }
725  else {
726  esyslog("ERROR: PMT section length too big (%d byte)!", pmtSize + Length);
727  pmtSize = 0;
728  }
730  return; // more packets to come
731  // the PMT section is now complete, so we run into the actual parsing
732  Data = pmt;
733  }
734  else
735  return; // fragment of broken packet - ignore
736  SI::PMT Pmt(Data, false);
737  if (Pmt.CheckCRCAndParse()) {
738  dbgpatpmt("PMT: sid = %d, c/n = %d, v = %d, s = %d, ls = %d\n", Pmt.getServiceId(), Pmt.getCurrentNextIndicator(), Pmt.getVersionNumber(), Pmt.getSectionNumber(), Pmt.getLastSectionNumber());
739  dbgpatpmt(" pcr = %d\n", Pmt.getPCRPid());
740  if (pmtVersion == Pmt.getVersionNumber())
741  return;
744  int NumApids = 0;
745  int NumDpids = 0;
746  int NumSpids = 0;
747  vpid = vtype = 0;
748  ppid = 0;
749  apids[0] = 0;
750  dpids[0] = 0;
751  spids[0] = 0;
752  atypes[0] = 0;
753  dtypes[0] = 0;
754  SI::PMT::Stream stream;
755  for (SI::Loop::Iterator it; Pmt.streamLoop.getNext(stream, it); ) {
756  dbgpatpmt(" stream type = %02X, pid = %d", stream.getStreamType(), stream.getPid());
757  switch (stream.getStreamType()) {
758  case 0x01: // STREAMTYPE_11172_VIDEO
759  case 0x02: // STREAMTYPE_13818_VIDEO
760  case 0x1B: // H.264
761  case 0x24: // H.265
762  vpid = stream.getPid();
763  vtype = stream.getStreamType();
764  ppid = Pmt.getPCRPid();
765  break;
766  case 0x03: // STREAMTYPE_11172_AUDIO
767  case 0x04: // STREAMTYPE_13818_AUDIO
768  case 0x0F: // ISO/IEC 13818-7 Audio with ADTS transport syntax
769  case 0x11: // ISO/IEC 14496-3 Audio with LATM transport syntax
770  {
771  if (NumApids < MAXAPIDS) {
772  apids[NumApids] = stream.getPid();
773  atypes[NumApids] = stream.getStreamType();
774  *alangs[NumApids] = 0;
775  SI::Descriptor *d;
776  for (SI::Loop::Iterator it; (d = stream.streamDescriptors.getNext(it)); ) {
777  switch (d->getDescriptorTag()) {
781  char *s = alangs[NumApids];
782  int n = 0;
783  for (SI::Loop::Iterator it; ld->languageLoop.getNext(l, it); ) {
784  if (*ld->languageCode != '-') { // some use "---" to indicate "none"
785  dbgpatpmt(" '%s'", l.languageCode);
786  if (n > 0)
787  *s++ = '+';
789  s += strlen(s);
790  if (n++ > 1)
791  break;
792  }
793  }
794  }
795  break;
796  default: ;
797  }
798  delete d;
799  }
801  cDevice::PrimaryDevice()->SetAvailableTrack(ttAudio, NumApids, apids[NumApids], alangs[NumApids]);
802  NumApids++;
803  apids[NumApids] = 0;
804  }
805  }
806  break;
807  case 0x06: // STREAMTYPE_13818_PES_PRIVATE
808  {
809  int dpid = 0;
810  int dtype = 0;
811  char lang[MAXLANGCODE1] = "";
812  SI::Descriptor *d;
813  for (SI::Loop::Iterator it; (d = stream.streamDescriptors.getNext(it)); ) {
814  switch (d->getDescriptorTag()) {
817  dbgpatpmt(" AC3");
818  dpid = stream.getPid();
819  dtype = d->getDescriptorTag();
820  break;
822  dbgpatpmt(" subtitling");
823  if (NumSpids < MAXSPIDS) {
824  spids[NumSpids] = stream.getPid();
825  *slangs[NumSpids] = 0;
826  subtitlingTypes[NumSpids] = 0;
827  compositionPageIds[NumSpids] = 0;
828  ancillaryPageIds[NumSpids] = 0;
831  char *s = slangs[NumSpids];
832  int n = 0;
833  for (SI::Loop::Iterator it; sd->subtitlingLoop.getNext(sub, it); ) {
834  if (sub.languageCode[0]) {
835  dbgpatpmt(" '%s'", sub.languageCode);
836  subtitlingTypes[NumSpids] = sub.getSubtitlingType();
837  compositionPageIds[NumSpids] = sub.getCompositionPageId();
838  ancillaryPageIds[NumSpids] = sub.getAncillaryPageId();
839  if (n > 0)
840  *s++ = '+';
842  s += strlen(s);
843  if (n++ > 1)
844  break;
845  }
846  }
848  cDevice::PrimaryDevice()->SetAvailableTrack(ttSubtitle, NumSpids, spids[NumSpids], slangs[NumSpids]);
849  NumSpids++;
850  spids[NumSpids] = 0;
851  }
852  break;
855  dbgpatpmt(" '%s'", ld->languageCode);
857  }
858  break;
859  default: ;
860  }
861  delete d;
862  }
863  if (dpid) {
864  if (NumDpids < MAXDPIDS) {
865  dpids[NumDpids] = dpid;
866  dtypes[NumDpids] = dtype;
867  strn0cpy(dlangs[NumDpids], lang, sizeof(dlangs[NumDpids]));
869  cDevice::PrimaryDevice()->SetAvailableTrack(ttDolby, NumDpids, dpid, lang);
870  NumDpids++;
871  dpids[NumDpids] = 0;
872  }
873  }
874  }
875  break;
876  case 0x81: // STREAMTYPE_USER_PRIVATE - AC3 audio for ATSC and BD
877  case 0x82: // STREAMTYPE_USER_PRIVATE - DTS audio for BD
878  case 0x87: // eac3
879  {
880  dbgpatpmt(" %s",
881  stream.getStreamType() == 0x81 ? "AC3" :
882  stream.getStreamType() == 0x87 ? "AC3" :
883  stream.getStreamType() == 0x82 ? "DTS" : "");
884  char lang[MAXLANGCODE1] = { 0 };
885  SI::Descriptor *d;
886  for (SI::Loop::Iterator it; (d = stream.streamDescriptors.getNext(it)); ) {
887  switch (d->getDescriptorTag()) {
890  dbgpatpmt(" '%s'", ld->languageCode);
892  }
893  break;
894  default: ;
895  }
896  delete d;
897  }
898  if (NumDpids < MAXDPIDS) {
899  dpids[NumDpids] = stream.getPid();
900  dtypes[NumDpids] = SI::AC3DescriptorTag;
901  strn0cpy(dlangs[NumDpids], lang, sizeof(dlangs[NumDpids]));
903  cDevice::PrimaryDevice()->SetAvailableTrack(ttDolby, NumDpids, stream.getPid(), lang);
904  NumDpids++;
905  dpids[NumDpids] = 0;
906  }
907  }
908  break;
909  case 0x90: // PGS subtitles for BD
910  {
911  dbgpatpmt(" subtitling");
912  char lang[MAXLANGCODE1] = { 0 };
913  SI::Descriptor *d;
914  for (SI::Loop::Iterator it; (d = stream.streamDescriptors.getNext(it)); ) {
915  switch (d->getDescriptorTag()) {
918  dbgpatpmt(" '%s'", ld->languageCode);
920  if (NumSpids < MAXSPIDS) {
921  spids[NumSpids] = stream.getPid();
922  *slangs[NumSpids] = 0;
923  subtitlingTypes[NumSpids] = 0;
924  compositionPageIds[NumSpids] = 0;
925  ancillaryPageIds[NumSpids] = 0;
927  cDevice::PrimaryDevice()->SetAvailableTrack(ttSubtitle, NumSpids, stream.getPid(), lang);
928  NumSpids++;
929  spids[NumSpids] = 0;
930  }
931  }
932  break;
933  default: ;
934  }
935  delete d;
936  }
937  }
938  break;
939  default: ;
940  }
941  dbgpatpmt("\n");
942  if (updatePrimaryDevice) {
945  }
946  }
948  completed = true;
949  }
950  else
951  esyslog("ERROR: can't parse PMT");
952  pmtSize = 0;
953 }
954 
955 bool cPatPmtParser::ParsePatPmt(const uchar *Data, int Length)
956 {
957  while (Length >= TS_SIZE) {
958  if (*Data != TS_SYNC_BYTE)
959  break; // just for safety
960  int Pid = TsPid(Data);
961  if (Pid == PATPID)
962  ParsePat(Data, TS_SIZE);
963  else if (IsPmtPid(Pid)) {
964  ParsePmt(Data, TS_SIZE);
965  if (patVersion >= 0 && pmtVersion >= 0)
966  return true;
967  }
968  Data += TS_SIZE;
969  Length -= TS_SIZE;
970  }
971  return false;
972 }
973 
974 bool cPatPmtParser::GetVersions(int &PatVersion, int &PmtVersion) const
975 {
976  PatVersion = patVersion;
977  PmtVersion = pmtVersion;
978  return patVersion >= 0 && pmtVersion >= 0;
979 }
980 
981 // --- cEitGenerator ---------------------------------------------------------
982 
984 {
985  counter = 0;
986  version = 0;
987  if (Sid)
988  Generate(Sid);
989 }
990 
991 uint16_t cEitGenerator::YMDtoMJD(int Y, int M, int D)
992 {
993  int L = (M < 3) ? 1 : 0;
994  return 14956 + D + int((Y - L) * 365.25) + int((M + 1 + L * 12) * 30.6001);
995 }
996 
998 {
1000  *p++ = 0x04; // descriptor length
1001  *p++ = 'D'; // country code
1002  *p++ = 'E';
1003  *p++ = 'U';
1004  *p++ = ParentalRating;
1005  return p;
1006 }
1007 
1009 {
1010  uchar *PayloadStart;
1011  uchar *SectionStart;
1012  uchar *DescriptorsStart;
1013  memset(eit, 0xFF, sizeof(eit));
1014  struct tm tm_r;
1015  time_t t = time(NULL) - 3600; // let's have the event start one hour in the past
1016  tm *tm = localtime_r(&t, &tm_r);
1017  uint16_t MJD = YMDtoMJD(tm->tm_year, tm->tm_mon + 1, tm->tm_mday);
1018  uchar *p = eit;
1019  // TS header:
1020  *p++ = TS_SYNC_BYTE;
1021  *p++ = TS_PAYLOAD_START;
1022  *p++ = EITPID;
1023  *p++ = 0x10 | (counter++ & 0x0F); // continuity counter
1024  *p++ = 0x00; // pointer field (payload unit start indicator is set)
1025  // payload:
1026  PayloadStart = p;
1027  *p++ = 0x4E; // TID present/following event on this transponder
1028  *p++ = 0xF0;
1029  *p++ = 0x00; // section length
1030  SectionStart = p;
1031  *p++ = Sid >> 8;
1032  *p++ = Sid & 0xFF;
1033  *p++ = 0xC1 | (version << 1);
1034  *p++ = 0x00; // section number
1035  *p++ = 0x00; // last section number
1036  *p++ = 0x00; // transport stream id
1037  *p++ = 0x00; // ...
1038  *p++ = 0x00; // original network id
1039  *p++ = 0x00; // ...
1040  *p++ = 0x00; // segment last section number
1041  *p++ = 0x4E; // last table id
1042  *p++ = 0x00; // event id
1043  *p++ = 0x01; // ...
1044  *p++ = MJD >> 8; // start time
1045  *p++ = MJD & 0xFF; // ...
1046  *p++ = tm->tm_hour; // ...
1047  *p++ = tm->tm_min; // ...
1048  *p++ = tm->tm_sec; // ...
1049  *p++ = 0x24; // duration (one day, should cover everything)
1050  *p++ = 0x00; // ...
1051  *p++ = 0x00; // ...
1052  *p++ = 0x90; // running status, free/CA mode
1053  *p++ = 0x00; // descriptors loop length
1054  DescriptorsStart = p;
1056  // fill in lengths:
1057  *(SectionStart - 1) = p - SectionStart + 4; // +4 = length of CRC
1058  *(DescriptorsStart - 1) = p - DescriptorsStart;
1059  // checksum
1060  int crc = SI::CRC32::crc32((char *)PayloadStart, p - PayloadStart, 0xFFFFFFFF);
1061  *p++ = crc >> 24;
1062  *p++ = crc >> 16;
1063  *p++ = crc >> 8;
1064  *p++ = crc;
1065  return eit;
1066 }
1067 
1068 // --- cTsToPes --------------------------------------------------------------
1069 
1071 {
1072  data = NULL;
1073  size = 0;
1074  Reset();
1075 }
1076 
1078 {
1079  free(data);
1080 }
1081 
1082 void cTsToPes::PutTs(const uchar *Data, int Length)
1083 {
1084  if (TsError(Data)) {
1085  Reset();
1086  return; // ignore packets with TEI set, and drop any PES data collected so far
1087  }
1088  if (TsPayloadStart(Data))
1089  Reset();
1090  else if (!size)
1091  return; // skip everything before the first payload start
1092  Length = TsGetPayload(&Data);
1093  if (length + Length > size) {
1094  int NewSize = max(KILOBYTE(2), length + Length);
1095  if (uchar *NewData = (uchar *)realloc(data, NewSize)) {
1096  data = NewData;
1097  size = NewSize;
1098  }
1099  else {
1100  esyslog("ERROR: out of memory");
1101  Reset();
1102  return;
1103  }
1104  }
1105  memcpy(data + length, Data, Length);
1106  length += Length;
1107 }
1108 
1109 #define MAXPESLENGTH 0xFFF0
1111 const uchar *cTsToPes::GetPes(int &Length)
1112 {
1113  if (repeatLast) {
1114  repeatLast = false;
1115  Length = lastLength;
1116  return lastData;
1117  }
1118  if (offset < length && PesLongEnough(length)) {
1119  if (!PesHasLength(data)) // this is a video PES packet with undefined length
1120  offset = 6; // trigger setting PES length for initial slice
1121  if (offset) {
1122  uchar *p = data + offset - 6;
1123  if (p != data) {
1124  p -= 3;
1125  if (p < data) {
1126  Reset();
1127  return NULL;
1128  }
1129  memmove(p, data, 4);
1130  }
1131  int l = min(length - offset, MAXPESLENGTH);
1132  offset += l;
1133  if (p != data) {
1134  l += 3;
1135  p[6] = 0x80;
1136  p[7] = 0x00;
1137  p[8] = 0x00;
1138  }
1139  p[4] = l / 256;
1140  p[5] = l & 0xFF;
1141  Length = l + 6;
1142  lastLength = Length;
1143  lastData = p;
1144  return p;
1145  }
1146  else {
1147  Length = PesLength(data);
1148  if (Length <= length) {
1149  offset = Length; // to make sure we break out in case of garbage data
1150  lastLength = Length;
1151  lastData = data;
1152  return data;
1153  }
1154  }
1155  }
1156  return NULL;
1157 }
1158 
1160 {
1161  repeatLast = true;
1162 }
1163 
1165 {
1166  length = offset = 0;
1167  lastData = NULL;
1168  lastLength = 0;
1169  repeatLast = false;
1170 }
1171 
1172 // --- Some helper functions for debugging -----------------------------------
1173 
1174 void BlockDump(const char *Name, const u_char *Data, int Length)
1175 {
1176  printf("--- %s\n", Name);
1177  for (int i = 0; i < Length; i++) {
1178  if (i && (i % 16) == 0)
1179  printf("\n");
1180  printf(" %02X", Data[i]);
1181  }
1182  printf("\n");
1183 }
1184 
1185 void TsDump(const char *Name, const u_char *Data, int Length)
1186 {
1187  printf("%s: %04X", Name, Length);
1188  int n = min(Length, 20);
1189  for (int i = 0; i < n; i++)
1190  printf(" %02X", Data[i]);
1191  if (n < Length) {
1192  printf(" ...");
1193  n = max(n, Length - 10);
1194  for (n = max(n, Length - 10); n < Length; n++)
1195  printf(" %02X", Data[n]);
1196  }
1197  printf("\n");
1198 }
1199 
1200 void PesDump(const char *Name, const u_char *Data, int Length)
1201 {
1202  TsDump(Name, Data, Length);
1203 }
1204 
1205 // --- cFrameParser ----------------------------------------------------------
1206 
1208 protected:
1209  bool debug;
1210  bool newFrame;
1213 public:
1214  cFrameParser(void);
1215  virtual ~cFrameParser() {};
1216  virtual int Parse(const uchar *Data, int Length, int Pid) = 0;
1223  void SetDebug(bool Debug) { debug = Debug; }
1224  bool NewFrame(void) { return newFrame; }
1225  bool IndependentFrame(void) { return independentFrame; }
1227  };
1228 
1230 {
1231  debug = true;
1232  newFrame = false;
1233  independentFrame = false;
1235 }
1236 
1237 // --- cAudioParser ----------------------------------------------------------
1238 
1239 class cAudioParser : public cFrameParser {
1240 public:
1241  cAudioParser(void);
1242  virtual int Parse(const uchar *Data, int Length, int Pid);
1243  };
1244 
1246 {
1247 }
1248 
1249 int cAudioParser::Parse(const uchar *Data, int Length, int Pid)
1250 {
1251  if (TsPayloadStart(Data)) {
1252  newFrame = independentFrame = true;
1253  if (debug)
1254  dbgframes("/");
1255  }
1256  else
1257  newFrame = independentFrame = false;
1258  return TS_SIZE;
1259 }
1260 
1261 // --- cMpeg2Parser ----------------------------------------------------------
1262 
1263 class cMpeg2Parser : public cFrameParser {
1264 private:
1265  uint32_t scanner;
1268 public:
1269  cMpeg2Parser(void);
1270  virtual int Parse(const uchar *Data, int Length, int Pid);
1271  };
1272 
1274 {
1276  seenIndependentFrame = false;
1277  lastIFrameTemporalReference = -1; // invalid
1278 }
1279 
1280 int cMpeg2Parser::Parse(const uchar *Data, int Length, int Pid)
1281 {
1282  newFrame = independentFrame = false;
1283  bool SeenPayloadStart = false;
1284  cTsPayload tsPayload(const_cast<uchar *>(Data), Length, Pid);
1285  if (TsPayloadStart(Data)) {
1286  SeenPayloadStart = true;
1287  tsPayload.SkipPesHeader();
1289  if (debug && seenIndependentFrame)
1290  dbgframes("/");
1291  }
1292  uint32_t OldScanner = scanner; // need to remember it in case of multiple frames per payload
1293  for (;;) {
1294  if (!SeenPayloadStart && tsPayload.AtTsStart())
1295  OldScanner = scanner;
1296  scanner = (scanner << 8) | tsPayload.GetByte();
1297  if (scanner == 0x00000100) { // Picture Start Code
1298  if (!SeenPayloadStart && tsPayload.GetLastIndex() > TS_SIZE) {
1299  scanner = OldScanner;
1300  return tsPayload.Used() - TS_SIZE;
1301  }
1302  uchar b1 = tsPayload.GetByte();
1303  uchar b2 = tsPayload.GetByte();
1304  int TemporalReference = (b1 << 2 ) + ((b2 & 0xC0) >> 6);
1305  uchar FrameType = (b2 >> 3) & 0x07;
1306  if (tsPayload.Find(0x000001B5)) { // Extension start code
1307  if (((tsPayload.GetByte() & 0xF0) >> 4) == 0x08) { // Picture coding extension
1308  tsPayload.GetByte();
1309  uchar PictureStructure = tsPayload.GetByte() & 0x03;
1310  if (PictureStructure == 0x02) // bottom field
1311  break;
1312  }
1313  }
1314  newFrame = true;
1315  independentFrame = FrameType == 1; // I-Frame
1316  if (independentFrame) {
1317  if (lastIFrameTemporalReference >= 0)
1319  lastIFrameTemporalReference = TemporalReference;
1320  }
1321  if (debug) {
1323  if (seenIndependentFrame) {
1324  static const char FrameTypes[] = "?IPBD???";
1325  dbgframes("%c", FrameTypes[FrameType]);
1326  }
1327  }
1328  tsPayload.Statistics();
1329  break;
1330  }
1331  if (tsPayload.AtPayloadStart() // stop at any new payload start to have the buffer refilled if necessary
1332  || tsPayload.Eof()) // or if we're out of data
1333  break;
1334  }
1335  return tsPayload.Used();
1336 }
1337 
1338 // --- cH264Parser -----------------------------------------------------------
1339 
1340 class cH264Parser : public cFrameParser {
1341 private:
1347  };
1348  uchar byte; // holds the current byte value in case of bitwise access
1349  int bit; // the bit index into the current byte (-1 if we're not in bit reading mode)
1350  int zeroBytes; // the number of consecutive zero bytes (to detect 0x000003)
1351  // Identifiers written in '_' notation as in "ITU-T H.264":
1355 protected:
1357  uint32_t scanner;
1360  uchar GetByte(bool Raw = false);
1364  uchar GetBit(void);
1365  uint32_t GetBits(int Bits);
1366  uint32_t GetGolombUe(void);
1367  int32_t GetGolombSe(void);
1368  void ParseAccessUnitDelimiter(void);
1369  void ParseSequenceParameterSet(void);
1370  void ParseSliceHeader(void);
1371 public:
1372  cH264Parser(void);
1376  virtual int Parse(const uchar *Data, int Length, int Pid);
1377  };
1378 
1380 {
1381  byte = 0;
1382  bit = -1;
1383  zeroBytes = 0;
1386  log2_max_frame_num = 0;
1387  frame_mbs_only_flag = false;
1388  gotAccessUnitDelimiter = false;
1389  gotSequenceParameterSet = false;
1390 }
1391 
1393 {
1394  uchar b = tsPayload.GetByte();
1395  if (!Raw) {
1396  // If we encounter the byte sequence 0x000003, we need to skip the 0x03:
1397  if (b == 0x00)
1398  zeroBytes++;
1399  else {
1400  if (b == 0x03 && zeroBytes >= 2)
1401  b = tsPayload.GetByte();
1402  zeroBytes = 0;
1403  }
1404  }
1405  else
1406  zeroBytes = 0;
1407  bit = -1;
1408  return b;
1409 }
1410 
1412 {
1413  if (bit < 0) {
1414  byte = GetByte();
1415  bit = 7;
1416  }
1417  return (byte & (1 << bit--)) ? 1 : 0;
1418 }
1419 
1420 uint32_t cH264Parser::GetBits(int Bits)
1421 {
1422  uint32_t b = 0;
1423  while (Bits--)
1424  b |= GetBit() << Bits;
1425  return b;
1426 }
1427 
1429 {
1430  int z = -1;
1431  for (int b = 0; !b && z < 32; z++) // limiting z to no get stuck if GetBit() always returns 0
1432  b = GetBit();
1433  return (1 << z) - 1 + GetBits(z);
1434 }
1435 
1437 {
1438  uint32_t v = GetGolombUe();
1439  if (v) {
1440  if ((v & 0x01) != 0)
1441  return (v + 1) / 2; // fails for v == 0xFFFFFFFF, but that will probably never happen
1442  else
1443  return -int32_t(v / 2);
1444  }
1445  return v;
1446 }
1447 
1448 int cH264Parser::Parse(const uchar *Data, int Length, int Pid)
1449 {
1450  newFrame = independentFrame = false;
1451  tsPayload.Setup(const_cast<uchar *>(Data), Length, Pid);
1452  if (TsPayloadStart(Data)) {
1455  if (debug && gotSequenceParameterSet) {
1456  dbgframes("/");
1457  }
1458  }
1459  for (;;) {
1460  scanner = (scanner << 8) | GetByte(true);
1461  if ((scanner & 0xFFFFFF00) == 0x00000100) { // NAL unit start
1462  uchar NalUnitType = scanner & 0x1F;
1463  switch (NalUnitType) {
1465  gotAccessUnitDelimiter = true;
1466  break;
1469  gotSequenceParameterSet = true;
1470  }
1471  break;
1472  case nutCodedSliceNonIdr:
1474  ParseSliceHeader();
1475  gotAccessUnitDelimiter = false;
1476  if (newFrame)
1478  return tsPayload.Used();
1479  }
1480  break;
1481  default: ;
1482  }
1483  }
1484  if (tsPayload.AtPayloadStart() // stop at any new payload start to have the buffer refilled if necessary
1485  || tsPayload.Eof()) // or if we're out of data
1486  break;
1487  }
1488  return tsPayload.Used();
1489 }
1490 
1492 {
1494  dbgframes("A");
1495  GetByte(); // primary_pic_type
1496 }
1497 
1499 {
1500  uchar profile_idc = GetByte(); // profile_idc
1501  GetByte(); // constraint_set[0-5]_flags, reserved_zero_2bits
1502  GetByte(); // level_idc
1503  GetGolombUe(); // seq_parameter_set_id
1504  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) {
1505  int chroma_format_idc = GetGolombUe(); // chroma_format_idc
1506  if (chroma_format_idc == 3)
1508  GetGolombUe(); // bit_depth_luma_minus8
1509  GetGolombUe(); // bit_depth_chroma_minus8
1510  GetBit(); // qpprime_y_zero_transform_bypass_flag
1511  if (GetBit()) { // seq_scaling_matrix_present_flag
1512  for (int i = 0; i < ((chroma_format_idc != 3) ? 8 : 12); i++) {
1513  if (GetBit()) { // seq_scaling_list_present_flag
1514  int SizeOfScalingList = (i < 6) ? 16 : 64;
1515  int LastScale = 8;
1516  int NextScale = 8;
1517  for (int j = 0; j < SizeOfScalingList; j++) {
1518  if (NextScale)
1519  NextScale = (LastScale + GetGolombSe() + 256) % 256; // delta_scale
1520  if (NextScale)
1521  LastScale = NextScale;
1522  }
1523  }
1524  }
1525  }
1526  }
1527  log2_max_frame_num = GetGolombUe() + 4; // log2_max_frame_num_minus4
1528  int pic_order_cnt_type = GetGolombUe(); // pic_order_cnt_type
1529  if (pic_order_cnt_type == 0)
1530  GetGolombUe(); // log2_max_pic_order_cnt_lsb_minus4
1531  else if (pic_order_cnt_type == 1) {
1532  GetBit(); // delta_pic_order_always_zero_flag
1533  GetGolombSe(); // offset_for_non_ref_pic
1534  GetGolombSe(); // offset_for_top_to_bottom_field
1535  for (int i = GetGolombUe(); i--; ) // num_ref_frames_in_pic_order_cnt_cycle
1536  GetGolombSe(); // offset_for_ref_frame
1537  }
1538  GetGolombUe(); // max_num_ref_frames
1539  GetBit(); // gaps_in_frame_num_value_allowed_flag
1540  GetGolombUe(); // pic_width_in_mbs_minus1
1541  GetGolombUe(); // pic_height_in_map_units_minus1
1542  frame_mbs_only_flag = GetBit(); // frame_mbs_only_flag
1543  if (debug) {
1545  dbgframes("A"); // just for completeness
1546  dbgframes(frame_mbs_only_flag ? "S" : "s");
1547  }
1548 }
1549 
1551 {
1552  newFrame = true;
1553  GetGolombUe(); // first_mb_in_slice
1554  int slice_type = GetGolombUe(); // slice_type, 0 = P, 1 = B, 2 = I, 3 = SP, 4 = SI
1555  independentFrame = (slice_type % 5) == 2;
1556  if (debug) {
1557  static const char SliceTypes[] = "PBIpi";
1558  dbgframes("%c", SliceTypes[slice_type % 5]);
1559  }
1560  if (frame_mbs_only_flag)
1561  return; // don't need the rest - a frame is complete
1562  GetGolombUe(); // pic_parameter_set_id
1564  GetBits(2); // colour_plane_id
1565  GetBits(log2_max_frame_num); // frame_num
1566  if (!frame_mbs_only_flag) {
1567  if (GetBit()) // field_pic_flag
1568  newFrame = !GetBit(); // bottom_field_flag
1569  if (debug)
1570  dbgframes(newFrame ? "t" : "b");
1571  }
1572 }
1573 
1574 // --- cH265Parser -----------------------------------------------------------
1575 
1576 class cH265Parser : public cH264Parser {
1577 private:
1608  };
1609 public:
1610  cH265Parser(void);
1611  virtual int Parse(const uchar *Data, int Length, int Pid);
1612  };
1613 
1615 :cH264Parser()
1616 {
1617 }
1618 
1619 int cH265Parser::Parse(const uchar *Data, int Length, int Pid)
1620 {
1621  newFrame = independentFrame = false;
1622  tsPayload.Setup(const_cast<uchar *>(Data), Length, Pid);
1623  if (TsPayloadStart(Data)) {
1626  }
1627  for (;;) {
1628  scanner = (scanner << 8) | GetByte(true);
1629  if ((scanner & 0xFFFFFF00) == 0x00000100) { // NAL unit start
1630  uchar NalUnitType = (scanner >> 1) & 0x3F;
1631  GetByte(); // nuh_layer_id + nuh_temporal_id_plus1
1632  if (NalUnitType <= nutSliceSegmentRASLR || (NalUnitType >= nutSliceSegmentBLAWLP && NalUnitType <= nutSliceSegmentCRANUT)) {
1633  if (NalUnitType == nutSliceSegmentIDRWRADL || NalUnitType == nutSliceSegmentIDRNLP || NalUnitType == nutSliceSegmentCRANUT)
1634  independentFrame = true;
1635  if (GetBit()) { // first_slice_segment_in_pic_flag
1636  newFrame = true;
1638  }
1639  break;
1640  }
1641  }
1642  if (tsPayload.AtPayloadStart() // stop at any new payload start to have the buffer refilled if necessary
1643  || tsPayload.Eof()) // or if we're out of data
1644  break;
1645  }
1646  return tsPayload.Used();
1647 }
1648 
1649 // --- cFrameDetector --------------------------------------------------------
1650 
1652 {
1653  parser = NULL;
1654  SetPid(Pid, Type);
1655  synced = false;
1656  newFrame = independentFrame = false;
1657  numPtsValues = 0;
1658  numIFrames = 0;
1659  framesPerSecond = 0;
1661  scanning = false;
1662 }
1663 
1664 static int CmpUint32(const void *p1, const void *p2)
1665 {
1666  if (*(uint32_t *)p1 < *(uint32_t *)p2) return -1;
1667  if (*(uint32_t *)p1 > *(uint32_t *)p2) return 1;
1668  return 0;
1669 }
1670 
1671 void cFrameDetector::SetPid(int Pid, int Type)
1672 {
1673  pid = Pid;
1674  type = Type;
1675  isVideo = type == 0x01 || type == 0x02 || type == 0x1B || type == 0x24; // MPEG 1, 2, H.264 or H.265
1676  delete parser;
1677  parser = NULL;
1678  if (type == 0x01 || type == 0x02)
1679  parser = new cMpeg2Parser;
1680  else if (type == 0x1B)
1681  parser = new cH264Parser;
1682  else if (type == 0x24)
1683  parser = new cH265Parser;
1684  else if (type == 0x03 || type == 0x04 || type == 0x06) // MPEG audio or AC3 audio
1685  parser = new cAudioParser;
1686  else if (type != 0)
1687  esyslog("ERROR: unknown stream type %d (PID %d) in frame detector", type, pid);
1688 }
1689 
1690 int cFrameDetector::Analyze(const uchar *Data, int Length)
1691 {
1692  if (!parser)
1693  return 0;
1694  int Processed = 0;
1695  newFrame = independentFrame = false;
1696  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
1697  // Sync on TS packet borders:
1698  if (int Skipped = TS_SYNC(Data, Length))
1699  return Processed + Skipped;
1700  // Handle one TS packet:
1701  int Handled = TS_SIZE;
1702  if (TsHasPayload(Data) && !TsIsScrambled(Data)) {
1703  int Pid = TsPid(Data);
1704  if (Pid == pid) {
1705  if (Processed)
1706  return Processed;
1707  if (TsPayloadStart(Data))
1708  scanning = true;
1709  if (scanning) {
1710  // Detect the beginning of a new frame:
1711  if (TsPayloadStart(Data)) {
1712  if (!framesPerPayloadUnit)
1714  }
1715  int n = parser->Parse(Data, Length, pid);
1716  if (n > 0) {
1717  if (parser->NewFrame()) {
1718  newFrame = true;
1720  if (synced) {
1721  if (framesPerPayloadUnit <= 1)
1722  scanning = false;
1723  }
1724  else {
1726  if (independentFrame)
1727  numIFrames++;
1728  }
1729  }
1730  Handled = n;
1731  }
1732  }
1733  if (TsPayloadStart(Data)) {
1734  // Determine the frame rate from the PTS values in the PES headers:
1735  if (framesPerSecond <= 0.0) {
1736  // frame rate unknown, so collect a sequence of PTS values:
1737  if (numPtsValues < 2 || numPtsValues < MaxPtsValues && numIFrames < 2) { // collect a sequence containing at least two I-frames
1738  if (newFrame) { // only take PTS values at the beginning of a frame (in case if fields!)
1739  const uchar *Pes = Data + TsPayloadOffset(Data);
1740  if (numIFrames && PesHasPts(Pes)) {
1742  // check for rollover:
1743  if (numPtsValues && ptsValues[numPtsValues - 1] > 0xF0000000 && ptsValues[numPtsValues] < 0x10000000) {
1744  dbgframes("#");
1745  numPtsValues = 0;
1746  numIFrames = 0;
1747  }
1748  else
1749  numPtsValues++;
1750  }
1751  }
1752  }
1753  if (numPtsValues >= 2 && numIFrames >= 2) {
1754  // find the smallest PTS delta:
1755  qsort(ptsValues, numPtsValues, sizeof(uint32_t), CmpUint32);
1756  numPtsValues--;
1757  for (int i = 0; i < numPtsValues; i++)
1758  ptsValues[i] = ptsValues[i + 1] - ptsValues[i];
1759  qsort(ptsValues, numPtsValues, sizeof(uint32_t), CmpUint32);
1760  int Div = framesPerPayloadUnit;
1761  if (framesPerPayloadUnit > 1)
1763  if (Div <= 0)
1764  Div = 1;
1765  int Delta = ptsValues[0] / Div;
1766  // determine frame info:
1767  if (isVideo) {
1768  if (Delta == 3753)
1769  framesPerSecond = 24.0 / 1.001;
1770  else if (abs(Delta - 3600) <= 1)
1771  framesPerSecond = 25.0;
1772  else if (Delta % 3003 == 0)
1773  framesPerSecond = 30.0 / 1.001;
1774  else if (abs(Delta - 1800) <= 1)
1775  framesPerSecond = 50.0;
1776  else if (Delta == 1501)
1777  framesPerSecond = 60.0 / 1.001;
1778  else {
1780  dsyslog("unknown frame delta (%d), assuming %5.2f fps", Delta, DEFAULTFRAMESPERSECOND);
1781  }
1782  }
1783  else // audio
1784  framesPerSecond = double(PTSTICKS) / Delta; // PTS of audio frames is always increasing
1785  dbgframes("\nDelta = %d FPS = %5.2f FPPU = %d NF = %d TRO = %d\n", Delta, framesPerSecond, framesPerPayloadUnit, numPtsValues + 1, parser->IFrameTemporalReferenceOffset());
1786  synced = true;
1787  parser->SetDebug(false);
1788  }
1789  }
1790  }
1791  }
1792  else if (Pid == PATPID && synced && Processed)
1793  return Processed; // allow the caller to see any PAT packets
1794  }
1795  Data += Handled;
1796  Length -= Handled;
1797  Processed += Handled;
1798  if (newFrame)
1799  break;
1800  }
1801  return Processed;
1802 }
1803 
1804 // --- cNaluDumper ---------------------------------------------------------
1805 
1807 {
1808  LastContinuityOutput = -1;
1809  reset();
1810 }
1811 
1813 {
1814  LastContinuityInput = -1;
1815  ContinuityOffset = 0;
1816  PesId = -1;
1817  PesOffset = 0;
1819  NaluOffset = 0;
1820  History = 0xffffffff;
1821  DropAllPayload = false;
1822 }
1823 
1824 void cNaluDumper::ProcessPayload(unsigned char *Payload, int size, bool PayloadStart, sPayloadInfo &Info)
1825 {
1826  Info.DropPayloadStartBytes = 0;
1827  Info.DropPayloadEndBytes = 0;
1828  int LastKeepByte = -1;
1829 
1830  if (PayloadStart)
1831  {
1832  History = 0xffffffff;
1833  PesId = -1;
1835  }
1836 
1837  for (int i=0; i<size; i++) {
1838  History = (History << 8) | Payload[i];
1839 
1840  PesOffset++;
1841  NaluOffset++;
1842 
1843  bool DropByte = false;
1844 
1845  if (History >= 0x00000180 && History <= 0x000001FF)
1846  {
1847  // Start of PES packet
1848  PesId = History & 0xff;
1849  PesOffset = 0;
1851  }
1852  else if (PesId >= 0xe0 && PesId <= 0xef // video stream
1853  && History >= 0x00000100 && History <= 0x0000017F) // NALU start code
1854  {
1855  int NaluId = History & 0xff;
1856  NaluOffset = 0;
1857  NaluFillState = ((NaluId & 0x1f) == 0x0c) ? NALU_FILL : NALU_NONE;
1858  }
1859 
1860  if (PesId >= 0xe0 && PesId <= 0xef // video stream
1861  && PesOffset >= 1 && PesOffset <= 2)
1862  {
1863  Payload[i] = 0; // Zero out PES length field
1864  }
1865 
1866  if (NaluFillState == NALU_FILL && NaluOffset > 0) // Within NALU fill data
1867  {
1868  // We expect a series of 0xff bytes terminated by a single 0x80 byte.
1869 
1870  if (Payload[i] == 0xFF)
1871  {
1872  DropByte = true;
1873  }
1874  else if (Payload[i] == 0x80)
1875  {
1876  NaluFillState = NALU_TERM; // Last byte of NALU fill, next byte sets NaluFillEnd=true
1877  DropByte = true;
1878  }
1879  else // Invalid NALU fill
1880  {
1881  dsyslog("cNaluDumper: Unexpected NALU fill data: %02x", Payload[i]);
1883  if (LastKeepByte == -1)
1884  {
1885  // Nalu fill from beginning of packet until last byte
1886  // packet start needs to be dropped
1887  Info.DropPayloadStartBytes = i;
1888  }
1889  }
1890  }
1891  else if (NaluFillState == NALU_TERM) // Within NALU fill data
1892  {
1893  // We are after the terminating 0x80 byte
1895  if (LastKeepByte == -1)
1896  {
1897  // Nalu fill from beginning of packet until last byte
1898  // packet start needs to be dropped
1899  Info.DropPayloadStartBytes = i;
1900  }
1901  }
1902 
1903  if (!DropByte)
1904  LastKeepByte = i; // Last useful byte
1905  }
1906 
1907  Info.DropAllPayloadBytes = (LastKeepByte == -1);
1908  Info.DropPayloadEndBytes = size-1-LastKeepByte;
1909 }
1910 
1911 bool cNaluDumper::ProcessTSPacket(unsigned char *Packet)
1912 {
1913  bool HasAdaption = TsHasAdaptationField(Packet);
1914  bool HasPayload = TsHasPayload(Packet);
1915 
1916  // Check continuity:
1917  int ContinuityInput = TsContinuityCounter(Packet);
1918  if (LastContinuityInput >= 0)
1919  {
1920  int NewContinuityInput = HasPayload ? (LastContinuityInput + 1) & TS_CONT_CNT_MASK : LastContinuityInput;
1921  int Offset = (NewContinuityInput - ContinuityInput) & TS_CONT_CNT_MASK;
1922  if (Offset > 0)
1923  dsyslog("cNaluDumper: TS continuity offset %i", Offset);
1924  if (Offset > ContinuityOffset)
1925  ContinuityOffset = Offset; // max if packets get dropped, otherwise always the current one.
1926  }
1927  LastContinuityInput = ContinuityInput;
1928 
1929  if (HasPayload) {
1930  sPayloadInfo Info;
1931  int Offset = TsPayloadOffset(Packet);
1932  ProcessPayload(Packet + Offset, TS_SIZE - Offset, TsPayloadStart(Packet), Info);
1933 
1934  if (DropAllPayload && !Info.DropAllPayloadBytes)
1935  {
1936  // Return from drop packet mode to normal mode
1937  DropAllPayload = false;
1938 
1939  // Does the packet start with some remaining NALU fill data?
1940  if (Info.DropPayloadStartBytes > 0)
1941  {
1942  // Add these bytes as stuffing to the adaption field.
1943 
1944  // Sample payload layout:
1945  // FF FF FF FF FF 80 00 00 01 xx xx xx xx
1946  // ^DropPayloadStartBytes
1947 
1948  TsExtendAdaptionField(Packet, Offset - 4 + Info.DropPayloadStartBytes);
1949  }
1950  }
1951 
1952  bool DropThisPayload = DropAllPayload;
1953 
1954  if (!DropAllPayload && Info.DropPayloadEndBytes > 0) // Payload ends with 0xff NALU Fill
1955  {
1956  // Last packet of useful data
1957  // Do early termination of NALU fill data
1958  Packet[TS_SIZE-1] = 0x80;
1959  DropAllPayload = true;
1960  // Drop all packets AFTER this one
1961 
1962  // Since we already wrote the 0x80, we have to make sure that
1963  // as soon as we stop dropping packets, any beginning NALU fill of next
1964  // packet gets dumped. (see DropPayloadStartBytes above)
1965  }
1966 
1967  if (DropThisPayload && HasAdaption)
1968  {
1969  // Drop payload data, but keep adaption field data
1970  TsExtendAdaptionField(Packet, TS_SIZE-4);
1971  DropThisPayload = false;
1972  }
1973 
1974  if (DropThisPayload)
1975  {
1976  return true; // Drop packet
1977  }
1978  }
1979 
1980  // Fix Continuity Counter and reproduce incoming offsets:
1981  int NewContinuityOutput = TsHasPayload(Packet) ? (LastContinuityOutput + 1) & TS_CONT_CNT_MASK : LastContinuityOutput;
1982  NewContinuityOutput = (NewContinuityOutput + ContinuityOffset) & TS_CONT_CNT_MASK;
1983  TsSetContinuityCounter(Packet, NewContinuityOutput);
1984  LastContinuityOutput = NewContinuityOutput;
1985  ContinuityOffset = 0;
1986 
1987  return false; // Keep packet
1988 }
1989 
1990 // --- cNaluStreamProcessor ---------------------------------------------------------
1991 
1993 {
1994  pPatPmtParser = NULL;
1995  vpid = -1;
1996  data = NULL;
1997  length = 0;
1998  tempLength = 0;
1999  tempLengthAtEnd = false;
2000  TotalPackets = 0;
2001  DroppedPackets = 0;
2002 }
2003 
2005 {
2006  if (length > 0)
2007  esyslog("cNaluStreamProcessor::PutBuffer: New data before old data was processed!");
2008 
2009  data = Data;
2010  length = Length;
2011 }
2012 
2014 {
2015  if (length <= 0)
2016  {
2017  // Need more data - quick exit
2018  OutLength = 0;
2019  return NULL;
2020  }
2021  if (tempLength > 0) // Data in temp buffer?
2022  {
2023  if (tempLengthAtEnd) // Data is at end, copy to beginning
2024  {
2025  // Overlapping src and dst!
2026  for (int i=0; i<tempLength; i++)
2028  }
2029  // Normalize TempBuffer fill
2030  if (tempLength < TS_SIZE && length > 0)
2031  {
2032  int Size = min(TS_SIZE-tempLength, length);
2033  memcpy(tempBuffer+tempLength, data, Size);
2034  data += Size;
2035  length -= Size;
2036  tempLength += Size;
2037  }
2038  if (tempLength < TS_SIZE)
2039  {
2040  // All incoming data buffered, but need more data
2041  tempLengthAtEnd = false;
2042  OutLength = 0;
2043  return NULL;
2044  }
2045  // Now: TempLength==TS_SIZE
2046  if (tempBuffer[0] != TS_SYNC_BYTE)
2047  {
2048  // Need to sync on TS within temp buffer
2049  int Skipped = 1;
2050  while (Skipped < TS_SIZE && (tempBuffer[Skipped] != TS_SYNC_BYTE || (Skipped < length && data[Skipped] != TS_SYNC_BYTE)))
2051  Skipped++;
2052  esyslog("ERROR: skipped %d bytes to sync on start of TS packet", Skipped);
2053  // Pass through skipped bytes
2054  tempLengthAtEnd = true;
2055  tempLength = TS_SIZE - Skipped; // may be 0, thats ok
2056  OutLength = Skipped;
2057  return tempBuffer;
2058  }
2059  // Now: TempBuffer is a TS packet
2060  int Pid = TsPid(tempBuffer);
2061  if (pPatPmtParser)
2062  {
2063  if (Pid == 0)
2065  else if (pPatPmtParser->IsPmtPid(Pid))
2067  }
2068 
2069  TotalPackets++;
2070  bool Drop = false;
2071  if (Pid == vpid || (pPatPmtParser && Pid == pPatPmtParser->Vpid() && pPatPmtParser->Vtype() == 0x1B))
2073  if (!Drop)
2074  {
2075  // Keep this packet, then continue with new data
2076  tempLength = 0;
2077  OutLength = TS_SIZE;
2078  return tempBuffer;
2079  }
2080  // Drop TempBuffer
2081  DroppedPackets++;
2082  tempLength = 0;
2083  }
2084  // Now: TempLength==0, just process data/length
2085 
2086  // Pointer to processed data / length:
2087  uchar *Out = data;
2088  uchar *OutEnd = Out;
2089 
2090  while (length >= TS_SIZE)
2091  {
2092  if (data[0] != TS_SYNC_BYTE) {
2093  int Skipped = 1;
2094  while (Skipped < length && (data[Skipped] != TS_SYNC_BYTE || (length - Skipped > TS_SIZE && data[Skipped + TS_SIZE] != TS_SYNC_BYTE)))
2095  Skipped++;
2096  esyslog("ERROR: skipped %d bytes to sync on start of TS packet", Skipped);
2097 
2098  // Pass through skipped bytes
2099  if (OutEnd != data)
2100  memcpy(OutEnd, data, Skipped);
2101  OutEnd += Skipped;
2102  continue;
2103  }
2104  // Now: Data starts with complete TS packet
2105 
2106  int Pid = TsPid(data);
2107  if (pPatPmtParser)
2108  {
2109  if (Pid == 0)
2111  else if (pPatPmtParser->IsPmtPid(Pid))
2113  }
2114 
2115  TotalPackets++;
2116  bool Drop = false;
2117  if (Pid == vpid || (pPatPmtParser && Pid == pPatPmtParser->Vpid() && pPatPmtParser->Vtype() == 0x1B))
2119  if (!Drop)
2120  {
2121  if (OutEnd != data)
2122  memcpy(OutEnd, data, TS_SIZE);
2123  OutEnd += TS_SIZE;
2124  }
2125  else
2126  {
2127  DroppedPackets++;
2128  }
2129  data += TS_SIZE;
2130  length -= TS_SIZE;
2131  }
2132  // Now: Less than a packet remains.
2133  if (length > 0)
2134  {
2135  // copy remains into temp buffer
2136  memcpy(tempBuffer, data, length);
2137  tempLength = length;
2138  tempLengthAtEnd = false;
2139  length = 0;
2140  }
2141  OutLength = (OutEnd - Out);
2142  return OutLength > 0 ? Out : NULL;
2143 }
cPatPmtGenerator::numPmtPackets
int numPmtPackets
Definition: remux.h:308
MAX_PMT_PIDS
#define MAX_PMT_PIDS
Definition: remux.h:357
TS_SIZE
#define TS_SIZE
Definition: remux.h:34
cH264Parser::bit
int bit
Definition: remux.c:1349
cTsToPes::offset
int offset
Definition: remux.h:461
cNaluStreamProcessor::pPatPmtParser
cPatPmtParser * pPatPmtParser
Definition: remux.h:610
TS_SYNC
#define TS_SYNC(Data, Length)
Definition: remux.h:154
cH265Parser::nutPrefixSEI
@ nutPrefixSEI
Definition: remux.c:1602
cNaluDumper::NaluOffset
int NaluOffset
Definition: remux.h:573
TsGetDts
int64_t TsGetDts(const uchar *p, int l)
Definition: remux.c:173
cPatPmtParser::IsPmtPid
bool IsPmtPid(int Pid) const
Returns true if Pid the one of the PMT pids as defined by the current PAT.
Definition: remux.h:406
cChannel::Ppid
int Ppid(void) const
Definition: channels.h:155
phInvalid
@ phInvalid
Definition: remux.h:18
PesLongEnough
bool PesLongEnough(int Length)
Definition: remux.h:169
cPatPmtParser::pmtSize
int pmtSize
Definition: remux.h:362
TS_SYNC_BYTE
#define TS_SYNC_BYTE
Definition: remux.h:33
TsGetPayload
int TsGetPayload(const uchar **p)
Definition: remux.h:119
cNaluDumper::sPayloadInfo
Definition: remux.h:584
recording.h
cPatPmtParser::atypes
int atypes[MAXAPIDS+1]
Definition: remux.h:370
cFrameDetector::SetPid
void SetPid(int Pid, int Type)
Sets the Pid and stream Type to detect frames for.
Definition: remux.c:1671
cTsPayload::numPacketsPid
int numPacketsPid
Definition: remux.h:238
cPatPmtGenerator::GeneratePmt
void GeneratePmt(const cChannel *Channel)
Generates a PMT section for the given Channel, for later use with GetPmt().
Definition: remux.c:546
SI::CRC32::crc32
static u_int32_t crc32(const char *d, int len, u_int32_t CRCvalue)
Definition: util.c:277
SI::Loop::Iterator
Definition: si.h:333
cPatPmtGenerator::GetPmt
uchar * GetPmt(int &Index)
Returns a pointer to the Index'th TS packet of the PMT section.
Definition: remux.c:636
cTsPayload::Statistics
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
cH265Parser::nutSliceSegmentIDRWRADL
@ nutSliceSegmentIDRWRADL
Definition: remux.c:1592
cNaluDumper::sPayloadInfo::DropPayloadEndBytes
int DropPayloadEndBytes
Definition: remux.h:586
SI::SubtitlingDescriptor::Subtitling::getCompositionPageId
int getCompositionPageId() const
Definition: descriptor.c:610
cFrameDetector::MaxPtsValues
@ MaxPtsValues
Definition: remux.h:515
cDevice::EnsureSubtitleTrack
void EnsureSubtitleTrack(void)
Makes sure one of the preferred language subtitle tracks is selected.
Definition: device.c:1183
cH264Parser::separate_colour_plane_flag
bool separate_colour_plane_flag
Definition: remux.c:1352
SI::PAT::Association::getServiceId
int getServiceId() const
Definition: section.c:40
cTsPayload
Definition: remux.h:232
cChannel::SubtitlingType
uchar SubtitlingType(int i) const
Definition: channels.h:168
cPatPmtParser::vpid
int vpid
Definition: remux.h:366
cFrameDetector::framesInPayloadUnit
int framesInPayloadUnit
Definition: remux.h:526
SI::PMT
Definition: section.h:65
MAXDPIDS
#define MAXDPIDS
Definition: channels.h:32
cTsPayload::AtPayloadStart
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:258
cMpeg2Parser
Definition: remux.c:1263
SI::PMT::Stream::getStreamType
int getStreamType() const
Definition: section.c:79
cH265Parser::nutSliceSegmentTSAR
@ nutSliceSegmentTSAR
Definition: remux.c:1582
WRN_TS_PACKETS_FOR_VIDEO_FRAME_DETECTION
#define WRN_TS_PACKETS_FOR_VIDEO_FRAME_DETECTION
Definition: remux.c:27
SI::SubtitlingDescriptor::Subtitling::languageCode
char languageCode[4]
Definition: descriptor.h:331
cPatPmtGenerator::patVersion
int patVersion
Definition: remux.h:311
cFrameParser::~cFrameParser
virtual ~cFrameParser()
Definition: remux.c:1215
cMpeg2Parser::Parse
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:1280
cNaluStreamProcessor::tempLength
int tempLength
Definition: remux.h:608
cTsPayload::Setup
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
cChannel::Dpid
int Dpid(int i) const
Definition: channels.h:161
cChannel::Spid
int Spid(int i) const
Definition: channels.h:162
TsHidePayload
void TsHidePayload(uchar *p)
Definition: remux.c:121
cChannel::Alang
const char * Alang(int i) const
Definition: channels.h:163
cFrameDetector::scanning
bool scanning
Definition: remux.h:529
cPatPmtGenerator::pmtCounter
int pmtCounter
Definition: remux.h:310
TS_CONT_CNT_MASK
#define TS_CONT_CNT_MASK
Definition: remux.h:42
cTsToPes::length
int length
Definition: remux.h:460
cPatPmtParser::completed
bool completed
Definition: remux.h:381
cH265Parser::cH265Parser
cH265Parser(void)
Definition: remux.c:1614
cTsPayload::index
int index
Definition: remux.h:237
cNaluStreamProcessor::data
uchar * data
Definition: remux.h:605
MAXSPIDS
#define MAXSPIDS
Definition: channels.h:33
section.h
cNaluDumper::NALU_TERM
@ NALU_TERM
Definition: remux.h:578
SI::SubtitlingDescriptor::Subtitling::getAncillaryPageId
int getAncillaryPageId() const
Definition: descriptor.c:614
EMPTY_SCANNER
#define EMPTY_SCANNER
Definition: remux.c:30
MAXLANGCODE1
#define MAXLANGCODE1
Definition: channels.h:36
cNaluDumper::LastContinuityInput
int LastContinuityInput
Definition: remux.h:564
cTsToPes::lastData
uchar * lastData
Definition: remux.h:462
SI::CRCSection::CheckCRCAndParse
bool CheckCRCAndParse()
Definition: si.c:75
cDevice::EnsureAudioTrack
void EnsureAudioTrack(bool Force=false)
Makes sure an audio track is selected that is actually available.
Definition: device.c:1150
cH265Parser::nutSliceSegmentRASLR
@ nutSliceSegmentRASLR
Definition: remux.c:1588
cH265Parser::nutSliceSegmentTSAN
@ nutSliceSegmentTSAN
Definition: remux.c:1581
PesSetDts
void PesSetDts(uchar *p, int64_t Dts)
Definition: remux.c:225
TS_ADAPT_FIELD_EXISTS
#define TS_ADAPT_FIELD_EXISTS
Definition: remux.h:40
cFrameDetector::synced
bool synced
Definition: remux.h:518
TsSetPts
void TsSetPts(uchar *p, int l, int64_t Pts)
Definition: remux.c:186
cNaluStreamProcessor::vpid
int vpid
Definition: remux.h:604
cH264Parser::gotAccessUnitDelimiter
bool gotAccessUnitDelimiter
Definition: remux.c:1358
DebugFrames
static bool DebugFrames
Definition: remux.c:21
cEitGenerator::version
int version
Definition: remux.h:442
cFrameDetector::isVideo
bool isVideo
Definition: remux.h:524
cH264Parser::nutCodedSliceNonIdr
@ nutCodedSliceNonIdr
Definition: remux.c:1343
cFrameDetector::Analyze
int Analyze(const uchar *Data, int Length)
Analyzes the TS packets pointed to by Data.
Definition: remux.c:1690
cPatPmtGenerator::esInfoLength
uchar * esInfoLength
Definition: remux.h:314
cPatPmtParser::alangs
char alangs[MAXAPIDS][MAXLANGCODE2]
Definition: remux.h:371
cSetup::UseDolbyDigital
int UseDolbyDigital
Definition: config.h:319
MIN_TS_PACKETS_FOR_FRAME_DETECTOR
#define MIN_TS_PACKETS_FOR_FRAME_DETECTOR
Definition: remux.h:509
TsError
bool TsError(const uchar *p)
Definition: remux.h:82
SI::NumberedSection::getCurrentNextIndicator
bool getCurrentNextIndicator() const
Definition: si.c:90
SI::SubtitlingDescriptor
Definition: descriptor.h:327
cH265Parser::nutSliceSegmentTrailingR
@ nutSliceSegmentTrailingR
Definition: remux.c:1580
TsHasAdaptationField
bool TsHasAdaptationField(const uchar *p)
Definition: remux.h:72
SI::u_char
unsigned char u_char
Definition: headers.h:38
cH264Parser::GetByte
uchar GetByte(bool Raw=false)
Gets the next data byte.
Definition: remux.c:1392
cH264Parser::cH264Parser
cH264Parser(void)
Sets up a new H.264 parser.
Definition: remux.c:1379
cChannel::AncillaryPageId
uint16_t AncillaryPageId(int i) const
Definition: channels.h:170
KILOBYTE
#define KILOBYTE(n)
Definition: tools.h:44
cH265Parser::nutNonVCLRes3
@ nutNonVCLRes3
Definition: remux.c:1605
SI::NumberedSection::getLastSectionNumber
int getLastSectionNumber() const
Definition: si.c:102
SI::PMT::streamLoop
StructureLoop< Stream > streamLoop
Definition: section.h:81
cFrameDetector::cFrameDetector
cFrameDetector(int Pid=0, int Type=0)
Sets up a frame detector for the given Pid and stream Type.
Definition: remux.c:1651
cChannel::Dtype
int Dtype(int i) const
Definition: channels.h:167
PesGetDts
int64_t PesGetDts(const uchar *p)
Definition: remux.h:208
Setup
cSetup Setup
Definition: config.c:372
cDevice::PrimaryDevice
static cDevice * PrimaryDevice(void)
Returns the primary device.
Definition: device.h:146
device.h
cH265Parser::nutSliceSegmentCRANUT
@ nutSliceSegmentCRANUT
Definition: remux.c:1594
cPatPmtParser::dlangs
char dlangs[MAXDPIDS][MAXLANGCODE2]
Definition: remux.h:374
cEitGenerator::counter
int counter
Definition: remux.h:441
cPatPmtParser::GetVersions
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:974
TsExtendAdaptionField
void TsExtendAdaptionField(unsigned char *Packet, int ToLength)
Definition: remux.c:359
cH264Parser::scanner
uint32_t scanner
Definition: remux.c:1357
cPatPmtParser::ParsePat
void ParsePat(const uchar *Data, int Length)
Parses the PAT data from the single TS packet in Data.
Definition: remux.c:663
cPatPmtParser::apids
int apids[MAXAPIDS+1]
Definition: remux.h:369
cPatPmtParser::pmt
uchar pmt[MAX_SECTION_SIZE]
Definition: remux.h:361
SI::NumberedSection::getSectionNumber
int getSectionNumber() const
Definition: si.c:98
cMpeg2Parser::scanner
uint32_t scanner
Definition: remux.c:1265
SI::PAT::getTransportStreamId
int getTransportStreamId() const
Definition: section.c:36
MAX_SECTION_SIZE
#define MAX_SECTION_SIZE
Definition: remux.h:301
shutdown.h
ttDolby
@ ttDolby
Definition: device.h:67
cNaluStreamProcessor::TotalPackets
long long int TotalPackets
Definition: remux.h:613
cH265Parser::nutAccessUnitDelimiter
@ nutAccessUnitDelimiter
Definition: remux.c:1598
cH265Parser::nutSliceSegmentIDRNLP
@ nutSliceSegmentIDRNLP
Definition: remux.c:1593
cPatPmtParser::ParsePatPmt
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:955
cH265Parser::nutEndOfSequence
@ nutEndOfSequence
Definition: remux.c:1599
cPatPmtParser::ppid
int ppid
Definition: remux.h:367
TS_ADAPT_PCR
#define TS_ADAPT_PCR
Definition: remux.h:46
cNaluDumper::DropAllPayload
bool DropAllPayload
Definition: remux.h:568
cMpeg2Parser::cMpeg2Parser
cMpeg2Parser(void)
Definition: remux.c:1273
MAX_TS_PACKETS_FOR_VIDEO_FRAME_DETECTION
#define MAX_TS_PACKETS_FOR_VIDEO_FRAME_DETECTION
Definition: remux.c:26
TsPayloadOffset
int TsPayloadOffset(const uchar *p)
Definition: remux.h:113
SI::PMT::getPCRPid
int getPCRPid() const
Definition: section.c:71
cAudioParser::Parse
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:1249
SI::SubtitlingDescriptor::Subtitling
Definition: descriptor.h:329
cPatPmtParser::Vpid
int Vpid(void) const
Returns the video pid as defined by the current PMT, or 0 if no video pid has been detected,...
Definition: remux.h:409
TsPid
int TsPid(const uchar *p)
Definition: remux.h:87
SI::ParentalRatingDescriptorTag
@ ParentalRatingDescriptorTag
Definition: si.h:109
SI::PAT::Association::getPid
int getPid() const
Definition: section.c:44
cNaluDumper::History
unsigned int History
Definition: remux.h:562
cTsPayload::SetEof
uchar SetEof(void)
Definition: remux.c:259
cFrameDetector::independentFrame
bool independentFrame
Definition: remux.h:520
cH264Parser::nutCodedSliceIdr
@ nutCodedSliceIdr
Definition: remux.c:1344
SI::EnhancedAC3DescriptorTag
@ EnhancedAC3DescriptorTag
Definition: si.h:147
cNaluStreamProcessor::tempLengthAtEnd
bool tempLengthAtEnd
Definition: remux.h:609
cPatPmtGenerator::IncVersion
void IncVersion(int &Version)
Definition: remux.c:414
cNaluDumper::ContinuityOffset
int ContinuityOffset
Definition: remux.h:566
cChannel::Dpids
const int * Dpids(void) const
Definition: channels.h:158
cTsPayload::Used
int Used(void)
Returns the number of raw bytes that have already been used (e.g.
Definition: remux.h:264
cEitGenerator::eit
uchar eit[TS_SIZE]
Definition: remux.h:440
cH264Parser::Parse
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:1448
cFrameParser::SetDebug
void SetDebug(bool Debug)
Definition: remux.c:1223
cTsPayload::GetByte
uchar GetByte(void)
Gets the next byte of the TS payload, skipping any intermediate TS header data.
Definition: remux.c:280
cNaluDumper::sPayloadInfo::DropAllPayloadBytes
bool DropAllPayloadBytes
Definition: remux.h:587
cNaluDumper::reset
void reset()
Definition: remux.c:1812
cH265Parser::nutSliceSegmentBLAWRADL
@ nutSliceSegmentBLAWRADL
Definition: remux.c:1590
dbgpatpmt
#define dbgpatpmt(a...)
Definition: remux.c:23
cTsPayload::pid
int pid
Definition: remux.h:236
cFrameParser::NewFrame
bool NewFrame(void)
Definition: remux.c:1224
cH265Parser::nutUnspecified0
@ nutUnspecified0
Definition: remux.c:1606
cFrameDetector::ptsValues
uint32_t ptsValues[MaxPtsValues]
Definition: remux.h:521
cH265Parser::nutSliceSegmentRADLN
@ nutSliceSegmentRADLN
Definition: remux.c:1585
cNaluDumper::PesOffset
int PesOffset
Definition: remux.h:571
SI::SubtitlingDescriptor::Subtitling::getSubtitlingType
int getSubtitlingType() const
Definition: descriptor.c:606
SI::AC3DescriptorTag
@ AC3DescriptorTag
Definition: si.h:130
phNeedMoreData
@ phNeedMoreData
Definition: remux.h:17
cNaluDumper::sPayloadInfo::DropPayloadStartBytes
int DropPayloadStartBytes
Definition: remux.h:585
PesHasLength
bool PesHasLength(const uchar *p)
Definition: remux.h:174
SI::SubtitlingDescriptor::subtitlingLoop
StructureLoop< Subtitling > subtitlingLoop
Definition: descriptor.h:341
cH264Parser::ParseSequenceParameterSet
void ParseSequenceParameterSet(void)
Definition: remux.c:1498
P_PMT_PID
#define P_PMT_PID
Definition: remux.c:499
cFrameDetector::numPtsValues
int numPtsValues
Definition: remux.h:522
cTsPayload::Find
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
cPatPmtParser::dpids
int dpids[MAXDPIDS+1]
Definition: remux.h:372
PesDump
void PesDump(const char *Name, const u_char *Data, int Length)
Definition: remux.c:1200
cFrameDetector::framesPerSecond
double framesPerSecond
Definition: remux.h:525
cH264Parser::zeroBytes
int zeroBytes
Definition: remux.c:1350
phMPEG2
@ phMPEG2
Definition: remux.h:20
cTsToPes::lastLength
int lastLength
Definition: remux.h:463
cPatPmtParser::updatePrimaryDevice
bool updatePrimaryDevice
Definition: remux.h:380
cTsPayload::Eof
bool Eof(void) const
Returns true if all available bytes of the TS payload have been processed.
Definition: remux.h:268
cChannel::Dlang
const char * Dlang(int i) const
Definition: channels.h:164
uchar
unsigned char uchar
Definition: tools.h:31
cPatPmtParser::vtype
int vtype
Definition: remux.h:368
cFrameParser::cFrameParser
cFrameParser(void)
Definition: remux.c:1229
cMpeg2Parser::seenIndependentFrame
bool seenIndependentFrame
Definition: remux.c:1266
cAudioParser::cAudioParser
cAudioParser(void)
Definition: remux.c:1245
SI::Descriptor::getDescriptorTag
DescriptorTag getDescriptorTag() const
Definition: si.c:110
PesLength
int PesLength(const uchar *p)
Definition: remux.h:179
TsHasPayload
bool TsHasPayload(const uchar *p)
Definition: remux.h:62
cTsPayload::length
int length
Definition: remux.h:235
cRemux::SetBrokenLink
static void SetBrokenLink(uchar *Data, int Length)
Definition: remux.c:102
cH264Parser::frame_mbs_only_flag
bool frame_mbs_only_flag
Definition: remux.c:1354
TsIsScrambled
bool TsIsScrambled(const uchar *p)
Definition: remux.h:98
cChannel::Tpid
int Tpid(void) const
Definition: channels.h:171
cH265Parser::nutSliceSegmentBLAWLP
@ nutSliceSegmentBLAWLP
Definition: remux.c:1589
SI::ISO639LanguageDescriptorTag
@ ISO639LanguageDescriptorTag
Definition: si.h:71
TS_PAYLOAD_START
#define TS_PAYLOAD_START
Definition: remux.h:36
cPatPmtGenerator::GetPat
uchar * GetPat(void)
Returns a pointer to the PAT section, which consists of exactly one TS packet.
Definition: remux.c:630
cTsToPes::data
uchar * data
Definition: remux.h:458
cFrameParser::newFrame
bool newFrame
Definition: remux.c:1210
cPatPmtParser::Vtype
int Vtype(void) const
Returns the video stream type as defined by the current PMT, or 0 if no video stream type has been de...
Definition: remux.h:415
SI::PMT::Stream::streamDescriptors
DescriptorLoop streamDescriptors
Definition: section.h:73
cNaluDumper::ProcessPayload
void ProcessPayload(unsigned char *Payload, int size, bool PayloadStart, sPayloadInfo &Info)
Definition: remux.c:1824
cNaluDumper::NALU_FILL
@ NALU_FILL
Definition: remux.h:577
cH264Parser::ParseSliceHeader
void ParseSliceHeader(void)
Definition: remux.c:1550
phMPEG1
@ phMPEG1
Definition: remux.h:19
cMpeg2Parser::lastIFrameTemporalReference
int lastIFrameTemporalReference
Definition: remux.c:1267
cDevice::SetAvailableTrack
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:1050
VIDEO_STREAM_S
#define VIDEO_STREAM_S
Definition: remux.c:98
cH264Parser::eNalUnitType
eNalUnitType
Definition: remux.c:1342
cPatPmtGenerator::pmtVersion
int pmtVersion
Definition: remux.h:312
cNaluDumper::ProcessTSPacket
bool ProcessTSPacket(unsigned char *Packet)
Definition: remux.c:1911
ttAudio
@ ttAudio
Definition: device.h:64
cTsPayload::GetLastIndex
int GetLastIndex(void)
Returns the index into the TS data of the payload byte that has most recently been read.
Definition: remux.c:323
SETPIDS
#define SETPIDS(l)
cH265Parser::nutVideoParameterSet
@ nutVideoParameterSet
Definition: remux.c:1595
DEFAULTFRAMESPERSECOND
#define DEFAULTFRAMESPERSECOND
Definition: recording.h:351
cPatPmtGenerator::IncCounter
void IncCounter(int &Counter, uchar *TsPacket)
Definition: remux.c:407
cNaluDumper::PesId
int PesId
Definition: remux.h:570
cChannel::CompositionPageId
uint16_t CompositionPageId(int i) const
Definition: channels.h:169
cH264Parser::ParseAccessUnitDelimiter
void ParseAccessUnitDelimiter(void)
Definition: remux.c:1491
PesHasDts
bool PesHasDts(const uchar *p)
Definition: remux.h:194
cH264Parser::GetGolombSe
int32_t GetGolombSe(void)
Definition: remux.c:1436
cNaluDumper::LastContinuityOutput
int LastContinuityOutput
Definition: remux.h:565
cTsPayload::numPacketsOther
int numPacketsOther
Definition: remux.h:239
cPatPmtParser::dtypes
int dtypes[MAXDPIDS+1]
Definition: remux.h:373
cH265Parser::Parse
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:1619
BlockDump
void BlockDump(const char *Name, const u_char *Data, int Length)
Definition: remux.c:1174
cH265Parser::nutSliceSegmentBLANLP
@ nutSliceSegmentBLANLP
Definition: remux.c:1591
cH264Parser::byte
uchar byte
Definition: remux.c:1348
cH265Parser::nutSuffixSEI
@ nutSuffixSEI
Definition: remux.c:1603
cFrameDetector::newFrame
bool newFrame
Definition: remux.h:519
cH264Parser
Definition: remux.c:1340
TsPayloadStart
bool TsPayloadStart(const uchar *p)
Definition: remux.h:77
cFrameDetector::pid
int pid
Definition: remux.h:516
cPatPmtGenerator::SetVersions
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:615
DebugPatPmt
static bool DebugPatPmt
Definition: remux.c:20
cChannel::Vpid
int Vpid(void) const
Definition: channels.h:154
cPatPmtGenerator::MakeLanguageDescriptor
int MakeLanguageDescriptor(uchar *Target, const char *Language)
Definition: remux.c:468
cNaluStreamProcessor::cNaluStreamProcessor
cNaluStreamProcessor()
Definition: remux.c:1992
cPatPmtParser::ancillaryPageIds
uint16_t ancillaryPageIds[MAXSPIDS]
Definition: remux.h:379
cPatPmtParser::pmtVersion
int pmtVersion
Definition: remux.h:364
dsyslog
#define dsyslog(a...)
Definition: tools.h:37
cEitGenerator::YMDtoMJD
uint16_t YMDtoMJD(int Y, int M, int D)
Definition: remux.c:991
SI::Descriptor
Definition: si.h:312
cFrameDetector::parser
cFrameParser * parser
Definition: remux.h:530
cChannel::Vtype
int Vtype(void) const
Definition: channels.h:156
PATPID
#define PATPID
Definition: remux.h:52
cEitGenerator::Generate
uchar * Generate(int Sid)
Definition: remux.c:1008
cEitGenerator::AddParentalRatingDescriptor
uchar * AddParentalRatingDescriptor(uchar *p, uchar ParentalRating=0)
Definition: remux.c:997
cChannel
Definition: channels.h:89
cPatPmtParser::Reset
void Reset(void)
Resets the parser.
Definition: remux.c:653
cNaluDumper::cNaluDumper
cNaluDumper()
Definition: remux.c:1806
I18nNormalizeLanguageCode
const char * I18nNormalizeLanguageCode(const char *Code)
Returns a 3 letter language code that may not be zero terminated.
Definition: i18n.c:238
cPatPmtParser::SectionLength
int SectionLength(const uchar *Data, int Length)
Definition: remux.h:383
cPatPmtGenerator::pat
uchar pat[TS_SIZE]
Definition: remux.h:306
cChannel::Apid
int Apid(int i) const
Definition: channels.h:160
cPatPmtParser::spids
int spids[MAXSPIDS+1]
Definition: remux.h:375
cNaluStreamProcessor::GetBuffer
uchar * GetBuffer(int &OutLength)
Definition: remux.c:2013
P_TSID
#define P_TSID
Definition: remux.c:498
cFrameDetector::type
int type
Definition: remux.h:517
cTsPayload::AtTsStart
bool AtTsStart(void)
Returns true if this payload handler is currently pointing to first byte of a TS packet.
Definition: remux.h:255
TsContinuityCounter
uchar TsContinuityCounter(const uchar *p)
Definition: remux.h:103
cTsToPes::PutTs
void PutTs(const uchar *Data, int Length)
Puts the payload data of the single TS packet at Data into the converter.
Definition: remux.c:1082
cNaluStreamProcessor::length
int length
Definition: remux.h:606
cH265Parser::nutUnspecified7
@ nutUnspecified7
Definition: remux.c:1607
CmpUint32
static int CmpUint32(const void *p1, const void *p2)
Definition: remux.c:1664
SI::SubtitlingDescriptorTag
@ SubtitlingDescriptorTag
Definition: si.h:113
cH264Parser::gotSequenceParameterSet
bool gotSequenceParameterSet
Definition: remux.c:1359
cTsPayload::Reset
void Reset(void)
Definition: remux.c:265
cAudioParser
Definition: remux.c:1239
cFrameParser::Parse
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.
ttSubtitle
@ ttSubtitle
Definition: device.h:70
cChannel::Atype
int Atype(int i) const
Definition: channels.h:166
SI::PAT::associationLoop
StructureLoop< Association > associationLoop
Definition: section.h:59
cH265Parser::nutEndOfBitstream
@ nutEndOfBitstream
Definition: remux.c:1600
cFrameParser::debug
bool debug
Definition: remux.c:1209
cFrameDetector::numIFrames
int numIFrames
Definition: remux.h:523
cFrameParser::IFrameTemporalReferenceOffset
int IFrameTemporalReferenceOffset(void)
Definition: remux.c:1226
PesSetPts
void PesSetPts(uchar *p, int64_t Pts)
Definition: remux.c:216
cPatPmtGenerator::MakeCRC
int MakeCRC(uchar *Target, const uchar *Data, int Length)
Definition: remux.c:487
cPatPmtGenerator::SetChannel
void SetChannel(const cChannel *Channel)
Sets the Channel for which the PAT/PMT shall be generated.
Definition: remux.c:621
SI::PMT::getServiceId
int getServiceId() const
Definition: section.c:67
cChannel::Slang
const char * Slang(int i) const
Definition: channels.h:165
cPatPmtGenerator::MakeSubtitlingDescriptor
int MakeSubtitlingDescriptor(uchar *Target, const char *Language, uchar SubtitlingType, uint16_t CompositionPageId, uint16_t AncillaryPageId)
Definition: remux.c:451
cH265Parser::nutSliceSegmentSTSAN
@ nutSliceSegmentSTSAN
Definition: remux.c:1583
cPatPmtGenerator::GeneratePmtPid
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:502
MAXPID
#define MAXPID
Definition: remux.c:500
cTsToPes::size
int size
Definition: remux.h:459
PTSTICKS
#define PTSTICKS
Definition: remux.h:57
SI::ISO639LanguageDescriptor::languageLoop
StructureLoop< Language > languageLoop
Definition: descriptor.h:499
cPatPmtParser::subtitlingTypes
uchar subtitlingTypes[MAXSPIDS]
Definition: remux.h:377
cTsToPes::repeatLast
bool repeatLast
Definition: remux.h:464
cTsPayload::SetByte
void SetByte(uchar Byte, int Index)
Sets the TS data byte at the given Index to the value Byte.
Definition: remux.c:328
cPatPmtParser::compositionPageIds
uint16_t compositionPageIds[MAXSPIDS]
Definition: remux.h:378
cH265Parser::nutPictureParameterSet
@ nutPictureParameterSet
Definition: remux.c:1597
cFrameDetector::framesPerPayloadUnit
int framesPerPayloadUnit
Definition: remux.h:527
cNaluDumper::NaluFillState
eNaluFillState NaluFillState
Definition: remux.h:582
cPatPmtParser::pmtPids
int pmtPids[MAX_PMT_PIDS+1]
Definition: remux.h:365
strn0cpy
char * strn0cpy(char *dest, const char *src, size_t n)
Definition: tools.c:131
cPatPmtGenerator::GeneratePat
void GeneratePat(void)
Generates a PAT section for later use with GetPat().
Definition: remux.c:517
cTsToPes::~cTsToPes
~cTsToPes()
Definition: remux.c:1077
cTsToPes::cTsToPes
cTsToPes(void)
Definition: remux.c:1070
cTsPayload::cTsPayload
cTsPayload(void)
Definition: remux.c:246
SI::PMT::Stream
Definition: section.h:69
cPatPmtParser::ParsePmt
void ParsePmt(const uchar *Data, int Length)
Parses the PMT data from the single TS packet in Data.
Definition: remux.c:695
SI::PAT::Association
Definition: section.h:47
cPatPmtGenerator::IncEsInfoLength
void IncEsInfoLength(int Length)
Definition: remux.c:420
SI::DescriptorLoop::getNext
Descriptor * getNext(Iterator &it)
Definition: si.c:122
TsSetPcr
void TsSetPcr(uchar *p, int64_t Pcr)
Definition: remux.c:131
max
T max(T a, T b)
Definition: tools.h:60
TsSetContinuityCounter
void TsSetContinuityCounter(uchar *p, uchar Counter)
Definition: remux.h:108
PtsDiff
int64_t PtsDiff(int64_t Pts1, int64_t Pts2)
Returns the difference between two PTS values.
Definition: remux.c:234
cH264Parser::GetBits
uint32_t GetBits(int Bits)
Definition: remux.c:1420
cPatPmtParser::cPatPmtParser
cPatPmtParser(bool UpdatePrimaryDevice=false)
Definition: remux.c:647
cFrameParser::iFrameTemporalReferenceOffset
int iFrameTemporalReferenceOffset
Definition: remux.c:1212
cH265Parser::nutSliceSegmentTrailingN
@ nutSliceSegmentTrailingN
Definition: remux.c:1579
AnalyzePesHeader
ePesHeader AnalyzePesHeader(const uchar *Data, int Count, int &PesPayloadOffset, bool *ContinuationHeader)
Definition: remux.c:32
TsDump
void TsDump(const char *Name, const u_char *Data, int Length)
Definition: remux.c:1185
cPatPmtGenerator::cPatPmtGenerator
cPatPmtGenerator(const cChannel *Channel=NULL)
Definition: remux.c:397
SI::ISO639LanguageDescriptor::Language
Definition: descriptor.h:489
cFrameParser::independentFrame
bool independentFrame
Definition: remux.c:1211
MAXAPIDS
#define MAXAPIDS
Definition: channels.h:31
cChannel::Spids
const int * Spids(void) const
Definition: channels.h:159
cH265Parser::nutFillerData
@ nutFillerData
Definition: remux.c:1601
remux.h
cTsPayload::SkipBytes
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
si.h
cNaluStreamProcessor::DroppedPackets
long long int DroppedPackets
Definition: remux.h:614
MAX33BIT
#define MAX33BIT
Definition: remux.h:59
cPatPmtGenerator::MakeAC3Descriptor
int MakeAC3Descriptor(uchar *Target, uchar Type)
Definition: remux.c:441
cTsToPes::Reset
void Reset(void)
Resets the converter.
Definition: remux.c:1164
TS_PAYLOAD_EXISTS
#define TS_PAYLOAD_EXISTS
Definition: remux.h:41
min
T min(T a, T b)
Definition: tools.h:59
cPatPmtParser::patVersion
int patVersion
Definition: remux.h:363
cNaluStreamProcessor::tempBuffer
uchar tempBuffer[TS_SIZE]
Definition: remux.h:607
cPatPmtGenerator::patCounter
int patCounter
Definition: remux.h:309
ePesHeader
ePesHeader
Definition: remux.h:16
cPatPmtGenerator::pmt
uchar pmt[MAX_PMT_TS][TS_SIZE]
Definition: remux.h:307
cPatPmtGenerator::MakeStream
int MakeStream(uchar *Target, uchar Type, int Pid)
Definition: remux.c:429
tools.h
cTsToPes::SetRepeatLast
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:1159
cDevice::ClrAvailableTracks
void ClrAvailableTracks(bool DescriptionsOnly=false, bool IdsOnly=false)
Clears the list of currently available tracks.
Definition: device.c:1027
MAXPESLENGTH
#define MAXPESLENGTH
Definition: remux.c:1109
cH265Parser::nutNonVCLRes0
@ nutNonVCLRes0
Definition: remux.c:1604
cH265Parser::nutSliceSegmentSTSAR
@ nutSliceSegmentSTSAR
Definition: remux.c:1584
cPatPmtParser::slangs
char slangs[MAXSPIDS][MAXLANGCODE2]
Definition: remux.h:376
PCRFACTOR
#define PCRFACTOR
Definition: remux.h:58
PesGetPts
int64_t PesGetPts(const uchar *p)
Definition: remux.h:199
cH265Parser::nutSliceSegmentRADLR
@ nutSliceSegmentRADLR
Definition: remux.c:1586
cH264Parser::GetGolombUe
uint32_t GetGolombUe(void)
Definition: remux.c:1428
cTsPayload::data
uchar * data
Definition: remux.h:234
PesPayloadOffset
int PesPayloadOffset(const uchar *p)
Definition: remux.h:184
cH264Parser::nutAccessUnitDelimiter
@ nutAccessUnitDelimiter
Definition: remux.c:1346
cH264Parser::log2_max_frame_num
int log2_max_frame_num
Definition: remux.c:1353
cH264Parser::tsPayload
cTsPayload tsPayload
Definition: remux.c:1356
TsGetPts
int64_t TsGetPts(const uchar *p, int l)
Definition: remux.c:160
SI::PAT
Definition: section.h:33
cTsToPes::GetPes
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:1111
esyslog
#define esyslog(a...)
Definition: tools.h:35
cNaluDumper::NALU_END
@ NALU_END
Definition: remux.h:579
cH265Parser
Definition: remux.c:1576
cH264Parser::nutSequenceParameterSet
@ nutSequenceParameterSet
Definition: remux.c:1345
SI::NumberedSection::getVersionNumber
int getVersionNumber() const
Definition: si.c:94
SI::PMT::Stream::getPid
int getPid() const
Definition: section.c:75
cH265Parser::nutSequenceParameterSet
@ nutSequenceParameterSet
Definition: remux.c:1596
TsSetDts
void TsSetDts(uchar *p, int l, int64_t Dts)
Definition: remux.c:200
SETPID
#define SETPID(p)
cTsPayload::SkipPesHeader
bool SkipPesHeader(void)
Skips all bytes belonging to the PES header of the payload.
Definition: remux.c:318
cFrameParser::IndependentFrame
bool IndependentFrame(void)
Definition: remux.c:1225
descriptor.h
PesHasPts
bool PesHasPts(const uchar *p)
Definition: remux.h:189
TsSync
int TsSync(const uchar *Data, int Length, const char *File, const char *Function, int Line)
Definition: remux.c:147
SI::PAT::Association::isNITPid
bool isNITPid() const
Definition: section.h:51
dbgframes
#define dbgframes(a...)
Definition: remux.c:24
SI::ISO639LanguageDescriptor::languageCode
char languageCode[4]
Definition: descriptor.h:488
EITPID
#define EITPID
Definition: remux.h:54
cNaluDumper::NALU_NONE
@ NALU_NONE
Definition: remux.h:576
cEitGenerator::cEitGenerator
cEitGenerator(int Sid=0)
Definition: remux.c:983
cNaluStreamProcessor::PutBuffer
void PutBuffer(uchar *Data, int Length)
Definition: remux.c:2004
cFrameParser
Definition: remux.c:1207
cChannel::Apids
const int * Apids(void) const
Definition: channels.h:157
cPatPmtGenerator::pmtPid
int pmtPid
Definition: remux.h:313
cNaluStreamProcessor::NaluDumper
cNaluDumper NaluDumper
Definition: remux.h:611
cH264Parser::GetBit
uchar GetBit(void)
Definition: remux.c:1411
SI::ISO639LanguageDescriptor::Language::languageCode
char languageCode[4]
Definition: descriptor.h:492
WRN_TS_PACKETS_FOR_FRAME_DETECTOR
#define WRN_TS_PACKETS_FOR_FRAME_DETECTOR
Definition: remux.c:28
SI::ISO639LanguageDescriptor
Definition: descriptor.h:486
cH265Parser::nutSliceSegmentRASLN
@ nutSliceSegmentRASLN
Definition: remux.c:1587