vdr  2.0.5
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 2.75 2013/03/03 10:37:58 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 EMPTY_SCANNER (0xFFFFFFFF)
27 
28 ePesHeader AnalyzePesHeader(const uchar *Data, int Count, int &PesPayloadOffset, bool *ContinuationHeader)
29 {
30  if (Count < 7)
31  return phNeedMoreData; // too short
32 
33  if ((Data[6] & 0xC0) == 0x80) { // MPEG 2
34  if (Count < 9)
35  return phNeedMoreData; // too short
36 
37  PesPayloadOffset = 6 + 3 + Data[8];
38  if (Count < PesPayloadOffset)
39  return phNeedMoreData; // too short
40 
41  if (ContinuationHeader)
42  *ContinuationHeader = ((Data[6] == 0x80) && !Data[7] && !Data[8]);
43 
44  return phMPEG2; // MPEG 2
45  }
46 
47  // check for MPEG 1 ...
48  PesPayloadOffset = 6;
49 
50  // skip up to 16 stuffing bytes
51  for (int i = 0; i < 16; i++) {
52  if (Data[PesPayloadOffset] != 0xFF)
53  break;
54 
55  if (Count <= ++PesPayloadOffset)
56  return phNeedMoreData; // too short
57  }
58 
59  // skip STD_buffer_scale/size
60  if ((Data[PesPayloadOffset] & 0xC0) == 0x40) {
61  PesPayloadOffset += 2;
62 
63  if (Count <= PesPayloadOffset)
64  return phNeedMoreData; // too short
65  }
66 
67  if (ContinuationHeader)
68  *ContinuationHeader = false;
69 
70  if ((Data[PesPayloadOffset] & 0xF0) == 0x20) {
71  // skip PTS only
72  PesPayloadOffset += 5;
73  }
74  else if ((Data[PesPayloadOffset] & 0xF0) == 0x30) {
75  // skip PTS and DTS
76  PesPayloadOffset += 10;
77  }
78  else if (Data[PesPayloadOffset] == 0x0F) {
79  // continuation header
80  PesPayloadOffset++;
81 
82  if (ContinuationHeader)
83  *ContinuationHeader = true;
84  }
85  else
86  return phInvalid; // unknown
87 
88  if (Count < PesPayloadOffset)
89  return phNeedMoreData; // too short
90 
91  return phMPEG1; // MPEG 1
92 }
93 
94 #define VIDEO_STREAM_S 0xE0
95 
96 // --- cRemux ----------------------------------------------------------------
97 
98 void cRemux::SetBrokenLink(uchar *Data, int Length)
99 {
100  int PesPayloadOffset = 0;
101  if (AnalyzePesHeader(Data, Length, PesPayloadOffset) >= phMPEG1 && (Data[3] & 0xF0) == VIDEO_STREAM_S) {
102  for (int i = PesPayloadOffset; i < Length - 7; i++) {
103  if (Data[i] == 0 && Data[i + 1] == 0 && Data[i + 2] == 1 && Data[i + 3] == 0xB8) {
104  if (!(Data[i + 7] & 0x40)) // set flag only if GOP is not closed
105  Data[i + 7] |= 0x20;
106  return;
107  }
108  }
109  dsyslog("SetBrokenLink: no GOP header found in video packet");
110  }
111  else
112  dsyslog("SetBrokenLink: no video packet in frame");
113 }
114 
115 // --- Some TS handling tools ------------------------------------------------
116 
118 {
119  p[1] &= ~TS_PAYLOAD_START;
120  p[3] |= TS_ADAPT_FIELD_EXISTS;
121  p[3] &= ~TS_PAYLOAD_EXISTS;
122  p[4] = TS_SIZE - 5;
123  p[5] = 0x00;
124  memset(p + 6, 0xFF, TS_SIZE - 6);
125 }
126 
127 void TsSetPcr(uchar *p, int64_t Pcr)
128 {
129  if (TsHasAdaptationField(p)) {
130  if (p[4] >= 7 && (p[5] & TS_ADAPT_PCR)) {
131  int64_t b = Pcr / PCRFACTOR;
132  int e = Pcr % PCRFACTOR;
133  p[ 6] = b >> 25;
134  p[ 7] = b >> 17;
135  p[ 8] = b >> 9;
136  p[ 9] = b >> 1;
137  p[10] = (b << 7) | (p[10] & 0x7E) | ((e >> 8) & 0x01);
138  p[11] = e;
139  }
140  }
141 }
142 
143 int64_t TsGetPts(const uchar *p, int l)
144 {
145  // Find the first packet with a PTS and use it:
146  while (l > 0) {
147  const uchar *d = p;
148  if (TsPayloadStart(d) && TsGetPayload(&d) && PesHasPts(d))
149  return PesGetPts(d);
150  p += TS_SIZE;
151  l -= TS_SIZE;
152  }
153  return -1;
154 }
155 
156 int64_t TsGetDts(const uchar *p, int l)
157 {
158  // Find the first packet with a DTS and use it:
159  while (l > 0) {
160  const uchar *d = p;
161  if (TsPayloadStart(d) && TsGetPayload(&d) && PesHasDts(d))
162  return PesGetDts(d);
163  p += TS_SIZE;
164  l -= TS_SIZE;
165  }
166  return -1;
167 }
168 
169 void TsSetPts(uchar *p, int l, int64_t Pts)
170 {
171  // Find the first packet with a PTS and use it:
172  while (l > 0) {
173  const uchar *d = p;
174  if (TsPayloadStart(d) && TsGetPayload(&d) && PesHasPts(d)) {
175  PesSetPts(const_cast<uchar *>(d), Pts);
176  return;
177  }
178  p += TS_SIZE;
179  l -= TS_SIZE;
180  }
181 }
182 
183 void TsSetDts(uchar *p, int l, int64_t Dts)
184 {
185  // Find the first packet with a DTS and use it:
186  while (l > 0) {
187  const uchar *d = p;
188  if (TsPayloadStart(d) && TsGetPayload(&d) && PesHasDts(d)) {
189  PesSetDts(const_cast<uchar *>(d), Dts);
190  return;
191  }
192  p += TS_SIZE;
193  l -= TS_SIZE;
194  }
195 }
196 
197 // --- Some PES handling tools -----------------------------------------------
198 
199 void PesSetPts(uchar *p, int64_t Pts)
200 {
201  p[ 9] = ((Pts >> 29) & 0x0E) | (p[9] & 0xF1);
202  p[10] = Pts >> 22;
203  p[11] = ((Pts >> 14) & 0xFE) | 0x01;
204  p[12] = Pts >> 7;
205  p[13] = ((Pts << 1) & 0xFE) | 0x01;
206 }
207 
208 void PesSetDts(uchar *p, int64_t Dts)
209 {
210  p[14] = ((Dts >> 29) & 0x0E) | (p[14] & 0xF1);
211  p[15] = Dts >> 22;
212  p[16] = ((Dts >> 14) & 0xFE) | 0x01;
213  p[17] = Dts >> 7;
214  p[18] = ((Dts << 1) & 0xFE) | 0x01;
215 }
216 
217 int64_t PtsDiff(int64_t Pts1, int64_t Pts2)
218 {
219  int64_t d = Pts2 - Pts1;
220  if (d > MAX33BIT / 2)
221  return d - (MAX33BIT + 1);
222  if (d < -MAX33BIT / 2)
223  return d + (MAX33BIT + 1);
224  return d;
225 }
226 
227 // --- cTsPayload ------------------------------------------------------------
228 
230 {
231  data = NULL;
232  length = 0;
233  pid = -1;
234  index = 0;
235 }
236 
237 cTsPayload::cTsPayload(uchar *Data, int Length, int Pid)
238 {
239  Setup(Data, Length, Pid);
240 }
241 
242 void cTsPayload::Setup(uchar *Data, int Length, int Pid)
243 {
244  data = Data;
245  length = Length;
246  pid = Pid >= 0 ? Pid : TsPid(Data);
247  index = 0;
248 }
249 
251 {
252  if (!Eof()) {
253  if (index % TS_SIZE == 0) { // encountered the next TS header
254  for (;; index += TS_SIZE) {
255  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
256  uchar *p = data + index;
257  if (TsPid(p) == pid) { // only handle TS packets for the initial PID
258  if (TsHasPayload(p)) {
259  if (index > 0 && TsPayloadStart(p)) { // checking index to not skip the very first TS packet
260  length = index; // triggers EOF
261  return 0x00;
262  }
263  index += TsPayloadOffset(p);
264  break;
265  }
266  }
267  }
268  else {
269  length = index; // triggers EOF
270  return 0x00;
271  }
272  }
273  }
274  return data[index++];
275  }
276  return 0x00;
277 }
278 
279 bool cTsPayload::SkipBytes(int Bytes)
280 {
281  while (Bytes-- > 0)
282  GetByte();
283  return !Eof();
284 }
285 
287 {
289 }
290 
292 {
293  return index - 1;
294 }
295 
296 void cTsPayload::SetByte(uchar Byte, int Index)
297 {
298  if (Index >= 0 && Index < length)
299  data[Index] = Byte;
300 }
301 
302 bool cTsPayload::Find(uint32_t Code)
303 {
304  int OldIndex = index;
305  uint32_t Scanner = EMPTY_SCANNER;
306  while (!Eof()) {
307  Scanner = (Scanner << 8) | GetByte();
308  if (Scanner == Code)
309  return true;
310  }
311  index = OldIndex;
312  return false;
313 }
314 
315 void TsExtendAdaptionField(unsigned char *Packet, int ToLength)
316 {
317  // Hint: ExtenAdaptionField(p, TsPayloadOffset(p) - 4) is a null operation
318 
319  int Offset = TsPayloadOffset(Packet); // First byte after existing adaption field
320 
321  if (ToLength <= 0)
322  {
323  // Remove adaption field
324  Packet[3] = Packet[3] & ~TS_ADAPT_FIELD_EXISTS;
325  return;
326  }
327 
328  // Set adaption field present
329  Packet[3] = Packet[3] | TS_ADAPT_FIELD_EXISTS;
330 
331  // Set new length of adaption field:
332  Packet[4] = ToLength <= TS_SIZE-4 ? ToLength-1 : TS_SIZE-4-1;
333 
334  if (Packet[4] == TS_SIZE-4-1)
335  {
336  // No more payload, remove payload flag
337  Packet[3] = Packet[3] & ~TS_PAYLOAD_EXISTS;
338  }
339 
340  int NewPayload = TsPayloadOffset(Packet); // First byte after new adaption field
341 
342  // Fill new adaption field
343  if (Offset == 4 && Offset < NewPayload)
344  Offset++; // skip adaptation_field_length
345  if (Offset == 5 && Offset < NewPayload)
346  Packet[Offset++] = 0; // various flags set to 0
347  while (Offset < NewPayload)
348  Packet[Offset++] = 0xff; // stuffing byte
349 }
350 
351 // --- cPatPmtGenerator ------------------------------------------------------
352 
354 {
355  numPmtPackets = 0;
356  patCounter = pmtCounter = 0;
357  patVersion = pmtVersion = 0;
358  pmtPid = 0;
359  esInfoLength = NULL;
360  SetChannel(Channel);
361 }
362 
363 void cPatPmtGenerator::IncCounter(int &Counter, uchar *TsPacket)
364 {
365  TsPacket[3] = (TsPacket[3] & 0xF0) | Counter;
366  if (++Counter > 0x0F)
367  Counter = 0x00;
368 }
369 
371 {
372  if (++Version > 0x1F)
373  Version = 0x00;
374 }
375 
377 {
378  if (esInfoLength) {
379  Length += ((*esInfoLength & 0x0F) << 8) | *(esInfoLength + 1);
380  *esInfoLength = 0xF0 | (Length >> 8);
381  *(esInfoLength + 1) = Length;
382  }
383 }
384 
385 int cPatPmtGenerator::MakeStream(uchar *Target, uchar Type, int Pid)
386 {
387  int i = 0;
388  Target[i++] = Type; // stream type
389  Target[i++] = 0xE0 | (Pid >> 8); // dummy (3), pid hi (5)
390  Target[i++] = Pid; // pid lo
391  esInfoLength = &Target[i];
392  Target[i++] = 0xF0; // dummy (4), ES info length hi
393  Target[i++] = 0x00; // ES info length lo
394  return i;
395 }
396 
398 {
399  int i = 0;
400  Target[i++] = Type;
401  Target[i++] = 0x01; // length
402  Target[i++] = 0x00;
403  IncEsInfoLength(i);
404  return i;
405 }
406 
407 int cPatPmtGenerator::MakeSubtitlingDescriptor(uchar *Target, const char *Language, uchar SubtitlingType, uint16_t CompositionPageId, uint16_t AncillaryPageId)
408 {
409  int i = 0;
410  Target[i++] = SI::SubtitlingDescriptorTag;
411  Target[i++] = 0x08; // length
412  Target[i++] = *Language++;
413  Target[i++] = *Language++;
414  Target[i++] = *Language++;
415  Target[i++] = SubtitlingType;
416  Target[i++] = CompositionPageId >> 8;
417  Target[i++] = CompositionPageId & 0xFF;
418  Target[i++] = AncillaryPageId >> 8;
419  Target[i++] = AncillaryPageId & 0xFF;
420  IncEsInfoLength(i);
421  return i;
422 }
423 
425 {
426  int i = 0, j = 0;
427  Target[i++] = SI::TeletextDescriptorTag;
428  int l = i;
429  Target[i++] = 0x00; // length
430  for (int n = 0; n < pageCount; n++) {
431  const char* Language = pages[n].ttxtLanguage;
432  Target[i++] = *Language++;
433  Target[i++] = *Language++;
434  Target[i++] = *Language++;
435  Target[i++] = (pages[n].ttxtType << 3) + pages[n].ttxtMagazine;
436  Target[i++] = pages[n].ttxtPage;
437  j++;
438  }
439  if (j > 0) {
440  Target[l] = j * 5; // update length
441  IncEsInfoLength(i);
442  return i;
443  }
444  return 0;
445 }
446 
447 int cPatPmtGenerator::MakeLanguageDescriptor(uchar *Target, const char *Language)
448 {
449  int i = 0;
450  Target[i++] = SI::ISO639LanguageDescriptorTag;
451  int Length = i++;
452  Target[Length] = 0x00; // length
453  for (const char *End = Language + strlen(Language); Language < End; ) {
454  Target[i++] = *Language++;
455  Target[i++] = *Language++;
456  Target[i++] = *Language++;
457  Target[i++] = 0x00; // audio type
458  Target[Length] += 0x04; // length
459  if (*Language == '+')
460  Language++;
461  }
462  IncEsInfoLength(i);
463  return i;
464 }
465 
466 int cPatPmtGenerator::MakeCRC(uchar *Target, const uchar *Data, int Length)
467 {
468  int crc = SI::CRC32::crc32((const char *)Data, Length, 0xFFFFFFFF);
469  int i = 0;
470  Target[i++] = crc >> 24;
471  Target[i++] = crc >> 16;
472  Target[i++] = crc >> 8;
473  Target[i++] = crc;
474  return i;
475 }
476 
477 #define P_TSID 0x8008 // pseudo TS ID
478 #define P_PMT_PID 0x0084 // pseudo PMT pid
479 #define MAXPID 0x2000 // the maximum possible number of pids
480 
482 {
483  bool Used[MAXPID] = { false };
484 #define SETPID(p) { if ((p) >= 0 && (p) < MAXPID) Used[p] = true; }
485 #define SETPIDS(l) { const int *p = l; while (*p) { SETPID(*p); p++; } }
486  SETPID(Channel->Vpid());
487  SETPID(Channel->Ppid());
488  SETPID(Channel->Tpid());
489  SETPIDS(Channel->Apids());
490  SETPIDS(Channel->Dpids());
491  SETPIDS(Channel->Spids());
492  for (pmtPid = P_PMT_PID; Used[pmtPid]; pmtPid++)
493  ;
494 }
495 
497 {
498  memset(pat, 0xFF, sizeof(pat));
499  uchar *p = pat;
500  int i = 0;
501  p[i++] = TS_SYNC_BYTE; // TS indicator
502  p[i++] = TS_PAYLOAD_START | (PATPID >> 8); // flags (3), pid hi (5)
503  p[i++] = PATPID & 0xFF; // pid lo
504  p[i++] = 0x10; // flags (4), continuity counter (4)
505  p[i++] = 0x00; // pointer field (payload unit start indicator is set)
506  int PayloadStart = i;
507  p[i++] = 0x00; // table id
508  p[i++] = 0xB0; // section syntax indicator (1), dummy (3), section length hi (4)
509  int SectionLength = i;
510  p[i++] = 0x00; // section length lo (filled in later)
511  p[i++] = P_TSID >> 8; // TS id hi
512  p[i++] = P_TSID & 0xFF; // TS id lo
513  p[i++] = 0xC1 | (patVersion << 1); // dummy (2), version number (5), current/next indicator (1)
514  p[i++] = 0x00; // section number
515  p[i++] = 0x00; // last section number
516  p[i++] = pmtPid >> 8; // program number hi
517  p[i++] = pmtPid & 0xFF; // program number lo
518  p[i++] = 0xE0 | (pmtPid >> 8); // dummy (3), PMT pid hi (5)
519  p[i++] = pmtPid & 0xFF; // PMT pid lo
520  pat[SectionLength] = i - SectionLength - 1 + 4; // -2 = SectionLength storage, +4 = length of CRC
521  MakeCRC(pat + i, pat + PayloadStart, i - PayloadStart);
523 }
524 
526 {
527  // generate the complete PMT section:
528  uchar buf[MAX_SECTION_SIZE];
529  memset(buf, 0xFF, sizeof(buf));
530  numPmtPackets = 0;
531  if (Channel) {
532  int Vpid = Channel->Vpid();
533  int Ppid = Channel->Ppid();
534  int Tpid = Channel->Tpid();
535  uchar *p = buf;
536  int i = 0;
537  p[i++] = 0x02; // table id
538  int SectionLength = i;
539  p[i++] = 0xB0; // section syntax indicator (1), dummy (3), section length hi (4)
540  p[i++] = 0x00; // section length lo (filled in later)
541  p[i++] = pmtPid >> 8; // program number hi
542  p[i++] = pmtPid & 0xFF; // program number lo
543  p[i++] = 0xC1 | (pmtVersion << 1); // dummy (2), version number (5), current/next indicator (1)
544  p[i++] = 0x00; // section number
545  p[i++] = 0x00; // last section number
546  p[i++] = 0xE0 | (Ppid >> 8); // dummy (3), PCR pid hi (5)
547  p[i++] = Ppid; // PCR pid lo
548  p[i++] = 0xF0; // dummy (4), program info length hi (4)
549  p[i++] = 0x00; // program info length lo
550 
551  if (Vpid)
552  i += MakeStream(buf + i, Channel->Vtype(), Vpid);
553  for (int n = 0; Channel->Apid(n); n++) {
554  i += MakeStream(buf + i, Channel->Atype(n), Channel->Apid(n));
555  const char *Alang = Channel->Alang(n);
556  i += MakeLanguageDescriptor(buf + i, Alang);
557  }
558  for (int n = 0; Channel->Dpid(n); n++) {
559  i += MakeStream(buf + i, 0x06, Channel->Dpid(n));
560  i += MakeAC3Descriptor(buf + i, Channel->Dtype(n));
561  i += MakeLanguageDescriptor(buf + i, Channel->Dlang(n));
562  }
563  for (int n = 0; Channel->Spid(n); n++) {
564  i += MakeStream(buf + i, 0x06, Channel->Spid(n));
565  i += MakeSubtitlingDescriptor(buf + i, Channel->Slang(n), Channel->SubtitlingType(n), Channel->CompositionPageId(n), Channel->AncillaryPageId(n));
566  }
567  if (Tpid) {
568  i += MakeStream(buf + i, 0x06, Tpid);
569  i += MakeTeletextDescriptor(buf + i, Channel->TeletextSubtitlePages(), Channel->TotalTeletextSubtitlePages());
570  }
571 
572  int sl = i - SectionLength - 2 + 4; // -2 = SectionLength storage, +4 = length of CRC
573  buf[SectionLength] |= (sl >> 8) & 0x0F;
574  buf[SectionLength + 1] = sl;
575  MakeCRC(buf + i, buf, i);
576  // split the PMT section into several TS packets:
577  uchar *q = buf;
578  bool pusi = true;
579  while (i > 0) {
580  uchar *p = pmt[numPmtPackets++];
581  int j = 0;
582  p[j++] = TS_SYNC_BYTE; // TS indicator
583  p[j++] = (pusi ? TS_PAYLOAD_START : 0x00) | (pmtPid >> 8); // flags (3), pid hi (5)
584  p[j++] = pmtPid & 0xFF; // pid lo
585  p[j++] = 0x10; // flags (4), continuity counter (4)
586  if (pusi) {
587  p[j++] = 0x00; // pointer field (payload unit start indicator is set)
588  pusi = false;
589  }
590  int l = TS_SIZE - j;
591  memcpy(p + j, q, l);
592  q += l;
593  i -= l;
594  }
596  }
597 }
598 
599 void cPatPmtGenerator::SetVersions(int PatVersion, int PmtVersion)
600 {
601  patVersion = PatVersion & 0x1F;
602  pmtVersion = PmtVersion & 0x1F;
603 }
604 
606 {
607  if (Channel) {
608  GeneratePmtPid(Channel);
609  GeneratePat();
610  GeneratePmt(Channel);
611  }
612 }
613 
615 {
617  return pat;
618 }
619 
621 {
622  if (Index < numPmtPackets) {
623  IncCounter(pmtCounter, pmt[Index]);
624  return pmt[Index++];
625  }
626  return NULL;
627 }
628 
629 // --- cPatPmtParser ---------------------------------------------------------
630 
631 cPatPmtParser::cPatPmtParser(bool UpdatePrimaryDevice)
632 {
633  updatePrimaryDevice = UpdatePrimaryDevice;
634  Reset();
635 }
636 
638 {
639  pmtSize = 0;
640  patVersion = pmtVersion = -1;
641  pmtPids[0] = 0;
642  vpid = vtype = 0;
643  ppid = 0;
644  tpid = 0;
645 }
646 
647 void cPatPmtParser::ParsePat(const uchar *Data, int Length)
648 {
649  // Unpack the TS packet:
650  int PayloadOffset = TsPayloadOffset(Data);
651  Data += PayloadOffset;
652  Length -= PayloadOffset;
653  // The PAT is always assumed to fit into a single TS packet
654  if ((Length -= Data[0] + 1) <= 0)
655  return;
656  Data += Data[0] + 1; // process pointer_field
657  SI::PAT Pat(Data, false);
658  if (Pat.CheckCRCAndParse()) {
659  dbgpatpmt("PAT: TSid = %d, c/n = %d, v = %d, s = %d, ls = %d\n", Pat.getTransportStreamId(), Pat.getCurrentNextIndicator(), Pat.getVersionNumber(), Pat.getSectionNumber(), Pat.getLastSectionNumber());
660  if (patVersion == Pat.getVersionNumber())
661  return;
662  int NumPmtPids = 0;
663  SI::PAT::Association assoc;
664  for (SI::Loop::Iterator it; Pat.associationLoop.getNext(assoc, it); ) {
665  dbgpatpmt(" isNITPid = %d\n", assoc.isNITPid());
666  if (!assoc.isNITPid()) {
667  if (NumPmtPids <= MAX_PMT_PIDS)
668  pmtPids[NumPmtPids++] = assoc.getPid();
669  dbgpatpmt(" service id = %d, pid = %d\n", assoc.getServiceId(), assoc.getPid());
670  }
671  }
672  pmtPids[NumPmtPids] = 0;
674  }
675  else
676  esyslog("ERROR: can't parse PAT");
677 }
678 
679 void cPatPmtParser::ParsePmt(const uchar *Data, int Length)
680 {
681  // Unpack the TS packet:
682  bool PayloadStart = TsPayloadStart(Data);
683  int PayloadOffset = TsPayloadOffset(Data);
684  Data += PayloadOffset;
685  Length -= PayloadOffset;
686  // The PMT may extend over several TS packets, so we need to assemble them
687  if (PayloadStart) {
688  pmtSize = 0;
689  if ((Length -= Data[0] + 1) <= 0)
690  return;
691  Data += Data[0] + 1; // this is the first packet
692  if (SectionLength(Data, Length) > Length) {
693  if (Length <= int(sizeof(pmt))) {
694  memcpy(pmt, Data, Length);
695  pmtSize = Length;
696  }
697  else
698  esyslog("ERROR: PMT packet length too big (%d byte)!", Length);
699  return;
700  }
701  // the packet contains the entire PMT section, so we run into the actual parsing
702  }
703  else if (pmtSize > 0) {
704  // this is a following packet, so we add it to the pmt storage
705  if (Length <= int(sizeof(pmt)) - pmtSize) {
706  memcpy(pmt + pmtSize, Data, Length);
707  pmtSize += Length;
708  }
709  else {
710  esyslog("ERROR: PMT section length too big (%d byte)!", pmtSize + Length);
711  pmtSize = 0;
712  }
714  return; // more packets to come
715  // the PMT section is now complete, so we run into the actual parsing
716  Data = pmt;
717  }
718  else
719  return; // fragment of broken packet - ignore
720  SI::PMT Pmt(Data, false);
721  if (Pmt.CheckCRCAndParse()) {
722  dbgpatpmt("PMT: sid = %d, c/n = %d, v = %d, s = %d, ls = %d\n", Pmt.getServiceId(), Pmt.getCurrentNextIndicator(), Pmt.getVersionNumber(), Pmt.getSectionNumber(), Pmt.getLastSectionNumber());
723  dbgpatpmt(" pcr = %d\n", Pmt.getPCRPid());
724  if (pmtVersion == Pmt.getVersionNumber())
725  return;
728  int NumApids = 0;
729  int NumDpids = 0;
730  int NumSpids = 0;
731  vpid = vtype = 0;
732  ppid = 0;
733  tpid = 0;
734  apids[0] = 0;
735  dpids[0] = 0;
736  spids[0] = 0;
737  atypes[0] = 0;
738  dtypes[0] = 0;
740  SI::PMT::Stream stream;
741  for (SI::Loop::Iterator it; Pmt.streamLoop.getNext(stream, it); ) {
742  dbgpatpmt(" stream type = %02X, pid = %d", stream.getStreamType(), stream.getPid());
743  switch (stream.getStreamType()) {
744  case 0x01: // STREAMTYPE_11172_VIDEO
745  case 0x02: // STREAMTYPE_13818_VIDEO
746  case 0x1B: // H.264
747  vpid = stream.getPid();
748  vtype = stream.getStreamType();
749  ppid = Pmt.getPCRPid();
750  break;
751  case 0x03: // STREAMTYPE_11172_AUDIO
752  case 0x04: // STREAMTYPE_13818_AUDIO
753  case 0x0F: // ISO/IEC 13818-7 Audio with ADTS transport syntax
754  case 0x11: // ISO/IEC 14496-3 Audio with LATM transport syntax
755  {
756  if (NumApids < MAXAPIDS) {
757  apids[NumApids] = stream.getPid();
758  atypes[NumApids] = stream.getStreamType();
759  *alangs[NumApids] = 0;
760  SI::Descriptor *d;
761  for (SI::Loop::Iterator it; (d = stream.streamDescriptors.getNext(it)); ) {
762  switch (d->getDescriptorTag()) {
766  char *s = alangs[NumApids];
767  int n = 0;
768  for (SI::Loop::Iterator it; ld->languageLoop.getNext(l, it); ) {
769  if (*ld->languageCode != '-') { // some use "---" to indicate "none"
770  dbgpatpmt(" '%s'", l.languageCode);
771  if (n > 0)
772  *s++ = '+';
774  s += strlen(s);
775  if (n++ > 1)
776  break;
777  }
778  }
779  }
780  break;
781  default: ;
782  }
783  delete d;
784  }
786  cDevice::PrimaryDevice()->SetAvailableTrack(ttAudio, NumApids, apids[NumApids], alangs[NumApids]);
787  NumApids++;
788  apids[NumApids] = 0;
789  }
790  }
791  break;
792  case 0x06: // STREAMTYPE_13818_PES_PRIVATE
793  {
794  int dpid = 0;
795  int dtype = 0;
796  char lang[MAXLANGCODE1] = "";
797  SI::Descriptor *d;
798  for (SI::Loop::Iterator it; (d = stream.streamDescriptors.getNext(it)); ) {
799  switch (d->getDescriptorTag()) {
802  dbgpatpmt(" AC3");
803  dpid = stream.getPid();
804  dtype = d->getDescriptorTag();
805  break;
807  dbgpatpmt(" subtitling");
808  if (NumSpids < MAXSPIDS) {
809  spids[NumSpids] = stream.getPid();
810  *slangs[NumSpids] = 0;
811  subtitlingTypes[NumSpids] = 0;
812  compositionPageIds[NumSpids] = 0;
813  ancillaryPageIds[NumSpids] = 0;
816  char *s = slangs[NumSpids];
817  int n = 0;
818  for (SI::Loop::Iterator it; sd->subtitlingLoop.getNext(sub, it); ) {
819  if (sub.languageCode[0]) {
820  dbgpatpmt(" '%s'", sub.languageCode);
821  subtitlingTypes[NumSpids] = sub.getSubtitlingType();
822  compositionPageIds[NumSpids] = sub.getCompositionPageId();
823  ancillaryPageIds[NumSpids] = sub.getAncillaryPageId();
824  if (n > 0)
825  *s++ = '+';
827  s += strlen(s);
828  if (n++ > 1)
829  break;
830  }
831  }
833  cDevice::PrimaryDevice()->SetAvailableTrack(ttSubtitle, NumSpids, spids[NumSpids], slangs[NumSpids]);
834  NumSpids++;
835  spids[NumSpids] = 0;
836  }
837  break;
839  dbgpatpmt(" teletext");
840  tpid = stream.getPid();
844  for (SI::Loop::Iterator it; sd->teletextLoop.getNext(ttxt, it); ) {
845  bool isSubtitlePage = (ttxt.getTeletextType() == 0x02) || (ttxt.getTeletextType() == 0x05);
846  if (isSubtitlePage && ttxt.languageCode[0]) {
847  dbgpatpmt(" '%s:%x.%x'", ttxt.languageCode, ttxt.getTeletextMagazineNumber(), ttxt.getTeletextPageNumber());
854  break;
855  }
856  }
857  }
858  }
859  break;
862  dbgpatpmt(" '%s'", ld->languageCode);
864  }
865  break;
866  default: ;
867  }
868  delete d;
869  }
870  if (dpid) {
871  if (NumDpids < MAXDPIDS) {
872  dpids[NumDpids] = dpid;
873  dtypes[NumDpids] = dtype;
874  strn0cpy(dlangs[NumDpids], lang, sizeof(dlangs[NumDpids]));
876  cDevice::PrimaryDevice()->SetAvailableTrack(ttDolby, NumDpids, dpid, lang);
877  NumDpids++;
878  dpids[NumDpids] = 0;
879  }
880  }
881  }
882  break;
883  case 0x81: // STREAMTYPE_USER_PRIVATE
884  {
885  dbgpatpmt(" AC3");
886  char lang[MAXLANGCODE1] = { 0 };
887  SI::Descriptor *d;
888  for (SI::Loop::Iterator it; (d = stream.streamDescriptors.getNext(it)); ) {
889  switch (d->getDescriptorTag()) {
892  dbgpatpmt(" '%s'", ld->languageCode);
894  }
895  break;
896  default: ;
897  }
898  delete d;
899  }
900  if (NumDpids < MAXDPIDS) {
901  dpids[NumDpids] = stream.getPid();
902  dtypes[NumDpids] = SI::AC3DescriptorTag;
903  strn0cpy(dlangs[NumDpids], lang, sizeof(dlangs[NumDpids]));
905  cDevice::PrimaryDevice()->SetAvailableTrack(ttDolby, NumDpids, stream.getPid(), lang);
906  NumDpids++;
907  dpids[NumDpids] = 0;
908  }
909  }
910  break;
911  default: ;
912  }
913  dbgpatpmt("\n");
914  if (updatePrimaryDevice) {
917  }
918  }
920  }
921  else
922  esyslog("ERROR: can't parse PMT");
923  pmtSize = 0;
924 }
925 
926 bool cPatPmtParser::ParsePatPmt(const uchar *Data, int Length)
927 {
928  while (Length >= TS_SIZE) {
929  if (*Data != TS_SYNC_BYTE)
930  break; // just for safety
931  int Pid = TsPid(Data);
932  if (Pid == PATPID)
933  ParsePat(Data, TS_SIZE);
934  else if (IsPmtPid(Pid)) {
935  ParsePmt(Data, TS_SIZE);
936  if (patVersion >= 0 && pmtVersion >= 0)
937  return true;
938  }
939  Data += TS_SIZE;
940  Length -= TS_SIZE;
941  }
942  return false;
943 }
944 
945 bool cPatPmtParser::GetVersions(int &PatVersion, int &PmtVersion) const
946 {
947  PatVersion = patVersion;
948  PmtVersion = pmtVersion;
949  return patVersion >= 0 && pmtVersion >= 0;
950 }
951 
952 // --- cTsToPes --------------------------------------------------------------
953 
955 {
956  data = NULL;
957  size = 0;
958  Reset();
959 }
960 
962 {
963  free(data);
964 }
965 
966 void cTsToPes::PutTs(const uchar *Data, int Length)
967 {
968  if (TsError(Data)) {
969  Reset();
970  return; // ignore packets with TEI set, and drop any PES data collected so far
971  }
972  if (TsPayloadStart(Data))
973  Reset();
974  else if (!size)
975  return; // skip everything before the first payload start
976  Length = TsGetPayload(&Data);
977  if (length + Length > size) {
978  int NewSize = max(KILOBYTE(2), length + Length);
979  if (uchar *NewData = (uchar *)realloc(data, NewSize)) {
980  data = NewData;
981  size = NewSize;
982  }
983  else {
984  esyslog("ERROR: out of memory");
985  Reset();
986  return;
987  }
988  }
989  memcpy(data + length, Data, Length);
990  length += Length;
991 }
992 
993 #define MAXPESLENGTH 0xFFF0
994 
995 const uchar *cTsToPes::GetPes(int &Length)
996 {
997  if (repeatLast) {
998  repeatLast = false;
999  Length = lastLength;
1000  return lastData;
1001  }
1002  if (offset < length && PesLongEnough(length)) {
1003  if (!PesHasLength(data)) // this is a video PES packet with undefined length
1004  offset = 6; // trigger setting PES length for initial slice
1005  if (offset) {
1006  uchar *p = data + offset - 6;
1007  if (p != data) {
1008  p -= 3;
1009  if (p < data) {
1010  Reset();
1011  return NULL;
1012  }
1013  memmove(p, data, 4);
1014  }
1015  int l = min(length - offset, MAXPESLENGTH);
1016  offset += l;
1017  if (p != data) {
1018  l += 3;
1019  p[6] = 0x80;
1020  p[7] = 0x00;
1021  p[8] = 0x00;
1022  }
1023  p[4] = l / 256;
1024  p[5] = l & 0xFF;
1025  Length = l + 6;
1026  lastLength = Length;
1027  lastData = p;
1028  return p;
1029  }
1030  else {
1031  Length = PesLength(data);
1032  if (Length <= length) {
1033  offset = Length; // to make sure we break out in case of garbage data
1034  lastLength = Length;
1035  lastData = data;
1036  return data;
1037  }
1038  }
1039  }
1040  return NULL;
1041 }
1042 
1044 {
1045  repeatLast = true;
1046 }
1047 
1049 {
1050  length = offset = 0;
1051  lastData = NULL;
1052  lastLength = 0;
1053  repeatLast = false;
1054 }
1055 
1056 // --- Some helper functions for debugging -----------------------------------
1057 
1058 void BlockDump(const char *Name, const u_char *Data, int Length)
1059 {
1060  printf("--- %s\n", Name);
1061  for (int i = 0; i < Length; i++) {
1062  if (i && (i % 16) == 0)
1063  printf("\n");
1064  printf(" %02X", Data[i]);
1065  }
1066  printf("\n");
1067 }
1068 
1069 void TsDump(const char *Name, const u_char *Data, int Length)
1070 {
1071  printf("%s: %04X", Name, Length);
1072  int n = min(Length, 20);
1073  for (int i = 0; i < n; i++)
1074  printf(" %02X", Data[i]);
1075  if (n < Length) {
1076  printf(" ...");
1077  n = max(n, Length - 10);
1078  for (n = max(n, Length - 10); n < Length; n++)
1079  printf(" %02X", Data[n]);
1080  }
1081  printf("\n");
1082 }
1083 
1084 void PesDump(const char *Name, const u_char *Data, int Length)
1085 {
1086  TsDump(Name, Data, Length);
1087 }
1088 
1089 // --- cFrameParser ----------------------------------------------------------
1090 
1092 protected:
1093  bool debug;
1094  bool newFrame;
1096 public:
1097  cFrameParser(void);
1098  virtual ~cFrameParser() {};
1099  virtual int Parse(const uchar *Data, int Length, int Pid) = 0;
1106  void SetDebug(bool Debug) { debug = Debug; }
1107  bool NewFrame(void) { return newFrame; }
1108  bool IndependentFrame(void) { return independentFrame; }
1109  };
1110 
1112 {
1113  debug = true;
1114  newFrame = false;
1115  independentFrame = false;
1116 }
1117 
1118 // --- cAudioParser ----------------------------------------------------------
1119 
1120 class cAudioParser : public cFrameParser {
1121 public:
1122  cAudioParser(void);
1123  virtual int Parse(const uchar *Data, int Length, int Pid);
1124  };
1125 
1127 {
1128 }
1129 
1130 int cAudioParser::Parse(const uchar *Data, int Length, int Pid)
1131 {
1132  if (TsPayloadStart(Data)) {
1133  newFrame = independentFrame = true;
1134  if (debug)
1135  dbgframes("/");
1136  }
1137  else
1138  newFrame = independentFrame = false;
1139  return TS_SIZE;
1140 }
1141 
1142 // --- cMpeg2Parser ----------------------------------------------------------
1143 
1144 class cMpeg2Parser : public cFrameParser {
1145 private:
1146  uint32_t scanner;
1148 public:
1149  cMpeg2Parser(void);
1150  virtual int Parse(const uchar *Data, int Length, int Pid);
1151  };
1152 
1154 {
1156  seenIndependentFrame = false;
1157 }
1158 
1159 int cMpeg2Parser::Parse(const uchar *Data, int Length, int Pid)
1160 {
1161  newFrame = independentFrame = false;
1162  bool SeenPayloadStart = false;
1163  cTsPayload tsPayload(const_cast<uchar *>(Data), Length, Pid);
1164  if (TsPayloadStart(Data)) {
1165  SeenPayloadStart = true;
1166  tsPayload.SkipPesHeader();
1168  if (debug && seenIndependentFrame)
1169  dbgframes("/");
1170  }
1171  uint32_t OldScanner = scanner; // need to remember it in case of multiple frames per payload
1172  for (;;) {
1173  if (!SeenPayloadStart && tsPayload.AtTsStart())
1174  OldScanner = scanner;
1175  scanner = (scanner << 8) | tsPayload.GetByte();
1176  if (scanner == 0x00000100) { // Picture Start Code
1177  if (!SeenPayloadStart && tsPayload.GetLastIndex() > TS_SIZE) {
1178  scanner = OldScanner;
1179  return tsPayload.Used() - TS_SIZE;
1180  }
1181  newFrame = true;
1182  tsPayload.GetByte();
1183  uchar FrameType = (tsPayload.GetByte() >> 3) & 0x07;
1184  independentFrame = FrameType == 1; // I-Frame
1185  if (debug) {
1187  if (seenIndependentFrame) {
1188  static const char FrameTypes[] = "?IPBD???";
1189  dbgframes("%c", FrameTypes[FrameType]);
1190  }
1191  }
1192  break;
1193  }
1194  if (tsPayload.AtPayloadStart() // stop at any new payload start to have the buffer refilled if necessary
1195  || (tsPayload.Available() < MIN_TS_PACKETS_FOR_FRAME_DETECTOR * TS_SIZE // stop if the available data is below the limit...
1196  && (tsPayload.Available() <= 0 || tsPayload.AtTsStart()))) // ...but only if there is no more data at all, or if we are at a TS boundary
1197  break;
1198  }
1199  return tsPayload.Used();
1200 }
1201 
1202 // --- cH264Parser -----------------------------------------------------------
1203 
1204 class cH264Parser : public cFrameParser {
1205 private:
1211  };
1213  uchar byte; // holds the current byte value in case of bitwise access
1214  int bit; // the bit index into the current byte (-1 if we're not in bit reading mode)
1215  int zeroBytes; // the number of consecutive zero bytes (to detect 0x000003)
1216  uint32_t scanner;
1217  // Identifiers written in '_' notation as in "ITU-T H.264":
1221  //
1224  uchar GetByte(bool Raw = false);
1228  uchar GetBit(void);
1229  uint32_t GetBits(int Bits);
1230  uint32_t GetGolombUe(void);
1231  int32_t GetGolombSe(void);
1232  void ParseAccessUnitDelimiter(void);
1233  void ParseSequenceParameterSet(void);
1234  void ParseSliceHeader(void);
1235 public:
1236  cH264Parser(void);
1240  virtual int Parse(const uchar *Data, int Length, int Pid);
1241  };
1242 
1244 {
1245  byte = 0;
1246  bit = -1;
1247  zeroBytes = 0;
1250  log2_max_frame_num = 0;
1251  frame_mbs_only_flag = false;
1252  gotAccessUnitDelimiter = false;
1253  gotSequenceParameterSet = false;
1254 }
1255 
1257 {
1258  uchar b = tsPayload.GetByte();
1259  if (!Raw) {
1260  // If we encounter the byte sequence 0x000003, we need to skip the 0x03:
1261  if (b == 0x00)
1262  zeroBytes++;
1263  else {
1264  if (b == 0x03 && zeroBytes >= 2)
1265  b = tsPayload.GetByte();
1266  zeroBytes = 0;
1267  }
1268  }
1269  else
1270  zeroBytes = 0;
1271  bit = -1;
1272  return b;
1273 }
1274 
1276 {
1277  if (bit < 0) {
1278  byte = GetByte();
1279  bit = 7;
1280  }
1281  return (byte & (1 << bit--)) ? 1 : 0;
1282 }
1283 
1284 uint32_t cH264Parser::GetBits(int Bits)
1285 {
1286  uint32_t b = 0;
1287  while (Bits--)
1288  b |= GetBit() << Bits;
1289  return b;
1290 }
1291 
1293 {
1294  int z = -1;
1295  for (int b = 0; !b; z++)
1296  b = GetBit();
1297  return (1 << z) - 1 + GetBits(z);
1298 }
1299 
1301 {
1302  uint32_t v = GetGolombUe();
1303  if (v) {
1304  if ((v & 0x01) != 0)
1305  return (v + 1) / 2; // fails for v == 0xFFFFFFFF, but that will probably never happen
1306  else
1307  return -int32_t(v / 2);
1308  }
1309  return v;
1310 }
1311 
1312 int cH264Parser::Parse(const uchar *Data, int Length, int Pid)
1313 {
1314  newFrame = independentFrame = false;
1315  tsPayload.Setup(const_cast<uchar *>(Data), Length, Pid);
1316  if (TsPayloadStart(Data)) {
1319  if (debug && gotSequenceParameterSet) {
1320  dbgframes("/");
1321  }
1322  }
1323  for (;;) {
1324  scanner = (scanner << 8) | GetByte(true);
1325  if ((scanner & 0xFFFFFF00) == 0x00000100) { // NAL unit start
1326  uchar NalUnitType = scanner & 0x1F;
1327  switch (NalUnitType) {
1329  gotAccessUnitDelimiter = true;
1330  break;
1332  gotSequenceParameterSet = true;
1333  break;
1334  case nutCodedSliceNonIdr:
1336  ParseSliceHeader();
1337  gotAccessUnitDelimiter = false;
1338  return tsPayload.Used();
1339  }
1340  break;
1341  default: ;
1342  }
1343  }
1344  if (tsPayload.AtPayloadStart() // stop at any new payload start to have the buffer refilled if necessary
1345  || (tsPayload.Available() < MIN_TS_PACKETS_FOR_FRAME_DETECTOR * TS_SIZE // stop if the available data is below the limit...
1346  && (tsPayload.Available() <= 0 || tsPayload.AtTsStart()))) // ...but only if there is no more data at all, or if we are at a TS boundary
1347  break;
1348  }
1349  return tsPayload.Used();
1350 }
1351 
1353 {
1355  dbgframes("A");
1356  GetByte(); // primary_pic_type
1357 }
1358 
1360 {
1361  uchar profile_idc = GetByte(); // profile_idc
1362  GetByte(); // constraint_set[0-5]_flags, reserved_zero_2bits
1363  GetByte(); // level_idc
1364  GetGolombUe(); // seq_parameter_set_id
1365  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) {
1366  int chroma_format_idc = GetGolombUe(); // chroma_format_idc
1367  if (chroma_format_idc == 3)
1369  GetGolombUe(); // bit_depth_luma_minus8
1370  GetGolombUe(); // bit_depth_chroma_minus8
1371  GetBit(); // qpprime_y_zero_transform_bypass_flag
1372  if (GetBit()) { // seq_scaling_matrix_present_flag
1373  for (int i = 0; i < ((chroma_format_idc != 3) ? 8 : 12); i++) {
1374  if (GetBit()) { // seq_scaling_list_present_flag
1375  int SizeOfScalingList = (i < 6) ? 16 : 64;
1376  int LastScale = 8;
1377  int NextScale = 8;
1378  for (int j = 0; j < SizeOfScalingList; j++) {
1379  if (NextScale)
1380  NextScale = (LastScale + GetGolombSe() + 256) % 256; // delta_scale
1381  if (NextScale)
1382  LastScale = NextScale;
1383  }
1384  }
1385  }
1386  }
1387  }
1388  log2_max_frame_num = GetGolombUe() + 4; // log2_max_frame_num_minus4
1389  int pic_order_cnt_type = GetGolombUe(); // pic_order_cnt_type
1390  if (pic_order_cnt_type == 0)
1391  GetGolombUe(); // log2_max_pic_order_cnt_lsb_minus4
1392  else if (pic_order_cnt_type == 1) {
1393  GetBit(); // delta_pic_order_always_zero_flag
1394  GetGolombSe(); // offset_for_non_ref_pic
1395  GetGolombSe(); // offset_for_top_to_bottom_field
1396  for (int i = GetGolombUe(); i--; ) // num_ref_frames_in_pic_order_cnt_cycle
1397  GetGolombSe(); // offset_for_ref_frame
1398  }
1399  GetGolombUe(); // max_num_ref_frames
1400  GetBit(); // gaps_in_frame_num_value_allowed_flag
1401  GetGolombUe(); // pic_width_in_mbs_minus1
1402  GetGolombUe(); // pic_height_in_map_units_minus1
1403  frame_mbs_only_flag = GetBit(); // frame_mbs_only_flag
1404  if (debug) {
1406  dbgframes("A"); // just for completeness
1407  dbgframes(frame_mbs_only_flag ? "S" : "s");
1408  }
1409 }
1410 
1412 {
1413  newFrame = true;
1414  GetGolombUe(); // first_mb_in_slice
1415  int slice_type = GetGolombUe(); // slice_type, 0 = P, 1 = B, 2 = I, 3 = SP, 4 = SI
1416  independentFrame = (slice_type % 5) == 2;
1417  if (debug) {
1418  static const char SliceTypes[] = "PBIpi";
1419  dbgframes("%c", SliceTypes[slice_type % 5]);
1420  }
1421  if (frame_mbs_only_flag)
1422  return; // don't need the rest - a frame is complete
1423  GetGolombUe(); // pic_parameter_set_id
1425  GetBits(2); // colour_plane_id
1426  GetBits(log2_max_frame_num); // frame_num
1427  if (!frame_mbs_only_flag) {
1428  if (GetBit()) // field_pic_flag
1429  newFrame = !GetBit(); // bottom_field_flag
1430  if (debug)
1431  dbgframes(newFrame ? "t" : "b");
1432  }
1433 }
1434 
1435 // --- cFrameDetector --------------------------------------------------------
1436 
1438 {
1439  parser = NULL;
1440  SetPid(Pid, Type);
1441  synced = false;
1442  newFrame = independentFrame = false;
1443  numPtsValues = 0;
1444  numIFrames = 0;
1445  framesPerSecond = 0;
1447  scanning = false;
1448 }
1449 
1450 static int CmpUint32(const void *p1, const void *p2)
1451 {
1452  if (*(uint32_t *)p1 < *(uint32_t *)p2) return -1;
1453  if (*(uint32_t *)p1 > *(uint32_t *)p2) return 1;
1454  return 0;
1455 }
1456 
1457 void cFrameDetector::SetPid(int Pid, int Type)
1458 {
1459  pid = Pid;
1460  type = Type;
1461  isVideo = type == 0x01 || type == 0x02 || type == 0x1B; // MPEG 1, 2 or H.264
1462  delete parser;
1463  parser = NULL;
1464  if (type == 0x01 || type == 0x02)
1465  parser = new cMpeg2Parser;
1466  else if (type == 0x1B)
1467  parser = new cH264Parser;
1468  else if (type == 0x04 || type == 0x06) // MPEG audio or AC3 audio
1469  parser = new cAudioParser;
1470  else if (type != 0)
1471  esyslog("ERROR: unknown stream type %d (PID %d) in frame detector", type, pid);
1472 }
1473 
1474 int cFrameDetector::Analyze(const uchar *Data, int Length)
1475 {
1476  if (!parser)
1477  return 0;
1478  int Processed = 0;
1479  newFrame = independentFrame = false;
1480  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
1481  // Sync on TS packet borders:
1482  if (Data[0] != TS_SYNC_BYTE) {
1483  int Skipped = 1;
1484  while (Skipped < Length && (Data[Skipped] != TS_SYNC_BYTE || Length - Skipped > TS_SIZE && Data[Skipped + TS_SIZE] != TS_SYNC_BYTE))
1485  Skipped++;
1486  esyslog("ERROR: skipped %d bytes to sync on start of TS packet", Skipped);
1487  return Processed + Skipped;
1488  }
1489  // Handle one TS packet:
1490  int Handled = TS_SIZE;
1491  if (TsHasPayload(Data) && !TsIsScrambled(Data)) {
1492  int Pid = TsPid(Data);
1493  if (Pid == pid) {
1494  if (Processed)
1495  return Processed;
1496  if (TsPayloadStart(Data))
1497  scanning = true;
1498  if (scanning) {
1499  // Detect the beginning of a new frame:
1500  if (TsPayloadStart(Data)) {
1501  if (!framesPerPayloadUnit)
1503  }
1504  int n = parser->Parse(Data, Length, pid);
1505  if (n > 0) {
1506  if (parser->NewFrame()) {
1507  newFrame = true;
1509  if (synced) {
1510  if (framesPerPayloadUnit <= 1)
1511  scanning = false;
1512  }
1513  else {
1515  if (independentFrame)
1516  numIFrames++;
1517  }
1518  }
1519  Handled = n;
1520  }
1521  }
1522  if (TsPayloadStart(Data)) {
1523  // Determine the frame rate from the PTS values in the PES headers:
1524  if (framesPerSecond <= 0.0) {
1525  // frame rate unknown, so collect a sequence of PTS values:
1526  if (numPtsValues < 2 || numPtsValues < MaxPtsValues && numIFrames < 2) { // collect a sequence containing at least two I-frames
1527  if (newFrame) { // only take PTS values at the beginning of a frame (in case if fields!)
1528  const uchar *Pes = Data + TsPayloadOffset(Data);
1529  if (numIFrames && PesHasPts(Pes)) {
1531  // check for rollover:
1532  if (numPtsValues && ptsValues[numPtsValues - 1] > 0xF0000000 && ptsValues[numPtsValues] < 0x10000000) {
1533  dbgframes("#");
1534  numPtsValues = 0;
1535  numIFrames = 0;
1536  }
1537  else
1538  numPtsValues++;
1539  }
1540  }
1541  }
1542  if (numPtsValues >= 2 && numIFrames >= 2) {
1543  // find the smallest PTS delta:
1544  qsort(ptsValues, numPtsValues, sizeof(uint32_t), CmpUint32);
1545  numPtsValues--;
1546  for (int i = 0; i < numPtsValues; i++)
1547  ptsValues[i] = ptsValues[i + 1] - ptsValues[i];
1548  qsort(ptsValues, numPtsValues, sizeof(uint32_t), CmpUint32);
1549  uint32_t Delta = ptsValues[0] / framesPerPayloadUnit;
1550  // determine frame info:
1551  if (isVideo) {
1552  if (abs(Delta - 3600) <= 1)
1553  framesPerSecond = 25.0;
1554  else if (Delta % 3003 == 0)
1555  framesPerSecond = 30.0 / 1.001;
1556  else if (abs(Delta - 1800) <= 1)
1557  framesPerSecond = 50.0;
1558  else if (Delta == 1501)
1559  framesPerSecond = 60.0 / 1.001;
1560  else {
1562  dsyslog("unknown frame delta (%d), assuming %5.2f fps", Delta, DEFAULTFRAMESPERSECOND);
1563  }
1564  }
1565  else // audio
1566  framesPerSecond = double(PTSTICKS) / Delta; // PTS of audio frames is always increasing
1567  dbgframes("\nDelta = %d FPS = %5.2f FPPU = %d NF = %d\n", Delta, framesPerSecond, framesPerPayloadUnit, numPtsValues + 1);
1568  synced = true;
1569  parser->SetDebug(false);
1570  }
1571  }
1572  }
1573  }
1574  else if (Pid == PATPID && synced && Processed)
1575  return Processed; // allow the caller to see any PAT packets
1576  }
1577  Data += Handled;
1578  Length -= Handled;
1579  Processed += Handled;
1580  if (newFrame)
1581  break;
1582  }
1583  return Processed;
1584 }
1585 
1586 // --- cNaluDumper ---------------------------------------------------------
1587 
1589 {
1590  LastContinuityOutput = -1;
1591  reset();
1592 }
1593 
1595 {
1596  LastContinuityInput = -1;
1597  ContinuityOffset = 0;
1598  PesId = -1;
1599  PesOffset = 0;
1601  NaluOffset = 0;
1602  History = 0xffffffff;
1603  DropAllPayload = false;
1604 }
1605 
1606 void cNaluDumper::ProcessPayload(unsigned char *Payload, int size, bool PayloadStart, sPayloadInfo &Info)
1607 {
1608  Info.DropPayloadStartBytes = 0;
1609  Info.DropPayloadEndBytes = 0;
1610  int LastKeepByte = -1;
1611 
1612  if (PayloadStart)
1613  {
1614  History = 0xffffffff;
1615  PesId = -1;
1617  }
1618 
1619  for (int i=0; i<size; i++) {
1620  History = (History << 8) | Payload[i];
1621 
1622  PesOffset++;
1623  NaluOffset++;
1624 
1625  bool DropByte = false;
1626 
1627  if (History >= 0x00000180 && History <= 0x000001FF)
1628  {
1629  // Start of PES packet
1630  PesId = History & 0xff;
1631  PesOffset = 0;
1633  }
1634  else if (PesId >= 0xe0 && PesId <= 0xef // video stream
1635  && History >= 0x00000100 && History <= 0x0000017F) // NALU start code
1636  {
1637  int NaluId = History & 0xff;
1638  NaluOffset = 0;
1639  NaluFillState = ((NaluId & 0x1f) == 0x0c) ? NALU_FILL : NALU_NONE;
1640  }
1641 
1642  if (PesId >= 0xe0 && PesId <= 0xef // video stream
1643  && PesOffset >= 1 && PesOffset <= 2)
1644  {
1645  Payload[i] = 0; // Zero out PES length field
1646  }
1647 
1648  if (NaluFillState == NALU_FILL && NaluOffset > 0) // Within NALU fill data
1649  {
1650  // We expect a series of 0xff bytes terminated by a single 0x80 byte.
1651 
1652  if (Payload[i] == 0xFF)
1653  {
1654  DropByte = true;
1655  }
1656  else if (Payload[i] == 0x80)
1657  {
1658  NaluFillState = NALU_TERM; // Last byte of NALU fill, next byte sets NaluFillEnd=true
1659  DropByte = true;
1660  }
1661  else // Invalid NALU fill
1662  {
1663  dsyslog("cNaluDumper: Unexpected NALU fill data: %02x", Payload[i]);
1665  if (LastKeepByte == -1)
1666  {
1667  // Nalu fill from beginning of packet until last byte
1668  // packet start needs to be dropped
1669  Info.DropPayloadStartBytes = i;
1670  }
1671  }
1672  }
1673  else if (NaluFillState == NALU_TERM) // Within NALU fill data
1674  {
1675  // We are after the terminating 0x80 byte
1677  if (LastKeepByte == -1)
1678  {
1679  // Nalu fill from beginning of packet until last byte
1680  // packet start needs to be dropped
1681  Info.DropPayloadStartBytes = i;
1682  }
1683  }
1684 
1685  if (!DropByte)
1686  LastKeepByte = i; // Last useful byte
1687  }
1688 
1689  Info.DropAllPayloadBytes = (LastKeepByte == -1);
1690  Info.DropPayloadEndBytes = size-1-LastKeepByte;
1691 }
1692 
1693 bool cNaluDumper::ProcessTSPacket(unsigned char *Packet)
1694 {
1695  bool HasAdaption = TsHasAdaptationField(Packet);
1696  bool HasPayload = TsHasPayload(Packet);
1697 
1698  // Check continuity:
1699  int ContinuityInput = TsContinuityCounter(Packet);
1700  if (LastContinuityInput >= 0)
1701  {
1702  int NewContinuityInput = HasPayload ? (LastContinuityInput + 1) & TS_CONT_CNT_MASK : LastContinuityInput;
1703  int Offset = (NewContinuityInput - ContinuityInput) & TS_CONT_CNT_MASK;
1704  if (Offset > 0)
1705  dsyslog("cNaluDumper: TS continuity offset %i", Offset);
1706  if (Offset > ContinuityOffset)
1707  ContinuityOffset = Offset; // max if packets get dropped, otherwise always the current one.
1708  }
1709  LastContinuityInput = ContinuityInput;
1710 
1711  if (HasPayload) {
1712  sPayloadInfo Info;
1713  int Offset = TsPayloadOffset(Packet);
1714  ProcessPayload(Packet + Offset, TS_SIZE - Offset, TsPayloadStart(Packet), Info);
1715 
1716  if (DropAllPayload && !Info.DropAllPayloadBytes)
1717  {
1718  // Return from drop packet mode to normal mode
1719  DropAllPayload = false;
1720 
1721  // Does the packet start with some remaining NALU fill data?
1722  if (Info.DropPayloadStartBytes > 0)
1723  {
1724  // Add these bytes as stuffing to the adaption field.
1725 
1726  // Sample payload layout:
1727  // FF FF FF FF FF 80 00 00 01 xx xx xx xx
1728  // ^DropPayloadStartBytes
1729 
1730  TsExtendAdaptionField(Packet, Offset - 4 + Info.DropPayloadStartBytes);
1731  }
1732  }
1733 
1734  bool DropThisPayload = DropAllPayload;
1735 
1736  if (!DropAllPayload && Info.DropPayloadEndBytes > 0) // Payload ends with 0xff NALU Fill
1737  {
1738  // Last packet of useful data
1739  // Do early termination of NALU fill data
1740  Packet[TS_SIZE-1] = 0x80;
1741  DropAllPayload = true;
1742  // Drop all packets AFTER this one
1743 
1744  // Since we already wrote the 0x80, we have to make sure that
1745  // as soon as we stop dropping packets, any beginning NALU fill of next
1746  // packet gets dumped. (see DropPayloadStartBytes above)
1747  }
1748 
1749  if (DropThisPayload && HasAdaption)
1750  {
1751  // Drop payload data, but keep adaption field data
1752  TsExtendAdaptionField(Packet, TS_SIZE-4);
1753  DropThisPayload = false;
1754  }
1755 
1756  if (DropThisPayload)
1757  {
1758  return true; // Drop packet
1759  }
1760  }
1761 
1762  // Fix Continuity Counter and reproduce incoming offsets:
1763  int NewContinuityOutput = TsHasPayload(Packet) ? (LastContinuityOutput + 1) & TS_CONT_CNT_MASK : LastContinuityOutput;
1764  NewContinuityOutput = (NewContinuityOutput + ContinuityOffset) & TS_CONT_CNT_MASK;
1765  TsSetContinuityCounter(Packet, NewContinuityOutput);
1766  LastContinuityOutput = NewContinuityOutput;
1767  ContinuityOffset = 0;
1768 
1769  return false; // Keep packet
1770 }
1771 
1772 // --- cNaluStreamProcessor ---------------------------------------------------------
1773 
1775 {
1776  pPatPmtParser = NULL;
1777  vpid = -1;
1778  data = NULL;
1779  length = 0;
1780  tempLength = 0;
1781  tempLengthAtEnd = false;
1782  TotalPackets = 0;
1783  DroppedPackets = 0;
1784 }
1785 
1787 {
1788  if (length > 0)
1789  esyslog("cNaluStreamProcessor::PutBuffer: New data before old data was processed!");
1790 
1791  data = Data;
1792  length = Length;
1793 }
1794 
1796 {
1797  if (length <= 0)
1798  {
1799  // Need more data - quick exit
1800  OutLength = 0;
1801  return NULL;
1802  }
1803  if (tempLength > 0) // Data in temp buffer?
1804  {
1805  if (tempLengthAtEnd) // Data is at end, copy to beginning
1806  {
1807  // Overlapping src and dst!
1808  for (int i=0; i<tempLength; i++)
1809  tempBuffer[i] = tempBuffer[TS_SIZE-tempLength+i];
1810  }
1811  // Normalize TempBuffer fill
1812  if (tempLength < TS_SIZE && length > 0)
1813  {
1814  int Size = min(TS_SIZE-tempLength, length);
1815  memcpy(tempBuffer+tempLength, data, Size);
1816  data += Size;
1817  length -= Size;
1818  tempLength += Size;
1819  }
1820  if (tempLength < TS_SIZE)
1821  {
1822  // All incoming data buffered, but need more data
1823  tempLengthAtEnd = false;
1824  OutLength = 0;
1825  return NULL;
1826  }
1827  // Now: TempLength==TS_SIZE
1828  if (tempBuffer[0] != TS_SYNC_BYTE)
1829  {
1830  // Need to sync on TS within temp buffer
1831  int Skipped = 1;
1832  while (Skipped < TS_SIZE && (tempBuffer[Skipped] != TS_SYNC_BYTE || (Skipped < length && data[Skipped] != TS_SYNC_BYTE)))
1833  Skipped++;
1834  esyslog("ERROR: skipped %d bytes to sync on start of TS packet", Skipped);
1835  // Pass through skipped bytes
1836  tempLengthAtEnd = true;
1837  tempLength = TS_SIZE - Skipped; // may be 0, thats ok
1838  OutLength = Skipped;
1839  return tempBuffer;
1840  }
1841  // Now: TempBuffer is a TS packet
1842  int Pid = TsPid(tempBuffer);
1843  if (pPatPmtParser)
1844  {
1845  if (Pid == 0)
1847  else if (pPatPmtParser->IsPmtPid(Pid))
1849  }
1850 
1851  TotalPackets++;
1852  bool Drop = false;
1853  if (Pid == vpid || (pPatPmtParser && Pid == pPatPmtParser->Vpid() && pPatPmtParser->Vtype() == 0x1B))
1855  if (!Drop)
1856  {
1857  // Keep this packet, then continue with new data
1858  tempLength = 0;
1859  OutLength = TS_SIZE;
1860  return tempBuffer;
1861  }
1862  // Drop TempBuffer
1863  DroppedPackets++;
1864  tempLength = 0;
1865  }
1866  // Now: TempLength==0, just process data/length
1867 
1868  // Pointer to processed data / length:
1869  uchar *Out = data;
1870  uchar *OutEnd = Out;
1871 
1872  while (length >= TS_SIZE)
1873  {
1874  if (data[0] != TS_SYNC_BYTE) {
1875  int Skipped = 1;
1876  while (Skipped < length && (data[Skipped] != TS_SYNC_BYTE || (length - Skipped > TS_SIZE && data[Skipped + TS_SIZE] != TS_SYNC_BYTE)))
1877  Skipped++;
1878  esyslog("ERROR: skipped %d bytes to sync on start of TS packet", Skipped);
1879 
1880  // Pass through skipped bytes
1881  if (OutEnd != data)
1882  memcpy(OutEnd, data, Skipped);
1883  OutEnd += Skipped;
1884  continue;
1885  }
1886  // Now: Data starts with complete TS packet
1887 
1888  int Pid = TsPid(data);
1889  if (pPatPmtParser)
1890  {
1891  if (Pid == 0)
1893  else if (pPatPmtParser->IsPmtPid(Pid))
1895  }
1896 
1897  TotalPackets++;
1898  bool Drop = false;
1899  if (Pid == vpid || (pPatPmtParser && Pid == pPatPmtParser->Vpid() && pPatPmtParser->Vtype() == 0x1B))
1901  if (!Drop)
1902  {
1903  if (OutEnd != data)
1904  memcpy(OutEnd, data, TS_SIZE);
1905  OutEnd += TS_SIZE;
1906  }
1907  else
1908  {
1909  DroppedPackets++;
1910  }
1911  data += TS_SIZE;
1912  length -= TS_SIZE;
1913  }
1914  // Now: Less than a packet remains.
1915  if (length > 0)
1916  {
1917  // copy remains into temp buffer
1918  memcpy(tempBuffer, data, length);
1919  tempLength = length;
1920  tempLengthAtEnd = false;
1921  length = 0;
1922  }
1923  OutLength = (OutEnd - Out);
1924  return OutLength > 0 ? Out : NULL;
1925 }
int framesInPayloadUnit
Definition: remux.h:498
#define VIDEO_STREAM_S
Definition: remux.c:94
uint16_t AncillaryPageId(int i) const
Definition: channels.h:181
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:926
unsigned char uchar
Definition: tools.h:30
void ParsePat(const uchar *Data, int Length)
Parses the PAT data from the single TS packet in Data.
Definition: remux.c:647
uchar * data
Definition: remux.h:222
int Used(void)
Returns the number of raw bytes that have already been used (e.g.
Definition: remux.h:249
uchar GetBit(void)
Definition: remux.c:1275
int Vpid(void) const
Definition: channels.h:165
bool separate_colour_plane_flag
Definition: remux.c:1218
uchar GetByte(void)
Gets the next byte of the TS payload, skipping any intermediate TS header data.
Definition: remux.c:250
const int * Dpids(void) const
Definition: channels.h:169
bool repeatLast
Definition: remux.h:435
int vpid
Definition: remux.h:348
int index
Definition: remux.h:225
int pid
Definition: remux.h:224
uchar subtitlingTypes[MAXSPIDS]
Definition: remux.h:360
Definition: device.h:66
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:599
#define dsyslog(a...)
Definition: tools.h:36
bool TsError(const uchar *p)
Definition: remux.h:80
void SetPid(int Pid, int Type)
Sets the Pid and stream Type to detect frames for.
Definition: remux.c:1457
#define DEFAULTFRAMESPERSECOND
Definition: recording.h:210
bool newFrame
Definition: remux.c:1094
int Dtype(int i) const
Definition: channels.h:178
int PesPayloadOffset(const uchar *p)
Definition: remux.h:172
void IncCounter(int &Counter, uchar *TsPacket)
Definition: remux.c:363
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:279
bool TsHasAdaptationField(const uchar *p)
Definition: remux.h:70
bool getCurrentNextIndicator() const
Definition: si.c:80
void ParsePmt(const uchar *Data, int Length)
Parses the PMT data from the single TS packet in Data.
Definition: remux.c:679
uint16_t ancillaryPageIds[MAXSPIDS]
Definition: remux.h:362
bool IsPmtPid(int Pid) const
Returns true if Pid the one of the PMT pids as defined by the current PAT.
Definition: remux.h:390
int framesPerPayloadUnit
Definition: remux.h:499
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:1159
int pmtSize
Definition: remux.h:344
uchar SubtitlingType(int i) const
Definition: channels.h:179
char alangs[MAXAPIDS][MAXLANGCODE2]
Definition: remux.h:354
bool IndependentFrame(void)
Definition: remux.c:1108
int Spid(int i) const
Definition: channels.h:173
cNaluDumper NaluDumper
Definition: remux.h:583
#define SETPID(p)
#define MAX33BIT
Definition: remux.h:57
int TotalTeletextSubtitlePages() const
Definition: channels.h:184
int LastContinuityInput
Definition: remux.h:536
bool TsPayloadStart(const uchar *p)
Definition: remux.h:75
int Dpid(int i) const
Definition: channels.h:172
uint32_t scanner
Definition: remux.c:1216
bool gotAccessUnitDelimiter
Definition: remux.c:1222
int MakeLanguageDescriptor(uchar *Target, const char *Language)
Definition: remux.c:447
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:481
int64_t PesGetPts(const uchar *p)
Definition: remux.h:187
int NaluOffset
Definition: remux.h:545
int Analyze(const uchar *Data, int Length)
Analyzes the TS packets pointed to by Data.
Definition: remux.c:1474
uchar pat[TS_SIZE]
Definition: remux.h:287
bool debug
Definition: remux.c:1093
bool TsHasPayload(const uchar *p)
Definition: remux.h:60
bool DropAllPayload
Definition: remux.h:540
StructureLoop< Association > associationLoop
Definition: section.h:39
uint32_t ptsValues[MaxPtsValues]
Definition: remux.h:492
#define esyslog(a...)
Definition: tools.h:34
StructureLoop< Stream > streamLoop
Definition: section.h:71
char slangs[MAXSPIDS][MAXLANGCODE2]
Definition: remux.h:359
#define TS_ADAPT_FIELD_EXISTS
Definition: remux.h:40
char * strn0cpy(char *dest, const char *src, size_t n)
Definition: tools.c:131
static u_int32_t crc32(const char *d, int len, u_int32_t CRCvalue)
Definition: util.c:267
void IncEsInfoLength(int Length)
Definition: remux.c:376
int MakeCRC(uchar *Target, const uchar *Data, int Length)
Definition: remux.c:466
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:950
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:393
T max(T a, T b)
Definition: tools.h:55
int MakeTeletextDescriptor(uchar *Target, const tTeletextSubtitlePage *pages, int pageCount)
Definition: remux.c:424
#define MAXTXTPAGES
Definition: channels.h:38
void SetChannel(const cChannel *Channel)
Sets the Channel for which the PAT/PMT shall be generated.
Definition: remux.c:605
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:243
bool PesHasPts(const uchar *p)
Definition: remux.h:177
#define PTSTICKS
Definition: remux.h:55
cPatPmtGenerator(const cChannel *Channel=NULL)
Definition: remux.c:353
int MakeSubtitlingDescriptor(uchar *Target, const char *Language, uchar SubtitlingType, uint16_t CompositionPageId, uint16_t AncillaryPageId)
Definition: remux.c:407
DescriptorTag getDescriptorTag() const
Definition: si.c:100
int length
Definition: remux.h:431
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:242
int PesOffset
Definition: remux.h:543
int getServiceId() const
Definition: section.c:57
StructureLoop< Teletext > teletextLoop
Definition: descriptor.h:138
const char * Dlang(int i) const
Definition: channels.h:175
StructureLoop< Subtitling > subtitlingLoop
Definition: descriptor.h:331
bool isVideo
Definition: remux.h:496
void ParseSequenceParameterSet(void)
Definition: remux.c:1359
int pmtVersion
Definition: remux.h:346
int64_t TsGetDts(const uchar *p, int l)
Definition: remux.c:156
int numPtsValues
Definition: remux.h:493
void TsExtendAdaptionField(unsigned char *Packet, int ToLength)
Definition: remux.c:315
bool independentFrame
Definition: remux.c:1095
cPatPmtParser * pPatPmtParser
Definition: remux.h:582
int Ppid(void) const
Definition: channels.h:166
T min(T a, T b)
Definition: tools.h:54
bool independentFrame
Definition: remux.h:491
#define TS_SYNC_BYTE
Definition: remux.h:33
int lastLength
Definition: remux.h:434
int MakeAC3Descriptor(uchar *Target, uchar Type)
Definition: remux.c:397
tTeletextSubtitlePage teletextSubtitlePages[MAXTXTPAGES]
Definition: remux.h:365
static bool DebugPatPmt
Definition: remux.c:20
void GeneratePat(void)
Generates a PAT section for later use with GetPat().
Definition: remux.c:496
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:302
#define dbgpatpmt(a...)
Definition: remux.c:23
cFrameParser(void)
Definition: remux.c:1111
int SectionLength(const uchar *Data, int Length)
Definition: remux.h:367
int Available(void)
Returns the number of raw bytes (including any TS headers) still available in the TS payload handler...
Definition: remux.h:246
int MakeStream(uchar *Target, uchar Type, int Pid)
Definition: remux.c:385
int getPid() const
Definition: section.c:65
uchar GetByte(bool Raw=false)
Gets the next data byte.
Definition: remux.c:1256
int patCounter
Definition: remux.h:290
bool Eof(void) const
Returns true if all available bytes of the TS payload have been processed.
Definition: remux.h:253
uchar pmt[MAX_PMT_TS][TS_SIZE]
Definition: remux.h:288
uchar * lastData
Definition: remux.h:433
const char * Alang(int i) const
Definition: channels.h:174
bool PesLongEnough(int Length)
Definition: remux.h:157
void TsSetPcr(uchar *p, int64_t Pcr)
Definition: remux.c:127
#define MAX_SECTION_SIZE
Definition: remux.h:282
#define EMPTY_SCANNER
Definition: remux.c:26
int TsPid(const uchar *p)
Definition: remux.h:85
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:1312
int getPid() const
Definition: section.c:34
long long int DroppedPackets
Definition: remux.h:586
cFrameDetector(int Pid=0, int Type=0)
Sets up a frame detector for the given Pid and stream Type.
Definition: remux.c:1437
#define SETPIDS(l)
void ParseSliceHeader(void)
Definition: remux.c:1411
double framesPerSecond
Definition: remux.h:497
void EnsureSubtitleTrack(void)
Makes sure one of the preferred language subtitle tracks is selected.
Definition: device.c:1083
#define TS_PAYLOAD_EXISTS
Definition: remux.h:41
int getSectionNumber() const
Definition: si.c:88
int PesLength(const uchar *p)
Definition: remux.h:167
void PesSetPts(uchar *p, int64_t Pts)
Definition: remux.c:199
void ParseAccessUnitDelimiter(void)
Definition: remux.c:1352
Definition: remux.h:20
int zeroBytes
Definition: remux.c:1215
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:399
int ppid
Definition: remux.h:349
int TsContinuityCounter(const uchar *p)
Definition: remux.h:121
cH264Parser(void)
Sets up a new H.264 parser.
Definition: remux.c:1243
char dlangs[MAXDPIDS][MAXLANGCODE2]
Definition: remux.h:357
void Reset(void)
Resets the converter.
Definition: remux.c:1048
int ContinuityOffset
Definition: remux.h:538
#define MAXPID
Definition: remux.c:479
bool synced
Definition: remux.h:489
bool PesHasDts(const uchar *p)
Definition: remux.h:182
void PesSetDts(uchar *p, int64_t Dts)
Definition: remux.c:208
void BlockDump(const char *Name, const u_char *Data, int Length)
Definition: remux.c:1058
void TsSetDts(uchar *p, int l, int64_t Dts)
Definition: remux.c:183
const tTeletextSubtitlePage * TeletextSubtitlePages() const
Definition: channels.h:183
cPatPmtParser(bool UpdatePrimaryDevice=false)
Definition: remux.c:631
int Tpid(void) const
Definition: channels.h:182
int GetLastIndex(void)
Returns the index into the TS data of the payload byte that has most recently been read...
Definition: remux.c:291
int PesId
Definition: remux.h:542
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.
cTsPayload(void)
Definition: remux.c:229
int dtypes[MAXDPIDS+1]
Definition: remux.h:356
int dpids[MAXDPIDS+1]
Definition: remux.h:355
void TsDump(const char *Name, const u_char *Data, int Length)
Definition: remux.c:1069
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:1130
int64_t PtsDiff(int64_t Pts1, int64_t Pts2)
Returns the difference between two PTS values.
Definition: remux.c:217
void PutTs(const uchar *Data, int Length)
Puts the payload data of the single TS packet at Data into the converter.
Definition: remux.c:966
void ClrAvailableTracks(bool DescriptionsOnly=false, bool IdsOnly=false)
Clears the list of currently available tracks.
Definition: device.c:927
ePesHeader AnalyzePesHeader(const uchar *Data, int Count, int &PesPayloadOffset, bool *ContinuationHeader)
Definition: remux.c:28
int atypes[MAXAPIDS+1]
Definition: remux.h:353
unsigned int History
Definition: remux.h:534
uchar byte
Definition: remux.c:1213
uchar * GetPmt(int &Index)
Returns a pointer to the Index'th TS packet of the PMT section.
Definition: remux.c:620
int Atype(int i) const
Definition: channels.h:177
void TsSetContinuityCounter(uchar *p, uchar Counter)
Definition: remux.h:100
int numPmtPackets
Definition: remux.h:289
cSetup Setup
Definition: config.c:373
void reset()
Definition: remux.c:1594
void ProcessPayload(unsigned char *Payload, int size, bool PayloadStart, sPayloadInfo &Info)
Definition: remux.c:1606
StructureLoop< Language > languageLoop
Definition: descriptor.h:489
~cTsToPes()
Definition: remux.c:961
#define MAXLANGCODE1
Definition: channels.h:40
int TsGetPayload(const uchar **p)
Definition: remux.h:111
#define MAXPESLENGTH
Definition: remux.c:993
int pmtCounter
Definition: remux.h:291
int LastContinuityOutput
Definition: remux.h:537
long long int TotalPackets
Definition: remux.h:585
void GeneratePmt(const cChannel *Channel)
Generates a PMT section for the given Channel, for later use with GetPmt().
Definition: remux.c:525
uchar pmt[MAX_SECTION_SIZE]
Definition: remux.h:343
int32_t GetGolombSe(void)
Definition: remux.c:1300
void TsHidePayload(uchar *p)
Definition: remux.c:117
#define P_TSID
Definition: remux.c:477
int length
Definition: remux.h:223
#define TS_CONT_CNT_MASK
Definition: remux.h:42
uint16_t compositionPageIds[MAXSPIDS]
Definition: remux.h:361
int getStreamType() const
Definition: section.c:69
void PesDump(const char *Name, const u_char *Data, int Length)
Definition: remux.c:1084
int pmtPids[MAX_PMT_PIDS+1]
Definition: remux.h:347
bool CheckCRCAndParse()
Definition: si.c:65
bool isNITPid() const
Definition: section.h:31
uint32_t GetBits(int Bits)
Definition: remux.c:1284
bool frame_mbs_only_flag
Definition: remux.c:1220
static void SetBrokenLink(uchar *Data, int Length)
Definition: remux.c:98
char ttxtLanguage[MAXLANGCODE1]
Definition: channels.h:78
virtual ~cFrameParser()
Definition: remux.c:1098
static bool DebugFrames
Definition: remux.c:21
Definition: device.h:69
bool seenIndependentFrame
Definition: remux.c:1147
const int * Apids(void) const
Definition: channels.h:168
int getServiceId() const
Definition: section.c:30
int patVersion
Definition: remux.h:292
int UseDolbyDigital
Definition: config.h:308
cFrameParser * parser
Definition: remux.h:502
bool ProcessTSPacket(unsigned char *Packet)
Definition: remux.c:1693
#define MAXDPIDS
Definition: channels.h:35
int spids[MAXSPIDS+1]
Definition: remux.h:358
#define MIN_TS_PACKETS_FOR_FRAME_DETECTOR
Definition: remux.h:480
int size
Definition: remux.h:430
#define PCRFACTOR
Definition: remux.h:56
void EnsureAudioTrack(bool Force=false)
Makes sure an audio track is selected that is actually available.
Definition: device.c:1050
#define PATPID
Definition: remux.h:52
#define MAX_PMT_PIDS
Definition: remux.h:339
static cDevice * PrimaryDevice(void)
Returns the primary device.
Definition: device.h:132
int getVersionNumber() const
Definition: si.c:84
bool PesHasLength(const uchar *p)
Definition: remux.h:162
#define P_PMT_PID
Definition: remux.c:478
int64_t TsGetPts(const uchar *p, int l)
Definition: remux.c:143
#define KILOBYTE(n)
Definition: tools.h:43
uint16_t CompositionPageId(int i) const
Definition: channels.h:180
int Apid(int i) const
Definition: channels.h:171
unsigned char u_char
Definition: headers.h:24
int getLastSectionNumber() const
Definition: si.c:92
int getPCRPid() const
Definition: section.c:61
int totalTtxtSubtitlePages
Definition: remux.h:364
bool TsIsScrambled(const uchar *p)
Definition: remux.h:90
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:945
int64_t PesGetDts(const uchar *p)
Definition: remux.h:196
cTsPayload tsPayload
Definition: remux.c:1212
ePesHeader
Definition: remux.h:16
void SetByte(uchar Byte, int Index)
Sets the TS data byte at the given Index to the value Byte.
Definition: remux.c:296
int tpid
Definition: remux.h:351
cNaluDumper()
Definition: remux.c:1588
int getTransportStreamId() const
Definition: section.c:26
uchar * esInfoLength
Definition: remux.h:295
#define TS_PAYLOAD_START
Definition: remux.h:36
bool updatePrimaryDevice
Definition: remux.h:363
DescriptorLoop streamDescriptors
Definition: section.h:63
#define MAXSPIDS
Definition: channels.h:36
eNaluFillState NaluFillState
Definition: remux.h:554
bool newFrame
Definition: remux.h:490
bool gotSequenceParameterSet
Definition: remux.c:1223
const char * Slang(int i) const
Definition: channels.h:176
#define TS_SIZE
Definition: remux.h:34
cMpeg2Parser(void)
Definition: remux.c:1153
Definition: remux.h:19
void IncVersion(int &Version)
Definition: remux.c:370
const int * Spids(void) const
Definition: channels.h:170
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:995
uint32_t GetGolombUe(void)
Definition: remux.c:1292
int bit
Definition: remux.c:1214
int log2_max_frame_num
Definition: remux.c:1219
void SetDebug(bool Debug)
Definition: remux.c:1106
int TsPayloadOffset(const uchar *p)
Definition: remux.h:105
bool scanning
Definition: remux.h:501
int offset
Definition: remux.h:432
#define TS_ADAPT_PCR
Definition: remux.h:46
int numIFrames
Definition: remux.h:495
int getTeletextMagazineNumber() const
Definition: descriptor.c:338
bool NewFrame(void)
Definition: remux.c:1107
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:1043
bool AtTsStart(void)
Returns true if this payload handler is currently pointing to first byte of a TS packet.
Definition: remux.h:240
void TsSetPts(uchar *p, int l, int64_t Pts)
Definition: remux.c:169
const char * I18nNormalizeLanguageCode(const char *Code)
Returns a 3 letter language code that may not be zero terminated.
Definition: i18n.c:238
static int CmpUint32(const void *p1, const void *p2)
Definition: remux.c:1450
void PutBuffer(uchar *Data, int Length)
Definition: remux.c:1786
void Reset(void)
Resets the parser.
Definition: remux.c:637
int Vtype(void) const
Definition: channels.h:167
Descriptor * getNext(Iterator &it)
Definition: si.c:112
uchar * data
Definition: remux.h:429
uchar * GetPat(void)
Returns a pointer to the PAT section, which consists of exactly one TS packet.
Definition: remux.c:614
uchar * GetBuffer(int &OutLength)
Definition: remux.c:1795
int patVersion
Definition: remux.h:345
int vtype
Definition: remux.h:350
#define dbgframes(a...)
Definition: remux.c:24
int pmtVersion
Definition: remux.h:293
bool SkipPesHeader(void)
Skips all bytes belonging to the PES header of the payload.
Definition: remux.c:286
uint32_t scanner
Definition: remux.c:1146
cTsToPes(void)
Definition: remux.c:954
int apids[MAXAPIDS+1]
Definition: remux.h:352
#define MAXAPIDS
Definition: channels.h:34
uchar tempBuffer[TS_SIZE]
Definition: remux.h:579
cAudioParser(void)
Definition: remux.c:1126
bool tempLengthAtEnd
Definition: remux.h:581