vdr  1.7.31
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.67 2012/09/19 10:28:42 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 ePesHeader AnalyzePesHeader(const uchar *Data, int Count, int &PesPayloadOffset, bool *ContinuationHeader)
27 {
28  if (Count < 7)
29  return phNeedMoreData; // too short
30 
31  if ((Data[6] & 0xC0) == 0x80) { // MPEG 2
32  if (Count < 9)
33  return phNeedMoreData; // too short
34 
35  PesPayloadOffset = 6 + 3 + Data[8];
36  if (Count < PesPayloadOffset)
37  return phNeedMoreData; // too short
38 
39  if (ContinuationHeader)
40  *ContinuationHeader = ((Data[6] == 0x80) && !Data[7] && !Data[8]);
41 
42  return phMPEG2; // MPEG 2
43  }
44 
45  // check for MPEG 1 ...
46  PesPayloadOffset = 6;
47 
48  // skip up to 16 stuffing bytes
49  for (int i = 0; i < 16; i++) {
50  if (Data[PesPayloadOffset] != 0xFF)
51  break;
52 
53  if (Count <= ++PesPayloadOffset)
54  return phNeedMoreData; // too short
55  }
56 
57  // skip STD_buffer_scale/size
58  if ((Data[PesPayloadOffset] & 0xC0) == 0x40) {
59  PesPayloadOffset += 2;
60 
61  if (Count <= PesPayloadOffset)
62  return phNeedMoreData; // too short
63  }
64 
65  if (ContinuationHeader)
66  *ContinuationHeader = false;
67 
68  if ((Data[PesPayloadOffset] & 0xF0) == 0x20) {
69  // skip PTS only
70  PesPayloadOffset += 5;
71  }
72  else if ((Data[PesPayloadOffset] & 0xF0) == 0x30) {
73  // skip PTS and DTS
74  PesPayloadOffset += 10;
75  }
76  else if (Data[PesPayloadOffset] == 0x0F) {
77  // continuation header
78  PesPayloadOffset++;
79 
80  if (ContinuationHeader)
81  *ContinuationHeader = true;
82  }
83  else
84  return phInvalid; // unknown
85 
86  if (Count < PesPayloadOffset)
87  return phNeedMoreData; // too short
88 
89  return phMPEG1; // MPEG 1
90 }
91 
92 #define VIDEO_STREAM_S 0xE0
93 
94 // --- cRemux ----------------------------------------------------------------
95 
96 void cRemux::SetBrokenLink(uchar *Data, int Length)
97 {
98  int PesPayloadOffset = 0;
99  if (AnalyzePesHeader(Data, Length, PesPayloadOffset) >= phMPEG1 && (Data[3] & 0xF0) == VIDEO_STREAM_S) {
100  for (int i = PesPayloadOffset; i < Length - 7; i++) {
101  if (Data[i] == 0 && Data[i + 1] == 0 && Data[i + 2] == 1 && Data[i + 3] == 0xB8) {
102  if (!(Data[i + 7] & 0x40)) // set flag only if GOP is not closed
103  Data[i + 7] |= 0x20;
104  return;
105  }
106  }
107  dsyslog("SetBrokenLink: no GOP header found in video packet");
108  }
109  else
110  dsyslog("SetBrokenLink: no video packet in frame");
111 }
112 
113 // --- Some TS handling tools ------------------------------------------------
114 
115 int64_t TsGetPts(const uchar *p, int l)
116 {
117  // Find the first packet with a PTS and use it:
118  while (l > 0) {
119  const uchar *d = p;
120  if (TsPayloadStart(d) && TsGetPayload(&d) && PesHasPts(d))
121  return PesGetPts(d);
122  p += TS_SIZE;
123  l -= TS_SIZE;
124  }
125  return -1;
126 }
127 
129 {
130  bool Processed[MAXPID] = { false };
131  while (l >= TS_SIZE) {
132  if (*p != TS_SYNC_BYTE)
133  break;
134  int Pid = TsPid(p);
135  if (!Processed[Pid]) {
136  if (!TsPayloadStart(p))
137  p[1] |= TS_ERROR;
138  else {
139  Processed[Pid] = true;
140  int offs = TsPayloadOffset(p);
141  cRemux::SetBrokenLink(p + offs, TS_SIZE - offs);
142  }
143  }
144  l -= TS_SIZE;
145  p += TS_SIZE;
146  }
147 }
148 
149 // --- cPatPmtGenerator ------------------------------------------------------
150 
152 {
153  numPmtPackets = 0;
154  patCounter = pmtCounter = 0;
155  patVersion = pmtVersion = 0;
156  pmtPid = 0;
157  esInfoLength = NULL;
158  SetChannel(Channel);
159 }
160 
161 void cPatPmtGenerator::IncCounter(int &Counter, uchar *TsPacket)
162 {
163  TsPacket[3] = (TsPacket[3] & 0xF0) | Counter;
164  if (++Counter > 0x0F)
165  Counter = 0x00;
166 }
167 
169 {
170  if (++Version > 0x1F)
171  Version = 0x00;
172 }
173 
175 {
176  if (esInfoLength) {
177  Length += ((*esInfoLength & 0x0F) << 8) | *(esInfoLength + 1);
178  *esInfoLength = 0xF0 | (Length >> 8);
179  *(esInfoLength + 1) = Length;
180  }
181 }
182 
183 int cPatPmtGenerator::MakeStream(uchar *Target, uchar Type, int Pid)
184 {
185  int i = 0;
186  Target[i++] = Type; // stream type
187  Target[i++] = 0xE0 | (Pid >> 8); // dummy (3), pid hi (5)
188  Target[i++] = Pid; // pid lo
189  esInfoLength = &Target[i];
190  Target[i++] = 0xF0; // dummy (4), ES info length hi
191  Target[i++] = 0x00; // ES info length lo
192  return i;
193 }
194 
196 {
197  int i = 0;
198  Target[i++] = Type;
199  Target[i++] = 0x01; // length
200  Target[i++] = 0x00;
201  IncEsInfoLength(i);
202  return i;
203 }
204 
205 int cPatPmtGenerator::MakeSubtitlingDescriptor(uchar *Target, const char *Language, uchar SubtitlingType, uint16_t CompositionPageId, uint16_t AncillaryPageId)
206 {
207  int i = 0;
208  Target[i++] = SI::SubtitlingDescriptorTag;
209  Target[i++] = 0x08; // length
210  Target[i++] = *Language++;
211  Target[i++] = *Language++;
212  Target[i++] = *Language++;
213  Target[i++] = SubtitlingType;
214  Target[i++] = CompositionPageId >> 8;
215  Target[i++] = CompositionPageId & 0xFF;
216  Target[i++] = AncillaryPageId >> 8;
217  Target[i++] = AncillaryPageId & 0xFF;
218  IncEsInfoLength(i);
219  return i;
220 }
221 
223 {
224  int i = 0, j = 0;
225  Target[i++] = SI::TeletextDescriptorTag;
226  int l = i;
227  Target[i++] = 0x00; // length
228  for (int n = 0; n < pageCount; n++) {
229  const char* Language = pages[n].ttxtLanguage;
230  Target[i++] = *Language++;
231  Target[i++] = *Language++;
232  Target[i++] = *Language++;
233  Target[i++] = (pages[n].ttxtType << 3) + pages[n].ttxtMagazine;
234  Target[i++] = pages[n].ttxtPage;
235  j++;
236  }
237  if (j > 0) {
238  Target[l] = j * 5; // update length
239  IncEsInfoLength(i);
240  return i;
241  }
242  return 0;
243 }
244 
245 int cPatPmtGenerator::MakeLanguageDescriptor(uchar *Target, const char *Language)
246 {
247  int i = 0;
248  Target[i++] = SI::ISO639LanguageDescriptorTag;
249  int Length = i++;
250  Target[Length] = 0x00; // length
251  for (const char *End = Language + strlen(Language); Language < End; ) {
252  Target[i++] = *Language++;
253  Target[i++] = *Language++;
254  Target[i++] = *Language++;
255  Target[i++] = 0x00; // audio type
256  Target[Length] += 0x04; // length
257  if (*Language == '+')
258  Language++;
259  }
260  IncEsInfoLength(i);
261  return i;
262 }
263 
264 int cPatPmtGenerator::MakeCRC(uchar *Target, const uchar *Data, int Length)
265 {
266  int crc = SI::CRC32::crc32((const char *)Data, Length, 0xFFFFFFFF);
267  int i = 0;
268  Target[i++] = crc >> 24;
269  Target[i++] = crc >> 16;
270  Target[i++] = crc >> 8;
271  Target[i++] = crc;
272  return i;
273 }
274 
275 #define P_TSID 0x8008 // pseudo TS ID
276 #define P_PMT_PID 0x0084 // pseudo PMT pid
277 #define MAXPID 0x2000 // the maximum possible number of pids
278 
280 {
281  bool Used[MAXPID] = { false };
282 #define SETPID(p) { if ((p) >= 0 && (p) < MAXPID) Used[p] = true; }
283 #define SETPIDS(l) { const int *p = l; while (*p) { SETPID(*p); p++; } }
284  SETPID(Channel->Vpid());
285  SETPID(Channel->Ppid());
286  SETPID(Channel->Tpid());
287  SETPIDS(Channel->Apids());
288  SETPIDS(Channel->Dpids());
289  SETPIDS(Channel->Spids());
290  for (pmtPid = P_PMT_PID; Used[pmtPid]; pmtPid++)
291  ;
292 }
293 
295 {
296  memset(pat, 0xFF, sizeof(pat));
297  uchar *p = pat;
298  int i = 0;
299  p[i++] = TS_SYNC_BYTE; // TS indicator
300  p[i++] = TS_PAYLOAD_START | (PATPID >> 8); // flags (3), pid hi (5)
301  p[i++] = PATPID & 0xFF; // pid lo
302  p[i++] = 0x10; // flags (4), continuity counter (4)
303  p[i++] = 0x00; // pointer field (payload unit start indicator is set)
304  int PayloadStart = i;
305  p[i++] = 0x00; // table id
306  p[i++] = 0xB0; // section syntax indicator (1), dummy (3), section length hi (4)
307  int SectionLength = i;
308  p[i++] = 0x00; // section length lo (filled in later)
309  p[i++] = P_TSID >> 8; // TS id hi
310  p[i++] = P_TSID & 0xFF; // TS id lo
311  p[i++] = 0xC1 | (patVersion << 1); // dummy (2), version number (5), current/next indicator (1)
312  p[i++] = 0x00; // section number
313  p[i++] = 0x00; // last section number
314  p[i++] = pmtPid >> 8; // program number hi
315  p[i++] = pmtPid & 0xFF; // program number lo
316  p[i++] = 0xE0 | (pmtPid >> 8); // dummy (3), PMT pid hi (5)
317  p[i++] = pmtPid & 0xFF; // PMT pid lo
318  pat[SectionLength] = i - SectionLength - 1 + 4; // -2 = SectionLength storage, +4 = length of CRC
319  MakeCRC(pat + i, pat + PayloadStart, i - PayloadStart);
321 }
322 
324 {
325  // generate the complete PMT section:
326  uchar buf[MAX_SECTION_SIZE];
327  memset(buf, 0xFF, sizeof(buf));
328  numPmtPackets = 0;
329  if (Channel) {
330  int Vpid = Channel->Vpid();
331  int Ppid = Channel->Ppid();
332  int Tpid = Channel->Tpid();
333  uchar *p = buf;
334  int i = 0;
335  p[i++] = 0x02; // table id
336  int SectionLength = i;
337  p[i++] = 0xB0; // section syntax indicator (1), dummy (3), section length hi (4)
338  p[i++] = 0x00; // section length lo (filled in later)
339  p[i++] = pmtPid >> 8; // program number hi
340  p[i++] = pmtPid & 0xFF; // program number lo
341  p[i++] = 0xC1 | (pmtVersion << 1); // dummy (2), version number (5), current/next indicator (1)
342  p[i++] = 0x00; // section number
343  p[i++] = 0x00; // last section number
344  p[i++] = 0xE0 | (Ppid >> 8); // dummy (3), PCR pid hi (5)
345  p[i++] = Ppid; // PCR pid lo
346  p[i++] = 0xF0; // dummy (4), program info length hi (4)
347  p[i++] = 0x00; // program info length lo
348 
349  if (Vpid)
350  i += MakeStream(buf + i, Channel->Vtype(), Vpid);
351  for (int n = 0; Channel->Apid(n); n++) {
352  i += MakeStream(buf + i, Channel->Atype(n), Channel->Apid(n));
353  const char *Alang = Channel->Alang(n);
354  i += MakeLanguageDescriptor(buf + i, Alang);
355  }
356  for (int n = 0; Channel->Dpid(n); n++) {
357  i += MakeStream(buf + i, 0x06, Channel->Dpid(n));
358  i += MakeAC3Descriptor(buf + i, Channel->Dtype(n));
359  i += MakeLanguageDescriptor(buf + i, Channel->Dlang(n));
360  }
361  for (int n = 0; Channel->Spid(n); n++) {
362  i += MakeStream(buf + i, 0x06, Channel->Spid(n));
363  i += MakeSubtitlingDescriptor(buf + i, Channel->Slang(n), Channel->SubtitlingType(n), Channel->CompositionPageId(n), Channel->AncillaryPageId(n));
364  }
365  if (Tpid) {
366  i += MakeStream(buf + i, 0x06, Tpid);
367  i += MakeTeletextDescriptor(buf + i, Channel->TeletextSubtitlePages(), Channel->TotalTeletextSubtitlePages());
368  }
369 
370  int sl = i - SectionLength - 2 + 4; // -2 = SectionLength storage, +4 = length of CRC
371  buf[SectionLength] |= (sl >> 8) & 0x0F;
372  buf[SectionLength + 1] = sl;
373  MakeCRC(buf + i, buf, i);
374  // split the PMT section into several TS packets:
375  uchar *q = buf;
376  bool pusi = true;
377  while (i > 0) {
378  uchar *p = pmt[numPmtPackets++];
379  int j = 0;
380  p[j++] = TS_SYNC_BYTE; // TS indicator
381  p[j++] = (pusi ? TS_PAYLOAD_START : 0x00) | (pmtPid >> 8); // flags (3), pid hi (5)
382  p[j++] = pmtPid & 0xFF; // pid lo
383  p[j++] = 0x10; // flags (4), continuity counter (4)
384  if (pusi) {
385  p[j++] = 0x00; // pointer field (payload unit start indicator is set)
386  pusi = false;
387  }
388  int l = TS_SIZE - j;
389  memcpy(p + j, q, l);
390  q += l;
391  i -= l;
392  }
394  }
395 }
396 
397 void cPatPmtGenerator::SetVersions(int PatVersion, int PmtVersion)
398 {
399  patVersion = PatVersion & 0x1F;
400  pmtVersion = PmtVersion & 0x1F;
401 }
402 
404 {
405  if (Channel) {
406  GeneratePmtPid(Channel);
407  GeneratePat();
408  GeneratePmt(Channel);
409  }
410 }
411 
413 {
415  return pat;
416 }
417 
419 {
420  if (Index < numPmtPackets) {
421  IncCounter(pmtCounter, pmt[Index]);
422  return pmt[Index++];
423  }
424  return NULL;
425 }
426 
427 // --- cPatPmtParser ---------------------------------------------------------
428 
429 cPatPmtParser::cPatPmtParser(bool UpdatePrimaryDevice)
430 {
431  updatePrimaryDevice = UpdatePrimaryDevice;
432  Reset();
433 }
434 
436 {
437  pmtSize = 0;
438  patVersion = pmtVersion = -1;
439  pmtPid = -1;
440  vpid = vtype = 0;
441  ppid = 0;
442  tpid = 0;
443 }
444 
445 void cPatPmtParser::ParsePat(const uchar *Data, int Length)
446 {
447  // Unpack the TS packet:
448  int PayloadOffset = TsPayloadOffset(Data);
449  Data += PayloadOffset;
450  Length -= PayloadOffset;
451  // The PAT is always assumed to fit into a single TS packet
452  if ((Length -= Data[0] + 1) <= 0)
453  return;
454  Data += Data[0] + 1; // process pointer_field
455  SI::PAT Pat(Data, false);
456  if (Pat.CheckCRCAndParse()) {
457  dbgpatpmt("PAT: TSid = %d, c/n = %d, v = %d, s = %d, ls = %d\n", Pat.getTransportStreamId(), Pat.getCurrentNextIndicator(), Pat.getVersionNumber(), Pat.getSectionNumber(), Pat.getLastSectionNumber());
458  if (patVersion == Pat.getVersionNumber())
459  return;
460  SI::PAT::Association assoc;
461  for (SI::Loop::Iterator it; Pat.associationLoop.getNext(assoc, it); ) {
462  dbgpatpmt(" isNITPid = %d\n", assoc.isNITPid());
463  if (!assoc.isNITPid()) {
464  pmtPid = assoc.getPid();
465  dbgpatpmt(" service id = %d, pid = %d\n", assoc.getServiceId(), assoc.getPid());
466  }
467  }
469  }
470  else
471  esyslog("ERROR: can't parse PAT");
472 }
473 
474 void cPatPmtParser::ParsePmt(const uchar *Data, int Length)
475 {
476  // Unpack the TS packet:
477  bool PayloadStart = TsPayloadStart(Data);
478  int PayloadOffset = TsPayloadOffset(Data);
479  Data += PayloadOffset;
480  Length -= PayloadOffset;
481  // The PMT may extend over several TS packets, so we need to assemble them
482  if (PayloadStart) {
483  pmtSize = 0;
484  if ((Length -= Data[0] + 1) <= 0)
485  return;
486  Data += Data[0] + 1; // this is the first packet
487  if (SectionLength(Data, Length) > Length) {
488  if (Length <= int(sizeof(pmt))) {
489  memcpy(pmt, Data, Length);
490  pmtSize = Length;
491  }
492  else
493  esyslog("ERROR: PMT packet length too big (%d byte)!", Length);
494  return;
495  }
496  // the packet contains the entire PMT section, so we run into the actual parsing
497  }
498  else if (pmtSize > 0) {
499  // this is a following packet, so we add it to the pmt storage
500  if (Length <= int(sizeof(pmt)) - pmtSize) {
501  memcpy(pmt + pmtSize, Data, Length);
502  pmtSize += Length;
503  }
504  else {
505  esyslog("ERROR: PMT section length too big (%d byte)!", pmtSize + Length);
506  pmtSize = 0;
507  }
509  return; // more packets to come
510  // the PMT section is now complete, so we run into the actual parsing
511  Data = pmt;
512  }
513  else
514  return; // fragment of broken packet - ignore
515  SI::PMT Pmt(Data, false);
516  if (Pmt.CheckCRCAndParse()) {
517  dbgpatpmt("PMT: sid = %d, c/n = %d, v = %d, s = %d, ls = %d\n", Pmt.getServiceId(), Pmt.getCurrentNextIndicator(), Pmt.getVersionNumber(), Pmt.getSectionNumber(), Pmt.getLastSectionNumber());
518  dbgpatpmt(" pcr = %d\n", Pmt.getPCRPid());
519  if (pmtVersion == Pmt.getVersionNumber())
520  return;
523  int NumApids = 0;
524  int NumDpids = 0;
525  int NumSpids = 0;
526  vpid = vtype = 0;
527  ppid = 0;
528  tpid = 0;
529  apids[0] = 0;
530  dpids[0] = 0;
531  spids[0] = 0;
532  atypes[0] = 0;
533  dtypes[0] = 0;
535  SI::PMT::Stream stream;
536  for (SI::Loop::Iterator it; Pmt.streamLoop.getNext(stream, it); ) {
537  dbgpatpmt(" stream type = %02X, pid = %d", stream.getStreamType(), stream.getPid());
538  switch (stream.getStreamType()) {
539  case 0x01: // STREAMTYPE_11172_VIDEO
540  case 0x02: // STREAMTYPE_13818_VIDEO
541  case 0x1B: // MPEG4
542  vpid = stream.getPid();
543  vtype = stream.getStreamType();
544  ppid = Pmt.getPCRPid();
545  break;
546  case 0x03: // STREAMTYPE_11172_AUDIO
547  case 0x04: // STREAMTYPE_13818_AUDIO
548  case 0x0F: // ISO/IEC 13818-7 Audio with ADTS transport syntax
549  case 0x11: // ISO/IEC 14496-3 Audio with LATM transport syntax
550  {
551  if (NumApids < MAXAPIDS) {
552  apids[NumApids] = stream.getPid();
553  atypes[NumApids] = stream.getStreamType();
554  *alangs[NumApids] = 0;
555  SI::Descriptor *d;
556  for (SI::Loop::Iterator it; (d = stream.streamDescriptors.getNext(it)); ) {
557  switch (d->getDescriptorTag()) {
561  char *s = alangs[NumApids];
562  int n = 0;
563  for (SI::Loop::Iterator it; ld->languageLoop.getNext(l, it); ) {
564  if (*ld->languageCode != '-') { // some use "---" to indicate "none"
565  dbgpatpmt(" '%s'", l.languageCode);
566  if (n > 0)
567  *s++ = '+';
569  s += strlen(s);
570  if (n++ > 1)
571  break;
572  }
573  }
574  }
575  break;
576  default: ;
577  }
578  delete d;
579  }
581  cDevice::PrimaryDevice()->SetAvailableTrack(ttAudio, NumApids, apids[NumApids], alangs[NumApids]);
582  NumApids++;
583  apids[NumApids]= 0;
584  }
585  }
586  break;
587  case 0x06: // STREAMTYPE_13818_PES_PRIVATE
588  {
589  int dpid = 0;
590  int dtype = 0;
591  char lang[MAXLANGCODE1] = "";
592  SI::Descriptor *d;
593  for (SI::Loop::Iterator it; (d = stream.streamDescriptors.getNext(it)); ) {
594  switch (d->getDescriptorTag()) {
597  dbgpatpmt(" AC3");
598  dpid = stream.getPid();
599  dtype = d->getDescriptorTag();
600  break;
602  dbgpatpmt(" subtitling");
603  if (NumSpids < MAXSPIDS) {
604  spids[NumSpids] = stream.getPid();
605  *slangs[NumSpids] = 0;
606  subtitlingTypes[NumSpids] = 0;
607  compositionPageIds[NumSpids] = 0;
608  ancillaryPageIds[NumSpids] = 0;
611  char *s = slangs[NumSpids];
612  int n = 0;
613  for (SI::Loop::Iterator it; sd->subtitlingLoop.getNext(sub, it); ) {
614  if (sub.languageCode[0]) {
615  dbgpatpmt(" '%s'", sub.languageCode);
616  subtitlingTypes[NumSpids] = sub.getSubtitlingType();
617  compositionPageIds[NumSpids] = sub.getCompositionPageId();
618  ancillaryPageIds[NumSpids] = sub.getAncillaryPageId();
619  if (n > 0)
620  *s++ = '+';
622  s += strlen(s);
623  if (n++ > 1)
624  break;
625  }
626  }
628  cDevice::PrimaryDevice()->SetAvailableTrack(ttSubtitle, NumSpids, spids[NumSpids], slangs[NumSpids]);
629  NumSpids++;
630  spids[NumSpids]= 0;
631  }
632  break;
634  dbgpatpmt(" teletext");
635  tpid = stream.getPid();
639  for (SI::Loop::Iterator it; sd->teletextLoop.getNext(ttxt, it); ) {
640  bool isSubtitlePage = (ttxt.getTeletextType() == 0x02) || (ttxt.getTeletextType() == 0x05);
641  if (isSubtitlePage && ttxt.languageCode[0]) {
642  dbgpatpmt(" '%s:%x.%x'", ttxt.languageCode, ttxt.getTeletextMagazineNumber(), ttxt.getTeletextPageNumber());
649  break;
650  }
651  }
652  }
653  }
654  break;
657  dbgpatpmt(" '%s'", ld->languageCode);
659  }
660  break;
661  default: ;
662  }
663  delete d;
664  }
665  if (dpid) {
666  if (NumDpids < MAXDPIDS) {
667  dpids[NumDpids] = dpid;
668  dtypes[NumDpids] = dtype;
669  strn0cpy(dlangs[NumDpids], lang, sizeof(dlangs[NumDpids]));
671  cDevice::PrimaryDevice()->SetAvailableTrack(ttDolby, NumDpids, dpid, lang);
672  NumDpids++;
673  dpids[NumDpids]= 0;
674  }
675  }
676  }
677  break;
678  case 0x81: // STREAMTYPE_USER_PRIVATE
679  {
680  dbgpatpmt(" AC3");
681  char lang[MAXLANGCODE1] = { 0 };
682  SI::Descriptor *d;
683  for (SI::Loop::Iterator it; (d = stream.streamDescriptors.getNext(it)); ) {
684  switch (d->getDescriptorTag()) {
687  dbgpatpmt(" '%s'", ld->languageCode);
689  }
690  break;
691  default: ;
692  }
693  delete d;
694  }
695  if (NumDpids < MAXDPIDS) {
696  dpids[NumDpids] = stream.getPid();
697  dtypes[NumDpids] = SI::AC3DescriptorTag;
698  strn0cpy(dlangs[NumDpids], lang, sizeof(dlangs[NumDpids]));
700  cDevice::PrimaryDevice()->SetAvailableTrack(ttDolby, NumDpids, stream.getPid(), lang);
701  NumDpids++;
702  dpids[NumDpids]= 0;
703  }
704  }
705  break;
706  default: ;
707  }
708  dbgpatpmt("\n");
709  if (updatePrimaryDevice) {
712  }
713  }
715  }
716  else
717  esyslog("ERROR: can't parse PMT");
718  pmtSize = 0;
719 }
720 
721 bool cPatPmtParser::GetVersions(int &PatVersion, int &PmtVersion) const
722 {
723  PatVersion = patVersion;
724  PmtVersion = pmtVersion;
725  return patVersion >= 0 && pmtVersion >= 0;
726 }
727 
728 // --- cTsToPes --------------------------------------------------------------
729 
731 {
732  data = NULL;
733  size = 0;
734  Reset();
735 }
736 
738 {
739  free(data);
740 }
741 
742 void cTsToPes::PutTs(const uchar *Data, int Length)
743 {
744  if (TsError(Data)) {
745  Reset();
746  return; // ignore packets with TEI set, and drop any PES data collected so far
747  }
748  if (TsPayloadStart(Data))
749  Reset();
750  else if (!size)
751  return; // skip everything before the first payload start
752  Length = TsGetPayload(&Data);
753  if (length + Length > size) {
754  int NewSize = max(KILOBYTE(2), length + Length);
755  if (uchar *NewData = (uchar *)realloc(data, NewSize)) {
756  data = NewData;
757  size = NewSize;
758  }
759  else {
760  esyslog("ERROR: out of memory");
761  Reset();
762  return;
763  }
764  }
765  memcpy(data + length, Data, Length);
766  length += Length;
767 }
768 
769 #define MAXPESLENGTH 0xFFF0
770 
771 const uchar *cTsToPes::GetPes(int &Length)
772 {
773  if (repeatLast) {
774  repeatLast = false;
775  Length = lastLength;
776  return lastData;
777  }
778  if (offset < length && PesLongEnough(length)) {
779  if (!PesHasLength(data)) // this is a video PES packet with undefined length
780  offset = 6; // trigger setting PES length for initial slice
781  if (offset) {
782  uchar *p = data + offset - 6;
783  if (p != data) {
784  p -= 3;
785  if (p < data) {
786  Reset();
787  return NULL;
788  }
789  memmove(p, data, 4);
790  }
791  int l = min(length - offset, MAXPESLENGTH);
792  offset += l;
793  if (p != data) {
794  l += 3;
795  p[6] = 0x80;
796  p[7] = 0x00;
797  p[8] = 0x00;
798  }
799  p[4] = l / 256;
800  p[5] = l & 0xFF;
801  Length = l + 6;
802  lastLength = Length;
803  lastData = p;
804  return p;
805  }
806  else {
807  Length = PesLength(data);
808  if (Length <= length) {
809  offset = Length; // to make sure we break out in case of garbage data
810  lastLength = Length;
811  lastData = data;
812  return data;
813  }
814  }
815  }
816  return NULL;
817 }
818 
820 {
821  repeatLast = true;
822 }
823 
824 void cTsToPes::Reset(void)
825 {
826  length = offset = 0;
827  lastData = NULL;
828  lastLength = 0;
829  repeatLast = false;
830 }
831 
832 // --- Some helper functions for debugging -----------------------------------
833 
834 void BlockDump(const char *Name, const u_char *Data, int Length)
835 {
836  printf("--- %s\n", Name);
837  for (int i = 0; i < Length; i++) {
838  if (i && (i % 16) == 0)
839  printf("\n");
840  printf(" %02X", Data[i]);
841  }
842  printf("\n");
843 }
844 
845 void TsDump(const char *Name, const u_char *Data, int Length)
846 {
847  printf("%s: %04X", Name, Length);
848  int n = min(Length, 20);
849  for (int i = 0; i < n; i++)
850  printf(" %02X", Data[i]);
851  if (n < Length) {
852  printf(" ...");
853  n = max(n, Length - 10);
854  for (n = max(n, Length - 10); n < Length; n++)
855  printf(" %02X", Data[n]);
856  }
857  printf("\n");
858 }
859 
860 void PesDump(const char *Name, const u_char *Data, int Length)
861 {
862  TsDump(Name, Data, Length);
863 }
864 
865 // --- cFrameDetector --------------------------------------------------------
866 
867 #define EMPTY_SCANNER (0xFFFFFFFF)
868 
870 {
871  SetPid(Pid, Type);
872  synced = false;
873  newFrame = independentFrame = false;
874  numPtsValues = 0;
875  numFrames = 0;
876  numIFrames = 0;
877  framesPerSecond = 0;
879  payloadUnitOfFrame = 0;
880  scanning = false;
882 }
883 
884 static int CmpUint32(const void *p1, const void *p2)
885 {
886  if (*(uint32_t *)p1 < *(uint32_t *)p2) return -1;
887  if (*(uint32_t *)p1 > *(uint32_t *)p2) return 1;
888  return 0;
889 }
890 
891 void cFrameDetector::SetPid(int Pid, int Type)
892 {
893  pid = Pid;
894  type = Type;
895  isVideo = type == 0x01 || type == 0x02 || type == 0x1B; // MPEG 1, 2 or 4
896 }
897 
899 {
900  newFrame = independentFrame = false;
901  payloadUnitOfFrame = 0;
902  scanning = false;
904 }
905 
906 int cFrameDetector::SkipPackets(const uchar *&Data, int &Length, int &Processed, int &FrameTypeOffset)
907 {
908  if (!synced)
909  dbgframes("%d>", FrameTypeOffset);
910  while (Length >= TS_SIZE) {
911  // switch to the next TS packet, but skip those that have a different PID:
912  Data += TS_SIZE;
913  Length -= TS_SIZE;
914  Processed += TS_SIZE;
915  if (TsPid(Data) == pid)
916  break;
917  else if (Length < TS_SIZE)
918  esyslog("ERROR: out of data while skipping TS packets in cFrameDetector");
919  }
920  FrameTypeOffset -= TS_SIZE;
921  FrameTypeOffset += TsPayloadOffset(Data);
922  return FrameTypeOffset;
923 }
924 
925 int cFrameDetector::Analyze(const uchar *Data, int Length)
926 {
927  bool SeenPayloadStart = false;
928  bool SeenAccessUnitDelimiter = false;
929  int Processed = 0;
930  newFrame = independentFrame = false;
931  while (Length >= TS_SIZE) {
932  if (Data[0] != TS_SYNC_BYTE) {
933  int Skipped = 1;
934  while (Skipped < Length && (Data[Skipped] != TS_SYNC_BYTE || Length - Skipped > TS_SIZE && Data[Skipped + TS_SIZE] != TS_SYNC_BYTE))
935  Skipped++;
936  esyslog("ERROR: skipped %d bytes to sync on start of TS packet", Skipped);
937  return Processed + Skipped;
938  }
939  if (TsHasPayload(Data) && !TsIsScrambled(Data)) {
940  int Pid = TsPid(Data);
941  if (Pid == pid) {
942  if (TsPayloadStart(Data)) {
943  SeenPayloadStart = true;
944  if (synced && Processed)
945  return Processed;
947  return Processed; // need more data, in case the frame type is not stored in the first TS packet
948  if (framesPerSecond <= 0.0) {
949  // frame rate unknown, so collect a sequence of PTS values:
950  if (numPtsValues < 2 || numPtsValues < MaxPtsValues && numIFrames < 2) { // collect a sequence containing at least two I-frames
951  const uchar *Pes = Data + TsPayloadOffset(Data);
952  if (numIFrames && PesHasPts(Pes)) {
954  // check for rollover:
955  if (numPtsValues && ptsValues[numPtsValues - 1] > 0xF0000000 && ptsValues[numPtsValues] < 0x10000000) {
956  dbgframes("#");
957  numPtsValues = 0;
958  numIFrames = 0;
959  numFrames = 0;
960  }
961  else
962  numPtsValues++;
963  }
964  }
965  else {
966  // find the smallest PTS delta:
967  qsort(ptsValues, numPtsValues, sizeof(uint32_t), CmpUint32);
968  numPtsValues--;
969  for (int i = 0; i < numPtsValues; i++)
970  ptsValues[i] = ptsValues[i + 1] - ptsValues[i];
971  qsort(ptsValues, numPtsValues, sizeof(uint32_t), CmpUint32);
972  uint32_t Delta = ptsValues[0];
973  // determine frame info:
974  if (isVideo) {
975  if (abs(Delta - 3600) <= 1)
976  framesPerSecond = 25.0;
977  else if (Delta % 3003 == 0)
978  framesPerSecond = 30.0 / 1.001;
979  else if (abs(Delta - 1800) <= 1) {
980  if (numFrames > 50) {
981  // this is a "best guess": if there are more than 50 frames between two I-frames, we assume each "frame" actually contains a "field", so two "fields" make one "frame"
982  framesPerSecond = 25.0;
984  }
985  else
986  framesPerSecond = 50.0;
987  }
988  else if (Delta == 1501)
989  if (numFrames > 50) {
990  // this is a "best guess": if there are more than 50 frames between two I-frames, we assume each "frame" actually contains a "field", so two "fields" make one "frame"
991  framesPerSecond = 30.0 / 1.001;
993  }
994  else
995  framesPerSecond = 60.0 / 1.001;
996  else {
998  dsyslog("unknown frame delta (%d), assuming %5.2f fps", Delta, DEFAULTFRAMESPERSECOND);
999  }
1000  }
1001  else // audio
1002  framesPerSecond = 90000.0 / Delta; // PTS of audio frames is always increasing
1003  dbgframes("\nDelta = %d FPS = %5.2f FPPU = %d NF = %d\n", Delta, framesPerSecond, framesPerPayloadUnit, numFrames);
1004  }
1005  }
1007  scanning = true;
1008  }
1009  if (scanning) {
1010  int PayloadOffset = TsPayloadOffset(Data);
1011  if (TsPayloadStart(Data)) {
1012  PayloadOffset += PesPayloadOffset(Data + PayloadOffset);
1013  if (!framesPerPayloadUnit)
1015  if (DebugFrames && !synced)
1016  dbgframes("/");
1017  }
1018  for (int i = PayloadOffset; scanning && i < TS_SIZE; i++) {
1019  scanner <<= 8;
1020  scanner |= Data[i];
1021  switch (type) {
1022  case 0x01: // MPEG 1 video
1023  case 0x02: // MPEG 2 video
1024  if (scanner == 0x00000100) { // Picture Start Code
1026  if (synced && !SeenPayloadStart && Processed)
1027  return Processed; // flush everything before this new frame
1028  int FrameTypeOffset = i + 2;
1029  if (FrameTypeOffset >= TS_SIZE) // the byte to check is in the next TS packet
1030  i = SkipPackets(Data, Length, Processed, FrameTypeOffset);
1031  newFrame = true;
1032  uchar FrameType = (Data[FrameTypeOffset] >> 3) & 0x07;
1033  independentFrame = FrameType == 1; // I-Frame
1034  if (synced) {
1035  if (framesPerPayloadUnit <= 1)
1036  scanning = false;
1037  }
1038  else {
1040  if (independentFrame)
1041  numIFrames++;
1042  if (numIFrames == 1)
1043  numFrames++;
1044  dbgframes("%u ", FrameType);
1045  }
1046  if (synced)
1047  return Processed + TS_SIZE; // flag this new frame
1048  }
1049  break;
1050  case 0x1B: // MPEG 4 video
1051  if (scanner == 0x00000109) { // Access Unit Delimiter
1053  if (synced && !SeenPayloadStart && Processed)
1054  return Processed; // flush everything before this new frame
1055  SeenAccessUnitDelimiter = true;
1056  }
1057  else if (SeenAccessUnitDelimiter && scanner == 0x00000001) { // NALU start
1058  SeenAccessUnitDelimiter = false;
1059  int FrameTypeOffset = i + 1;
1060  if (FrameTypeOffset >= TS_SIZE) // the byte to check is in the next TS packet
1061  i = SkipPackets(Data, Length, Processed, FrameTypeOffset);
1062  newFrame = true;
1063  uchar FrameType = Data[FrameTypeOffset] & 0x1F;
1064  independentFrame = FrameType == 0x07;
1065  if (synced) {
1066  if (framesPerPayloadUnit < 0) {
1069  payloadUnitOfFrame = 0;
1070  if (payloadUnitOfFrame)
1071  newFrame = false;
1072  }
1073  if (framesPerPayloadUnit <= 1)
1074  scanning = false;
1075  }
1076  else {
1078  if (independentFrame)
1079  numIFrames++;
1080  if (numIFrames == 1)
1081  numFrames++;
1082  dbgframes("%02X ", FrameType);
1083  }
1084  if (synced)
1085  return Processed + TS_SIZE; // flag this new frame
1086  }
1087  break;
1088  case 0x04: // MPEG audio
1089  case 0x06: // AC3 audio
1090  if (synced && Processed)
1091  return Processed;
1092  newFrame = true;
1093  independentFrame = true;
1094  if (!synced) {
1095  framesInPayloadUnit = 1;
1096  if (TsPayloadStart(Data))
1097  numIFrames++;
1098  }
1099  scanning = false;
1100  break;
1101  default: esyslog("ERROR: unknown stream type %d (PID %d) in frame detector", type, pid);
1102  pid = 0; // let's just ignore any further data
1103  }
1104  }
1105  if (!synced && framesPerSecond > 0.0 && independentFrame) {
1106  synced = true;
1107  dbgframes("*\n");
1108  Reset();
1109  return Processed + TS_SIZE;
1110  }
1111  }
1112  }
1113  else if (Pid == PATPID && synced && Processed)
1114  return Processed; // allow the caller to see any PAT packets
1115  }
1116  Data += TS_SIZE;
1117  Length -= TS_SIZE;
1118  Processed += TS_SIZE;
1119  }
1120  return Processed;
1121 }