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
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)
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]
Definition: remux.h:434
cEitGenerator(int Sid=0)
Definition: remux.c:947
int counter
Definition: remux.h:435
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
int version
Definition: remux.h:436
@ MaxPtsValues
Definition: remux.h:509
uint32_t ptsValues[MaxPtsValues]
Definition: remux.h:515
bool synced
Definition: remux.h:512
bool scanning
Definition: remux.h:523
int framesPerPayloadUnit
Definition: remux.h:521
double framesPerSecond
Definition: remux.h:519
int framesInPayloadUnit
Definition: remux.h:520
int numIFrames
Definition: remux.h:517
bool independentFrame
Definition: remux.h:514
cFrameDetector(int Pid=0, int Type=0)
Sets up a frame detector for the given Pid and stream Type.
Definition: remux.c:1615
bool newFrame
Definition: remux.h:513
cFrameParser * parser
Definition: remux.h:524
int numPtsValues
Definition: remux.h:516
int Analyze(const uchar *Data, int Length)
Analyzes the TS packets pointed to by Data.
Definition: remux.c:1654
bool isVideo
Definition: remux.h:518
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 pmtVersion
Definition: remux.h:306
int pmtCounter
Definition: remux.h:304
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 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:405
void GeneratePat(void)
Generates a PAT section for later use with GetPat().
Definition: remux.c:481
uchar * GetPat(void)
Returns a pointer to the PAT section, which consists of exactly one TS packet.
Definition: remux.c:594
int patVersion
Definition: remux.h:305
uchar pmt[MAX_PMT_TS][TS_SIZE]
Definition: remux.h:301
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 patCounter
Definition: remux.h:303
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
int ppid
Definition: remux.h:361
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
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
int vpid
Definition: remux.h:360
cPatPmtParser(bool UpdatePrimaryDevice=false)
Definition: remux.c:611
void Reset(void)
Resets the parser.
Definition: remux.c:617
void ParsePat(const uchar *Data, int Length)
Parses the PAT data from the single TS packet in Data.
Definition: remux.c:627
int vtype
Definition: remux.h:362
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:919
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:659
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
int UseDolbyDigital
Definition: config.h:326
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: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.
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: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
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:351
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:334
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:311
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: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
cTsToPes(void)
Definition: remux.c:1034
int length
Definition: remux.h:454
~cTsToPes()
Definition: remux.c:1041
void Reset(void)
Resets the converter.
Definition: remux.c:1128
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:285
@ EnhancedAC3DescriptorTag
Definition: si.h:137
@ SubtitlingDescriptorTag
Definition: si.h:103
@ ISO639LanguageDescriptorTag
Definition: si.h:61
@ ParentalRatingDescriptorTag
Definition: si.h:99
@ AC3DescriptorTag
Definition: si.h:120
#define DEFAULTFRAMESPERSECOND
Definition: recording.h:352
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
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
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
int TsGetPayload(const uchar **p)
Definition: remux.h:114
bool PesHasPts(const uchar *p)
Definition: remux.h:183
bool PesLongEnough(int Length)
Definition: remux.h:163
#define TS_SIZE
Definition: remux.h:34
#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_PAYLOAD_START
Definition: remux.h:36
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