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