2 * remux.c: Tools for detecting frames and handling PAT/PMT
4 * See the main source file 'vdr.c' for copyright information and
5 * how to reach the author.
7 * $Id: remux.c 2.57 2011/06/12 14:24:09 kls Exp $
13 #include "libsi/section.h"
14 #include "libsi/descriptor.h"
15 #include "recording.h"
19 // Set these to 'true' for debug output:
20 static bool DebugPatPmt = false;
21 static bool DebugFrames = false;
23 #define dbgpatpmt(a...) if (DebugPatPmt) fprintf(stderr, a)
24 #define dbgframes(a...) if (DebugFrames) fprintf(stderr, a)
26 ePesHeader AnalyzePesHeader(const uchar *Data, int Count, int &PesPayloadOffset, bool *ContinuationHeader)
29 return phNeedMoreData; // too short
31 if ((Data[6] & 0xC0) == 0x80) { // MPEG 2
33 return phNeedMoreData; // too short
35 PesPayloadOffset = 6 + 3 + Data[8];
36 if (Count < PesPayloadOffset)
37 return phNeedMoreData; // too short
39 if (ContinuationHeader)
40 *ContinuationHeader = ((Data[6] == 0x80) && !Data[7] && !Data[8]);
42 return phMPEG2; // MPEG 2
45 // check for MPEG 1 ...
48 // skip up to 16 stuffing bytes
49 for (int i = 0; i < 16; i++) {
50 if (Data[PesPayloadOffset] != 0xFF)
53 if (Count <= ++PesPayloadOffset)
54 return phNeedMoreData; // too short
57 // skip STD_buffer_scale/size
58 if ((Data[PesPayloadOffset] & 0xC0) == 0x40) {
59 PesPayloadOffset += 2;
61 if (Count <= PesPayloadOffset)
62 return phNeedMoreData; // too short
65 if (ContinuationHeader)
66 *ContinuationHeader = false;
68 if ((Data[PesPayloadOffset] & 0xF0) == 0x20) {
70 PesPayloadOffset += 5;
72 else if ((Data[PesPayloadOffset] & 0xF0) == 0x30) {
74 PesPayloadOffset += 10;
76 else if (Data[PesPayloadOffset] == 0x0F) {
77 // continuation header
80 if (ContinuationHeader)
81 *ContinuationHeader = true;
84 return phInvalid; // unknown
86 if (Count < PesPayloadOffset)
87 return phNeedMoreData; // too short
89 return phMPEG1; // MPEG 1
92 #define VIDEO_STREAM_S 0xE0
94 // --- cRemux ----------------------------------------------------------------
96 void cRemux::SetBrokenLink(uchar *Data, int Length)
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
107 dsyslog("SetBrokenLink: no GOP header found in video packet");
110 dsyslog("SetBrokenLink: no video packet in frame");
113 // --- Some TS handling tools ------------------------------------------------
115 int64_t TsGetPts(const uchar *p, int l)
117 // Find the first packet with a PTS and use it:
120 if (TsPayloadStart(d) && TsGetPayload(&d) && PesHasPts(d))
128 void TsSetTeiOnBrokenPackets(uchar *p, int l)
130 bool Processed[MAXPID] = { false };
131 while (l >= TS_SIZE) {
132 if (*p != TS_SYNC_BYTE)
135 if (!Processed[Pid]) {
136 if (!TsPayloadStart(p))
139 Processed[Pid] = true;
146 // --- cPatPmtGenerator ------------------------------------------------------
148 cPatPmtGenerator::cPatPmtGenerator(const cChannel *Channel)
151 patCounter = pmtCounter = 0;
152 patVersion = pmtVersion = 0;
158 void cPatPmtGenerator::IncCounter(int &Counter, uchar *TsPacket)
160 TsPacket[3] = (TsPacket[3] & 0xF0) | Counter;
161 if (++Counter > 0x0F)
165 void cPatPmtGenerator::IncVersion(int &Version)
167 if (++Version > 0x1F)
171 void cPatPmtGenerator::IncEsInfoLength(int Length)
174 Length += ((*esInfoLength & 0x0F) << 8) | *(esInfoLength + 1);
175 *esInfoLength = 0xF0 | (Length >> 8);
176 *(esInfoLength + 1) = Length;
180 int cPatPmtGenerator::MakeStream(uchar *Target, uchar Type, int Pid)
183 Target[i++] = Type; // stream type
184 Target[i++] = 0xE0 | (Pid >> 8); // dummy (3), pid hi (5)
185 Target[i++] = Pid; // pid lo
186 esInfoLength = &Target[i];
187 Target[i++] = 0xF0; // dummy (4), ES info length hi
188 Target[i++] = 0x00; // ES info length lo
192 int cPatPmtGenerator::MakeAC3Descriptor(uchar *Target, uchar Type)
196 Target[i++] = 0x01; // length
202 int cPatPmtGenerator::MakeSubtitlingDescriptor(uchar *Target, const char *Language, uchar SubtitlingType, uint16_t CompositionPageId, uint16_t AncillaryPageId)
205 Target[i++] = SI::SubtitlingDescriptorTag;
206 Target[i++] = 0x08; // length
207 Target[i++] = *Language++;
208 Target[i++] = *Language++;
209 Target[i++] = *Language++;
210 Target[i++] = SubtitlingType;
211 Target[i++] = CompositionPageId >> 8;
212 Target[i++] = CompositionPageId & 0xFF;
213 Target[i++] = AncillaryPageId >> 8;
214 Target[i++] = AncillaryPageId & 0xFF;
219 int cPatPmtGenerator::MakeLanguageDescriptor(uchar *Target, const char *Language)
222 Target[i++] = SI::ISO639LanguageDescriptorTag;
224 Target[Length] = 0x00; // length
225 for (const char *End = Language + strlen(Language); Language < End; ) {
226 Target[i++] = *Language++;
227 Target[i++] = *Language++;
228 Target[i++] = *Language++;
229 Target[i++] = 0x00; // audio type
230 Target[Length] += 0x04; // length
231 if (*Language == '+')
238 int cPatPmtGenerator::MakeCRC(uchar *Target, const uchar *Data, int Length)
240 int crc = SI::CRC32::crc32((const char *)Data, Length, 0xFFFFFFFF);
242 Target[i++] = crc >> 24;
243 Target[i++] = crc >> 16;
244 Target[i++] = crc >> 8;
249 #define P_TSID 0x8008 // pseudo TS ID
250 #define P_PMT_PID 0x0084 // pseudo PMT pid
251 #define MAXPID 0x2000 // the maximum possible number of pids
253 void cPatPmtGenerator::GeneratePmtPid(const cChannel *Channel)
255 bool Used[MAXPID] = { false };
256 #define SETPID(p) { if ((p) >= 0 && (p) < MAXPID) Used[p] = true; }
257 #define SETPIDS(l) { const int *p = l; while (*p) { SETPID(*p); p++; } }
258 SETPID(Channel->Vpid());
259 SETPID(Channel->Ppid());
260 SETPID(Channel->Tpid());
261 SETPIDS(Channel->Apids());
262 SETPIDS(Channel->Dpids());
263 SETPIDS(Channel->Spids());
264 for (pmtPid = P_PMT_PID; Used[pmtPid]; pmtPid++)
268 void cPatPmtGenerator::GeneratePat(void)
270 memset(pat, 0xFF, sizeof(pat));
273 p[i++] = TS_SYNC_BYTE; // TS indicator
274 p[i++] = TS_PAYLOAD_START | (PATPID >> 8); // flags (3), pid hi (5)
275 p[i++] = PATPID & 0xFF; // pid lo
276 p[i++] = 0x10; // flags (4), continuity counter (4)
277 p[i++] = 0x00; // pointer field (payload unit start indicator is set)
278 int PayloadStart = i;
279 p[i++] = 0x00; // table id
280 p[i++] = 0xB0; // section syntax indicator (1), dummy (3), section length hi (4)
281 int SectionLength = i;
282 p[i++] = 0x00; // section length lo (filled in later)
283 p[i++] = P_TSID >> 8; // TS id hi
284 p[i++] = P_TSID & 0xFF; // TS id lo
285 p[i++] = 0xC1 | (patVersion << 1); // dummy (2), version number (5), current/next indicator (1)
286 p[i++] = 0x00; // section number
287 p[i++] = 0x00; // last section number
288 p[i++] = pmtPid >> 8; // program number hi
289 p[i++] = pmtPid & 0xFF; // program number lo
290 p[i++] = 0xE0 | (pmtPid >> 8); // dummy (3), PMT pid hi (5)
291 p[i++] = pmtPid & 0xFF; // PMT pid lo
292 pat[SectionLength] = i - SectionLength - 1 + 4; // -2 = SectionLength storage, +4 = length of CRC
293 MakeCRC(pat + i, pat + PayloadStart, i - PayloadStart);
294 IncVersion(patVersion);
297 void cPatPmtGenerator::GeneratePmt(const cChannel *Channel)
299 // generate the complete PMT section:
300 uchar buf[MAX_SECTION_SIZE];
301 memset(buf, 0xFF, sizeof(buf));
304 int Vpid = Channel->Vpid();
305 int Ppid = Channel->Ppid();
308 p[i++] = 0x02; // table id
309 int SectionLength = i;
310 p[i++] = 0xB0; // section syntax indicator (1), dummy (3), section length hi (4)
311 p[i++] = 0x00; // section length lo (filled in later)
312 p[i++] = pmtPid >> 8; // program number hi
313 p[i++] = pmtPid & 0xFF; // program number lo
314 p[i++] = 0xC1 | (pmtVersion << 1); // dummy (2), version number (5), current/next indicator (1)
315 p[i++] = 0x00; // section number
316 p[i++] = 0x00; // last section number
317 p[i++] = 0xE0 | (Ppid >> 8); // dummy (3), PCR pid hi (5)
318 p[i++] = Ppid; // PCR pid lo
319 p[i++] = 0xF0; // dummy (4), program info length hi (4)
320 p[i++] = 0x00; // program info length lo
323 i += MakeStream(buf + i, Channel->Vtype(), Vpid);
324 for (int n = 0; Channel->Apid(n); n++) {
325 i += MakeStream(buf + i, Channel->Atype(n), Channel->Apid(n));
326 const char *Alang = Channel->Alang(n);
327 i += MakeLanguageDescriptor(buf + i, Alang);
329 for (int n = 0; Channel->Dpid(n); n++) {
330 i += MakeStream(buf + i, 0x06, Channel->Dpid(n));
331 i += MakeAC3Descriptor(buf + i, Channel->Dtype(n));
332 i += MakeLanguageDescriptor(buf + i, Channel->Dlang(n));
334 for (int n = 0; Channel->Spid(n); n++) {
335 i += MakeStream(buf + i, 0x06, Channel->Spid(n));
336 i += MakeSubtitlingDescriptor(buf + i, Channel->Slang(n), Channel->SubtitlingType(n), Channel->CompositionPageId(n), Channel->AncillaryPageId(n));
339 int sl = i - SectionLength - 2 + 4; // -2 = SectionLength storage, +4 = length of CRC
340 buf[SectionLength] |= (sl >> 8) & 0x0F;
341 buf[SectionLength + 1] = sl;
342 MakeCRC(buf + i, buf, i);
343 // split the PMT section into several TS packets:
347 uchar *p = pmt[numPmtPackets++];
349 p[j++] = TS_SYNC_BYTE; // TS indicator
350 p[j++] = (pusi ? TS_PAYLOAD_START : 0x00) | (pmtPid >> 8); // flags (3), pid hi (5)
351 p[j++] = pmtPid & 0xFF; // pid lo
352 p[j++] = 0x10; // flags (4), continuity counter (4)
354 p[j++] = 0x00; // pointer field (payload unit start indicator is set)
362 IncVersion(pmtVersion);
366 void cPatPmtGenerator::SetVersions(int PatVersion, int PmtVersion)
368 patVersion = PatVersion & 0x1F;
369 pmtVersion = PmtVersion & 0x1F;
372 void cPatPmtGenerator::SetChannel(const cChannel *Channel)
375 GeneratePmtPid(Channel);
377 GeneratePmt(Channel);
381 uchar *cPatPmtGenerator::GetPat(void)
383 IncCounter(patCounter, pat);
387 uchar *cPatPmtGenerator::GetPmt(int &Index)
389 if (Index < numPmtPackets) {
390 IncCounter(pmtCounter, pmt[Index]);
396 // --- cPatPmtParser ---------------------------------------------------------
398 cPatPmtParser::cPatPmtParser(bool UpdatePrimaryDevice)
400 updatePrimaryDevice = UpdatePrimaryDevice;
404 void cPatPmtParser::Reset(void)
407 patVersion = pmtVersion = -1;
413 void cPatPmtParser::ParsePat(const uchar *Data, int Length)
415 // Unpack the TS packet:
416 int PayloadOffset = TsPayloadOffset(Data);
417 Data += PayloadOffset;
418 Length -= PayloadOffset;
419 // The PAT is always assumed to fit into a single TS packet
420 if ((Length -= Data[0] + 1) <= 0)
422 Data += Data[0] + 1; // process pointer_field
423 SI::PAT Pat(Data, false);
424 if (Pat.CheckCRCAndParse()) {
425 dbgpatpmt("PAT: TSid = %d, c/n = %d, v = %d, s = %d, ls = %d\n", Pat.getTransportStreamId(), Pat.getCurrentNextIndicator(), Pat.getVersionNumber(), Pat.getSectionNumber(), Pat.getLastSectionNumber());
426 if (patVersion == Pat.getVersionNumber())
428 SI::PAT::Association assoc;
429 for (SI::Loop::Iterator it; Pat.associationLoop.getNext(assoc, it); ) {
430 dbgpatpmt(" isNITPid = %d\n", assoc.isNITPid());
431 if (!assoc.isNITPid()) {
432 pmtPid = assoc.getPid();
433 dbgpatpmt(" service id = %d, pid = %d\n", assoc.getServiceId(), assoc.getPid());
436 patVersion = Pat.getVersionNumber();
439 esyslog("ERROR: can't parse PAT");
442 void cPatPmtParser::ParsePmt(const uchar *Data, int Length)
444 // Unpack the TS packet:
445 bool PayloadStart = TsPayloadStart(Data);
446 int PayloadOffset = TsPayloadOffset(Data);
447 Data += PayloadOffset;
448 Length -= PayloadOffset;
449 // The PMT may extend over several TS packets, so we need to assemble them
452 if ((Length -= Data[0] + 1) <= 0)
454 Data += Data[0] + 1; // this is the first packet
455 if (SectionLength(Data, Length) > Length) {
456 if (Length <= int(sizeof(pmt))) {
457 memcpy(pmt, Data, Length);
461 esyslog("ERROR: PMT packet length too big (%d byte)!", Length);
464 // the packet contains the entire PMT section, so we run into the actual parsing
466 else if (pmtSize > 0) {
467 // this is a following packet, so we add it to the pmt storage
468 if (Length <= int(sizeof(pmt)) - pmtSize) {
469 memcpy(pmt + pmtSize, Data, Length);
473 esyslog("ERROR: PMT section length too big (%d byte)!", pmtSize + Length);
476 if (SectionLength(pmt, pmtSize) > pmtSize)
477 return; // more packets to come
478 // the PMT section is now complete, so we run into the actual parsing
482 return; // fragment of broken packet - ignore
483 SI::PMT Pmt(Data, false);
484 if (Pmt.CheckCRCAndParse()) {
485 dbgpatpmt("PMT: sid = %d, c/n = %d, v = %d, s = %d, ls = %d\n", Pmt.getServiceId(), Pmt.getCurrentNextIndicator(), Pmt.getVersionNumber(), Pmt.getSectionNumber(), Pmt.getLastSectionNumber());
486 dbgpatpmt(" pcr = %d\n", Pmt.getPCRPid());
487 if (pmtVersion == Pmt.getVersionNumber())
489 if (updatePrimaryDevice)
490 cDevice::PrimaryDevice()->ClrAvailableTracks(false, true);
501 SI::PMT::Stream stream;
502 for (SI::Loop::Iterator it; Pmt.streamLoop.getNext(stream, it); ) {
503 dbgpatpmt(" stream type = %02X, pid = %d", stream.getStreamType(), stream.getPid());
504 switch (stream.getStreamType()) {
505 case 0x01: // STREAMTYPE_11172_VIDEO
506 case 0x02: // STREAMTYPE_13818_VIDEO
508 vpid = stream.getPid();
509 vtype = stream.getStreamType();
510 ppid = Pmt.getPCRPid();
512 case 0x03: // STREAMTYPE_11172_AUDIO
513 case 0x04: // STREAMTYPE_13818_AUDIO
514 case 0x0F: // ISO/IEC 13818-7 Audio with ADTS transport sytax
515 case 0x11: // ISO/IEC 14496-3 Audio with LATM transport syntax
517 if (NumApids < MAXAPIDS) {
518 apids[NumApids] = stream.getPid();
519 atypes[NumApids] = stream.getStreamType();
520 *alangs[NumApids] = 0;
522 for (SI::Loop::Iterator it; (d = stream.streamDescriptors.getNext(it)); ) {
523 switch (d->getDescriptorTag()) {
524 case SI::ISO639LanguageDescriptorTag: {
525 SI::ISO639LanguageDescriptor *ld = (SI::ISO639LanguageDescriptor *)d;
526 SI::ISO639LanguageDescriptor::Language l;
527 char *s = alangs[NumApids];
529 for (SI::Loop::Iterator it; ld->languageLoop.getNext(l, it); ) {
530 if (*ld->languageCode != '-') { // some use "---" to indicate "none"
531 dbgpatpmt(" '%s'", l.languageCode);
534 strn0cpy(s, I18nNormalizeLanguageCode(l.languageCode), MAXLANGCODE1);
546 if (updatePrimaryDevice)
547 cDevice::PrimaryDevice()->SetAvailableTrack(ttAudio, NumApids, apids[NumApids], alangs[NumApids]);
553 case 0x06: // STREAMTYPE_13818_PES_PRIVATE
557 char lang[MAXLANGCODE1] = "";
559 for (SI::Loop::Iterator it; (d = stream.streamDescriptors.getNext(it)); ) {
560 switch (d->getDescriptorTag()) {
561 case SI::AC3DescriptorTag:
562 case SI::EnhancedAC3DescriptorTag:
564 dpid = stream.getPid();
565 dtype = d->getDescriptorTag();
567 case SI::SubtitlingDescriptorTag:
568 dbgpatpmt(" subtitling");
569 if (NumSpids < MAXSPIDS) {
570 spids[NumSpids] = stream.getPid();
571 *slangs[NumSpids] = 0;
572 subtitlingTypes[NumSpids] = 0;
573 compositionPageIds[NumSpids] = 0;
574 ancillaryPageIds[NumSpids] = 0;
575 SI::SubtitlingDescriptor *sd = (SI::SubtitlingDescriptor *)d;
576 SI::SubtitlingDescriptor::Subtitling sub;
577 char *s = slangs[NumSpids];
579 for (SI::Loop::Iterator it; sd->subtitlingLoop.getNext(sub, it); ) {
580 if (sub.languageCode[0]) {
581 dbgpatpmt(" '%s'", sub.languageCode);
582 subtitlingTypes[NumSpids] = sub.getSubtitlingType();
583 compositionPageIds[NumSpids] = sub.getCompositionPageId();
584 ancillaryPageIds[NumSpids] = sub.getAncillaryPageId();
587 strn0cpy(s, I18nNormalizeLanguageCode(sub.languageCode), MAXLANGCODE1);
593 if (updatePrimaryDevice)
594 cDevice::PrimaryDevice()->SetAvailableTrack(ttSubtitle, NumSpids, spids[NumSpids], slangs[NumSpids]);
599 case SI::ISO639LanguageDescriptorTag: {
600 SI::ISO639LanguageDescriptor *ld = (SI::ISO639LanguageDescriptor *)d;
601 dbgpatpmt(" '%s'", ld->languageCode);
602 strn0cpy(lang, I18nNormalizeLanguageCode(ld->languageCode), MAXLANGCODE1);
610 if (NumDpids < MAXDPIDS) {
611 dpids[NumDpids] = dpid;
612 dtypes[NumDpids] = dtype;
613 strn0cpy(dlangs[NumDpids], lang, sizeof(dlangs[NumDpids]));
614 if (updatePrimaryDevice && Setup.UseDolbyDigital)
615 cDevice::PrimaryDevice()->SetAvailableTrack(ttDolby, NumDpids, dpid, lang);
625 if (updatePrimaryDevice) {
626 cDevice::PrimaryDevice()->EnsureAudioTrack(true);
627 cDevice::PrimaryDevice()->EnsureSubtitleTrack();
630 pmtVersion = Pmt.getVersionNumber();
633 esyslog("ERROR: can't parse PMT");
637 bool cPatPmtParser::GetVersions(int &PatVersion, int &PmtVersion) const
639 PatVersion = patVersion;
640 PmtVersion = pmtVersion;
641 return patVersion >= 0 && pmtVersion >= 0;
644 // --- cTsToPes --------------------------------------------------------------
646 cTsToPes::cTsToPes(void)
653 cTsToPes::~cTsToPes()
658 void cTsToPes::PutTs(const uchar *Data, int Length)
662 return; // ignore packets with TEI set, and drop any PES data collected so far
664 if (TsPayloadStart(Data))
667 return; // skip everything before the first payload start
668 Length = TsGetPayload(&Data);
669 if (length + Length > size) {
670 int NewSize = max(KILOBYTE(2), length + Length);
671 if (uchar *NewData = (uchar *)realloc(data, NewSize)) {
676 esyslog("ERROR: out of memory");
681 memcpy(data + length, Data, Length);
685 #define MAXPESLENGTH 0xFFF0
687 const uchar *cTsToPes::GetPes(int &Length)
694 if (offset < length && PesLongEnough(length)) {
695 if (!PesHasLength(data)) // this is a video PES packet with undefined length
696 offset = 6; // trigger setting PES length for initial slice
698 uchar *p = data + offset - 6;
703 int l = min(length - offset, MAXPESLENGTH);
719 Length = PesLength(data);
720 if (Length <= length) {
721 offset = Length; // to make sure we break out in case of garbage data
731 void cTsToPes::SetRepeatLast(void)
736 void cTsToPes::Reset(void)
744 // --- Some helper functions for debugging -----------------------------------
746 void BlockDump(const char *Name, const u_char *Data, int Length)
748 printf("--- %s\n", Name);
749 for (int i = 0; i < Length; i++) {
750 if (i && (i % 16) == 0)
752 printf(" %02X", Data[i]);
757 void TsDump(const char *Name, const u_char *Data, int Length)
759 printf("%s: %04X", Name, Length);
760 int n = min(Length, 20);
761 for (int i = 0; i < n; i++)
762 printf(" %02X", Data[i]);
765 n = max(n, Length - 10);
766 for (n = max(n, Length - 10); n < Length; n++)
767 printf(" %02X", Data[n]);
772 void PesDump(const char *Name, const u_char *Data, int Length)
774 TsDump(Name, Data, Length);
777 // --- cFrameDetector --------------------------------------------------------
779 #define EMPTY_SCANNER (0xFFFFFFFF)
781 cFrameDetector::cFrameDetector(int Pid, int Type)
785 newPayload = newFrame = independentFrame = false;
786 frameTypeOffset = -1;
791 framesInPayloadUnit = framesPerPayloadUnit = 0;
792 payloadUnitOfFrame = 0;
794 scanner = EMPTY_SCANNER;
797 static int CmpUint32(const void *p1, const void *p2)
799 if (*(uint32_t *)p1 < *(uint32_t *)p2) return -1;
800 if (*(uint32_t *)p1 > *(uint32_t *)p2) return 1;
804 void cFrameDetector::SetPid(int Pid, int Type)
808 isVideo = type == 0x01 || type == 0x02 || type == 0x1B; // MPEG 1, 2 or 4
811 void cFrameDetector::Reset(void)
813 newPayload = newFrame = independentFrame = false;
814 frameTypeOffset = -1;
815 payloadUnitOfFrame = 0;
817 scanner = EMPTY_SCANNER;
820 int cFrameDetector::Analyze(const uchar *Data, int Length)
823 newPayload = newFrame = independentFrame = false;
824 while (Length >= TS_SIZE) {
825 if (Data[0] != TS_SYNC_BYTE) {
827 while (Skipped < Length && (Data[Skipped] != TS_SYNC_BYTE || Length - Skipped > TS_SIZE && Data[Skipped + TS_SIZE] != TS_SYNC_BYTE))
829 esyslog("ERROR: skipped %d bytes to sync on start of TS packet", Skipped);
830 return Processed + Skipped;
832 if (TsHasPayload(Data) && !TsIsScrambled(Data)) {
833 int Pid = TsPid(Data);
835 if (TsPayloadStart(Data)) {
836 if (synced && Processed)
837 return Processed; // flush everything before this new payload
838 if (framesPerSecond <= 0.0) {
839 // frame rate unknown, so collect a sequence of PTS values:
840 if (numPtsValues < MaxPtsValues && numIFrames < 2) { // collect a sequence containing at least two I-frames
841 const uchar *Pes = Data + TsPayloadOffset(Data);
842 if (numIFrames && PesHasPts(Pes)) {
843 ptsValues[numPtsValues] = PesGetPts(Pes);
844 // check for rollover:
845 if (numPtsValues && ptsValues[numPtsValues - 1] > 0xF0000000 && ptsValues[numPtsValues] < 0x10000000) {
856 // find the smallest PTS delta:
857 qsort(ptsValues, numPtsValues, sizeof(uint32_t), CmpUint32);
859 for (int i = 0; i < numPtsValues; i++)
860 ptsValues[i] = ptsValues[i + 1] - ptsValues[i];
861 qsort(ptsValues, numPtsValues, sizeof(uint32_t), CmpUint32);
862 uint32_t Delta = ptsValues[0];
863 // determine frame info:
865 if (abs(Delta - 3600) <= 1)
866 framesPerSecond = 25.0;
867 else if (Delta % 3003 == 0)
868 framesPerSecond = 30.0 / 1.001;
869 else if (abs(Delta - 1800) <= 1) {
870 if (numFrames > 50) {
871 // 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"
872 framesPerSecond = 25.0;
873 framesPerPayloadUnit = -2;
876 framesPerSecond = 50.0;
878 else if (Delta == 1501)
879 if (numFrames > 50) {
880 // 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"
881 framesPerSecond = 30.0 / 1.001;
882 framesPerPayloadUnit = -2;
885 framesPerSecond = 60.0 / 1.001;
887 framesPerSecond = DEFAULTFRAMESPERSECOND;
888 dsyslog("unknown frame delta (%d), assuming %5.2f fps", Delta, DEFAULTFRAMESPERSECOND);
892 framesPerSecond = 90000.0 / Delta; // PTS of audio frames is always increasing
893 dbgframes("\nDelta = %d FPS = %5.2f FPPU = %d NF = %d\n", Delta, framesPerSecond, framesPerPayloadUnit, numFrames);
896 scanner = EMPTY_SCANNER;
900 int PayloadOffset = TsPayloadOffset(Data);
901 if (TsPayloadStart(Data)) {
902 if (synced && Processed)
903 return Processed; // flush everything before this new payload
905 scanner = EMPTY_SCANNER;
906 PayloadOffset += PesPayloadOffset(Data + PayloadOffset);
907 if (!framesPerPayloadUnit)
908 framesPerPayloadUnit = framesInPayloadUnit;
909 if (DebugFrames && !synced)
912 for (int i = PayloadOffset; scanning && i < TS_SIZE; i++) {
913 if (frameTypeOffset < 0) {
918 frameTypeOffset += PayloadOffset;
920 case 0x01: // MPEG 1 video
921 case 0x02: // MPEG 2 video
922 if (scanner == 0x00000100) { // Picture Start Code
923 if (frameTypeOffset < 0) {
924 frameTypeOffset = i + 2;
925 if (frameTypeOffset >= TS_SIZE) { // the byte to check is in the next TS packet
926 frameTypeOffset -= TS_SIZE;
928 dbgframes("%d>", frameTypeOffset);
932 scanner = EMPTY_SCANNER;
934 uchar FrameType = (Data[frameTypeOffset] >> 3) & 0x07;
935 frameTypeOffset = -1;
936 independentFrame = FrameType == 1; // I-Frame
938 if (framesPerPayloadUnit <= 1)
942 framesInPayloadUnit++;
943 if (independentFrame)
947 dbgframes("%u ", FrameType);
950 return Processed + TS_SIZE; // flag this new frame
953 case 0x1B: // MPEG 4 video
954 if (scanner == 0x00000109) { // Access Unit Delimiter
955 if (frameTypeOffset < 0) {
956 frameTypeOffset = i + 1;
957 if (frameTypeOffset >= TS_SIZE) { // the byte to check is in the next TS packet
958 frameTypeOffset -= TS_SIZE;
960 dbgframes("%d>", frameTypeOffset);
964 scanner = EMPTY_SCANNER;
966 uchar FrameType = Data[frameTypeOffset];
967 frameTypeOffset = -1;
968 independentFrame = FrameType == 0x10;
970 if (framesPerPayloadUnit < 0) {
971 payloadUnitOfFrame = (payloadUnitOfFrame + 1) % -framesPerPayloadUnit;
972 if (payloadUnitOfFrame != 0 && independentFrame)
973 payloadUnitOfFrame = 0;
974 if (payloadUnitOfFrame)
977 if (framesPerPayloadUnit <= 1)
981 framesInPayloadUnit++;
982 if (independentFrame)
986 dbgframes("%02X ", FrameType);
989 return Processed + TS_SIZE; // flag this new frame
992 case 0x04: // MPEG audio
993 case 0x06: // AC3 audio
994 if (synced && Processed)
997 independentFrame = true;
999 framesInPayloadUnit = 1;
1000 if (TsPayloadStart(Data))
1005 default: esyslog("ERROR: unknown stream type %d (PID %d) in frame detector", type, pid);
1006 pid = 0; // let's just ignore any further data
1009 if (!synced && framesPerSecond > 0.0 && independentFrame) {
1013 return Processed + TS_SIZE;
1017 else if (Pid == PATPID && synced && Processed)
1018 return Processed; // allow the caller to see any PAT packets
1022 Processed += TS_SIZE;