vdr 2.6.1
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.2 2022/01/18 14:24:33 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 (TsHasPayload(p)) {
291 if (index > 0 && TsPayloadStart(p)) // checking index to not skip the very first TS packet
292 return SetEof();
294 break;
295 }
296 }
297 else if (TsPid(p) == PATPID)
298 return SetEof(); // caller must see PAT packets in case of index regeneration
299 else
301 }
302 else
303 return SetEof();
304 }
305 }
306 return data[index++];
307 }
308 return 0x00;
309}
310
312{
313 while (Bytes-- > 0)
314 GetByte();
315 return !Eof();
316}
317
319{
321}
322
324{
325 return index - 1;
326}
327
328void cTsPayload::SetByte(uchar Byte, int Index)
329{
330 if (Index >= 0 && Index < length)
331 data[Index] = Byte;
332}
333
334bool cTsPayload::Find(uint32_t Code)
335{
336 int OldIndex = index;
337 int OldNumPacketsPid = numPacketsPid;
338 int OldNumPacketsOther = numPacketsOther;
339 uint32_t Scanner = EMPTY_SCANNER;
340 while (!Eof()) {
341 Scanner = (Scanner << 8) | GetByte();
342 if (Scanner == Code)
343 return true;
344 }
345 index = OldIndex;
346 numPacketsPid = OldNumPacketsPid;
347 numPacketsOther = OldNumPacketsOther;
348 return false;
349}
350
352{
354 dsyslog("WARNING: required (%d+%d) TS packets to determine frame type", numPacketsOther, numPacketsPid);
356 dsyslog("WARNING: required %d video TS packets to determine frame type", numPacketsPid);
357}
358
359// --- cPatPmtGenerator ------------------------------------------------------
360
362{
363 numPmtPackets = 0;
366 pmtPid = 0;
367 esInfoLength = NULL;
368 SetChannel(Channel);
369}
370
371void cPatPmtGenerator::IncCounter(int &Counter, uchar *TsPacket)
372{
373 TsPacket[3] = (TsPacket[3] & 0xF0) | Counter;
374 if (++Counter > 0x0F)
375 Counter = 0x00;
376}
377
379{
380 if (++Version > 0x1F)
381 Version = 0x00;
382}
383
385{
386 if (esInfoLength) {
387 Length += ((*esInfoLength & 0x0F) << 8) | *(esInfoLength + 1);
388 *esInfoLength = 0xF0 | (Length >> 8);
389 *(esInfoLength + 1) = Length;
390 }
391}
392
393int cPatPmtGenerator::MakeStream(uchar *Target, uchar Type, int Pid)
394{
395 int i = 0;
396 Target[i++] = Type; // stream type
397 Target[i++] = 0xE0 | (Pid >> 8); // dummy (3), pid hi (5)
398 Target[i++] = Pid; // pid lo
399 esInfoLength = &Target[i];
400 Target[i++] = 0xF0; // dummy (4), ES info length hi
401 Target[i++] = 0x00; // ES info length lo
402 return i;
403}
404
406{
407 int i = 0;
408 Target[i++] = Type;
409 Target[i++] = 0x01; // length
410 Target[i++] = 0x00;
412 return i;
413}
414
415int cPatPmtGenerator::MakeSubtitlingDescriptor(uchar *Target, const char *Language, uchar SubtitlingType, uint16_t CompositionPageId, uint16_t AncillaryPageId)
416{
417 int i = 0;
418 Target[i++] = SI::SubtitlingDescriptorTag;
419 Target[i++] = 0x08; // length
420 Target[i++] = *Language++;
421 Target[i++] = *Language++;
422 Target[i++] = *Language++;
423 Target[i++] = SubtitlingType;
424 Target[i++] = CompositionPageId >> 8;
425 Target[i++] = CompositionPageId & 0xFF;
426 Target[i++] = AncillaryPageId >> 8;
427 Target[i++] = AncillaryPageId & 0xFF;
429 return i;
430}
431
432int cPatPmtGenerator::MakeLanguageDescriptor(uchar *Target, const char *Language)
433{
434 int i = 0;
436 int Length = i++;
437 Target[Length] = 0x00; // length
438 for (const char *End = Language + strlen(Language); Language < End; ) {
439 Target[i++] = *Language++;
440 Target[i++] = *Language++;
441 Target[i++] = *Language++;
442 Target[i++] = 0x00; // audio type
443 Target[Length] += 0x04; // length
444 if (*Language == '+')
445 Language++;
446 }
448 return i;
449}
450
451int cPatPmtGenerator::MakeCRC(uchar *Target, const uchar *Data, int Length)
452{
453 int crc = SI::CRC32::crc32((const char *)Data, Length, 0xFFFFFFFF);
454 int i = 0;
455 Target[i++] = crc >> 24;
456 Target[i++] = crc >> 16;
457 Target[i++] = crc >> 8;
458 Target[i++] = crc;
459 return i;
460}
461
462#define P_TSID 0x8008 // pseudo TS ID
463#define P_PMT_PID 0x0084 // pseudo PMT pid
464#define MAXPID 0x2000 // the maximum possible number of pids
465
467{
468 bool Used[MAXPID] = { false };
469#define SETPID(p) { if ((p) >= 0 && (p) < MAXPID) Used[p] = true; }
470#define SETPIDS(l) { const int *p = l; while (*p) { SETPID(*p); p++; } }
471 SETPID(Channel->Vpid());
472 SETPID(Channel->Ppid());
473 SETPID(Channel->Tpid());
474 SETPIDS(Channel->Apids());
475 SETPIDS(Channel->Dpids());
476 SETPIDS(Channel->Spids());
477 for (pmtPid = P_PMT_PID; Used[pmtPid]; pmtPid++)
478 ;
479}
480
482{
483 memset(pat, 0xFF, sizeof(pat));
484 uchar *p = pat;
485 int i = 0;
486 p[i++] = TS_SYNC_BYTE; // TS indicator
487 p[i++] = TS_PAYLOAD_START | (PATPID >> 8); // flags (3), pid hi (5)
488 p[i++] = PATPID & 0xFF; // pid lo
489 p[i++] = 0x10; // flags (4), continuity counter (4)
490 p[i++] = 0x00; // pointer field (payload unit start indicator is set)
491 int PayloadStart = i;
492 p[i++] = 0x00; // table id
493 p[i++] = 0xB0; // section syntax indicator (1), dummy (3), section length hi (4)
494 int SectionLength = i;
495 p[i++] = 0x00; // section length lo (filled in later)
496 p[i++] = P_TSID >> 8; // TS id hi
497 p[i++] = P_TSID & 0xFF; // TS id lo
498 p[i++] = 0xC1 | (patVersion << 1); // dummy (2), version number (5), current/next indicator (1)
499 p[i++] = 0x00; // section number
500 p[i++] = 0x00; // last section number
501 p[i++] = pmtPid >> 8; // program number hi
502 p[i++] = pmtPid & 0xFF; // program number lo
503 p[i++] = 0xE0 | (pmtPid >> 8); // dummy (3), PMT pid hi (5)
504 p[i++] = pmtPid & 0xFF; // PMT pid lo
505 pat[SectionLength] = i - SectionLength - 1 + 4; // -1 = SectionLength storage, +4 = length of CRC
506 MakeCRC(pat + i, pat + PayloadStart, i - PayloadStart);
508}
509
511{
512 // generate the complete PMT section:
514 memset(buf, 0xFF, sizeof(buf));
515 numPmtPackets = 0;
516 if (Channel) {
517 int Vpid = Channel->Vpid();
518 int Ppid = Channel->Ppid();
519 uchar *p = buf;
520 int i = 0;
521 p[i++] = 0x02; // table id
522 int SectionLength = i;
523 p[i++] = 0xB0; // section syntax indicator (1), dummy (3), section length hi (4)
524 p[i++] = 0x00; // section length lo (filled in later)
525 p[i++] = pmtPid >> 8; // program number hi
526 p[i++] = pmtPid & 0xFF; // program number lo
527 p[i++] = 0xC1 | (pmtVersion << 1); // dummy (2), version number (5), current/next indicator (1)
528 p[i++] = 0x00; // section number
529 p[i++] = 0x00; // last section number
530 p[i++] = 0xE0 | (Ppid >> 8); // dummy (3), PCR pid hi (5)
531 p[i++] = Ppid; // PCR pid lo
532 p[i++] = 0xF0; // dummy (4), program info length hi (4)
533 p[i++] = 0x00; // program info length lo
534
535 if (Vpid)
536 i += MakeStream(buf + i, Channel->Vtype(), Vpid);
537 for (int n = 0; Channel->Apid(n); n++) {
538 i += MakeStream(buf + i, Channel->Atype(n), Channel->Apid(n));
539 const char *Alang = Channel->Alang(n);
540 i += MakeLanguageDescriptor(buf + i, Alang);
541 }
542 for (int n = 0; Channel->Dpid(n); n++) {
543 i += MakeStream(buf + i, 0x06, Channel->Dpid(n));
544 i += MakeAC3Descriptor(buf + i, Channel->Dtype(n));
545 i += MakeLanguageDescriptor(buf + i, Channel->Dlang(n));
546 }
547 for (int n = 0; Channel->Spid(n); n++) {
548 i += MakeStream(buf + i, 0x06, Channel->Spid(n));
549 i += MakeSubtitlingDescriptor(buf + i, Channel->Slang(n), Channel->SubtitlingType(n), Channel->CompositionPageId(n), Channel->AncillaryPageId(n));
550 }
551
552 int sl = i - SectionLength - 2 + 4; // -2 = SectionLength storage, +4 = length of CRC
553 buf[SectionLength] |= (sl >> 8) & 0x0F;
554 buf[SectionLength + 1] = sl;
555 MakeCRC(buf + i, buf, i);
556 // split the PMT section into several TS packets:
557 uchar *q = buf;
558 bool pusi = true;
559 while (i > 0) {
560 uchar *p = pmt[numPmtPackets++];
561 int j = 0;
562 p[j++] = TS_SYNC_BYTE; // TS indicator
563 p[j++] = (pusi ? TS_PAYLOAD_START : 0x00) | (pmtPid >> 8); // flags (3), pid hi (5)
564 p[j++] = pmtPid & 0xFF; // pid lo
565 p[j++] = 0x10; // flags (4), continuity counter (4)
566 if (pusi) {
567 p[j++] = 0x00; // pointer field (payload unit start indicator is set)
568 pusi = false;
569 }
570 int l = TS_SIZE - j;
571 memcpy(p + j, q, l);
572 q += l;
573 i -= l;
574 }
576 }
577}
578
579void cPatPmtGenerator::SetVersions(int PatVersion, int PmtVersion)
580{
581 patVersion = PatVersion & 0x1F;
582 pmtVersion = PmtVersion & 0x1F;
583}
584
586{
587 if (Channel) {
588 GeneratePmtPid(Channel);
589 GeneratePat();
590 GeneratePmt(Channel);
591 }
592}
593
595{
597 return pat;
598}
599
601{
602 if (Index < numPmtPackets) {
603 IncCounter(pmtCounter, pmt[Index]);
604 return pmt[Index++];
605 }
606 return NULL;
607}
608
609// --- cPatPmtParser ---------------------------------------------------------
610
611cPatPmtParser::cPatPmtParser(bool UpdatePrimaryDevice)
612{
613 updatePrimaryDevice = UpdatePrimaryDevice;
614 Reset();
615}
616
618{
619 completed = false;
620 pmtSize = 0;
621 patVersion = pmtVersion = -1;
622 pmtPids[0] = 0;
623 vpid = vtype = 0;
624 ppid = 0;
625}
626
627void cPatPmtParser::ParsePat(const uchar *Data, int Length)
628{
629 // Unpack the TS packet:
630 int PayloadOffset = TsPayloadOffset(Data);
631 Data += PayloadOffset;
632 Length -= PayloadOffset;
633 // The PAT is always assumed to fit into a single TS packet
634 if ((Length -= Data[0] + 1) <= 0)
635 return;
636 Data += Data[0] + 1; // process pointer_field
637 SI::PAT Pat(Data, false);
638 if (Pat.CheckCRCAndParse()) {
639 dbgpatpmt("PAT: TSid = %d, c/n = %d, v = %d, s = %d, ls = %d\n", Pat.getTransportStreamId(), Pat.getCurrentNextIndicator(), Pat.getVersionNumber(), Pat.getSectionNumber(), Pat.getLastSectionNumber());
640 if (patVersion == Pat.getVersionNumber())
641 return;
642 int NumPmtPids = 0;
644 for (SI::Loop::Iterator it; Pat.associationLoop.getNext(assoc, it); ) {
645 dbgpatpmt(" isNITPid = %d\n", assoc.isNITPid());
646 if (!assoc.isNITPid()) {
647 if (NumPmtPids <= MAX_PMT_PIDS)
648 pmtPids[NumPmtPids++] = assoc.getPid();
649 dbgpatpmt(" service id = %d, pid = %d\n", assoc.getServiceId(), assoc.getPid());
650 }
651 }
652 pmtPids[NumPmtPids] = 0;
654 }
655 else
656 esyslog("ERROR: can't parse PAT");
657}
658
659void cPatPmtParser::ParsePmt(const uchar *Data, int Length)
660{
661 // Unpack the TS packet:
662 bool PayloadStart = TsPayloadStart(Data);
663 int PayloadOffset = TsPayloadOffset(Data);
664 Data += PayloadOffset;
665 Length -= PayloadOffset;
666 // The PMT may extend over several TS packets, so we need to assemble them
667 if (PayloadStart) {
668 pmtSize = 0;
669 if ((Length -= Data[0] + 1) <= 0)
670 return;
671 Data += Data[0] + 1; // this is the first packet
672 if (SectionLength(Data, Length) > Length) {
673 if (Length <= int(sizeof(pmt))) {
674 memcpy(pmt, Data, Length);
675 pmtSize = Length;
676 }
677 else
678 esyslog("ERROR: PMT packet length too big (%d byte)!", Length);
679 return;
680 }
681 // the packet contains the entire PMT section, so we run into the actual parsing
682 }
683 else if (pmtSize > 0) {
684 // this is a following packet, so we add it to the pmt storage
685 if (Length <= int(sizeof(pmt)) - pmtSize) {
686 memcpy(pmt + pmtSize, Data, Length);
687 pmtSize += Length;
688 }
689 else {
690 esyslog("ERROR: PMT section length too big (%d byte)!", pmtSize + Length);
691 pmtSize = 0;
692 }
694 return; // more packets to come
695 // the PMT section is now complete, so we run into the actual parsing
696 Data = pmt;
697 }
698 else
699 return; // fragment of broken packet - ignore
700 SI::PMT Pmt(Data, false);
701 if (Pmt.CheckCRCAndParse()) {
702 dbgpatpmt("PMT: sid = %d, c/n = %d, v = %d, s = %d, ls = %d\n", Pmt.getServiceId(), Pmt.getCurrentNextIndicator(), Pmt.getVersionNumber(), Pmt.getSectionNumber(), Pmt.getLastSectionNumber());
703 dbgpatpmt(" pcr = %d\n", Pmt.getPCRPid());
704 if (pmtVersion == Pmt.getVersionNumber())
705 return;
708 int NumApids = 0;
709 int NumDpids = 0;
710 int NumSpids = 0;
711 vpid = vtype = 0;
712 ppid = 0;
713 apids[0] = 0;
714 dpids[0] = 0;
715 spids[0] = 0;
716 atypes[0] = 0;
717 dtypes[0] = 0;
718 SI::PMT::Stream stream;
719 for (SI::Loop::Iterator it; Pmt.streamLoop.getNext(stream, it); ) {
720 dbgpatpmt(" stream type = %02X, pid = %d", stream.getStreamType(), stream.getPid());
721 switch (stream.getStreamType()) {
722 case 0x01: // STREAMTYPE_11172_VIDEO
723 case 0x02: // STREAMTYPE_13818_VIDEO
724 case 0x1B: // H.264
725 case 0x24: // H.265
726 vpid = stream.getPid();
727 vtype = stream.getStreamType();
728 ppid = Pmt.getPCRPid();
729 break;
730 case 0x03: // STREAMTYPE_11172_AUDIO
731 case 0x04: // STREAMTYPE_13818_AUDIO
732 case 0x0F: // ISO/IEC 13818-7 Audio with ADTS transport syntax
733 case 0x11: // ISO/IEC 14496-3 Audio with LATM transport syntax
734 {
735 if (NumApids < MAXAPIDS) {
736 apids[NumApids] = stream.getPid();
737 atypes[NumApids] = stream.getStreamType();
738 *alangs[NumApids] = 0;
740 for (SI::Loop::Iterator it; (d = stream.streamDescriptors.getNext(it)); ) {
741 switch (d->getDescriptorTag()) {
745 char *s = alangs[NumApids];
746 int n = 0;
747 for (SI::Loop::Iterator it; ld->languageLoop.getNext(l, it); ) {
748 if (*ld->languageCode != '-') { // some use "---" to indicate "none"
749 dbgpatpmt(" '%s'", l.languageCode);
750 if (n > 0)
751 *s++ = '+';
753 s += strlen(s);
754 if (n++ > 1)
755 break;
756 }
757 }
758 }
759 break;
760 default: ;
761 }
762 delete d;
763 }
765 cDevice::PrimaryDevice()->SetAvailableTrack(ttAudio, NumApids, apids[NumApids], alangs[NumApids]);
766 NumApids++;
767 apids[NumApids] = 0;
768 }
769 }
770 break;
771 case 0x06: // STREAMTYPE_13818_PES_PRIVATE
772 {
773 int dpid = 0;
774 int dtype = 0;
775 char lang[MAXLANGCODE1] = "";
777 for (SI::Loop::Iterator it; (d = stream.streamDescriptors.getNext(it)); ) {
778 switch (d->getDescriptorTag()) {
781 dbgpatpmt(" AC3");
782 dpid = stream.getPid();
783 dtype = d->getDescriptorTag();
784 break;
786 dbgpatpmt(" subtitling");
787 if (NumSpids < MAXSPIDS) {
788 spids[NumSpids] = stream.getPid();
789 *slangs[NumSpids] = 0;
790 subtitlingTypes[NumSpids] = 0;
791 compositionPageIds[NumSpids] = 0;
792 ancillaryPageIds[NumSpids] = 0;
795 char *s = slangs[NumSpids];
796 int n = 0;
797 for (SI::Loop::Iterator it; sd->subtitlingLoop.getNext(sub, it); ) {
798 if (sub.languageCode[0]) {
799 dbgpatpmt(" '%s'", sub.languageCode);
800 subtitlingTypes[NumSpids] = sub.getSubtitlingType();
802 ancillaryPageIds[NumSpids] = sub.getAncillaryPageId();
803 if (n > 0)
804 *s++ = '+';
806 s += strlen(s);
807 if (n++ > 1)
808 break;
809 }
810 }
812 cDevice::PrimaryDevice()->SetAvailableTrack(ttSubtitle, NumSpids, spids[NumSpids], slangs[NumSpids]);
813 NumSpids++;
814 spids[NumSpids] = 0;
815 }
816 break;
819 dbgpatpmt(" '%s'", ld->languageCode);
821 }
822 break;
823 default: ;
824 }
825 delete d;
826 }
827 if (dpid) {
828 if (NumDpids < MAXDPIDS) {
829 dpids[NumDpids] = dpid;
830 dtypes[NumDpids] = dtype;
831 strn0cpy(dlangs[NumDpids], lang, sizeof(dlangs[NumDpids]));
833 cDevice::PrimaryDevice()->SetAvailableTrack(ttDolby, NumDpids, dpid, lang);
834 NumDpids++;
835 dpids[NumDpids] = 0;
836 }
837 }
838 }
839 break;
840 case 0x81: // STREAMTYPE_USER_PRIVATE - AC3 audio for ATSC and BD
841 case 0x82: // STREAMTYPE_USER_PRIVATE - DTS audio for BD
842 case 0x87: // eac3
843 {
844 dbgpatpmt(" %s",
845 stream.getStreamType() == 0x81 ? "AC3" :
846 stream.getStreamType() == 0x87 ? "AC3" :
847 stream.getStreamType() == 0x82 ? "DTS" : "");
848 char lang[MAXLANGCODE1] = { 0 };
850 for (SI::Loop::Iterator it; (d = stream.streamDescriptors.getNext(it)); ) {
851 switch (d->getDescriptorTag()) {
854 dbgpatpmt(" '%s'", ld->languageCode);
856 }
857 break;
858 default: ;
859 }
860 delete d;
861 }
862 if (NumDpids < MAXDPIDS) {
863 dpids[NumDpids] = stream.getPid();
864 dtypes[NumDpids] = SI::AC3DescriptorTag;
865 strn0cpy(dlangs[NumDpids], lang, sizeof(dlangs[NumDpids]));
867 cDevice::PrimaryDevice()->SetAvailableTrack(ttDolby, NumDpids, stream.getPid(), lang);
868 NumDpids++;
869 dpids[NumDpids] = 0;
870 }
871 }
872 break;
873 case 0x90: // PGS subtitles for BD
874 {
875 dbgpatpmt(" subtitling");
876 char lang[MAXLANGCODE1] = { 0 };
878 for (SI::Loop::Iterator it; (d = stream.streamDescriptors.getNext(it)); ) {
879 switch (d->getDescriptorTag()) {
882 dbgpatpmt(" '%s'", ld->languageCode);
884 if (NumSpids < MAXSPIDS) {
885 spids[NumSpids] = stream.getPid();
886 *slangs[NumSpids] = 0;
887 subtitlingTypes[NumSpids] = 0;
888 compositionPageIds[NumSpids] = 0;
889 ancillaryPageIds[NumSpids] = 0;
891 cDevice::PrimaryDevice()->SetAvailableTrack(ttSubtitle, NumSpids, stream.getPid(), lang);
892 NumSpids++;
893 spids[NumSpids] = 0;
894 }
895 }
896 break;
897 default: ;
898 }
899 delete d;
900 }
901 }
902 break;
903 default: ;
904 }
905 dbgpatpmt("\n");
909 }
910 }
912 completed = true;
913 }
914 else
915 esyslog("ERROR: can't parse PMT");
916 pmtSize = 0;
917}
918
919bool cPatPmtParser::ParsePatPmt(const uchar *Data, int Length)
920{
921 while (Length >= TS_SIZE) {
922 if (*Data != TS_SYNC_BYTE)
923 break; // just for safety
924 int Pid = TsPid(Data);
925 if (Pid == PATPID)
926 ParsePat(Data, TS_SIZE);
927 else if (IsPmtPid(Pid)) {
928 ParsePmt(Data, TS_SIZE);
929 if (patVersion >= 0 && pmtVersion >= 0)
930 return true;
931 }
932 Data += TS_SIZE;
933 Length -= TS_SIZE;
934 }
935 return false;
936}
937
938bool cPatPmtParser::GetVersions(int &PatVersion, int &PmtVersion) const
939{
940 PatVersion = patVersion;
941 PmtVersion = pmtVersion;
942 return patVersion >= 0 && pmtVersion >= 0;
943}
944
945// --- cEitGenerator ---------------------------------------------------------
946
948{
949 counter = 0;
950 version = 0;
951 if (Sid)
952 Generate(Sid);
953}
954
955uint16_t cEitGenerator::YMDtoMJD(int Y, int M, int D)
956{
957 int L = (M < 3) ? 1 : 0;
958 return 14956 + D + int((Y - L) * 365.25) + int((M + 1 + L * 12) * 30.6001);
959}
960
962{
964 *p++ = 0x04; // descriptor length
965 *p++ = '9'; // country code "902" ("All countries") -> EN 300 468 / 6.2.28; www.dvbservices.com/country_codes/index.php
966 *p++ = '0';
967 *p++ = '2';
968 *p++ = ParentalRating;
969 return p;
970}
971
973{
974 uchar *PayloadStart;
975 uchar *SectionStart;
976 uchar *DescriptorsStart;
977 memset(eit, 0xFF, sizeof(eit));
978 struct tm tm_r;
979 time_t t = time(NULL) - 3600; // let's have the event start one hour in the past
980 tm *tm = localtime_r(&t, &tm_r);
981 uint16_t MJD = YMDtoMJD(tm->tm_year, tm->tm_mon + 1, tm->tm_mday);
982 uchar *p = eit;
983 // TS header:
984 *p++ = TS_SYNC_BYTE;
985 *p++ = TS_PAYLOAD_START;
986 *p++ = EITPID;
987 *p++ = 0x10 | (counter++ & 0x0F); // continuity counter
988 *p++ = 0x00; // pointer field (payload unit start indicator is set)
989 // payload:
990 PayloadStart = p;
991 *p++ = 0x4E; // TID present/following event on this transponder
992 *p++ = 0xF0;
993 *p++ = 0x00; // section length
994 SectionStart = p;
995 *p++ = Sid >> 8;
996 *p++ = Sid & 0xFF;
997 *p++ = 0xC1 | (version << 1);
998 *p++ = 0x00; // section number
999 *p++ = 0x00; // last section number
1000 *p++ = 0x00; // transport stream id
1001 *p++ = 0x00; // ...
1002 *p++ = 0x00; // original network id
1003 *p++ = 0x00; // ...
1004 *p++ = 0x00; // segment last section number
1005 *p++ = 0x4E; // last table id
1006 *p++ = 0x00; // event id
1007 *p++ = 0x01; // ...
1008 *p++ = MJD >> 8; // start time
1009 *p++ = MJD & 0xFF; // ...
1010 *p++ = tm->tm_hour; // ...
1011 *p++ = tm->tm_min; // ...
1012 *p++ = tm->tm_sec; // ...
1013 *p++ = 0x24; // duration (one day, should cover everything)
1014 *p++ = 0x00; // ...
1015 *p++ = 0x00; // ...
1016 *p++ = 0x90; // running status, free/CA mode
1017 *p++ = 0x00; // descriptors loop length
1018 DescriptorsStart = p;
1020 // fill in lengths:
1021 *(SectionStart - 1) = p - SectionStart + 4; // +4 = length of CRC
1022 *(DescriptorsStart - 1) = p - DescriptorsStart;
1023 // checksum
1024 int crc = SI::CRC32::crc32((char *)PayloadStart, p - PayloadStart, 0xFFFFFFFF);
1025 *p++ = crc >> 24;
1026 *p++ = crc >> 16;
1027 *p++ = crc >> 8;
1028 *p++ = crc;
1029 return eit;
1030}
1031
1032// --- cTsToPes --------------------------------------------------------------
1033
1035{
1036 data = NULL;
1037 size = 0;
1038 Reset();
1039}
1040
1042{
1043 free(data);
1044}
1045
1046void cTsToPes::PutTs(const uchar *Data, int Length)
1047{
1048 if (TsError(Data)) {
1049 Reset();
1050 return; // ignore packets with TEI set, and drop any PES data collected so far
1051 }
1052 if (TsPayloadStart(Data))
1053 Reset();
1054 else if (!size)
1055 return; // skip everything before the first payload start
1056 Length = TsGetPayload(&Data);
1057 if (length + Length > size) {
1058 int NewSize = max(KILOBYTE(2), length + Length);
1059 if (uchar *NewData = (uchar *)realloc(data, NewSize)) {
1060 data = NewData;
1061 size = NewSize;
1062 }
1063 else {
1064 esyslog("ERROR: out of memory");
1065 Reset();
1066 return;
1067 }
1068 }
1069 memcpy(data + length, Data, Length);
1070 length += Length;
1071}
1072
1073#define MAXPESLENGTH 0xFFF0
1074
1075const uchar *cTsToPes::GetPes(int &Length)
1076{
1077 if (repeatLast) {
1078 repeatLast = false;
1079 Length = lastLength;
1080 return lastData;
1081 }
1082 if (offset < length && PesLongEnough(length)) {
1083 if (!PesHasLength(data)) // this is a video PES packet with undefined length
1084 offset = 6; // trigger setting PES length for initial slice
1085 if (offset) {
1086 uchar *p = data + offset - 6;
1087 if (p != data) {
1088 p -= 3;
1089 if (p < data) {
1090 Reset();
1091 return NULL;
1092 }
1093 memmove(p, data, 4);
1094 }
1095 int l = min(length - offset, MAXPESLENGTH);
1096 offset += l;
1097 if (p != data) {
1098 l += 3;
1099 p[6] = 0x80;
1100 p[7] = 0x00;
1101 p[8] = 0x00;
1102 }
1103 p[4] = l / 256;
1104 p[5] = l & 0xFF;
1105 Length = l + 6;
1106 lastLength = Length;
1107 lastData = p;
1108 return p;
1109 }
1110 else {
1111 Length = PesLength(data);
1112 if (Length <= length) {
1113 offset = Length; // to make sure we break out in case of garbage data
1114 lastLength = Length;
1115 lastData = data;
1116 return data;
1117 }
1118 }
1119 }
1120 return NULL;
1121}
1122
1124{
1125 repeatLast = true;
1126}
1127
1129{
1130 length = offset = 0;
1131 lastData = NULL;
1132 lastLength = 0;
1133 repeatLast = false;
1134}
1135
1136// --- Some helper functions for debugging -----------------------------------
1137
1138void BlockDump(const char *Name, const u_char *Data, int Length)
1139{
1140 printf("--- %s\n", Name);
1141 for (int i = 0; i < Length; i++) {
1142 if (i && (i % 16) == 0)
1143 printf("\n");
1144 printf(" %02X", Data[i]);
1145 }
1146 printf("\n");
1147}
1148
1149void TsDump(const char *Name, const u_char *Data, int Length)
1150{
1151 printf("%s: %04X", Name, Length);
1152 int n = min(Length, 20);
1153 for (int i = 0; i < n; i++)
1154 printf(" %02X", Data[i]);
1155 if (n < Length) {
1156 printf(" ...");
1157 n = max(n, Length - 10);
1158 for (n = max(n, Length - 10); n < Length; n++)
1159 printf(" %02X", Data[n]);
1160 }
1161 printf("\n");
1162}
1163
1164void PesDump(const char *Name, const u_char *Data, int Length)
1165{
1166 TsDump(Name, Data, Length);
1167}
1168
1169// --- cFrameParser ----------------------------------------------------------
1170
1172protected:
1173 bool debug;
1177public:
1178 cFrameParser(void);
1179 virtual ~cFrameParser() {};
1180 virtual int Parse(const uchar *Data, int Length, int Pid) = 0;
1187 void SetDebug(bool Debug) { debug = Debug; }
1188 bool NewFrame(void) { return newFrame; }
1189 bool IndependentFrame(void) { return independentFrame; }
1191 };
1192
1194{
1195 debug = true;
1196 newFrame = false;
1197 independentFrame = false;
1199}
1200
1201// --- cAudioParser ----------------------------------------------------------
1202
1204public:
1205 cAudioParser(void);
1206 virtual int Parse(const uchar *Data, int Length, int Pid);
1207 };
1208
1210{
1211}
1212
1213int cAudioParser::Parse(const uchar *Data, int Length, int Pid)
1214{
1215 if (TsPayloadStart(Data)) {
1216 newFrame = independentFrame = true;
1217 if (debug)
1218 dbgframes("/");
1219 }
1220 else
1221 newFrame = independentFrame = false;
1222 return TS_SIZE;
1223}
1224
1225// --- cMpeg2Parser ----------------------------------------------------------
1226
1228private:
1229 uint32_t scanner;
1232public:
1233 cMpeg2Parser(void);
1234 virtual int Parse(const uchar *Data, int Length, int Pid);
1235 };
1236
1238{
1240 seenIndependentFrame = false;
1241 lastIFrameTemporalReference = -1; // invalid
1242}
1243
1244int cMpeg2Parser::Parse(const uchar *Data, int Length, int Pid)
1245{
1246 newFrame = independentFrame = false;
1247 bool SeenPayloadStart = false;
1248 cTsPayload tsPayload(const_cast<uchar *>(Data), Length, Pid);
1249 if (TsPayloadStart(Data)) {
1250 SeenPayloadStart = true;
1251 tsPayload.SkipPesHeader();
1254 dbgframes("/");
1255 }
1256 uint32_t OldScanner = scanner; // need to remember it in case of multiple frames per payload
1257 for (;;) {
1258 if (!SeenPayloadStart && tsPayload.AtTsStart())
1259 OldScanner = scanner;
1260 scanner = (scanner << 8) | tsPayload.GetByte();
1261 if (scanner == 0x00000100) { // Picture Start Code
1262 if (!SeenPayloadStart && tsPayload.GetLastIndex() > TS_SIZE) {
1263 scanner = OldScanner;
1264 return tsPayload.Used() - TS_SIZE;
1265 }
1266 uchar b1 = tsPayload.GetByte();
1267 uchar b2 = tsPayload.GetByte();
1268 int TemporalReference = (b1 << 2 ) + ((b2 & 0xC0) >> 6);
1269 uchar FrameType = (b2 >> 3) & 0x07;
1270 if (tsPayload.Find(0x000001B5)) { // Extension start code
1271 if (((tsPayload.GetByte() & 0xF0) >> 4) == 0x08) { // Picture coding extension
1272 tsPayload.GetByte();
1273 uchar PictureStructure = tsPayload.GetByte() & 0x03;
1274 if (PictureStructure == 0x02) // bottom field
1275 break;
1276 }
1277 }
1278 newFrame = true;
1279 independentFrame = FrameType == 1; // I-Frame
1280 if (independentFrame) {
1283 lastIFrameTemporalReference = TemporalReference;
1284 }
1285 if (debug) {
1288 static const char FrameTypes[] = "?IPBD???";
1289 dbgframes("%c", FrameTypes[FrameType]);
1290 }
1291 }
1292 tsPayload.Statistics();
1293 break;
1294 }
1295 if (tsPayload.AtPayloadStart() // stop at a new payload start to have the buffer refilled if necessary
1296 || tsPayload.Eof()) // or if we're out of data
1297 break;
1298 }
1299 return tsPayload.Used();
1300}
1301
1302// --- cH264Parser -----------------------------------------------------------
1303
1305private:
1311 };
1312 uchar byte; // holds the current byte value in case of bitwise access
1313 int bit; // the bit index into the current byte (-1 if we're not in bit reading mode)
1314 int zeroBytes; // the number of consecutive zero bytes (to detect 0x000003)
1315 // Identifiers written in '_' notation as in "ITU-T H.264":
1319protected:
1321 uint32_t scanner;
1324 uchar GetByte(bool Raw = false);
1328 uchar GetBit(void);
1329 uint32_t GetBits(int Bits);
1330 uint32_t GetGolombUe(void);
1331 int32_t GetGolombSe(void);
1332 void ParseAccessUnitDelimiter(void);
1333 void ParseSequenceParameterSet(void);
1334 void ParseSliceHeader(void);
1335public:
1336 cH264Parser(void);
1340 virtual int Parse(const uchar *Data, int Length, int Pid);
1341 };
1342
1344{
1345 byte = 0;
1346 bit = -1;
1347 zeroBytes = 0;
1351 frame_mbs_only_flag = false;
1352 gotAccessUnitDelimiter = false;
1354}
1355
1357{
1358 uchar b = tsPayload.GetByte();
1359 if (!Raw) {
1360 // If we encounter the byte sequence 0x000003, we need to skip the 0x03:
1361 if (b == 0x00)
1362 zeroBytes++;
1363 else {
1364 if (b == 0x03 && zeroBytes >= 2)
1365 b = tsPayload.GetByte();
1366 zeroBytes = b ? 0 : 1;
1367 }
1368 }
1369 else
1370 zeroBytes = 0;
1371 bit = -1;
1372 return b;
1373}
1374
1376{
1377 if (bit < 0) {
1378 byte = GetByte();
1379 bit = 7;
1380 }
1381 return (byte & (1 << bit--)) ? 1 : 0;
1382}
1383
1384uint32_t cH264Parser::GetBits(int Bits)
1385{
1386 uint32_t b = 0;
1387 while (Bits--)
1388 b |= GetBit() << Bits;
1389 return b;
1390}
1391
1393{
1394 int z = -1;
1395 for (int b = 0; !b && z < 32; z++) // limiting z to no get stuck if GetBit() always returns 0
1396 b = GetBit();
1397 return (1 << z) - 1 + GetBits(z);
1398}
1399
1401{
1402 uint32_t v = GetGolombUe();
1403 if (v) {
1404 if ((v & 0x01) != 0)
1405 return (v + 1) / 2; // fails for v == 0xFFFFFFFF, but that will probably never happen
1406 else
1407 return -int32_t(v / 2);
1408 }
1409 return v;
1410}
1411
1412int cH264Parser::Parse(const uchar *Data, int Length, int Pid)
1413{
1414 newFrame = independentFrame = false;
1415 tsPayload.Setup(const_cast<uchar *>(Data), Length, Pid);
1416 if (TsPayloadStart(Data)) {
1420 dbgframes("/");
1421 }
1422 }
1423 for (;;) {
1424 scanner = (scanner << 8) | GetByte(true);
1425 if ((scanner & 0xFFFFFF00) == 0x00000100) { // NAL unit start
1426 uchar NalUnitType = scanner & 0x1F;
1427 switch (NalUnitType) {
1430 break;
1434 }
1435 break;
1439 gotAccessUnitDelimiter = false;
1440 if (newFrame)
1442 return tsPayload.Used();
1443 }
1444 break;
1445 default: ;
1446 }
1447 }
1448 if (tsPayload.AtPayloadStart() // stop at a new payload start to have the buffer refilled if necessary
1449 || tsPayload.Eof()) // or if we're out of data
1450 break;
1451 }
1452 return tsPayload.Used();
1453}
1454
1456{
1458 dbgframes("A");
1459 GetByte(); // primary_pic_type
1460}
1461
1463{
1464 uchar profile_idc = GetByte(); // profile_idc
1465 GetByte(); // constraint_set[0-5]_flags, reserved_zero_2bits
1466 GetByte(); // level_idc
1467 GetGolombUe(); // seq_parameter_set_id
1468 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) {
1469 int chroma_format_idc = GetGolombUe(); // chroma_format_idc
1470 if (chroma_format_idc == 3)
1472 GetGolombUe(); // bit_depth_luma_minus8
1473 GetGolombUe(); // bit_depth_chroma_minus8
1474 GetBit(); // qpprime_y_zero_transform_bypass_flag
1475 if (GetBit()) { // seq_scaling_matrix_present_flag
1476 for (int i = 0; i < ((chroma_format_idc != 3) ? 8 : 12); i++) {
1477 if (GetBit()) { // seq_scaling_list_present_flag
1478 int SizeOfScalingList = (i < 6) ? 16 : 64;
1479 int LastScale = 8;
1480 int NextScale = 8;
1481 for (int j = 0; j < SizeOfScalingList; j++) {
1482 if (NextScale)
1483 NextScale = (LastScale + GetGolombSe() + 256) % 256; // delta_scale
1484 if (NextScale)
1485 LastScale = NextScale;
1486 }
1487 }
1488 }
1489 }
1490 }
1491 log2_max_frame_num = GetGolombUe() + 4; // log2_max_frame_num_minus4
1492 int pic_order_cnt_type = GetGolombUe(); // pic_order_cnt_type
1493 if (pic_order_cnt_type == 0)
1494 GetGolombUe(); // log2_max_pic_order_cnt_lsb_minus4
1495 else if (pic_order_cnt_type == 1) {
1496 GetBit(); // delta_pic_order_always_zero_flag
1497 GetGolombSe(); // offset_for_non_ref_pic
1498 GetGolombSe(); // offset_for_top_to_bottom_field
1499 for (int i = GetGolombUe(); i--; ) // num_ref_frames_in_pic_order_cnt_cycle
1500 GetGolombSe(); // offset_for_ref_frame
1501 }
1502 GetGolombUe(); // max_num_ref_frames
1503 GetBit(); // gaps_in_frame_num_value_allowed_flag
1504 GetGolombUe(); // pic_width_in_mbs_minus1
1505 GetGolombUe(); // pic_height_in_map_units_minus1
1506 frame_mbs_only_flag = GetBit(); // frame_mbs_only_flag
1507 if (debug) {
1509 dbgframes("A"); // just for completeness
1510 dbgframes(frame_mbs_only_flag ? "S" : "s");
1511 }
1512}
1513
1515{
1516 newFrame = true;
1517 GetGolombUe(); // first_mb_in_slice
1518 int slice_type = GetGolombUe(); // slice_type, 0 = P, 1 = B, 2 = I, 3 = SP, 4 = SI
1519 independentFrame = (slice_type % 5) == 2;
1520 if (debug) {
1521 static const char SliceTypes[] = "PBIpi";
1522 dbgframes("%c", SliceTypes[slice_type % 5]);
1523 }
1525 return; // don't need the rest - a frame is complete
1526 GetGolombUe(); // pic_parameter_set_id
1528 GetBits(2); // colour_plane_id
1529 GetBits(log2_max_frame_num); // frame_num
1530 if (!frame_mbs_only_flag) {
1531 if (GetBit()) // field_pic_flag
1532 newFrame = !GetBit(); // bottom_field_flag
1533 if (debug)
1534 dbgframes(newFrame ? "t" : "b");
1535 }
1536}
1537
1538// --- cH265Parser -----------------------------------------------------------
1539
1540class cH265Parser : public cH264Parser {
1541private:
1572 };
1573public:
1574 cH265Parser(void);
1575 virtual int Parse(const uchar *Data, int Length, int Pid);
1576 };
1577
1579:cH264Parser()
1580{
1581}
1582
1583int cH265Parser::Parse(const uchar *Data, int Length, int Pid)
1584{
1585 newFrame = independentFrame = false;
1586 tsPayload.Setup(const_cast<uchar *>(Data), Length, Pid);
1587 if (TsPayloadStart(Data)) {
1590 }
1591 for (;;) {
1592 scanner = (scanner << 8) | GetByte(true);
1593 if ((scanner & 0xFFFFFF00) == 0x00000100) { // NAL unit start
1594 uchar NalUnitType = (scanner >> 1) & 0x3F;
1595 GetByte(); // nuh_layer_id + nuh_temporal_id_plus1
1596 if (NalUnitType <= nutSliceSegmentRASLR || (NalUnitType >= nutSliceSegmentBLAWLP && NalUnitType <= nutSliceSegmentCRANUT)) {
1597 if (NalUnitType == nutSliceSegmentIDRWRADL || NalUnitType == nutSliceSegmentIDRNLP || NalUnitType == nutSliceSegmentCRANUT)
1598 independentFrame = true;
1599 if (GetBit()) { // first_slice_segment_in_pic_flag
1600 newFrame = true;
1602 }
1603 break;
1604 }
1605 }
1606 if (tsPayload.AtPayloadStart() // stop at a new payload start to have the buffer refilled if necessary
1607 || tsPayload.Eof()) // or if we're out of data
1608 break;
1609 }
1610 return tsPayload.Used();
1611}
1612
1613// --- cFrameDetector --------------------------------------------------------
1614
1616{
1617 parser = NULL;
1618 SetPid(Pid, Type);
1619 synced = false;
1620 newFrame = independentFrame = false;
1621 numPtsValues = 0;
1622 numIFrames = 0;
1623 framesPerSecond = 0;
1625 scanning = false;
1626}
1627
1628static int CmpUint32(const void *p1, const void *p2)
1629{
1630 if (*(uint32_t *)p1 < *(uint32_t *)p2) return -1;
1631 if (*(uint32_t *)p1 > *(uint32_t *)p2) return 1;
1632 return 0;
1633}
1634
1635void cFrameDetector::SetPid(int Pid, int Type)
1636{
1637 pid = Pid;
1638 type = Type;
1639 isVideo = type == 0x01 || type == 0x02 || type == 0x1B || type == 0x24; // MPEG 1, 2, H.264 or H.265
1640 delete parser;
1641 parser = NULL;
1642 if (type == 0x01 || type == 0x02)
1643 parser = new cMpeg2Parser;
1644 else if (type == 0x1B)
1645 parser = new cH264Parser;
1646 else if (type == 0x24)
1647 parser = new cH265Parser;
1648 else if (type == 0x03 || type == 0x04 || type == 0x06) // MPEG audio or AC3 audio
1649 parser = new cAudioParser;
1650 else if (type != 0)
1651 esyslog("ERROR: unknown stream type %d (PID %d) in frame detector", type, pid);
1652}
1653
1654int cFrameDetector::Analyze(const uchar *Data, int Length)
1655{
1656 if (!parser)
1657 return 0;
1658 int Processed = 0;
1659 newFrame = independentFrame = false;
1660 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
1661 // Sync on TS packet borders:
1662 if (int Skipped = TS_SYNC(Data, Length))
1663 return Processed + Skipped;
1664 // Handle one TS packet:
1665 int Handled = TS_SIZE;
1666 if (TsHasPayload(Data) && !TsIsScrambled(Data)) {
1667 int Pid = TsPid(Data);
1668 if (Pid == pid) {
1669 if (Processed)
1670 return Processed;
1671 if (TsPayloadStart(Data))
1672 scanning = true;
1673 if (scanning) {
1674 // Detect the beginning of a new frame:
1675 if (TsPayloadStart(Data)) {
1678 }
1679 int n = parser->Parse(Data, Length, pid);
1680 if (n > 0) {
1681 if (parser->NewFrame()) {
1682 newFrame = true;
1684 if (synced) {
1685 if (framesPerPayloadUnit <= 1)
1686 scanning = false;
1687 }
1688 else {
1690 if (independentFrame)
1691 numIFrames++;
1692 }
1693 }
1694 Handled = n;
1695 }
1696 }
1697 if (TsPayloadStart(Data)) {
1698 // Determine the frame rate from the PTS values in the PES headers:
1699 if (framesPerSecond <= 0.0) {
1700 // frame rate unknown, so collect a sequence of PTS values:
1701 if (numPtsValues < 2 || numPtsValues < MaxPtsValues && numIFrames < 2) { // collect a sequence containing at least two I-frames
1702 if (newFrame) { // only take PTS values at the beginning of a frame (in case if fields!)
1703 const uchar *Pes = Data + TsPayloadOffset(Data);
1704 if (numIFrames && PesHasPts(Pes)) {
1706 // check for rollover:
1707 if (numPtsValues && ptsValues[numPtsValues - 1] > 0xF0000000 && ptsValues[numPtsValues] < 0x10000000) {
1708 dbgframes("#");
1709 numPtsValues = 0;
1710 numIFrames = 0;
1711 }
1712 else
1713 numPtsValues++;
1714 }
1715 }
1716 }
1717 if (numPtsValues >= 2 && numIFrames >= 2) {
1718 // find the smallest PTS delta:
1719 qsort(ptsValues, numPtsValues, sizeof(uint32_t), CmpUint32);
1720 numPtsValues--;
1721 for (int i = 0; i < numPtsValues; i++)
1722 ptsValues[i] = ptsValues[i + 1] - ptsValues[i];
1723 qsort(ptsValues, numPtsValues, sizeof(uint32_t), CmpUint32);
1724 int Div = framesPerPayloadUnit;
1725 if (framesPerPayloadUnit > 1)
1727 if (Div <= 0)
1728 Div = 1;
1729 int Delta = ptsValues[0] / Div;
1730 // determine frame info:
1731 if (isVideo) {
1732 if (Delta == 3753)
1733 framesPerSecond = 24.0 / 1.001;
1734 else if (abs(Delta - 3600) <= 1)
1735 framesPerSecond = 25.0;
1736 else if (Delta % 3003 == 0)
1737 framesPerSecond = 30.0 / 1.001;
1738 else if (abs(Delta - 1800) <= 1)
1739 framesPerSecond = 50.0;
1740 else if (Delta == 1501)
1741 framesPerSecond = 60.0 / 1.001;
1742 else {
1744 dsyslog("unknown frame delta (%d), assuming %5.2f fps", Delta, DEFAULTFRAMESPERSECOND);
1745 }
1746 }
1747 else // audio
1748 framesPerSecond = double(PTSTICKS) / Delta; // PTS of audio frames is always increasing
1749 dbgframes("\nDelta = %d FPS = %5.2f FPPU = %d NF = %d TRO = %d\n", Delta, framesPerSecond, framesPerPayloadUnit, numPtsValues + 1, parser->IFrameTemporalReferenceOffset());
1750 synced = true;
1751 parser->SetDebug(false);
1752 }
1753 }
1754 }
1755 }
1756 else if (Pid == PATPID && synced && Processed)
1757 return Processed; // allow the caller to see any PAT packets
1758 }
1759 Data += Handled;
1760 Length -= Handled;
1761 Processed += Handled;
1762 if (newFrame)
1763 break;
1764 }
1765 return Processed;
1766}
#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
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
StructureLoop< Association > associationLoop
int getTransportStreamId() const
Definition: section.c:26
DescriptorLoop streamDescriptors
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
StructureLoop< Subtitling > subtitlingLoop
virtual int Parse(const uchar *Data, int Length, int Pid)
Parses the given Data, which is a sequence of Length bytes of TS packets.
Definition: remux.c:1213
cAudioParser(void)
Definition: remux.c:1209
const int * Dpids(void) const
Definition: channels.h:157
uint16_t AncillaryPageId(int i) const
Definition: channels.h:169
uint16_t CompositionPageId(int i) const
Definition: channels.h:168
int Tpid(void) const
Definition: channels.h:170
const char * Slang(int i) const
Definition: channels.h:164
int Vpid(void) const
Definition: channels.h:153
int Atype(int i) const
Definition: channels.h:165
int Dtype(int i) const
Definition: channels.h:166
int Dpid(int i) const
Definition: channels.h:160
int Vtype(void) const
Definition: channels.h:155
int Apid(int i) const
Definition: channels.h:159
int Ppid(void) const
Definition: channels.h:154
uchar SubtitlingType(int i) const
Definition: channels.h:167
const char * Dlang(int i) const
Definition: channels.h:163
int Spid(int i) const
Definition: channels.h:161
const int * Apids(void) const
Definition: channels.h:156
const char * Alang(int i) const
Definition: channels.h:162
const int * Spids(void) const
Definition: channels.h:158
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:1179
void ClrAvailableTracks(bool DescriptionsOnly=false, bool IdsOnly=false)
Clears the list of currently available tracks.
Definition: device.c:1056
void EnsureSubtitleTrack(void)
Makes sure one of the preferred language subtitle tracks is selected.
Definition: device.c:1212
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:1079
uchar eit[TS_SIZE]
cEitGenerator(int Sid=0)
Definition: remux.c:947
uchar * AddParentalRatingDescriptor(uchar *p, uchar ParentalRating=0)
Definition: remux.c:961
uint16_t YMDtoMJD(int Y, int M, int D)
Definition: remux.c:955
uchar * Generate(int Sid)
Definition: remux.c:972
cFrameParser * parser
cFrameDetector(int Pid=0, int Type=0)
Sets up a frame detector for the given Pid and stream Type.
Definition: remux.c:1615
uint32_t ptsValues[MaxPtsValues]
int Analyze(const uchar *Data, int Length)
Analyzes the TS packets pointed to by Data.
Definition: remux.c:1654
void SetPid(int Pid, int Type)
Sets the Pid and stream Type to detect frames for.
Definition: remux.c:1635
void SetDebug(bool Debug)
Definition: remux.c:1187
bool NewFrame(void)
Definition: remux.c:1188
bool IndependentFrame(void)
Definition: remux.c:1189
bool newFrame
Definition: remux.c:1174
int iFrameTemporalReferenceOffset
Definition: remux.c:1176
bool independentFrame
Definition: remux.c:1175
virtual ~cFrameParser()
Definition: remux.c:1179
bool debug
Definition: remux.c:1173
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.
int IFrameTemporalReferenceOffset(void)
Definition: remux.c:1190
cFrameParser(void)
Definition: remux.c:1193
uint32_t GetBits(int Bits)
Definition: remux.c:1384
cTsPayload tsPayload
Definition: remux.c:1320
void ParseAccessUnitDelimiter(void)
Definition: remux.c:1455
@ nutSequenceParameterSet
Definition: remux.c:1309
@ nutCodedSliceNonIdr
Definition: remux.c:1307
@ nutAccessUnitDelimiter
Definition: remux.c:1310
@ nutCodedSliceIdr
Definition: remux.c:1308
bool separate_colour_plane_flag
Definition: remux.c:1316
bool gotAccessUnitDelimiter
Definition: remux.c:1322
int zeroBytes
Definition: remux.c:1314
bool frame_mbs_only_flag
Definition: remux.c:1318
virtual int Parse(const uchar *Data, int Length, int Pid)
Parses the given Data, which is a sequence of Length bytes of TS packets.
Definition: remux.c:1412
int bit
Definition: remux.c:1313
int log2_max_frame_num
Definition: remux.c:1317
uint32_t GetGolombUe(void)
Definition: remux.c:1392
uchar GetByte(bool Raw=false)
Gets the next data byte.
Definition: remux.c:1356
void ParseSliceHeader(void)
Definition: remux.c:1514
void ParseSequenceParameterSet(void)
Definition: remux.c:1462
uchar byte
Definition: remux.c:1312
uint32_t scanner
Definition: remux.c:1321
bool gotSequenceParameterSet
Definition: remux.c:1323
int32_t GetGolombSe(void)
Definition: remux.c:1400
cH264Parser(void)
Sets up a new H.264 parser.
Definition: remux.c:1343
uchar GetBit(void)
Definition: remux.c:1375
virtual int Parse(const uchar *Data, int Length, int Pid)
Parses the given Data, which is a sequence of Length bytes of TS packets.
Definition: remux.c:1583
cH265Parser(void)
Definition: remux.c:1578
@ nutSliceSegmentIDRWRADL
Definition: remux.c:1556
@ nutUnspecified0
Definition: remux.c:1570
@ nutSliceSegmentSTSAN
Definition: remux.c:1547
@ nutSliceSegmentRADLN
Definition: remux.c:1549
@ nutSliceSegmentIDRNLP
Definition: remux.c:1557
@ nutPrefixSEI
Definition: remux.c:1566
@ nutAccessUnitDelimiter
Definition: remux.c:1562
@ nutUnspecified7
Definition: remux.c:1571
@ nutSliceSegmentBLAWRADL
Definition: remux.c:1554
@ nutSliceSegmentTSAR
Definition: remux.c:1546
@ nutSliceSegmentRADLR
Definition: remux.c:1550
@ nutSliceSegmentTrailingR
Definition: remux.c:1544
@ nutVideoParameterSet
Definition: remux.c:1559
@ nutSequenceParameterSet
Definition: remux.c:1560
@ nutSliceSegmentTSAN
Definition: remux.c:1545
@ nutSliceSegmentRASLN
Definition: remux.c:1551
@ nutSuffixSEI
Definition: remux.c:1567
@ nutSliceSegmentBLAWLP
Definition: remux.c:1553
@ nutEndOfBitstream
Definition: remux.c:1564
@ nutSliceSegmentBLANLP
Definition: remux.c:1555
@ nutSliceSegmentRASLR
Definition: remux.c:1552
@ nutPictureParameterSet
Definition: remux.c:1561
@ nutNonVCLRes3
Definition: remux.c:1569
@ nutSliceSegmentCRANUT
Definition: remux.c:1558
@ nutSliceSegmentTrailingN
Definition: remux.c:1543
@ nutNonVCLRes0
Definition: remux.c:1568
@ nutFillerData
Definition: remux.c:1565
@ nutSliceSegmentSTSAR
Definition: remux.c:1548
@ nutEndOfSequence
Definition: remux.c:1563
bool seenIndependentFrame
Definition: remux.c:1230
cMpeg2Parser(void)
Definition: remux.c:1237
int lastIFrameTemporalReference
Definition: remux.c:1231
uint32_t scanner
Definition: remux.c:1229
virtual int Parse(const uchar *Data, int Length, int Pid)
Parses the given Data, which is a sequence of Length bytes of TS packets.
Definition: remux.c:1244
int MakeCRC(uchar *Target, const uchar *Data, int Length)
Definition: remux.c:451
uchar * GetPmt(int &Index)
Returns a pointer to the Index'th TS packet of the PMT section.
Definition: remux.c:600
void SetChannel(const cChannel *Channel)
Sets the Channel for which the PAT/PMT shall be generated.
Definition: remux.c:585
void IncEsInfoLength(int Length)
Definition: remux.c:384
void IncCounter(int &Counter, uchar *TsPacket)
Definition: remux.c:371
cPatPmtGenerator(const cChannel *Channel=NULL)
Definition: remux.c:361
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:579
int MakeAC3Descriptor(uchar *Target, uchar Type)
Definition: remux.c:405
void GeneratePat(void)
Generates a PAT section for later use with GetPat().
Definition: remux.c:481
uchar pat[TS_SIZE]
uchar * GetPat(void)
Returns a pointer to the PAT section, which consists of exactly one TS packet.
Definition: remux.c:594
uchar pmt[MAX_PMT_TS][TS_SIZE]
int MakeLanguageDescriptor(uchar *Target, const char *Language)
Definition: remux.c:432
void GeneratePmt(const cChannel *Channel)
Generates a PMT section for the given Channel, for later use with GetPmt().
Definition: remux.c:510
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:466
int MakeStream(uchar *Target, uchar Type, int Pid)
Definition: remux.c:393
int MakeSubtitlingDescriptor(uchar *Target, const char *Language, uchar SubtitlingType, uint16_t CompositionPageId, uint16_t AncillaryPageId)
Definition: remux.c:415
void IncVersion(int &Version)
Definition: remux.c:378
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:938
char alangs[MAXAPIDS][MAXLANGCODE2]
char slangs[MAXSPIDS][MAXLANGCODE2]
cPatPmtParser(bool UpdatePrimaryDevice=false)
Definition: remux.c:611
void Reset(void)
Resets the parser.
Definition: remux.c:617
int dpids[MAXDPIDS+1]
void ParsePat(const uchar *Data, int Length)
Parses the PAT data from the single TS packet in Data.
Definition: remux.c:627
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:919
uint16_t ancillaryPageIds[MAXSPIDS]
char dlangs[MAXDPIDS][MAXLANGCODE2]
int SectionLength(const uchar *Data, int Length)
int dtypes[MAXDPIDS+1]
void ParsePmt(const uchar *Data, int Length)
Parses the PMT data from the single TS packet in Data.
Definition: remux.c:659
uchar pmt[MAX_SECTION_SIZE]
int apids[MAXAPIDS+1]
bool IsPmtPid(int Pid) const
Returns true if Pid the one of the PMT pids as defined by the current PAT.
int atypes[MAXAPIDS+1]
uint16_t compositionPageIds[MAXSPIDS]
uchar subtitlingTypes[MAXSPIDS]
int spids[MAXSPIDS+1]
int pmtPids[MAX_PMT_PIDS+1]
static void SetBrokenLink(uchar *Data, int Length)
Definition: remux.c:102
int UseDolbyDigital
Definition: config.h:326
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...
int Used(void)
Returns the number of raw bytes that have already been used (e.g.
bool Eof(void) const
Returns true if all available bytes of the TS payload have been processed.
void SetByte(uchar Byte, int Index)
Sets the TS data byte at the given Index to the value Byte.
Definition: remux.c:328
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.
int GetLastIndex(void)
Returns the index into the TS data of the payload byte that has most recently been read.
Definition: remux.c:323
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:318
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:351
uchar SetEof(void)
Definition: remux.c:259
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:334
void Reset(void)
Definition: remux.c:265
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:311
void PutTs(const uchar *Data, int Length)
Puts the payload data of the single TS packet at Data into the converter.
Definition: remux.c:1046
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:1123
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:1075
uchar * lastData
cTsToPes(void)
Definition: remux.c:1034
~cTsToPes()
Definition: remux.c:1041
void Reset(void)
Resets the converter.
Definition: remux.c:1128
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:285
#define DEFAULTFRAMESPERSECOND
bool TsError(const uchar *p)
#define TS_ADAPT_PCR
int TsPid(const uchar *p)
bool TsHasPayload(const uchar *p)
#define MAX33BIT
#define MAX_PMT_PIDS
int PesPayloadOffset(const uchar *p)
#define PATPID
bool TsIsScrambled(const uchar *p)
int TsGetPayload(const uchar **p)
bool PesHasPts(const uchar *p)
bool PesLongEnough(int Length)
#define TS_SIZE
#define MAX_SECTION_SIZE
int64_t PesGetDts(const uchar *p)
#define TS_ADAPT_FIELD_EXISTS
int64_t PesGetPts(const uchar *p)
bool TsPayloadStart(const uchar *p)
#define TS_SYNC(Data, Length)
int TsPayloadOffset(const uchar *p)
bool PesHasDts(const uchar *p)
#define PCRFACTOR
#define TS_SYNC_BYTE
bool PesHasLength(const uchar *p)
bool TsHasAdaptationField(const uchar *p)
#define PTSTICKS
#define MIN_TS_PACKETS_FOR_FRAME_DETECTOR
int PesLength(const uchar *p)
ePesHeader
@ phMPEG2
@ phNeedMoreData
@ phInvalid
@ phMPEG1
#define EITPID
#define TS_PAYLOAD_START
unsigned char uchar
#define dsyslog(a...)
T min(T a, T b)
T max(T a, T b)
#define esyslog(a...)
char * strn0cpy(char *dest, const char *src, size_t n)
Definition: tools.c:131
#define KILOBYTE(n)
@ SubtitlingDescriptorTag
@ ISO639LanguageDescriptorTag
@ ParentalRatingDescriptorTag
@ EnhancedAC3DescriptorTag
@ AC3DescriptorTag
unsigned char u_char
void TsSetPcr(uchar *p, int64_t Pcr)
Definition: remux.c:131
#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:1164
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
#define MAXPESLENGTH
Definition: remux.c:1073
#define P_PMT_PID
Definition: remux.c:463
void TsHidePayload(uchar *p)
Definition: remux.c:121
static int CmpUint32(const void *p1, const void *p2)
Definition: remux.c:1628
#define MAXPID
Definition: remux.c:464
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
int64_t TsGetDts(const uchar *p, int l)
Definition: remux.c:173
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:1138
int TsSync(const uchar *Data, int Length, const char *File, const char *Function, int Line)
Definition: remux.c:147
#define SETPIDS(l)
#define P_TSID
Definition: remux.c:462
void TsDump(const char *Name, const u_char *Data, int Length)
Definition: remux.c:1149
#define MAX_TS_PACKETS_FOR_VIDEO_FRAME_DETECTION
Definition: remux.c:26