vdr 2.7.7
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 5.19 2025/03/02 11:03:35 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:
20static bool DebugPatPmt = false;
21static 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
32ePesHeader 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 ...
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) {
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
77 }
78 else if ((Data[PesPayloadOffset] & 0xF0) == 0x30) {
79 // skip PTS and DTS
80 PesPayloadOffset += 10;
81 }
82 else if (Data[PesPayloadOffset] == 0x0F) {
83 // continuation header
85
86 if (ContinuationHeader)
87 *ContinuationHeader = true;
88 }
89 else
90 return phInvalid; // unknown
91
92 if (Count < PesPayloadOffset)
93 return phNeedMoreData; // too short
94
95 return phMPEG1; // MPEG 1
96}
97
98#define VIDEO_STREAM_S 0xE0
99
100// --- cRemux ----------------------------------------------------------------
101
102void 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
131void 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
147int TsSync(const uchar *Data, int Length, const char *File, const char *Function, int Line)
148{
149 int Skipped = 0;
150 while (Length > 0 && (*Data != TS_SYNC_BYTE || Length > TS_SIZE && Data[TS_SIZE] != TS_SYNC_BYTE)) {
151 Data++;
152 Length--;
153 Skipped++;
154 }
155 if (Skipped && File && Function && Line)
156 esyslog("ERROR: skipped %d bytes to sync on start of TS packet at %s/%s(%d)", Skipped, File, Function, Line);
157 return Skipped;
158}
159
160int64_t TsGetPts(const uchar *p, int l)
161{
162 // Find the first packet with a PTS and use it:
163 while (l > 0) {
164 const uchar *d = p;
165 if (TsPayloadStart(d) && TsGetPayload(&d) && PesHasPts(d))
166 return PesGetPts(d);
167 p += TS_SIZE;
168 l -= TS_SIZE;
169 }
170 return -1;
171}
172
173int64_t TsGetDts(const uchar *p, int l)
174{
175 // Find the first packet with a DTS and use it:
176 while (l > 0) {
177 const uchar *d = p;
178 if (TsPayloadStart(d) && TsGetPayload(&d) && PesHasDts(d))
179 return PesGetDts(d);
180 p += TS_SIZE;
181 l -= TS_SIZE;
182 }
183 return -1;
184}
185
186void TsSetPts(uchar *p, int l, int64_t Pts)
187{
188 // Find the first packet with a PTS and use it:
189 while (l > 0) {
190 const uchar *d = p;
191 if (TsPayloadStart(d) && TsGetPayload(&d) && PesHasPts(d)) {
192 PesSetPts(const_cast<uchar *>(d), Pts);
193 return;
194 }
195 p += TS_SIZE;
196 l -= TS_SIZE;
197 }
198}
199
200void TsSetDts(uchar *p, int l, int64_t Dts)
201{
202 // Find the first packet with a DTS and use it:
203 while (l > 0) {
204 const uchar *d = p;
205 if (TsPayloadStart(d) && TsGetPayload(&d) && PesHasDts(d)) {
206 PesSetDts(const_cast<uchar *>(d), Dts);
207 return;
208 }
209 p += TS_SIZE;
210 l -= TS_SIZE;
211 }
212}
213
214// --- Some PES handling tools -----------------------------------------------
215
216void PesSetPts(uchar *p, int64_t Pts)
217{
218 p[ 9] = ((Pts >> 29) & 0x0E) | (p[9] & 0xF1);
219 p[10] = Pts >> 22;
220 p[11] = ((Pts >> 14) & 0xFE) | 0x01;
221 p[12] = Pts >> 7;
222 p[13] = ((Pts << 1) & 0xFE) | 0x01;
223}
224
225void PesSetDts(uchar *p, int64_t Dts)
226{
227 p[14] = ((Dts >> 29) & 0x0E) | (p[14] & 0xF1);
228 p[15] = Dts >> 22;
229 p[16] = ((Dts >> 14) & 0xFE) | 0x01;
230 p[17] = Dts >> 7;
231 p[18] = ((Dts << 1) & 0xFE) | 0x01;
232}
233
234int64_t PtsDiff(int64_t Pts1, int64_t Pts2)
235{
236 int64_t d = Pts2 - Pts1;
237 if (d > MAX33BIT / 2)
238 return d - (MAX33BIT + 1);
239 if (d < -MAX33BIT / 2)
240 return d + (MAX33BIT + 1);
241 return d;
242}
243
244// --- cTsPayload ------------------------------------------------------------
245
247{
248 data = NULL;
249 length = 0;
250 pid = -1;
251 Reset();
252}
253
254cTsPayload::cTsPayload(uchar *Data, int Length, int Pid)
255{
256 Setup(Data, Length, Pid);
257}
258
260{
261 length = index; // triggers EOF
262 return 0x00;
263}
264
266{
267 index = 0;
268 numPacketsPid = 0;
269 numPacketsOther = 0;
270}
271
272void cTsPayload::Setup(uchar *Data, int Length, int Pid)
273{
274 data = Data;
275 length = Length;
276 pid = Pid >= 0 ? Pid : TsPid(Data);
277 Reset();
278}
279
281{
282 if (!Eof()) {
283 if (index % TS_SIZE == 0) { // encountered the next TS header
284 for (;; index += TS_SIZE) {
285 if (data[index] == TS_SYNC_BYTE && index + TS_SIZE <= length) { // to make sure we are at a TS header start and drop incomplete TS packets at the end
286 uchar *p = data + index;
287 if (TsPid(p) == pid) { // only handle TS packets for the initial PID
289 return SetEof();
290 if (TsError(p))
291 return SetEof(); // don't parse TS packets with errors
292 if (TsHasPayload(p)) {
293 if (index > 0 && TsPayloadStart(p)) // checking index to not skip the very first TS packet
294 return SetEof();
296 break;
297 }
298 }
299 else if (TsPid(p) == PATPID)
300 return SetEof(); // caller must see PAT packets in case of index regeneration
301 else
303 }
304 else
305 return SetEof();
306 }
307 }
308 return data[index++];
309 }
310 return 0x00;
311}
312
314{
315 while (Bytes-- > 0)
316 GetByte();
317 return !Eof();
318}
319
324
326{
327 return index - 1;
328}
329
330void cTsPayload::SetByte(uchar Byte, int Index)
331{
332 if (Index >= 0 && Index < length)
333 data[Index] = Byte;
334}
335
336bool cTsPayload::Find(uint32_t Code)
337{
338 int OldIndex = index;
339 int OldNumPacketsPid = numPacketsPid;
340 int OldNumPacketsOther = numPacketsOther;
341 uint32_t Scanner = EMPTY_SCANNER;
342 while (!Eof()) {
343 Scanner = (Scanner << 8) | GetByte();
344 if (Scanner == Code)
345 return true;
346 }
347 index = OldIndex;
348 numPacketsPid = OldNumPacketsPid;
349 numPacketsOther = OldNumPacketsOther;
350 return false;
351}
352
354{
356 dsyslog("WARNING: required (%d+%d) TS packets to determine frame type", numPacketsOther, numPacketsPid);
358 dsyslog("WARNING: required %d video TS packets to determine frame type", numPacketsPid);
359}
360
361// --- cPatPmtGenerator ------------------------------------------------------
362
364{
365 numPmtPackets = 0;
368 pmtPid = 0;
369 esInfoLength = NULL;
370 SetChannel(Channel);
371}
372
373void cPatPmtGenerator::IncCounter(int &Counter, uchar *TsPacket)
374{
375 TsPacket[3] = (TsPacket[3] & 0xF0) | Counter;
376 if (++Counter > 0x0F)
377 Counter = 0x00;
378}
379
381{
382 if (++Version > 0x1F)
383 Version = 0x00;
384}
385
387{
388 if (esInfoLength) {
389 Length += ((*esInfoLength & 0x0F) << 8) | *(esInfoLength + 1);
390 *esInfoLength = 0xF0 | (Length >> 8);
391 *(esInfoLength + 1) = Length;
392 }
393}
394
395int cPatPmtGenerator::MakeStream(uchar *Target, uchar Type, int Pid)
396{
397 int i = 0;
398 Target[i++] = Type; // stream type
399 Target[i++] = 0xE0 | (Pid >> 8); // dummy (3), pid hi (5)
400 Target[i++] = Pid; // pid lo
401 esInfoLength = &Target[i];
402 Target[i++] = 0xF0; // dummy (4), ES info length hi
403 Target[i++] = 0x00; // ES info length lo
404 return i;
405}
406
408{
409 int i = 0;
410 Target[i++] = Type;
411 Target[i++] = 0x01; // length
412 Target[i++] = 0x00;
414 return i;
415}
416
417int cPatPmtGenerator::MakeSubtitlingDescriptor(uchar *Target, const char *Language, uchar SubtitlingType, uint16_t CompositionPageId, uint16_t AncillaryPageId)
418{
419 int i = 0;
420 Target[i++] = SI::SubtitlingDescriptorTag;
421 Target[i++] = 0x08; // length
422 Target[i++] = *Language++;
423 Target[i++] = *Language++;
424 Target[i++] = *Language++;
425 Target[i++] = SubtitlingType;
426 Target[i++] = CompositionPageId >> 8;
427 Target[i++] = CompositionPageId & 0xFF;
428 Target[i++] = AncillaryPageId >> 8;
429 Target[i++] = AncillaryPageId & 0xFF;
431 return i;
432}
433
434int cPatPmtGenerator::MakeLanguageDescriptor(uchar *Target, const char *Language)
435{
436 int i = 0;
438 int Length = i++;
439 Target[Length] = 0x00; // length
440 for (const char *End = Language + strlen(Language); Language < End; ) {
441 Target[i++] = *Language++;
442 Target[i++] = *Language++;
443 Target[i++] = *Language++;
444 Target[i++] = 0x00; // audio type
445 Target[Length] += 0x04; // length
446 if (*Language == '+')
447 Language++;
448 }
450 return i;
451}
452
453int cPatPmtGenerator::MakeCRC(uchar *Target, const uchar *Data, int Length)
454{
455 int crc = SI::CRC32::crc32((const char *)Data, Length, 0xFFFFFFFF);
456 int i = 0;
457 Target[i++] = crc >> 24;
458 Target[i++] = crc >> 16;
459 Target[i++] = crc >> 8;
460 Target[i++] = crc;
461 return i;
462}
463
464#define P_TSID 0x8008 // pseudo TS ID
465#define P_PMT_PID 0x0084 // pseudo PMT pid
466#define MAXPID 0x2000 // the maximum possible number of pids
467
469{
470 bool Used[MAXPID] = { false };
471#define SETPID(p) { if ((p) >= 0 && (p) < MAXPID) Used[p] = true; }
472#define SETPIDS(l) { const int *p = l; while (*p) { SETPID(*p); p++; } }
473 SETPID(Channel->Vpid());
474 SETPID(Channel->Ppid());
475 SETPID(Channel->Tpid());
476 SETPIDS(Channel->Apids());
477 SETPIDS(Channel->Dpids());
478 SETPIDS(Channel->Spids());
479 for (pmtPid = P_PMT_PID; Used[pmtPid]; pmtPid++)
480 ;
481}
482
484{
485 memset(pat, 0xFF, sizeof(pat));
486 uchar *p = pat;
487 int i = 0;
488 p[i++] = TS_SYNC_BYTE; // TS indicator
489 p[i++] = TS_PAYLOAD_START | (PATPID >> 8); // flags (3), pid hi (5)
490 p[i++] = PATPID & 0xFF; // pid lo
491 p[i++] = 0x10; // flags (4), continuity counter (4)
492 p[i++] = 0x00; // pointer field (payload unit start indicator is set)
493 int PayloadStart = i;
494 p[i++] = 0x00; // table id
495 p[i++] = 0xB0; // section syntax indicator (1), dummy (3), section length hi (4)
496 int SectionLength = i;
497 p[i++] = 0x00; // section length lo (filled in later)
498 p[i++] = P_TSID >> 8; // TS id hi
499 p[i++] = P_TSID & 0xFF; // TS id lo
500 p[i++] = 0xC1 | (patVersion << 1); // dummy (2), version number (5), current/next indicator (1)
501 p[i++] = 0x00; // section number
502 p[i++] = 0x00; // last section number
503 p[i++] = pmtPid >> 8; // program number hi
504 p[i++] = pmtPid & 0xFF; // program number lo
505 p[i++] = 0xE0 | (pmtPid >> 8); // dummy (3), PMT pid hi (5)
506 p[i++] = pmtPid & 0xFF; // PMT pid lo
507 pat[SectionLength] = i - SectionLength - 1 + 4; // -1 = SectionLength storage, +4 = length of CRC
508 MakeCRC(pat + i, pat + PayloadStart, i - PayloadStart);
510}
511
513{
514 // generate the complete PMT section:
516 memset(buf, 0xFF, sizeof(buf));
517 numPmtPackets = 0;
518 if (Channel) {
519 int Vpid = Channel->Vpid();
520 int Ppid = Channel->Ppid();
521 uchar *p = buf;
522 int i = 0;
523 p[i++] = 0x02; // table id
524 int SectionLength = i;
525 p[i++] = 0xB0; // section syntax indicator (1), dummy (3), section length hi (4)
526 p[i++] = 0x00; // section length lo (filled in later)
527 p[i++] = pmtPid >> 8; // program number hi
528 p[i++] = pmtPid & 0xFF; // program number lo
529 p[i++] = 0xC1 | (pmtVersion << 1); // dummy (2), version number (5), current/next indicator (1)
530 p[i++] = 0x00; // section number
531 p[i++] = 0x00; // last section number
532 p[i++] = 0xE0 | (Ppid >> 8); // dummy (3), PCR pid hi (5)
533 p[i++] = Ppid; // PCR pid lo
534 p[i++] = 0xF0; // dummy (4), program info length hi (4)
535 p[i++] = 0x00; // program info length lo
536
537 if (Vpid)
538 i += MakeStream(buf + i, Channel->Vtype(), Vpid);
539 for (int n = 0; Channel->Apid(n); n++) {
540 i += MakeStream(buf + i, Channel->Atype(n), Channel->Apid(n));
541 const char *Alang = Channel->Alang(n);
542 i += MakeLanguageDescriptor(buf + i, Alang);
543 }
544 for (int n = 0; Channel->Dpid(n); n++) {
545 i += MakeStream(buf + i, 0x06, Channel->Dpid(n));
546 i += MakeAC3Descriptor(buf + i, Channel->Dtype(n));
547 i += MakeLanguageDescriptor(buf + i, Channel->Dlang(n));
548 }
549 for (int n = 0; Channel->Spid(n); n++) {
550 i += MakeStream(buf + i, 0x06, Channel->Spid(n));
551 i += MakeSubtitlingDescriptor(buf + i, Channel->Slang(n), Channel->SubtitlingType(n), Channel->CompositionPageId(n), Channel->AncillaryPageId(n));
552 }
553
554 int sl = i - SectionLength - 2 + 4; // -2 = SectionLength storage, +4 = length of CRC
555 buf[SectionLength] |= (sl >> 8) & 0x0F;
556 buf[SectionLength + 1] = sl;
557 MakeCRC(buf + i, buf, i);
558 // split the PMT section into several TS packets:
559 uchar *q = buf;
560 bool pusi = true;
561 while (i > 0) {
562 uchar *p = pmt[numPmtPackets++];
563 int j = 0;
564 p[j++] = TS_SYNC_BYTE; // TS indicator
565 p[j++] = (pusi ? TS_PAYLOAD_START : 0x00) | (pmtPid >> 8); // flags (3), pid hi (5)
566 p[j++] = pmtPid & 0xFF; // pid lo
567 p[j++] = 0x10; // flags (4), continuity counter (4)
568 if (pusi) {
569 p[j++] = 0x00; // pointer field (payload unit start indicator is set)
570 pusi = false;
571 }
572 int l = TS_SIZE - j;
573 memcpy(p + j, q, l);
574 q += l;
575 i -= l;
576 }
578 }
579}
580
581void cPatPmtGenerator::SetVersions(int PatVersion, int PmtVersion)
582{
583 patVersion = PatVersion & 0x1F;
584 pmtVersion = PmtVersion & 0x1F;
585}
586
588{
589 if (Channel) {
590 GeneratePmtPid(Channel);
591 GeneratePat();
592 GeneratePmt(Channel);
593 }
594}
595
597{
599 return pat;
600}
601
603{
604 if (Index < numPmtPackets) {
605 IncCounter(pmtCounter, pmt[Index]);
606 return pmt[Index++];
607 }
608 return NULL;
609}
610
611// --- cPatPmtParser ---------------------------------------------------------
612
613cPatPmtParser::cPatPmtParser(bool UpdatePrimaryDevice)
614{
615 updatePrimaryDevice = UpdatePrimaryDevice;
616 Reset();
617}
618
620{
621 completed = false;
622 pmtSize = 0;
623 patVersion = pmtVersion = -1;
624 pmtPids[0] = 0;
625 vpid = vtype = 0;
626 ppid = 0;
627}
628
629void cPatPmtParser::ParsePat(const uchar *Data, int Length)
630{
631 // Unpack the TS packet:
632 int PayloadOffset = TsPayloadOffset(Data);
633 Data += PayloadOffset;
634 Length -= PayloadOffset;
635 // The PAT is always assumed to fit into a single TS packet
636 if ((Length -= Data[0] + 1) <= 0)
637 return;
638 Data += Data[0] + 1; // process pointer_field
639 SI::PAT Pat(Data, false);
640 if (Pat.CheckCRCAndParse()) {
641 dbgpatpmt("PAT: TSid = %d, c/n = %d, v = %d, s = %d, ls = %d\n", Pat.getTransportStreamId(), Pat.getCurrentNextIndicator(), Pat.getVersionNumber(), Pat.getSectionNumber(), Pat.getLastSectionNumber());
642 if (patVersion == Pat.getVersionNumber())
643 return;
644 int NumPmtPids = 0;
646 for (SI::Loop::Iterator it; Pat.associationLoop.getNext(assoc, it); ) {
647 dbgpatpmt(" isNITPid = %d\n", assoc.isNITPid());
648 if (!assoc.isNITPid()) {
649 if (NumPmtPids <= MAX_PMT_PIDS)
650 pmtPids[NumPmtPids++] = assoc.getPid();
651 dbgpatpmt(" service id = %d, pid = %d\n", assoc.getServiceId(), assoc.getPid());
652 }
653 }
654 pmtPids[NumPmtPids] = 0;
656 }
657 else
658 esyslog("ERROR: can't parse PAT");
659}
660
661void cPatPmtParser::ParsePmt(const uchar *Data, int Length)
662{
663 // Unpack the TS packet:
664 bool PayloadStart = TsPayloadStart(Data);
665 int PayloadOffset = TsPayloadOffset(Data);
666 Data += PayloadOffset;
667 Length -= PayloadOffset;
668 // The PMT may extend over several TS packets, so we need to assemble them
669 if (PayloadStart) {
670 pmtSize = 0;
671 if ((Length -= Data[0] + 1) <= 0)
672 return;
673 Data += Data[0] + 1; // this is the first packet
674 if (SectionLength(Data, Length) > Length) {
675 if (Length <= int(sizeof(pmt))) {
676 memcpy(pmt, Data, Length);
677 pmtSize = Length;
678 }
679 else
680 esyslog("ERROR: PMT packet length too big (%d byte)!", Length);
681 return;
682 }
683 // the packet contains the entire PMT section, so we run into the actual parsing
684 }
685 else if (pmtSize > 0) {
686 // this is a following packet, so we add it to the pmt storage
687 if (Length <= int(sizeof(pmt)) - pmtSize) {
688 memcpy(pmt + pmtSize, Data, Length);
689 pmtSize += Length;
690 }
691 else {
692 esyslog("ERROR: PMT section length too big (%d byte)!", pmtSize + Length);
693 pmtSize = 0;
694 }
696 return; // more packets to come
697 // the PMT section is now complete, so we run into the actual parsing
698 Data = pmt;
699 }
700 else
701 return; // fragment of broken packet - ignore
702 SI::PMT Pmt(Data, false);
703 if (Pmt.CheckCRCAndParse()) {
704 dbgpatpmt("PMT: sid = %d, c/n = %d, v = %d, s = %d, ls = %d\n", Pmt.getServiceId(), Pmt.getCurrentNextIndicator(), Pmt.getVersionNumber(), Pmt.getSectionNumber(), Pmt.getLastSectionNumber());
705 dbgpatpmt(" pcr = %d\n", Pmt.getPCRPid());
706 if (pmtVersion == Pmt.getVersionNumber())
707 return;
710 int NumApids = 0;
711 int NumDpids = 0;
712 int NumSpids = 0;
713 vpid = vtype = 0;
714 ppid = 0;
715 apids[0] = 0;
716 dpids[0] = 0;
717 spids[0] = 0;
718 atypes[0] = 0;
719 dtypes[0] = 0;
720 SI::PMT::Stream stream;
721 for (SI::Loop::Iterator it; Pmt.streamLoop.getNext(stream, it); ) {
722 dbgpatpmt(" stream type = %02X, pid = %d", stream.getStreamType(), stream.getPid());
723 switch (stream.getStreamType()) {
724 case 0x01: // STREAMTYPE_11172_VIDEO
725 case 0x02: // STREAMTYPE_13818_VIDEO
726 case 0x1B: // H.264
727 case 0x24: // H.265
728 vpid = stream.getPid();
729 vtype = stream.getStreamType();
730 ppid = Pmt.getPCRPid();
731 break;
732 case 0x03: // STREAMTYPE_11172_AUDIO
733 case 0x04: // STREAMTYPE_13818_AUDIO
734 case 0x0F: // ISO/IEC 13818-7 Audio with ADTS transport syntax
735 case 0x11: // ISO/IEC 14496-3 Audio with LATM transport syntax
736 {
737 if (NumApids < MAXAPIDS) {
738 apids[NumApids] = stream.getPid();
739 atypes[NumApids] = stream.getStreamType();
740 *alangs[NumApids] = 0;
742 for (SI::Loop::Iterator it; (d = stream.streamDescriptors.getNext(it)); ) {
743 switch (d->getDescriptorTag()) {
747 char *s = alangs[NumApids];
748 int n = 0;
749 for (SI::Loop::Iterator it; ld->languageLoop.getNext(l, it); ) {
750 if (*ld->languageCode != '-') { // some use "---" to indicate "none"
751 dbgpatpmt(" '%s'", l.languageCode);
752 if (n > 0)
753 *s++ = '+';
755 s += strlen(s);
756 if (n++ > 1)
757 break;
758 }
759 }
760 }
761 break;
762 default: ;
763 }
764 delete d;
765 }
767 cDevice::PrimaryDevice()->SetAvailableTrack(ttAudio, NumApids, apids[NumApids], alangs[NumApids]);
768 NumApids++;
769 apids[NumApids] = 0;
770 }
771 }
772 break;
773 case 0x06: // STREAMTYPE_13818_PES_PRIVATE
774 {
775 int dpid = 0;
776 int dtype = 0;
777 char lang[MAXLANGCODE1] = "";
779 for (SI::Loop::Iterator it; (d = stream.streamDescriptors.getNext(it)); ) {
780 switch (d->getDescriptorTag()) {
783 dbgpatpmt(" AC3");
784 dpid = stream.getPid();
785 dtype = d->getDescriptorTag();
786 break;
788 dbgpatpmt(" subtitling");
789 if (NumSpids < MAXSPIDS) {
790 spids[NumSpids] = stream.getPid();
791 *slangs[NumSpids] = 0;
792 subtitlingTypes[NumSpids] = 0;
793 compositionPageIds[NumSpids] = 0;
794 ancillaryPageIds[NumSpids] = 0;
797 char *s = slangs[NumSpids];
798 int n = 0;
799 for (SI::Loop::Iterator it; sd->subtitlingLoop.getNext(sub, it); ) {
800 if (sub.languageCode[0]) {
801 dbgpatpmt(" '%s'", sub.languageCode);
802 subtitlingTypes[NumSpids] = sub.getSubtitlingType();
804 ancillaryPageIds[NumSpids] = sub.getAncillaryPageId();
805 if (n > 0)
806 *s++ = '+';
808 s += strlen(s);
809 if (n++ > 1)
810 break;
811 }
812 }
814 cDevice::PrimaryDevice()->SetAvailableTrack(ttSubtitle, NumSpids, spids[NumSpids], slangs[NumSpids]);
815 NumSpids++;
816 spids[NumSpids] = 0;
817 }
818 break;
821 dbgpatpmt(" '%s'", ld->languageCode);
823 }
824 break;
825 default: ;
826 }
827 delete d;
828 }
829 if (dpid) {
830 if (NumDpids < MAXDPIDS) {
831 dpids[NumDpids] = dpid;
832 dtypes[NumDpids] = dtype;
833 strn0cpy(dlangs[NumDpids], lang, sizeof(dlangs[NumDpids]));
834 if (updatePrimaryDevice && Setup.UseDolbyDigital)
835 cDevice::PrimaryDevice()->SetAvailableTrack(ttDolby, NumDpids, dpid, lang);
836 NumDpids++;
837 dpids[NumDpids] = 0;
838 }
839 }
840 }
841 break;
842 case 0x81: // STREAMTYPE_USER_PRIVATE - AC3 audio for ATSC and BD
843 case 0x82: // STREAMTYPE_USER_PRIVATE - DTS audio for BD
844 case 0x87: // eac3
845 {
846 dbgpatpmt(" %s",
847 stream.getStreamType() == 0x81 ? "AC3" :
848 stream.getStreamType() == 0x87 ? "AC3" :
849 stream.getStreamType() == 0x82 ? "DTS" : "");
850 char lang[MAXLANGCODE1] = { 0 };
852 for (SI::Loop::Iterator it; (d = stream.streamDescriptors.getNext(it)); ) {
853 switch (d->getDescriptorTag()) {
856 dbgpatpmt(" '%s'", ld->languageCode);
858 }
859 break;
860 default: ;
861 }
862 delete d;
863 }
864 if (NumDpids < MAXDPIDS) {
865 dpids[NumDpids] = stream.getPid();
866 dtypes[NumDpids] = SI::AC3DescriptorTag;
867 strn0cpy(dlangs[NumDpids], lang, sizeof(dlangs[NumDpids]));
868 if (updatePrimaryDevice && Setup.UseDolbyDigital)
869 cDevice::PrimaryDevice()->SetAvailableTrack(ttDolby, NumDpids, stream.getPid(), lang);
870 NumDpids++;
871 dpids[NumDpids] = 0;
872 }
873 }
874 break;
875 case 0x90: // PGS subtitles for BD
876 {
877 dbgpatpmt(" subtitling");
878 char lang[MAXLANGCODE1] = { 0 };
880 for (SI::Loop::Iterator it; (d = stream.streamDescriptors.getNext(it)); ) {
881 switch (d->getDescriptorTag()) {
884 dbgpatpmt(" '%s'", ld->languageCode);
886 if (NumSpids < MAXSPIDS) {
887 spids[NumSpids] = stream.getPid();
888 *slangs[NumSpids] = 0;
889 subtitlingTypes[NumSpids] = 0;
890 compositionPageIds[NumSpids] = 0;
891 ancillaryPageIds[NumSpids] = 0;
893 cDevice::PrimaryDevice()->SetAvailableTrack(ttSubtitle, NumSpids, stream.getPid(), lang);
894 NumSpids++;
895 spids[NumSpids] = 0;
896 }
897 }
898 break;
899 default: ;
900 }
901 delete d;
902 }
903 }
904 break;
905 default: ;
906 }
907 dbgpatpmt("\n");
911 }
912 }
914 completed = true;
915 }
916 else
917 esyslog("ERROR: can't parse PMT");
918 pmtSize = 0;
919}
920
921bool cPatPmtParser::ParsePatPmt(const uchar *Data, int Length)
922{
923 while (Length >= TS_SIZE) {
924 if (*Data != TS_SYNC_BYTE)
925 break; // just for safety
926 int Pid = TsPid(Data);
927 if (Pid == PATPID)
928 ParsePat(Data, TS_SIZE);
929 else if (IsPmtPid(Pid)) {
930 ParsePmt(Data, TS_SIZE);
931 if (patVersion >= 0 && pmtVersion >= 0)
932 return true;
933 }
934 Data += TS_SIZE;
935 Length -= TS_SIZE;
936 }
937 return false;
938}
939
940bool cPatPmtParser::GetVersions(int &PatVersion, int &PmtVersion) const
941{
942 PatVersion = patVersion;
943 PmtVersion = pmtVersion;
944 return patVersion >= 0 && pmtVersion >= 0;
945}
946
947// --- cEitGenerator ---------------------------------------------------------
948
950{
951 counter = 0;
952 version = 0;
953 if (Sid)
954 Generate(Sid);
955}
956
957uint16_t cEitGenerator::YMDtoMJD(int Y, int M, int D)
958{
959 int L = (M < 3) ? 1 : 0;
960 return 14956 + D + int((Y - L) * 365.25) + int((M + 1 + L * 12) * 30.6001);
961}
962
964{
966 *p++ = 0x04; // descriptor length
967 *p++ = '9'; // country code "902" ("All countries") -> EN 300 468 / 6.2.28; www.dvbservices.com/country_codes/index.php
968 *p++ = '0';
969 *p++ = '2';
970 *p++ = ParentalRating;
971 return p;
972}
973
975{
976 uchar *PayloadStart;
977 uchar *SectionStart;
978 uchar *DescriptorsStart;
979 memset(eit, 0xFF, sizeof(eit));
980 struct tm tm_r;
981 time_t t = time(NULL) - 3600; // let's have the event start one hour in the past
982 tm *tm = localtime_r(&t, &tm_r);
983 uint16_t MJD = YMDtoMJD(tm->tm_year, tm->tm_mon + 1, tm->tm_mday);
984 uchar *p = eit;
985 // TS header:
986 *p++ = TS_SYNC_BYTE;
987 *p++ = TS_PAYLOAD_START;
988 *p++ = EITPID;
989 *p++ = 0x10 | (counter++ & 0x0F); // continuity counter
990 *p++ = 0x00; // pointer field (payload unit start indicator is set)
991 // payload:
992 PayloadStart = p;
993 *p++ = 0x4E; // TID present/following event on this transponder
994 *p++ = 0xF0;
995 *p++ = 0x00; // section length
996 SectionStart = p;
997 *p++ = Sid >> 8;
998 *p++ = Sid & 0xFF;
999 *p++ = 0xC1 | (version << 1);
1000 *p++ = 0x00; // section number
1001 *p++ = 0x00; // last section number
1002 *p++ = 0x00; // transport stream id
1003 *p++ = 0x00; // ...
1004 *p++ = 0x00; // original network id
1005 *p++ = 0x00; // ...
1006 *p++ = 0x00; // segment last section number
1007 *p++ = 0x4E; // last table id
1008 *p++ = 0x00; // event id
1009 *p++ = 0x01; // ...
1010 *p++ = MJD >> 8; // start time
1011 *p++ = MJD & 0xFF; // ...
1012 *p++ = tm->tm_hour; // ...
1013 *p++ = tm->tm_min; // ...
1014 *p++ = tm->tm_sec; // ...
1015 *p++ = 0x24; // duration (one day, should cover everything)
1016 *p++ = 0x00; // ...
1017 *p++ = 0x00; // ...
1018 *p++ = 0x90; // running status, free/CA mode
1019 *p++ = 0x00; // descriptors loop length
1020 DescriptorsStart = p;
1022 // fill in lengths:
1023 *(SectionStart - 1) = p - SectionStart + 4; // +4 = length of CRC
1024 *(DescriptorsStart - 1) = p - DescriptorsStart;
1025 // checksum
1026 int crc = SI::CRC32::crc32((char *)PayloadStart, p - PayloadStart, 0xFFFFFFFF);
1027 *p++ = crc >> 24;
1028 *p++ = crc >> 16;
1029 *p++ = crc >> 8;
1030 *p++ = crc;
1031 return eit;
1032}
1033
1034// --- cTsToPes --------------------------------------------------------------
1035
1037{
1038 data = NULL;
1039 size = 0;
1040 Reset();
1041}
1042
1044{
1045 free(data);
1046}
1047
1048void cTsToPes::PutTs(const uchar *Data, int Length)
1049{
1050 if (TsError(Data)) {
1051 Reset();
1052 return; // ignore packets with TEI set, and drop any PES data collected so far
1053 }
1054 if (TsPayloadStart(Data))
1055 Reset();
1056 else if (!size)
1057 return; // skip everything before the first payload start
1058 Length = TsGetPayload(&Data);
1059 if (length + Length > size) {
1060 int NewSize = max(KILOBYTE(2), length + Length);
1061 if (uchar *NewData = (uchar *)realloc(data, NewSize)) {
1062 data = NewData;
1063 size = NewSize;
1064 }
1065 else {
1066 esyslog("ERROR: out of memory");
1067 Reset();
1068 return;
1069 }
1070 }
1071 memcpy(data + length, Data, Length);
1072 length += Length;
1073}
1074
1075#define MAXPESLENGTH 0xFFF0
1076
1077const uchar *cTsToPes::GetPes(int &Length)
1078{
1079 if (repeatLast) {
1080 repeatLast = false;
1081 Length = lastLength;
1082 return lastData;
1083 }
1084 if (offset < length && PesLongEnough(length)) {
1085 if (!PesHasLength(data)) // this is a video PES packet with undefined length
1086 offset = 6; // trigger setting PES length for initial slice
1087 if (offset) {
1088 uchar *p = data + offset - 6;
1089 if (p != data) {
1090 p -= 3;
1091 if (p < data) {
1092 Reset();
1093 return NULL;
1094 }
1095 memmove(p, data, 4);
1096 }
1097 int l = min(length - offset, MAXPESLENGTH);
1098 offset += l;
1099 if (p != data) {
1100 l += 3;
1101 p[6] = 0x80;
1102 p[7] = 0x00;
1103 p[8] = 0x00;
1104 }
1105 p[4] = l / 256;
1106 p[5] = l & 0xFF;
1107 Length = l + 6;
1108 lastLength = Length;
1109 lastData = p;
1110 return p;
1111 }
1112 else {
1113 Length = PesLength(data);
1114 if (Length <= length) {
1115 offset = Length; // to make sure we break out in case of garbage data
1116 lastLength = Length;
1117 lastData = data;
1118 return data;
1119 }
1120 }
1121 }
1122 return NULL;
1123}
1124
1126{
1127 repeatLast = true;
1128}
1129
1131{
1132 length = offset = 0;
1133 lastData = NULL;
1134 lastLength = 0;
1135 repeatLast = false;
1136}
1137
1138// --- Some helper functions for debugging -----------------------------------
1139
1140void BlockDump(const char *Name, const u_char *Data, int Length)
1141{
1142 printf("--- %s\n", Name);
1143 for (int i = 0; i < Length; i++) {
1144 if (i && (i % 16) == 0)
1145 printf("\n");
1146 printf(" %02X", Data[i]);
1147 }
1148 printf("\n");
1149}
1150
1151void TsDump(const char *Name, const u_char *Data, int Length)
1152{
1153 printf("%s: %04X", Name, Length);
1154 int n = min(Length, 20);
1155 for (int i = 0; i < n; i++)
1156 printf(" %02X", Data[i]);
1157 if (n < Length) {
1158 printf(" ...");
1159 n = max(n, Length - 10);
1160 for (n = max(n, Length - 10); n < Length; n++)
1161 printf(" %02X", Data[n]);
1162 }
1163 printf("\n");
1164}
1165
1166void PesDump(const char *Name, const u_char *Data, int Length)
1167{
1168 TsDump(Name, Data, Length);
1169}
1170
1171// --- cFrameParser ----------------------------------------------------------
1172
1174protected:
1175 bool debug;
1179 uint16_t frameWidth;
1180 uint16_t frameHeight;
1184public:
1185 cFrameParser(void);
1186 virtual ~cFrameParser() {};
1187 virtual int Parse(const uchar *Data, int Length, int Pid) = 0;
1194 void SetDebug(bool Debug) { debug = Debug; }
1195 bool NewFrame(void) { return newFrame; }
1196 bool IndependentFrame(void) { return independentFrame; }
1198 uint16_t FrameWidth(void) { return frameWidth; }
1199 uint16_t FrameHeight(void) { return frameHeight; }
1200 double FramesPerSecond(void) { return framesPerSecond; }
1201 eScanType ScanType(void) { return scanType; }
1203 };
1204
1206{
1207 debug = true;
1208 newFrame = false;
1209 independentFrame = false;
1211 frameWidth = 0;
1212 frameHeight = 0;
1213 framesPerSecond = 0.0;
1216}
1217
1218// --- cAudioParser ----------------------------------------------------------
1219
1221public:
1222 cAudioParser(void);
1223 virtual int Parse(const uchar *Data, int Length, int Pid) override;
1224 };
1225
1229
1230int cAudioParser::Parse(const uchar *Data, int Length, int Pid)
1231{
1232 if (TsPayloadStart(Data)) {
1233 newFrame = independentFrame = true;
1234 if (debug)
1235 dbgframes("/");
1236 }
1237 else
1238 newFrame = independentFrame = false;
1239 return TS_SIZE;
1240}
1241
1242// --- cMpeg2Parser ----------------------------------------------------------
1243
1245private:
1246 uint32_t scanner;
1250 const double frame_rate_table[9] = {
1251 0, // 0 forbidden
1252 24000./1001., // 1 23.976...
1253 24., // 2 24
1254 25., // 3 25
1255 30000./1001., // 4 29.97...
1256 30., // 5 30
1257 50., // 6 50
1258 60000./1001., // 7 59.94...
1259 60. // 8 60
1260 };
1261public:
1262 cMpeg2Parser(void);
1263 virtual int Parse(const uchar *Data, int Length, int Pid) override;
1264 };
1265
1267{
1269 seenIndependentFrame = false;
1270 lastIFrameTemporalReference = -1; // invalid
1271 seenScanType = false;
1272}
1273
1274int cMpeg2Parser::Parse(const uchar *Data, int Length, int Pid)
1275{
1276 newFrame = independentFrame = false;
1277 bool SeenPayloadStart = false;
1278 cTsPayload tsPayload(const_cast<uchar *>(Data), Length, Pid);
1279 if (TsPayloadStart(Data)) {
1280 SeenPayloadStart = true;
1281 tsPayload.SkipPesHeader();
1284 dbgframes("/");
1285 }
1286 uint32_t OldScanner = scanner; // need to remember it in case of multiple frames per payload
1287 for (;;) {
1288 if (!SeenPayloadStart && tsPayload.AtTsStart())
1289 OldScanner = scanner;
1290 scanner = (scanner << 8) | tsPayload.GetByte();
1291 if (scanner == 0x00000100) { // Picture Start Code
1292 if (!SeenPayloadStart && tsPayload.GetLastIndex() > TS_SIZE) {
1293 scanner = OldScanner;
1294 return tsPayload.Used() - TS_SIZE;
1295 }
1296 uchar b1 = tsPayload.GetByte();
1297 uchar b2 = tsPayload.GetByte();
1298 int TemporalReference = (b1 << 2 ) + ((b2 & 0xC0) >> 6);
1299 uchar FrameType = (b2 >> 3) & 0x07;
1300 if (tsPayload.Find(0x000001B5)) { // Extension start code
1301 if (((tsPayload.GetByte() & 0xF0) >> 4) == 0x08) { // Picture coding extension
1302 tsPayload.GetByte();
1303 uchar PictureStructure = tsPayload.GetByte() & 0x03;
1304 if (PictureStructure == 0x02) // bottom field
1305 break;
1306 }
1307 }
1308 newFrame = true;
1309 independentFrame = FrameType == 1; // I-Frame
1310 if (independentFrame) {
1313 lastIFrameTemporalReference = TemporalReference;
1314 }
1315 if (debug) {
1318 static const char FrameTypes[] = "?IPBD???";
1319 dbgframes("%c", FrameTypes[FrameType]);
1320 }
1321 }
1322 tsPayload.Statistics();
1323 break;
1324 }
1325 else if (frameWidth == 0 && scanner == 0x000001B3) { // Sequence header code
1326 frameWidth = tsPayload.GetByte() << 4;
1327 uchar b = tsPayload.GetByte(); // ignoring two MSB of width and height in sequence extension
1328 frameWidth |= b >> 4; // as 12 Bit = max 4095 should be sufficient for all available MPEG2 streams
1329 frameHeight = (b & 0x0F) << 8 | tsPayload.GetByte();
1330 b = tsPayload.GetByte(); // hi: aspect ratio info, lo: frame rate code
1331 switch (b >> 4) {
1332 case 1: aspectRatio = ar_1_1; break;
1333 case 2: aspectRatio = ar_4_3; break;
1334 case 3: aspectRatio = ar_16_9; break;
1335 case 4: aspectRatio = ar_2_21_1; break;
1336 default: aspectRatio = arUnknown;
1337 }
1338 uchar frame_rate_value = b & 0x0F;
1339 if (frame_rate_value > 0 && frame_rate_value <= 8)
1340 framesPerSecond = frame_rate_table[frame_rate_value];
1341 }
1342 else if (!seenScanType && scanner == 0x000001B5) { // Extension start code
1343 if ((tsPayload.GetByte() & 0xF0) == 0x10) { // Sequence Extension
1344 scanType = (tsPayload.GetByte() & 0x40) ? stProgressive : stInterlaced;
1345 seenScanType = true;
1346 if (debug) {
1348 dsyslog("%s", *s);
1349 dbgframes("\n%s", *s);
1350 }
1351 }
1352 }
1353 if (tsPayload.AtPayloadStart() // stop at a new payload start to have the buffer refilled if necessary
1354 || tsPayload.Eof()) // or if we're out of data
1355 break;
1356 }
1357 return tsPayload.Used();
1358}
1359
1360// --- cH264Parser -----------------------------------------------------------
1361
1363private:
1370 uchar byte; // holds the current byte value in case of bitwise access
1371 int bit; // the bit index into the current byte (-1 if we're not in bit reading mode)
1372 int zeroBytes; // the number of consecutive zero bytes (to detect 0x000003)
1373 // Identifiers written in '_' notation as in "ITU-T H.264":
1377protected:
1379 uint32_t scanner;
1382 uchar GetByte(bool Raw = false);
1386 uchar GetBit(void);
1387 uint32_t GetBits(int Bits);
1388 uint32_t GetGolombUe(void);
1389 int32_t GetGolombSe(void);
1390 void ParseAccessUnitDelimiter(void);
1391 void ParseSequenceParameterSet(void);
1392 void ParseSliceHeader(void);
1393public:
1394 cH264Parser(void);
1398 virtual int Parse(const uchar *Data, int Length, int Pid) override;
1399 };
1400
1402{
1403 byte = 0;
1404 bit = -1;
1405 zeroBytes = 0;
1409 frame_mbs_only_flag = false;
1410 gotAccessUnitDelimiter = false;
1412}
1413
1415{
1416 uchar b = tsPayload.GetByte();
1417 if (!Raw) {
1418 // If we encounter the byte sequence 0x000003, we need to skip the 0x03:
1419 if (b == 0x00)
1420 zeroBytes++;
1421 else {
1422 if (b == 0x03 && zeroBytes >= 2)
1423 b = tsPayload.GetByte();
1424 zeroBytes = b ? 0 : 1;
1425 }
1426 }
1427 else
1428 zeroBytes = 0;
1429 bit = -1;
1430 return b;
1431}
1432
1434{
1435 if (bit < 0) {
1436 byte = GetByte();
1437 bit = 7;
1438 }
1439 return (byte & (1 << bit--)) ? 1 : 0;
1440}
1441
1442uint32_t cH264Parser::GetBits(int Bits)
1443{
1444 uint32_t b = 0;
1445 while (Bits--)
1446 b |= GetBit() << Bits;
1447 return b;
1448}
1449
1451{
1452 int z = -1;
1453 for (int b = 0; !b && z < 32; z++) // limiting z to no get stuck if GetBit() always returns 0
1454 b = GetBit();
1455 return (1 << z) - 1 + GetBits(z);
1456}
1457
1459{
1460 uint32_t v = GetGolombUe();
1461 if (v) {
1462 if ((v & 0x01) != 0)
1463 return (v + 1) / 2; // fails for v == 0xFFFFFFFF, but that will probably never happen
1464 else
1465 return -int32_t(v / 2);
1466 }
1467 return v;
1468}
1469
1470int cH264Parser::Parse(const uchar *Data, int Length, int Pid)
1471{
1472 newFrame = independentFrame = false;
1473 tsPayload.Setup(const_cast<uchar *>(Data), Length, Pid);
1474 if (TsPayloadStart(Data)) {
1475 tsPayload.SkipPesHeader();
1478 dbgframes("/");
1479 }
1480 }
1481 for (;;) {
1482 scanner = (scanner << 8) | GetByte(true);
1483 if ((scanner & 0xFFFFFF00) == 0x00000100) { // NAL unit start
1484 uchar NalUnitType = scanner & 0x1F;
1485 switch (NalUnitType) {
1488 break;
1492 }
1493 break;
1497 gotAccessUnitDelimiter = false;
1498 if (newFrame)
1499 tsPayload.Statistics();
1500 return tsPayload.Used();
1501 }
1502 break;
1503 default: ;
1504 }
1505 }
1506 if (tsPayload.AtPayloadStart() // stop at a new payload start to have the buffer refilled if necessary
1507 || tsPayload.Eof()) // or if we're out of data
1508 break;
1509 }
1510 return tsPayload.Used();
1511}
1512
1514{
1516 dbgframes("A");
1517 GetByte(); // primary_pic_type
1518}
1519
1521{
1522 int chroma_format_idc = 0;
1523 int bitDepth = 0;
1524 uchar profile_idc = GetByte(); // profile_idc
1525 GetByte(); // constraint_set[0-5]_flags, reserved_zero_2bits
1526 GetByte(); // level_idc
1527 GetGolombUe(); // seq_parameter_set_id
1528 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) {
1529 chroma_format_idc = GetGolombUe(); // chroma_format_idc
1530 if (chroma_format_idc == 3)
1532 bitDepth = 8 + GetGolombUe(); // bit_depth_luma_minus8
1533 GetGolombUe(); // bit_depth_chroma_minus8
1534 GetBit(); // qpprime_y_zero_transform_bypass_flag
1535 if (GetBit()) { // seq_scaling_matrix_present_flag
1536 for (int i = 0; i < ((chroma_format_idc != 3) ? 8 : 12); i++) {
1537 if (GetBit()) { // seq_scaling_list_present_flag
1538 int SizeOfScalingList = (i < 6) ? 16 : 64;
1539 int LastScale = 8;
1540 int NextScale = 8;
1541 for (int j = 0; j < SizeOfScalingList; j++) {
1542 if (NextScale)
1543 NextScale = (LastScale + GetGolombSe() + 256) % 256; // delta_scale
1544 if (NextScale)
1545 LastScale = NextScale;
1546 }
1547 }
1548 }
1549 }
1550 }
1551 log2_max_frame_num = GetGolombUe() + 4; // log2_max_frame_num_minus4
1552 int pic_order_cnt_type = GetGolombUe(); // pic_order_cnt_type
1553 if (pic_order_cnt_type == 0)
1554 GetGolombUe(); // log2_max_pic_order_cnt_lsb_minus4
1555 else if (pic_order_cnt_type == 1) {
1556 GetBit(); // delta_pic_order_always_zero_flag
1557 GetGolombSe(); // offset_for_non_ref_pic
1558 GetGolombSe(); // offset_for_top_to_bottom_field
1559 for (int i = GetGolombUe(); i--; ) // num_ref_frames_in_pic_order_cnt_cycle
1560 GetGolombSe(); // offset_for_ref_frame
1561 }
1562 GetGolombUe(); // max_num_ref_frames
1563 GetBit(); // gaps_in_frame_num_value_allowed_flag
1564 uint16_t frame_Width = 16 * (1 + GetGolombUe()); // pic_width_in_mbs_minus1
1565 uint16_t frame_Height = 16 * (1 + GetGolombUe()); // pic_height_in_map_units_minus1
1566 frame_mbs_only_flag = GetBit(); // frame_mbs_only_flag
1567 if (frameWidth == 0) {
1569 if (!frame_mbs_only_flag) {
1570 GetBit(); // mb_adaptive_frame_field_flag
1571 frame_Height *= 2;
1572 }
1573 GetBit(); // direct_8x8_inference_flag
1574 bool frame_cropping_flag = GetBit(); // frame_cropping_flag
1575 if (frame_cropping_flag) {
1576 uint16_t frame_crop_left_offset = GetGolombUe(); // frame_crop_left_offset
1577 uint16_t frame_crop_right_offset = GetGolombUe(); // frame_crop_right_offset
1578 uint16_t frame_crop_top_offset = GetGolombUe(); // frame_crop_top_offset
1579 uint16_t frame_crop_bottom_offset = GetGolombUe(); // frame_crop_bottom_offset
1580 uint16_t CropUnitX = 1;
1581 uint16_t CropUnitY = frame_mbs_only_flag ? 1 : 2;
1582 if (!separate_colour_plane_flag && chroma_format_idc > 0) {
1583 if (chroma_format_idc == 1) {
1584 CropUnitX = 2;
1585 CropUnitY *= 2;
1586 }
1587 else if (chroma_format_idc == 2)
1588 CropUnitX = 2;
1589 }
1590 frame_Width -= CropUnitX * (frame_crop_left_offset + frame_crop_right_offset);
1591 frame_Height -= CropUnitY * (frame_crop_top_offset + frame_crop_bottom_offset);
1592 if (frame_Height > 1080 && frame_Height <= 1090) // workaround for channels with wrong crop parameters
1593 frame_Height = 1080;
1594 }
1595 frameWidth = frame_Width;
1596 frameHeight = frame_Height;
1597 // VUI parameters
1598 if (GetBit()) { // vui_parameters_present_flag
1599 if (GetBit()) { // aspect_ratio_info_present
1600 int aspect_ratio_idc = GetBits(8); // aspect_ratio_idc
1601 if (aspect_ratio_idc == 255) // EXTENDED_SAR
1602 GetBits(32); // sar_width, sar_height
1603 else if (frameHeight >= 720 && (aspect_ratio_idc == 1 || aspect_ratio_idc == 14 || aspect_ratio_idc == 15 || aspect_ratio_idc == 16))
1605 // implement decoding of other aspect_ratio_idc values when they are required
1606 }
1607 if (GetBit()) // overscan_info_present_flag
1608 GetBit(); // overscan_approriate_flag
1609 if (GetBit()) { // video_signal_type_present_flag
1610 GetBits(4); // video_format, video_full_range_flag
1611 if (GetBit()) // colour_description_present_flag
1612 GetBits(24); // colour_primaries, transfer_characteristics, matrix_coefficients
1613 }
1614 if (GetBit()) { // chroma_loc_info_present_flag
1615 GetGolombUe(); // chroma_sample_loc_type_top_field
1616 GetGolombUe(); // chroma_sample_loc_type_bottom_field
1617 }
1618 if (GetBit()) { // timing_info_present_flag
1619 uint32_t num_units_in_tick = GetBits(32); // num_units_in_tick
1620 uint32_t time_scale = GetBits(32); // time_scale
1621 if (num_units_in_tick > 0)
1622 framesPerSecond = double(time_scale) / (num_units_in_tick << 1);
1623 }
1624 }
1625 if (debug) {
1626 cString s = cString::sprintf("H.264: %d x %d%c %.2f fps %d Bit %s", frameWidth, frameHeight, ScanTypeChars[scanType], framesPerSecond, bitDepth, AspectRatioTexts[aspectRatio]);
1627 dsyslog("%s", *s);
1628 dbgframes("\n%s", *s);
1629 }
1630 }
1631 if (debug) {
1633 dbgframes("A"); // just for completeness
1634 dbgframes(frame_mbs_only_flag ? "S" : "s");
1635 }
1636}
1637
1639{
1640 newFrame = true;
1641 GetGolombUe(); // first_mb_in_slice
1642 int slice_type = GetGolombUe(); // slice_type, 0 = P, 1 = B, 2 = I, 3 = SP, 4 = SI
1643 independentFrame = (slice_type % 5) == 2;
1644 if (debug) {
1645 static const char SliceTypes[] = "PBIpi";
1646 dbgframes("%c", SliceTypes[slice_type % 5]);
1647 }
1649 return; // don't need the rest - a frame is complete
1650 GetGolombUe(); // pic_parameter_set_id
1652 GetBits(2); // colour_plane_id
1653 GetBits(log2_max_frame_num); // frame_num
1654 if (!frame_mbs_only_flag) {
1655 if (GetBit()) // field_pic_flag
1656 newFrame = !GetBit(); // bottom_field_flag
1657 if (debug)
1658 dbgframes(newFrame ? "t" : "b");
1659 }
1660}
1661
1662// --- cH265Parser -----------------------------------------------------------
1663
1702
1704:cH264Parser()
1705{
1706}
1707
1708int cH265Parser::Parse(const uchar *Data, int Length, int Pid)
1709{
1710 newFrame = independentFrame = false;
1711 tsPayload.Setup(const_cast<uchar *>(Data), Length, Pid);
1712 if (TsPayloadStart(Data)) {
1713 tsPayload.SkipPesHeader();
1715 }
1716 for (;;) {
1717 scanner = (scanner << 8) | GetByte(true);
1718 if ((scanner & 0xFFFFFF00) == 0x00000100) { // NAL unit start
1719 uchar NalUnitType = (scanner >> 1) & 0x3F;
1720 GetByte(); // nuh_layer_id + nuh_temporal_id_plus1
1721 if (NalUnitType <= nutSliceSegmentRASLR || (NalUnitType >= nutSliceSegmentBLAWLP && NalUnitType <= nutSliceSegmentCRANUT)) {
1722 if (NalUnitType == nutSliceSegmentIDRWRADL || NalUnitType == nutSliceSegmentIDRNLP || NalUnitType == nutSliceSegmentCRANUT)
1723 independentFrame = true;
1724 if (GetBit()) { // first_slice_segment_in_pic_flag
1725 newFrame = true;
1726 tsPayload.Statistics();
1727 }
1728 break;
1729 }
1730 else if (frameWidth == 0 && NalUnitType == nutSequenceParameterSet) {
1733 }
1734 }
1735 if (tsPayload.AtPayloadStart() // stop at a new payload start to have the buffer refilled if necessary
1736 || tsPayload.Eof()) // or if we're out of data
1737 break;
1738 }
1739 return tsPayload.Used();
1740}
1741
1743{
1745 uint8_t sub_layer_profile_present_flag[8];
1746 uint8_t sub_layer_level_present_flag[8];
1747 GetBits(4); // sps_video_parameter_set_id
1748 int sps_max_sub_layers_minus1 = GetBits(3) & 7; // sps_max_sub_layers_minus1 ("& 7" to silence a compiler warning with gcc 14.1.0)
1749 GetBit(); // sps_temporal_id_nesting_flag
1750 // begin profile_tier_level(1, sps_max_sub_layers_minus1)
1751 GetByte();
1752 GetByte();
1753 GetByte();
1754 GetByte();
1755 GetByte();
1756 bool general_progressive_source_flag = GetBit(); // general_progressive_source_flag
1757 scanType = general_progressive_source_flag ? stProgressive : stInterlaced;
1758 GetBit(); // general_interlaced_source_flag
1759 GetBits(6);
1760 GetByte();
1761 GetByte();
1762 GetByte();
1763 GetByte();
1764 GetByte();
1765 GetByte(); // general_level_idc
1766 for (int i = 0; i < sps_max_sub_layers_minus1; i++ ) {
1767 sub_layer_profile_present_flag[i] = GetBit(); // sub_layer_profile_present_flag[i]
1768 sub_layer_level_present_flag[i] = GetBit(); // sub_layer_level_present_flag[i]
1769 }
1770 if (sps_max_sub_layers_minus1 > 0) {
1771 for (int i = sps_max_sub_layers_minus1; i < 8; i++ )
1772 GetBits(2); // reserved_zero_2bits[i]
1773 }
1774 for (int i = 0; i < sps_max_sub_layers_minus1; i++ ) {
1775 if (sub_layer_profile_present_flag[i] )
1776 GetBits(88);
1777 if (sub_layer_level_present_flag[i])
1778 GetBits(8);
1779 }
1780 // end profile_tier_level
1781 GetGolombUe(); // sps_seq_parameter_set_id
1782 int chroma_format_idc = GetGolombUe(); // chroma_format_idc
1783 if (chroma_format_idc == 3)
1784 separate_colour_plane_flag = GetBit(); // separate_colour_plane_flag
1785 frameWidth = GetGolombUe(); // pic_width_in_luma_samples
1786 frameHeight = GetGolombUe(); // pic_height_in_luma_samples
1787 bool conformance_window_flag = GetBit(); // conformance_window_flag
1788 if (conformance_window_flag) {
1789 int conf_win_left_offset = GetGolombUe(); // conf_win_left_offset
1790 int conf_win_right_offset = GetGolombUe(); // conf_win_right_offset
1791 int conf_win_top_offset = GetGolombUe(); // conf_win_top_offset
1792 int conf_win_bottom_offset = GetGolombUe(); // conf_win_bottom_offset
1793 uint16_t SubWidthC = 1;
1794 uint16_t SubHeightC = 1;
1795 if (!separate_colour_plane_flag && chroma_format_idc > 0) {
1796 if (chroma_format_idc == 1) {
1797 SubWidthC = 2;
1798 SubHeightC = 2;
1799 }
1800 else if (chroma_format_idc == 2)
1801 SubWidthC = 2;
1802 }
1803 frameWidth -= SubWidthC * (conf_win_left_offset + conf_win_right_offset);
1804 frameHeight -= SubHeightC * (conf_win_top_offset + conf_win_bottom_offset);
1805 }
1806 int bitDepth = 8 + GetGolombUe(); // bit_depth_luma_minus8
1807 GetGolombUe(); // bit_depth_chroma_minus8
1808 int log2_max_pic_order_cnt_lsb_minus4 = GetGolombUe(); // log2_max_pic_order_cnt_lsb_minus4
1809 int sps_sub_layer_ordering_info_present_flag = GetBit(); // sps_sub_layer_ordering_info_present_flag
1810 for (int i = sps_sub_layer_ordering_info_present_flag ? 0 : sps_max_sub_layers_minus1; i <= sps_max_sub_layers_minus1; ++i) {
1811 GetGolombUe(); // sps_max_dec_pic_buffering_minus1[i]
1812 GetGolombUe(); // sps_max_num_reorder_pics[i]
1813 GetGolombUe(); // sps_max_latency_increase_plus1[i]
1814 }
1815 GetGolombUe(); // log2_min_luma_coding_block_size_minus3
1816 GetGolombUe(); // log2_diff_max_min_luma_coding_block_size
1817 GetGolombUe(); // log2_min_luma_transform_block_size_minus2
1818 GetGolombUe(); // log2_diff_max_min_luma_transform_block_size
1819 GetGolombUe(); // max_transform_hierarchy_depth_inter
1820 GetGolombUe(); // max_transform_hierarchy_depth_intra
1821 if (GetBit()) { // scaling_list_enabled_flag
1822 if (GetBit()) { // sps_scaling_list_data_present_flag
1823 // begin scaling_list_data
1824 for (int sizeId = 0; sizeId < 4; ++sizeId) {
1825 for (int matrixId = 0; matrixId < 6; matrixId += (sizeId == 3) ? 3 : 1) {
1826 if (!GetBit()) // scaling_list_pred_mode_flag[sizeId][matrixId]
1827 GetGolombUe(); // scaling_list_pred_matrix_id_delta[sizeId][matrixId]
1828 else {
1829 int coefNum = min(64, (1 << (4 + (sizeId << 1))));
1830 if (sizeId > 1)
1831 GetGolombSe(); // scaling_list_dc_coef_minus8[sizeId−2][matrixId]
1832 for (int i = 0; i < coefNum; ++i)
1833 GetGolombSe(); // scaling_list_delta_coef
1834 }
1835 }
1836 }
1837 }
1838 // end scaling_list_data
1839 }
1840 GetBits(2); // amp_enabled_flag, sample_adaptive_offset_enabled_flag
1841 if (GetBit()) { // pcm_enabled_flag
1842 GetBits(8); // pcm_sample_bit_depth_luma_minus1, pcm_sample_bit_depth_chroma_minus1
1843 GetGolombUe(); // log2_min_pcm_luma_coding_block_size_minus3
1844 GetGolombUe(); // log2_diff_max_min_pcm_luma_coding_block_size
1845 GetBit(); // pcm_loop_filter_disabled_flag
1846 }
1847 uint32_t num_short_term_ref_pic_sets = GetGolombUe(); // num_short_term_ref_pic_sets
1848 uint32_t NumDeltaPocs[num_short_term_ref_pic_sets];
1849 for (uint32_t stRpsIdx = 0; stRpsIdx < num_short_term_ref_pic_sets; ++stRpsIdx) {
1850 // start of st_ref_pic_set(stRpsIdx)
1851 bool inter_ref_pic_set_prediction_flag = false;
1852 if (stRpsIdx != 0)
1853 inter_ref_pic_set_prediction_flag = GetBit(); // inter_ref_pic_set_prediction_flag
1854 if (inter_ref_pic_set_prediction_flag) {
1855 uint32_t RefRpsIdx, delta_idx_minus1 = 0;
1856 if (stRpsIdx == num_short_term_ref_pic_sets)
1857 delta_idx_minus1 = GetGolombUe(); // delta_idx_minus1
1858 GetBit(); // delta_rps_sign
1859 GetGolombUe(); // abs_delta_rps_minus1
1860 RefRpsIdx = stRpsIdx - (delta_idx_minus1 + 1);
1861 NumDeltaPocs[stRpsIdx] = 0;
1862 for (uint32_t j = 0; j <= NumDeltaPocs[RefRpsIdx]; ++j) {
1863 if (!GetBit()) { // used_by_curr_pic_flag[j]
1864 if (GetBit()) // use_delta_flag[j]
1865 NumDeltaPocs[stRpsIdx]++;
1866 }
1867 else
1868 NumDeltaPocs[stRpsIdx]++;
1869 }
1870 }
1871 else {
1872 uint32_t num_negative_pics = GetGolombUe(); // num_negative_pics
1873 uint32_t num_positive_pics = GetGolombUe(); // num_positive_pics
1874 for (uint32_t j = 0; j < num_negative_pics; ++j) {
1875 GetGolombUe(); // delta_poc_s0_minus1[i]
1876 GetBit(); // used_by_curr_pic_s0_flag[i]
1877 }
1878 for (uint32_t j = 0; j < num_positive_pics; ++j) {
1879 GetGolombUe(); // delta_poc_s1_minus1[i]
1880 GetBit(); // delta_poc_s1_minus1[i]
1881 }
1882 NumDeltaPocs[stRpsIdx] = num_negative_pics + num_positive_pics;
1883 }
1884 // end of st_ref_pic_set(stRpsIdx)
1885 }
1886 if (GetBit()) { // long_term_ref_pics_present_flag
1887 uint32_t num_long_term_ref_pics_sps = GetGolombUe(); // num_long_term_ref_pics_sps
1888 for (uint32_t i = 0; i < num_long_term_ref_pics_sps; ++i) {
1889 GetBits(log2_max_pic_order_cnt_lsb_minus4 + 4); // lt_ref_pic_poc_lsb_sps[i]
1890 GetBit(); // used_by_curr_pic_lt_sps_flag[i]
1891 }
1892 }
1893 GetBits(2); // sps_temporal_mvp_enabled_flag, strong_intra_smoothing_enabled_flag
1894 if (GetBit()) { // vui_parameters_present_flag
1895 // begin of vui_parameters()
1896 if (GetBit()) { // aspect_ratio_info_present_flag
1897 int aspect_ratio_idc = GetBits(8); // aspect_ratio_idc
1898 if (aspect_ratio_idc == 255) // EXTENDED_SAR
1899 GetBits(32); // sar_width, sar_height
1900 else if (aspect_ratio_idc == 1 || aspect_ratio_idc == 14)
1902 // implement decoding of other aspect_ratio_idc values when they are required
1903 }
1904 if (GetBit()) // overscan_info_present_flag
1905 GetBit(); // overscan_appropriate_flag
1906 if (GetBit()) { // video_signal_type_present_flag
1907 GetBits(4); // video_format, video_full_range_flag
1908 if (GetBit()) // colour_description_present_flag
1909 GetBits(24); // colour_primaries, transfer_characteristics, matrix_coeffs
1910 }
1911 if (GetBit()) { // chroma_loc_info_present_flag
1912 GetGolombUe(); // chroma_sample_loc_type_top_field
1913 GetGolombUe(); // chroma_sample_loc_type_bottom_field
1914 }
1915 GetBits(3); // neutral_chroma_indication_flag, field_seq_flag, frame_field_info_present_flag
1916 if (GetBit()) { // default_display_window_flag
1917 GetGolombUe(); // def_disp_win_left_offset
1918 GetGolombUe(); // def_disp_win_right_offset
1919 GetGolombUe(); // def_disp_win_top_offset
1920 GetGolombUe(); // def_disp_win_bottom_offset
1921 }
1922 if (GetBit()) { // vui_timing_info_present_flag
1923 uint32_t vui_num_units_in_tick = GetBits(32); // vui_num_units_in_tick
1924 uint32_t vui_time_scale = GetBits(32); // vui_time_scale
1925 if (vui_num_units_in_tick > 0)
1926 framesPerSecond = (double)vui_time_scale / vui_num_units_in_tick;
1927 }
1928 }
1929 if (debug) {
1930 cString s = cString::sprintf("H.265: %d x %d%c %.2f fps %d Bit %s", frameWidth, frameHeight, ScanTypeChars[scanType], framesPerSecond, bitDepth, AspectRatioTexts[aspectRatio]);
1931 dsyslog("%s", *s);
1932 dbgframes("\n%s", *s);
1933 }
1934}
1935
1936static bool DebugChecks = false;
1937
1938// cTsChecker and cFrameChecker are used to detect errors in the recorded data stream.
1939// While cTsChecker checks the continuity counter of the incoming TS packets, cFrameChecker
1940// works on entire frames, checking their PTS (Presentation Time Stamps) to see whether
1941// all expected frames arrive. The resulting number of errors is not a precise value.
1942// If it is zero, the recording can be safely considered error free. The higher the value,
1943// the more damaged the recording is.
1944
1945// --- cTsChecker ------------------------------------------------------------
1946
1947#define TS_CC_UNKNOWN 0xFF
1948
1950private:
1953 void Report(int Pid, const char *Message);
1954public:
1955 cTsChecker(void);
1956 void CheckTs(const uchar *Data, int Length);
1957 int Errors(void) { return errors; }
1958 void Clear(void) { errors = 0; }
1959 };
1960
1962{
1963 memset(counter, TS_CC_UNKNOWN, sizeof(counter));
1964 errors = 0;
1965}
1966
1967void cTsChecker::Report(int Pid, const char *Message)
1968{
1969 errors++;
1970 if (DebugChecks)
1971 fprintf(stderr, "%s: TS error #%d on PID %d (%s)\n", *TimeToString(time(NULL)), errors, Pid, Message);
1972}
1973
1974void cTsChecker::CheckTs(const uchar *Data, int Length)
1975{
1976 while (Length >= TS_SIZE) {
1977 int Pid = TsPid(Data);
1978 uchar Cc = TsContinuityCounter(Data);
1979 if (TsHasPayload(Data)) {
1980 if (TsError(Data))
1981 Report(Pid, "tei");
1982 else if (TsIsScrambled(Data))
1983 Report(Pid, "scrambled");
1984 else {
1985 uchar OldCc = counter[Pid];
1986 if (OldCc != TS_CC_UNKNOWN) {
1987 uchar NewCc = (OldCc + 1) & TS_CONT_CNT_MASK;
1988 if (Cc != NewCc)
1989 Report(Pid, "continuity");
1990 }
1991 }
1992 }
1993 counter[Pid] = Cc;
1994 Data += TS_SIZE;
1995 Length -= TS_SIZE;
1996 }
1997}
1998
1999// --- cFrameChecker ---------------------------------------------------------
2000
2001#define MAX_BACK_REFS 32
2002
2004private:
2007 int64_t lastPts;
2008 uint32_t backRefs;
2013 void Report(const char *Message, int NumErrors = 1);
2014public:
2015 cFrameChecker(void);
2016 void SetMissing(void) { missingFrames++; }
2017 void SetFrameDelta(int FrameDelta) { frameDelta = FrameDelta; }
2018 void CheckTs(const uchar *Data, int Length);
2019 void CheckFrame(const uchar *Data, int Length, bool IndependentFrame);
2020 int PreviousErrors(void) { return previousErrors; }
2021 int MissingFrames(void) { return missingFrames; }
2022 };
2023
2025{
2027 lastPts = -1;
2028 backRefs = 0;
2029 lastFwdRef = 0;
2030 errors = 0;
2031 previousErrors = 0;
2032 missingFrames = 0;
2033}
2034
2035void cFrameChecker::Report(const char *Message, int NumErrors)
2036{
2037 errors += NumErrors;
2038 if (DebugChecks)
2039 fprintf(stderr, "%s: frame error #%d (%s)\n", *TimeToString(time(NULL)), errors, Message);
2040}
2041
2042void cFrameChecker::CheckTs(const uchar *Data, int Length)
2043{
2044 tsChecker.CheckTs(Data, Length);
2045}
2046
2047void cFrameChecker::CheckFrame(const uchar *Data, int Length, bool IndependentFrame)
2048{
2049 previousErrors = tsChecker.Errors();
2051 errors = 0;
2052 tsChecker.Clear();
2053 int64_t Pts = TsGetPts(Data, Length);
2054 if (Pts >= 0) {
2055 if (lastPts >= 0) {
2056 int Diff = int(round((PtsDiff(lastPts, Pts) / double(frameDelta))));
2057 if (Diff > 0) {
2058 if (Diff <= MAX_BACK_REFS) {
2059 if (lastFwdRef > 1) {
2060 if (backRefs != uint32_t((1 << (lastFwdRef - 1)) - 1))
2061 Report("missing backref");
2062 }
2063 }
2064 else
2065 Report("missed", Diff);
2066 backRefs = 0;
2067 lastFwdRef = Diff;
2068 lastPts = Pts;
2069 }
2070 else if (Diff < 0) {
2071 Diff = -Diff;
2072 if (Diff <= MAX_BACK_REFS) {
2073 int b = 1 << (Diff - 1);
2074 if ((backRefs & b) != 0)
2075 Report("duplicate backref");
2076 backRefs |= b;
2077 }
2078 else {
2079 Report("rev diff too big");
2080 lastPts = Pts;
2081 }
2082 }
2083 else
2084 Report("zero diff");
2085 }
2086 else if (IndependentFrame)
2087 lastPts = Pts;
2088 }
2089 else
2090 Report("no PTS");
2091}
2092
2093// --- cFrameDetector --------------------------------------------------------
2094
2095const char *ScanTypeChars = "-pi"; // index is eScanType
2096const char *AspectRatioTexts[] = { // index is eAspectRatio
2097 "-",
2098 "1:1",
2099 "4:3",
2100 "16:9",
2101 "2.21:1",
2102 NULL
2103 };
2104
2106{
2107 parser = NULL;
2108 SetPid(Pid, Type);
2109 synced = false;
2110 newFrame = independentFrame = false;
2111 numPtsValues = 0;
2112 numIFrames = 0;
2113 framesPerSecond = 0;
2114 frameWidth = 0;
2115 frameHeight = 0;
2119 scanning = false;
2120 firstIframeSeen = false;
2122}
2123
2128
2129static int CmpUint32(const void *p1, const void *p2)
2130{
2131 if (*(uint32_t *)p1 < *(uint32_t *)p2) return -1;
2132 if (*(uint32_t *)p1 > *(uint32_t *)p2) return 1;
2133 return 0;
2134}
2135
2136void cFrameDetector::SetPid(int Pid, int Type)
2137{
2138 pid = Pid;
2139 type = Type;
2140 isVideo = type == 0x01 || type == 0x02 || type == 0x1B || type == 0x24; // MPEG 1, 2, H.264 or H.265
2141 delete parser;
2142 parser = NULL;
2143 if (type == 0x01 || type == 0x02)
2144 parser = new cMpeg2Parser;
2145 else if (type == 0x1B)
2146 parser = new cH264Parser;
2147 else if (type == 0x24)
2148 parser = new cH265Parser;
2149 else if (type == 0x03 || type == 0x04 || type == 0x06) // MPEG audio or AC3 audio
2150 parser = new cAudioParser;
2151 else if (type != 0)
2152 esyslog("ERROR: unknown stream type %d (PID %d) in frame detector", type, pid);
2153}
2154
2156{
2157 frameChecker->SetMissing();
2158}
2159
2160bool cFrameDetector::NewFrame(int *PreviousErrors, int *MissingFrames)
2161{
2162 if (newFrame) {
2163 if (PreviousErrors)
2164 *PreviousErrors = frameChecker->PreviousErrors();
2165 if (MissingFrames)
2166 *MissingFrames = frameChecker->MissingFrames();
2167 }
2168 return newFrame;
2169}
2170
2171int cFrameDetector::Analyze(const uchar *Data, int Length, bool ErrorCheck)
2172{
2173 if (!parser)
2174 return 0;
2175 int Processed = 0;
2176 newFrame = independentFrame = false;
2177 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
2178 // Sync on TS packet borders:
2179 if (int Skipped = TS_SYNC(Data, Length))
2180 return Processed + Skipped;
2181 // Handle one TS packet:
2182 int Handled = TS_SIZE;
2183 if (TsHasPayload(Data) && !TsIsScrambled(Data)) {
2184 int Pid = TsPid(Data);
2185 if (Pid == pid) {
2186 if (Processed)
2187 return Processed;
2188 if (TsPayloadStart(Data))
2189 scanning = true;
2190 if (scanning) {
2191 // Detect the beginning of a new frame:
2192 if (TsPayloadStart(Data)) {
2195 }
2196 int n = parser->Parse(Data, Length, pid);
2197 if (n > 0) {
2198 if (parser->NewFrame()) {
2199 newFrame = true;
2200 independentFrame = parser->IndependentFrame();
2202 if (synced) {
2203 if (ErrorCheck)
2204 frameChecker->CheckFrame(Data, n, independentFrame);
2205 if (framesPerPayloadUnit <= 1)
2206 scanning = false;
2207 }
2208 else {
2209 if (parser->FramesPerSecond() > 0.0) {
2210 framesPerSecond = parser->FramesPerSecond();
2211 frameWidth = parser->FrameWidth();
2212 frameHeight = parser->FrameHeight();
2213 scanType = parser->ScanType();
2214 aspectRatio = parser->AspectRatio();
2215 frameChecker->SetFrameDelta(PTSTICKS / framesPerSecond);
2216 synced = true;
2217 parser->SetDebug(false);
2218 }
2220 if (independentFrame)
2221 numIFrames++;
2222 }
2223 }
2224 Handled = n;
2225 }
2226 }
2227 if (TsPayloadStart(Data)) {
2228 // Determine the frame rate from the PTS values in the PES headers:
2229 if (framesPerSecond <= 0.0) {
2230 // frame rate unknown, so collect a sequence of PTS values:
2231 if (numPtsValues < 2 || numPtsValues < MaxPtsValues && numIFrames < 2) { // collect a sequence containing at least two I-frames
2232 if (newFrame) { // only take PTS values at the beginning of a frame (in case of fields!)
2233 const uchar *Pes = Data + TsPayloadOffset(Data);
2234 if (numIFrames && PesHasPts(Pes)) {
2236 // check for rollover:
2237 if (numPtsValues && ptsValues[numPtsValues - 1] > 0xF0000000 && ptsValues[numPtsValues] < 0x10000000) {
2238 dbgframes("#");
2239 numPtsValues = 0;
2240 numIFrames = 0;
2241 }
2242 else
2243 numPtsValues++;
2244 }
2245 }
2246 }
2247 if (numPtsValues >= 2 && numIFrames >= 2) {
2248 // find the smallest PTS delta:
2249 qsort(ptsValues, numPtsValues, sizeof(uint32_t), CmpUint32);
2250 numPtsValues--;
2251 for (int i = 0; i < numPtsValues; i++)
2252 ptsValues[i] = ptsValues[i + 1] - ptsValues[i];
2253 qsort(ptsValues, numPtsValues, sizeof(uint32_t), CmpUint32);
2254 int Div = framesPerPayloadUnit;
2255 if (framesPerPayloadUnit > 1)
2256 Div += parser->IFrameTemporalReferenceOffset();
2257 if (Div <= 0)
2258 Div = 1;
2259 int Delta = ptsValues[0] / Div;
2260 // determine frame info:
2261 if (isVideo) {
2262 if (Delta == 3753)
2263 framesPerSecond = 24.0 / 1.001;
2264 else if (abs(Delta - 3600) <= 1)
2265 framesPerSecond = 25.0;
2266 else if (Delta % 3003 == 0)
2267 framesPerSecond = 30.0 / 1.001;
2268 else if (abs(Delta - 1800) <= 1)
2269 framesPerSecond = 50.0;
2270 else if (Delta == 1501)
2271 framesPerSecond = 60.0 / 1.001;
2272 else {
2274 dsyslog("unknown frame delta (%d), assuming %5.2f fps", Delta, framesPerSecond);
2275 }
2276 }
2277 else // audio
2278 framesPerSecond = double(PTSTICKS) / Delta; // PTS of audio frames is always increasing
2279 frameChecker->SetFrameDelta(PTSTICKS / framesPerSecond);
2280 dbgframes("\nDelta = %d FPS = %5.2f FPPU = %d NF = %d TRO = %d\n", Delta, framesPerSecond, framesPerPayloadUnit, numPtsValues + 1, parser->IFrameTemporalReferenceOffset());
2281 synced = true;
2282 parser->SetDebug(false);
2283 }
2284 }
2285 }
2286 }
2287 else if (Pid == PATPID && synced && Processed)
2288 return Processed; // allow the caller to see any PAT packets
2289 }
2290 if (firstIframeSeen && ErrorCheck)
2291 frameChecker->CheckTs(Data, Handled);
2292 Data += Handled;
2293 Length -= Handled;
2294 Processed += Handled;
2295 if (newFrame)
2296 break;
2297 }
2298 return Processed;
2299}
#define MAXDPIDS
Definition channels.h:32
#define MAXAPIDS
Definition channels.h:31
#define MAXSPIDS
Definition channels.h:33
#define MAXLANGCODE1
Definition channels.h:36
static u_int32_t crc32(const char *d, int len, u_int32_t CRCvalue)
Definition util.c:267
bool CheckCRCAndParse()
Definition si.c:65
Descriptor * getNext(Iterator &it)
Definition si.c:112
DescriptorTag getDescriptorTag() const
Definition si.c:100
StructureLoop< Language > languageLoop
Definition descriptor.h:490
bool getCurrentNextIndicator() const
Definition si.c:80
int getSectionNumber() const
Definition si.c:88
int getLastSectionNumber() const
Definition si.c:92
int getVersionNumber() const
Definition si.c:84
int getPid() const
Definition section.c:34
int getServiceId() const
Definition section.c:30
bool isNITPid() const
Definition section.h:31
StructureLoop< Association > associationLoop
Definition section.h:39
int getTransportStreamId() const
Definition section.c:26
DescriptorLoop streamDescriptors
Definition section.h:63
int getPid() const
Definition section.c:65
int getStreamType() const
Definition section.c:69
int getServiceId() const
Definition section.c:57
int getPCRPid() const
Definition section.c:61
StructureLoop< Stream > streamLoop
Definition section.h:71
StructureLoop< Subtitling > subtitlingLoop
Definition descriptor.h:332
virtual int Parse(const uchar *Data, int Length, int Pid) override
Parses the given Data, which is a sequence of Length bytes of TS packets.
Definition remux.c:1230
cAudioParser(void)
Definition remux.c:1226
const int * Dpids(void) const
Definition channels.h:158
uint16_t AncillaryPageId(int i) const
Definition channels.h:170
uint16_t CompositionPageId(int i) const
Definition channels.h:169
int Tpid(void) const
Definition channels.h:171
const char * Slang(int i) const
Definition channels.h:165
int Vpid(void) const
Definition channels.h:154
int Atype(int i) const
Definition channels.h:166
int Dtype(int i) const
Definition channels.h:167
int Dpid(int i) const
Definition channels.h:161
int Vtype(void) const
Definition channels.h:156
int Apid(int i) const
Definition channels.h:160
int Ppid(void) const
Definition channels.h:155
uchar SubtitlingType(int i) const
Definition channels.h:168
const char * Dlang(int i) const
Definition channels.h:164
int Spid(int i) const
Definition channels.h:162
const int * Apids(void) const
Definition channels.h:157
const char * Alang(int i) const
Definition channels.h:163
const int * Spids(void) const
Definition channels.h:159
static cDevice * PrimaryDevice(void)
Returns the primary device.
Definition device.h:148
void EnsureAudioTrack(bool Force=false)
Makes sure an audio track is selected that is actually available.
Definition device.c:1227
void ClrAvailableTracks(bool DescriptionsOnly=false, bool IdsOnly=false)
Clears the list of currently available tracks.
Definition device.c:1091
void EnsureSubtitleTrack(void)
Makes sure one of the preferred language subtitle tracks is selected.
Definition device.c:1260
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:1114
uchar eit[TS_SIZE]
Definition remux.h:434
cEitGenerator(int Sid=0)
Definition remux.c:949
int counter
Definition remux.h:435
uchar * AddParentalRatingDescriptor(uchar *p, uchar ParentalRating=0)
Definition remux.c:963
uint16_t YMDtoMJD(int Y, int M, int D)
Definition remux.c:957
uchar * Generate(int Sid)
Definition remux.c:974
int version
Definition remux.h:436
uint32_t backRefs
Definition remux.c:2008
int missingFrames
Definition remux.c:2012
cTsChecker tsChecker
Definition remux.c:2005
int MissingFrames(void)
Definition remux.c:2021
int frameDelta
Definition remux.c:2006
void Report(const char *Message, int NumErrors=1)
Definition remux.c:2035
cFrameChecker(void)
Definition remux.c:2024
void SetFrameDelta(int FrameDelta)
Definition remux.c:2017
void CheckTs(const uchar *Data, int Length)
Definition remux.c:2042
int previousErrors
Definition remux.c:2011
int PreviousErrors(void)
Definition remux.c:2020
int lastFwdRef
Definition remux.c:2009
void SetMissing(void)
Definition remux.c:2016
int64_t lastPts
Definition remux.c:2007
void CheckFrame(const uchar *Data, int Length, bool IndependentFrame)
Definition remux.c:2047
uint32_t ptsValues[MaxPtsValues]
Definition remux.h:536
bool synced
Definition remux.h:533
uint16_t frameHeight
Definition remux.h:542
cFrameChecker * frameChecker
Definition remux.h:552
uint16_t frameWidth
Definition remux.h:541
bool scanning
Definition remux.h:548
int framesPerPayloadUnit
Definition remux.h:546
bool NewFrame(int *PreviousErrors=NULL, int *MissingFrames=NULL)
Returns true if the data given to the last call to Analyze() started a new frame.
Definition remux.c:2160
bool firstIframeSeen
Definition remux.h:549
int Analyze(const uchar *Data, int Length, bool ErrorCheck=true)
Analyzes the TS packets pointed to by Data.
Definition remux.c:2171
double framesPerSecond
Definition remux.h:540
int framesInPayloadUnit
Definition remux.h:545
int numIFrames
Definition remux.h:538
bool independentFrame
Definition remux.h:535
cFrameDetector(int Pid=0, int Type=0)
Sets up a frame detector for the given Pid and stream Type.
Definition remux.c:2105
eScanType scanType
Definition remux.h:543
void SetMissing(void)
Call if this is a resumed recording, which has missing frames.
Definition remux.c:2155
bool newFrame
Definition remux.h:534
cFrameParser * parser
Definition remux.h:550
int numPtsValues
Definition remux.h:537
bool isVideo
Definition remux.h:539
void SetPid(int Pid, int Type)
Sets the Pid and stream Type to detect frames for.
Definition remux.c:2136
eAspectRatio aspectRatio
Definition remux.h:544
uint16_t FrameWidth(void)
Definition remux.c:1198
void SetDebug(bool Debug)
Definition remux.c:1194
bool NewFrame(void)
Definition remux.c:1195
eAspectRatio aspectRatio
Definition remux.c:1183
double FramesPerSecond(void)
Definition remux.c:1200
bool IndependentFrame(void)
Definition remux.c:1196
bool newFrame
Definition remux.c:1176
int iFrameTemporalReferenceOffset
Definition remux.c:1178
double framesPerSecond
Definition remux.c:1181
eScanType ScanType(void)
Definition remux.c:1201
bool independentFrame
Definition remux.c:1177
virtual ~cFrameParser()
Definition remux.c:1186
uint16_t frameHeight
Definition remux.c:1180
bool debug
Definition remux.c:1175
virtual int Parse(const uchar *Data, int Length, int Pid)=0
Parses the given Data, which is a sequence of Length bytes of TS packets.
eAspectRatio AspectRatio(void)
Definition remux.c:1202
eScanType scanType
Definition remux.c:1182
uint16_t FrameHeight(void)
Definition remux.c:1199
int IFrameTemporalReferenceOffset(void)
Definition remux.c:1197
uint16_t frameWidth
Definition remux.c:1179
cFrameParser(void)
Definition remux.c:1205
uint32_t GetBits(int Bits)
Definition remux.c:1442
cTsPayload tsPayload
Definition remux.c:1378
void ParseAccessUnitDelimiter(void)
Definition remux.c:1513
@ nutSequenceParameterSet
Definition remux.c:1367
@ nutCodedSliceNonIdr
Definition remux.c:1365
@ nutAccessUnitDelimiter
Definition remux.c:1368
@ nutCodedSliceIdr
Definition remux.c:1366
bool separate_colour_plane_flag
Definition remux.c:1374
bool gotAccessUnitDelimiter
Definition remux.c:1380
int zeroBytes
Definition remux.c:1372
bool frame_mbs_only_flag
Definition remux.c:1376
int log2_max_frame_num
Definition remux.c:1375
virtual int Parse(const uchar *Data, int Length, int Pid) override
Parses the given Data, which is a sequence of Length bytes of TS packets.
Definition remux.c:1470
uint32_t GetGolombUe(void)
Definition remux.c:1450
uchar GetByte(bool Raw=false)
Gets the next data byte.
Definition remux.c:1414
void ParseSliceHeader(void)
Definition remux.c:1638
void ParseSequenceParameterSet(void)
Definition remux.c:1520
uchar byte
Definition remux.c:1370
uint32_t scanner
Definition remux.c:1379
bool gotSequenceParameterSet
Definition remux.c:1381
int32_t GetGolombSe(void)
Definition remux.c:1458
cH264Parser(void)
Sets up a new H.264 parser.
Definition remux.c:1401
uchar GetBit(void)
Definition remux.c:1433
virtual int Parse(const uchar *Data, int Length, int Pid) override
Parses the given Data, which is a sequence of Length bytes of TS packets.
Definition remux.c:1708
cH265Parser(void)
Definition remux.c:1703
@ nutSliceSegmentIDRWRADL
Definition remux.c:1680
@ nutUnspecified0
Definition remux.c:1694
@ nutSliceSegmentSTSAN
Definition remux.c:1671
@ nutSliceSegmentRADLN
Definition remux.c:1673
@ nutSliceSegmentIDRNLP
Definition remux.c:1681
@ nutPrefixSEI
Definition remux.c:1690
@ nutAccessUnitDelimiter
Definition remux.c:1686
@ nutUnspecified7
Definition remux.c:1695
@ nutSliceSegmentBLAWRADL
Definition remux.c:1678
@ nutSliceSegmentTSAR
Definition remux.c:1670
@ nutSliceSegmentRADLR
Definition remux.c:1674
@ nutSliceSegmentTrailingR
Definition remux.c:1668
@ nutVideoParameterSet
Definition remux.c:1683
@ nutSequenceParameterSet
Definition remux.c:1684
@ nutSliceSegmentTSAN
Definition remux.c:1669
@ nutSliceSegmentRASLN
Definition remux.c:1675
@ nutSuffixSEI
Definition remux.c:1691
@ nutSliceSegmentBLAWLP
Definition remux.c:1677
@ nutEndOfBitstream
Definition remux.c:1688
@ nutSliceSegmentBLANLP
Definition remux.c:1679
@ nutSliceSegmentRASLR
Definition remux.c:1676
@ nutPictureParameterSet
Definition remux.c:1685
@ nutNonVCLRes3
Definition remux.c:1693
@ nutSliceSegmentCRANUT
Definition remux.c:1682
@ nutSliceSegmentTrailingN
Definition remux.c:1667
@ nutNonVCLRes0
Definition remux.c:1692
@ nutFillerData
Definition remux.c:1689
@ nutSliceSegmentSTSAR
Definition remux.c:1672
@ nutEndOfSequence
Definition remux.c:1687
void ParseSequenceParameterSet(void)
Definition remux.c:1742
bool seenIndependentFrame
Definition remux.c:1247
cMpeg2Parser(void)
Definition remux.c:1266
bool seenScanType
Definition remux.c:1249
int lastIFrameTemporalReference
Definition remux.c:1248
uint32_t scanner
Definition remux.c:1246
const double frame_rate_table[9]
Definition remux.c:1250
virtual int Parse(const uchar *Data, int Length, int Pid) override
Parses the given Data, which is a sequence of Length bytes of TS packets.
Definition remux.c:1274
int MakeCRC(uchar *Target, const uchar *Data, int Length)
Definition remux.c:453
uchar * GetPmt(int &Index)
Returns a pointer to the Index'th TS packet of the PMT section.
Definition remux.c:602
void SetChannel(const cChannel *Channel)
Sets the Channel for which the PAT/PMT shall be generated.
Definition remux.c:587
void IncEsInfoLength(int Length)
Definition remux.c:386
void IncCounter(int &Counter, uchar *TsPacket)
Definition remux.c:373
cPatPmtGenerator(const cChannel *Channel=NULL)
Definition remux.c:363
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:581
int numPmtPackets
Definition remux.h:302
uchar * esInfoLength
Definition remux.h:308
uchar pat[TS_SIZE]
Definition remux.h:300
int MakeAC3Descriptor(uchar *Target, uchar Type)
Definition remux.c:407
void GeneratePat(void)
Generates a PAT section for later use with GetPat().
Definition remux.c:483
uchar * GetPat(void)
Returns a pointer to the PAT section, which consists of exactly one TS packet.
Definition remux.c:596
uchar pmt[MAX_PMT_TS][TS_SIZE]
Definition remux.h:301
int MakeLanguageDescriptor(uchar *Target, const char *Language)
Definition remux.c:434
void GeneratePmt(const cChannel *Channel)
Generates a PMT section for the given Channel, for later use with GetPmt().
Definition remux.c:512
void GeneratePmtPid(const cChannel *Channel)
Generates a PMT pid that doesn't collide with any of the actual pids of the Channel.
Definition remux.c:468
int MakeStream(uchar *Target, uchar Type, int Pid)
Definition remux.c:395
int MakeSubtitlingDescriptor(uchar *Target, const char *Language, uchar SubtitlingType, uint16_t CompositionPageId, uint16_t AncillaryPageId)
Definition remux.c:417
void IncVersion(int &Version)
Definition remux.c:380
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:940
int dpids[MAXDPIDS+1]
Definition remux.h:366
uchar pmt[MAX_SECTION_SIZE]
Definition remux.h:355
int apids[MAXAPIDS+1]
Definition remux.h:363
cPatPmtParser(bool UpdatePrimaryDevice=false)
Definition remux.c:613
void Reset(void)
Resets the parser.
Definition remux.c:619
void ParsePat(const uchar *Data, int Length)
Parses the PAT data from the single TS packet in Data.
Definition remux.c:629
int pmtSize
Definition remux.h:356
char dlangs[MAXDPIDS][MAXLANGCODE2]
Definition remux.h:368
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:921
int patVersion
Definition remux.h:357
int pmtPids[MAX_PMT_PIDS+1]
Definition remux.h:359
uchar subtitlingTypes[MAXSPIDS]
Definition remux.h:371
int dtypes[MAXDPIDS+1]
Definition remux.h:367
uint16_t ancillaryPageIds[MAXSPIDS]
Definition remux.h:373
int SectionLength(const uchar *Data, int Length)
Definition remux.h:377
void ParsePmt(const uchar *Data, int Length)
Parses the PMT data from the single TS packet in Data.
Definition remux.c:661
bool completed
Definition remux.h:375
bool IsPmtPid(int Pid) const
Returns true if Pid the one of the PMT pids as defined by the current PAT.
Definition remux.h:400
uint16_t compositionPageIds[MAXSPIDS]
Definition remux.h:372
char alangs[MAXAPIDS][MAXLANGCODE2]
Definition remux.h:365
int spids[MAXSPIDS+1]
Definition remux.h:369
int pmtVersion
Definition remux.h:358
bool updatePrimaryDevice
Definition remux.h:374
char slangs[MAXSPIDS][MAXLANGCODE2]
Definition remux.h:370
int atypes[MAXAPIDS+1]
Definition remux.h:364
static void SetBrokenLink(uchar *Data, int Length)
Definition remux.c:102
static cString sprintf(const char *fmt,...) __attribute__((format(printf
Definition tools.c:1195
uchar counter[MAXPID]
Definition remux.c:1951
cTsChecker(void)
Definition remux.c:1961
void CheckTs(const uchar *Data, int Length)
Definition remux.c:1974
int errors
Definition remux.c:1952
int Errors(void)
Definition remux.c:1957
void Report(int Pid, const char *Message)
Definition remux.c:1967
void Clear(void)
Definition remux.c:1958
int numPacketsPid
Definition remux.h:232
int pid
Definition remux.h:230
cTsPayload(void)
Definition remux.c:246
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:252
int Used(void)
Returns the number of raw bytes that have already been used (e.g.
Definition remux.h:258
bool Eof(void) const
Returns true if all available bytes of the TS payload have been processed.
Definition remux.h:262
void SetByte(uchar Byte, int Index)
Sets the TS data byte at the given Index to the value Byte.
Definition remux.c:330
uchar GetByte(void)
Gets the next byte of the TS payload, skipping any intermediate TS header data.
Definition remux.c:280
bool AtTsStart(void)
Returns true if this payload handler is currently pointing to first byte of a TS packet.
Definition remux.h:249
int GetLastIndex(void)
Returns the index into the TS data of the payload byte that has most recently been read.
Definition remux.c:325
void Setup(uchar *Data, int Length, int Pid=-1)
Sets up this TS payload handler with the given Data, which points to a sequence of Length bytes of co...
Definition remux.c:272
bool SkipPesHeader(void)
Skips all bytes belonging to the PES header of the payload.
Definition remux.c:320
int index
Definition remux.h:231
int numPacketsOther
Definition remux.h:233
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:353
uchar SetEof(void)
Definition remux.c:259
int length
Definition remux.h:229
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:336
void Reset(void)
Definition remux.c:265
uchar * data
Definition remux.h:228
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:313
int lastLength
Definition remux.h:457
bool repeatLast
Definition remux.h:458
uchar * lastData
Definition remux.h:456
uchar * data
Definition remux.h:452
void PutTs(const uchar *Data, int Length)
Puts the payload data of the single TS packet at Data into the converter.
Definition remux.c:1048
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:1125
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:1077
cTsToPes(void)
Definition remux.c:1036
int length
Definition remux.h:454
~cTsToPes()
Definition remux.c:1043
void Reset(void)
Resets the converter.
Definition remux.c:1130
int offset
Definition remux.h:455
int size
Definition remux.h:453
cSetup Setup
Definition config.c:372
@ ttSubtitle
Definition device.h:70
@ ttDolby
Definition device.h:67
@ ttAudio
Definition device.h:64
const char * I18nNormalizeLanguageCode(const char *Code)
Returns a 3 letter language code that may not be zero terminated.
Definition i18n.c:286
@ EnhancedAC3DescriptorTag
Definition si.h:136
@ SubtitlingDescriptorTag
Definition si.h:102
@ ISO639LanguageDescriptorTag
Definition si.h:60
@ ParentalRatingDescriptorTag
Definition si.h:98
@ AC3DescriptorTag
Definition si.h:119
#define DEFAULTFRAMESPERSECOND
Definition recording.h:378
void TsSetPcr(uchar *p, int64_t Pcr)
Definition remux.c:131
const char * AspectRatioTexts[]
Definition remux.c:2096
#define WRN_TS_PACKETS_FOR_VIDEO_FRAME_DETECTION
Definition remux.c:27
#define dbgframes(a...)
Definition remux.c:24
#define WRN_TS_PACKETS_FOR_FRAME_DETECTOR
Definition remux.c:28
#define SETPID(p)
void PesDump(const char *Name, const u_char *Data, int Length)
Definition remux.c:1166
static bool DebugFrames
Definition remux.c:21
int64_t PtsDiff(int64_t Pts1, int64_t Pts2)
Returns the difference between two PTS values.
Definition remux.c:234
const char * ScanTypeChars
Definition remux.c:2095
#define MAXPESLENGTH
Definition remux.c:1075
#define P_PMT_PID
Definition remux.c:465
void TsHidePayload(uchar *p)
Definition remux.c:121
static int CmpUint32(const void *p1, const void *p2)
Definition remux.c:2129
#define MAXPID
Definition remux.c:466
void PesSetDts(uchar *p, int64_t Dts)
Definition remux.c:225
#define EMPTY_SCANNER
Definition remux.c:30
static bool DebugPatPmt
Definition remux.c:20
static bool DebugChecks
Definition remux.c:1936
int64_t TsGetDts(const uchar *p, int l)
Definition remux.c:173
#define TS_CC_UNKNOWN
Definition remux.c:1947
void TsSetDts(uchar *p, int l, int64_t Dts)
Definition remux.c:200
void TsSetPts(uchar *p, int l, int64_t Pts)
Definition remux.c:186
ePesHeader AnalyzePesHeader(const uchar *Data, int Count, int &PesPayloadOffset, bool *ContinuationHeader)
Definition remux.c:32
#define dbgpatpmt(a...)
Definition remux.c:23
#define VIDEO_STREAM_S
Definition remux.c:98
void PesSetPts(uchar *p, int64_t Pts)
Definition remux.c:216
int64_t TsGetPts(const uchar *p, int l)
Definition remux.c:160
void BlockDump(const char *Name, const u_char *Data, int Length)
Definition remux.c:1140
int TsSync(const uchar *Data, int Length, const char *File, const char *Function, int Line)
Definition remux.c:147
#define MAX_BACK_REFS
Definition remux.c:2001
#define SETPIDS(l)
#define P_TSID
Definition remux.c:464
void TsDump(const char *Name, const u_char *Data, int Length)
Definition remux.c:1151
#define MAX_TS_PACKETS_FOR_VIDEO_FRAME_DETECTION
Definition remux.c:26
bool TsError(const uchar *p)
Definition remux.h:77
#define TS_ADAPT_PCR
Definition remux.h:46
int TsPid(const uchar *p)
Definition remux.h:82
bool TsHasPayload(const uchar *p)
Definition remux.h:62
#define MAX33BIT
Definition remux.h:59
#define MAX_PMT_PIDS
Definition remux.h:351
int PesPayloadOffset(const uchar *p)
Definition remux.h:178
#define PATPID
Definition remux.h:52
bool TsIsScrambled(const uchar *p)
Definition remux.h:93
uchar TsContinuityCounter(const uchar *p)
Definition remux.h:98
int TsGetPayload(const uchar **p)
Definition remux.h:114
#define TS_PAYLOAD_EXISTS
Definition remux.h:41
bool PesHasPts(const uchar *p)
Definition remux.h:183
bool PesLongEnough(int Length)
Definition remux.h:163
#define TS_SIZE
Definition remux.h:34
eAspectRatio
Definition remux.h:514
@ ar_16_9
Definition remux.h:518
@ ar_1_1
Definition remux.h:516
@ arUnknown
Definition remux.h:515
@ ar_4_3
Definition remux.h:517
@ ar_2_21_1
Definition remux.h:519
eScanType
Definition remux.h:507
@ stInterlaced
Definition remux.h:510
@ stProgressive
Definition remux.h:509
@ stUnknown
Definition remux.h:508
#define MAX_SECTION_SIZE
Definition remux.h:295
int64_t PesGetDts(const uchar *p)
Definition remux.h:202
#define TS_ADAPT_FIELD_EXISTS
Definition remux.h:40
int64_t PesGetPts(const uchar *p)
Definition remux.h:193
bool TsPayloadStart(const uchar *p)
Definition remux.h:72
#define TS_SYNC(Data, Length)
Definition remux.h:149
int TsPayloadOffset(const uchar *p)
Definition remux.h:108
#define MAXPID
Definition remux.h:55
bool PesHasDts(const uchar *p)
Definition remux.h:188
#define PCRFACTOR
Definition remux.h:58
#define TS_SYNC_BYTE
Definition remux.h:33
bool PesHasLength(const uchar *p)
Definition remux.h:168
bool TsHasAdaptationField(const uchar *p)
Definition remux.h:67
#define PTSTICKS
Definition remux.h:57
ePesHeader AnalyzePesHeader(const uchar *Data, int Count, int &PesPayloadOffset, bool *ContinuationHeader=NULL)
Definition remux.c:32
#define MIN_TS_PACKETS_FOR_FRAME_DETECTOR
Definition remux.h:503
int PesLength(const uchar *p)
Definition remux.h:173
ePesHeader
Definition remux.h:16
@ phMPEG2
Definition remux.h:20
@ phNeedMoreData
Definition remux.h:17
@ phInvalid
Definition remux.h:18
@ phMPEG1
Definition remux.h:19
#define EITPID
Definition remux.h:54
#define TS_CONT_CNT_MASK
Definition remux.h:42
#define TS_PAYLOAD_START
Definition remux.h:36
cString TimeToString(time_t t)
Converts the given time to a string of the form "www mmm dd hh:mm:ss yyyy".
Definition tools.c:1271
char * strn0cpy(char *dest, const char *src, size_t n)
Definition tools.c:131
unsigned char uchar
Definition tools.h:31
#define dsyslog(a...)
Definition tools.h:37
T min(T a, T b)
Definition tools.h:63
T max(T a, T b)
Definition tools.h:64
#define esyslog(a...)
Definition tools.h:35
#define KILOBYTE(n)
Definition tools.h:44