vdr 2.6.4
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.5 2022/11/30 14:38:46 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
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
359void TsExtendAdaptionField(unsigned char *Packet, int ToLength)
360{
361 // Hint: ExtenAdaptionField(p, TsPayloadOffset(p) - 4) is a null operation
362
363 int Offset = TsPayloadOffset(Packet); // First byte after existing adaption field
364
365 if (ToLength <= 0)
366 {
367 // Remove adaption field
368 Packet[3] = Packet[3] & ~TS_ADAPT_FIELD_EXISTS;
369 return;
370 }
371
372 // Set adaption field present
373 Packet[3] = Packet[3] | TS_ADAPT_FIELD_EXISTS;
374
375 // Set new length of adaption field:
376 Packet[4] = ToLength <= TS_SIZE-4 ? ToLength-1 : TS_SIZE-4-1;
377
378 if (Packet[4] == TS_SIZE-4-1)
379 {
380 // No more payload, remove payload flag
381 Packet[3] = Packet[3] & ~TS_PAYLOAD_EXISTS;
382 }
383
384 int NewPayload = TsPayloadOffset(Packet); // First byte after new adaption field
385
386 // Fill new adaption field
387 if (Offset == 4 && Offset < NewPayload)
388 Offset++; // skip adaptation_field_length
389 if (Offset == 5 && Offset < NewPayload)
390 Packet[Offset++] = 0; // various flags set to 0
391 while (Offset < NewPayload)
392 Packet[Offset++] = 0xff; // stuffing byte
393}
394
395// --- cPatPmtGenerator ------------------------------------------------------
396
398{
399 numPmtPackets = 0;
402 pmtPid = 0;
403 esInfoLength = NULL;
404 SetChannel(Channel);
405}
406
407void cPatPmtGenerator::IncCounter(int &Counter, uchar *TsPacket)
408{
409 TsPacket[3] = (TsPacket[3] & 0xF0) | Counter;
410 if (++Counter > 0x0F)
411 Counter = 0x00;
412}
413
415{
416 if (++Version > 0x1F)
417 Version = 0x00;
418}
419
421{
422 if (esInfoLength) {
423 Length += ((*esInfoLength & 0x0F) << 8) | *(esInfoLength + 1);
424 *esInfoLength = 0xF0 | (Length >> 8);
425 *(esInfoLength + 1) = Length;
426 }
427}
428
429int cPatPmtGenerator::MakeStream(uchar *Target, uchar Type, int Pid)
430{
431 int i = 0;
432 Target[i++] = Type; // stream type
433 Target[i++] = 0xE0 | (Pid >> 8); // dummy (3), pid hi (5)
434 Target[i++] = Pid; // pid lo
435 esInfoLength = &Target[i];
436 Target[i++] = 0xF0; // dummy (4), ES info length hi
437 Target[i++] = 0x00; // ES info length lo
438 return i;
439}
440
442{
443 int i = 0;
444 Target[i++] = Type;
445 Target[i++] = 0x01; // length
446 Target[i++] = 0x00;
448 return i;
449}
450
451int cPatPmtGenerator::MakeSubtitlingDescriptor(uchar *Target, const char *Language, uchar SubtitlingType, uint16_t CompositionPageId, uint16_t AncillaryPageId)
452{
453 int i = 0;
454 Target[i++] = SI::SubtitlingDescriptorTag;
455 Target[i++] = 0x08; // length
456 Target[i++] = *Language++;
457 Target[i++] = *Language++;
458 Target[i++] = *Language++;
459 Target[i++] = SubtitlingType;
460 Target[i++] = CompositionPageId >> 8;
461 Target[i++] = CompositionPageId & 0xFF;
462 Target[i++] = AncillaryPageId >> 8;
463 Target[i++] = AncillaryPageId & 0xFF;
465 return i;
466}
467
468int cPatPmtGenerator::MakeLanguageDescriptor(uchar *Target, const char *Language)
469{
470 int i = 0;
472 int Length = i++;
473 Target[Length] = 0x00; // length
474 for (const char *End = Language + strlen(Language); Language < End; ) {
475 Target[i++] = *Language++;
476 Target[i++] = *Language++;
477 Target[i++] = *Language++;
478 Target[i++] = 0x00; // audio type
479 Target[Length] += 0x04; // length
480 if (*Language == '+')
481 Language++;
482 }
484 return i;
485}
486
487int cPatPmtGenerator::MakeCRC(uchar *Target, const uchar *Data, int Length)
488{
489 int crc = SI::CRC32::crc32((const char *)Data, Length, 0xFFFFFFFF);
490 int i = 0;
491 Target[i++] = crc >> 24;
492 Target[i++] = crc >> 16;
493 Target[i++] = crc >> 8;
494 Target[i++] = crc;
495 return i;
496}
497
498#define P_TSID 0x8008 // pseudo TS ID
499#define P_PMT_PID 0x0084 // pseudo PMT pid
500#define MAXPID 0x2000 // the maximum possible number of pids
501
503{
504 bool Used[MAXPID] = { false };
505#define SETPID(p) { if ((p) >= 0 && (p) < MAXPID) Used[p] = true; }
506#define SETPIDS(l) { const int *p = l; while (*p) { SETPID(*p); p++; } }
507 SETPID(Channel->Vpid());
508 SETPID(Channel->Ppid());
509 SETPID(Channel->Tpid());
510 SETPIDS(Channel->Apids());
511 SETPIDS(Channel->Dpids());
512 SETPIDS(Channel->Spids());
513 for (pmtPid = P_PMT_PID; Used[pmtPid]; pmtPid++)
514 ;
515}
516
518{
519 memset(pat, 0xFF, sizeof(pat));
520 uchar *p = pat;
521 int i = 0;
522 p[i++] = TS_SYNC_BYTE; // TS indicator
523 p[i++] = TS_PAYLOAD_START | (PATPID >> 8); // flags (3), pid hi (5)
524 p[i++] = PATPID & 0xFF; // pid lo
525 p[i++] = 0x10; // flags (4), continuity counter (4)
526 p[i++] = 0x00; // pointer field (payload unit start indicator is set)
527 int PayloadStart = i;
528 p[i++] = 0x00; // table id
529 p[i++] = 0xB0; // section syntax indicator (1), dummy (3), section length hi (4)
530 int SectionLength = i;
531 p[i++] = 0x00; // section length lo (filled in later)
532 p[i++] = P_TSID >> 8; // TS id hi
533 p[i++] = P_TSID & 0xFF; // TS id lo
534 p[i++] = 0xC1 | (patVersion << 1); // dummy (2), version number (5), current/next indicator (1)
535 p[i++] = 0x00; // section number
536 p[i++] = 0x00; // last section number
537 p[i++] = pmtPid >> 8; // program number hi
538 p[i++] = pmtPid & 0xFF; // program number lo
539 p[i++] = 0xE0 | (pmtPid >> 8); // dummy (3), PMT pid hi (5)
540 p[i++] = pmtPid & 0xFF; // PMT pid lo
541 pat[SectionLength] = i - SectionLength - 1 + 4; // -1 = SectionLength storage, +4 = length of CRC
542 MakeCRC(pat + i, pat + PayloadStart, i - PayloadStart);
544}
545
547{
548 // generate the complete PMT section:
550 memset(buf, 0xFF, sizeof(buf));
551 numPmtPackets = 0;
552 if (Channel) {
553 int Vpid = Channel->Vpid();
554 int Ppid = Channel->Ppid();
555 uchar *p = buf;
556 int i = 0;
557 p[i++] = 0x02; // table id
558 int SectionLength = i;
559 p[i++] = 0xB0; // section syntax indicator (1), dummy (3), section length hi (4)
560 p[i++] = 0x00; // section length lo (filled in later)
561 p[i++] = pmtPid >> 8; // program number hi
562 p[i++] = pmtPid & 0xFF; // program number lo
563 p[i++] = 0xC1 | (pmtVersion << 1); // dummy (2), version number (5), current/next indicator (1)
564 p[i++] = 0x00; // section number
565 p[i++] = 0x00; // last section number
566 p[i++] = 0xE0 | (Ppid >> 8); // dummy (3), PCR pid hi (5)
567 p[i++] = Ppid; // PCR pid lo
568 p[i++] = 0xF0; // dummy (4), program info length hi (4)
569 p[i++] = 0x00; // program info length lo
570
571 if (Vpid)
572 i += MakeStream(buf + i, Channel->Vtype(), Vpid);
573 for (int n = 0; Channel->Apid(n); n++) {
574 i += MakeStream(buf + i, Channel->Atype(n), Channel->Apid(n));
575 const char *Alang = Channel->Alang(n);
576 i += MakeLanguageDescriptor(buf + i, Alang);
577 }
578 for (int n = 0; Channel->Dpid(n); n++) {
579 i += MakeStream(buf + i, 0x06, Channel->Dpid(n));
580 i += MakeAC3Descriptor(buf + i, Channel->Dtype(n));
581 i += MakeLanguageDescriptor(buf + i, Channel->Dlang(n));
582 }
583 for (int n = 0; Channel->Spid(n); n++) {
584 i += MakeStream(buf + i, 0x06, Channel->Spid(n));
585 i += MakeSubtitlingDescriptor(buf + i, Channel->Slang(n), Channel->SubtitlingType(n), Channel->CompositionPageId(n), Channel->AncillaryPageId(n));
586 }
587
588 int sl = i - SectionLength - 2 + 4; // -2 = SectionLength storage, +4 = length of CRC
589 buf[SectionLength] |= (sl >> 8) & 0x0F;
590 buf[SectionLength + 1] = sl;
591 MakeCRC(buf + i, buf, i);
592 // split the PMT section into several TS packets:
593 uchar *q = buf;
594 bool pusi = true;
595 while (i > 0) {
596 uchar *p = pmt[numPmtPackets++];
597 int j = 0;
598 p[j++] = TS_SYNC_BYTE; // TS indicator
599 p[j++] = (pusi ? TS_PAYLOAD_START : 0x00) | (pmtPid >> 8); // flags (3), pid hi (5)
600 p[j++] = pmtPid & 0xFF; // pid lo
601 p[j++] = 0x10; // flags (4), continuity counter (4)
602 if (pusi) {
603 p[j++] = 0x00; // pointer field (payload unit start indicator is set)
604 pusi = false;
605 }
606 int l = TS_SIZE - j;
607 memcpy(p + j, q, l);
608 q += l;
609 i -= l;
610 }
612 }
613}
614
615void cPatPmtGenerator::SetVersions(int PatVersion, int PmtVersion)
616{
617 patVersion = PatVersion & 0x1F;
618 pmtVersion = PmtVersion & 0x1F;
619}
620
622{
623 if (Channel) {
624 GeneratePmtPid(Channel);
625 GeneratePat();
626 GeneratePmt(Channel);
627 }
628}
629
631{
633 return pat;
634}
635
637{
638 if (Index < numPmtPackets) {
639 IncCounter(pmtCounter, pmt[Index]);
640 return pmt[Index++];
641 }
642 return NULL;
643}
644
645// --- cPatPmtParser ---------------------------------------------------------
646
647cPatPmtParser::cPatPmtParser(bool UpdatePrimaryDevice)
648{
649 updatePrimaryDevice = UpdatePrimaryDevice;
650 Reset();
651}
652
654{
655 completed = false;
656 pmtSize = 0;
657 patVersion = pmtVersion = -1;
658 pmtPids[0] = 0;
659 vpid = vtype = 0;
660 ppid = 0;
661}
662
663void cPatPmtParser::ParsePat(const uchar *Data, int Length)
664{
665 // Unpack the TS packet:
666 int PayloadOffset = TsPayloadOffset(Data);
667 Data += PayloadOffset;
668 Length -= PayloadOffset;
669 // The PAT is always assumed to fit into a single TS packet
670 if ((Length -= Data[0] + 1) <= 0)
671 return;
672 Data += Data[0] + 1; // process pointer_field
673 SI::PAT Pat(Data, false);
674 if (Pat.CheckCRCAndParse()) {
675 dbgpatpmt("PAT: TSid = %d, c/n = %d, v = %d, s = %d, ls = %d\n", Pat.getTransportStreamId(), Pat.getCurrentNextIndicator(), Pat.getVersionNumber(), Pat.getSectionNumber(), Pat.getLastSectionNumber());
676 if (patVersion == Pat.getVersionNumber())
677 return;
678 int NumPmtPids = 0;
680 for (SI::Loop::Iterator it; Pat.associationLoop.getNext(assoc, it); ) {
681 dbgpatpmt(" isNITPid = %d\n", assoc.isNITPid());
682 if (!assoc.isNITPid()) {
683 if (NumPmtPids <= MAX_PMT_PIDS)
684 pmtPids[NumPmtPids++] = assoc.getPid();
685 dbgpatpmt(" service id = %d, pid = %d\n", assoc.getServiceId(), assoc.getPid());
686 }
687 }
688 pmtPids[NumPmtPids] = 0;
690 }
691 else
692 esyslog("ERROR: can't parse PAT");
693}
694
695void cPatPmtParser::ParsePmt(const uchar *Data, int Length)
696{
697 // Unpack the TS packet:
698 bool PayloadStart = TsPayloadStart(Data);
699 int PayloadOffset = TsPayloadOffset(Data);
700 Data += PayloadOffset;
701 Length -= PayloadOffset;
702 // The PMT may extend over several TS packets, so we need to assemble them
703 if (PayloadStart) {
704 pmtSize = 0;
705 if ((Length -= Data[0] + 1) <= 0)
706 return;
707 Data += Data[0] + 1; // this is the first packet
708 if (SectionLength(Data, Length) > Length) {
709 if (Length <= int(sizeof(pmt))) {
710 memcpy(pmt, Data, Length);
711 pmtSize = Length;
712 }
713 else
714 esyslog("ERROR: PMT packet length too big (%d byte)!", Length);
715 return;
716 }
717 // the packet contains the entire PMT section, so we run into the actual parsing
718 }
719 else if (pmtSize > 0) {
720 // this is a following packet, so we add it to the pmt storage
721 if (Length <= int(sizeof(pmt)) - pmtSize) {
722 memcpy(pmt + pmtSize, Data, Length);
723 pmtSize += Length;
724 }
725 else {
726 esyslog("ERROR: PMT section length too big (%d byte)!", pmtSize + Length);
727 pmtSize = 0;
728 }
730 return; // more packets to come
731 // the PMT section is now complete, so we run into the actual parsing
732 Data = pmt;
733 }
734 else
735 return; // fragment of broken packet - ignore
736 SI::PMT Pmt(Data, false);
737 if (Pmt.CheckCRCAndParse()) {
738 dbgpatpmt("PMT: sid = %d, c/n = %d, v = %d, s = %d, ls = %d\n", Pmt.getServiceId(), Pmt.getCurrentNextIndicator(), Pmt.getVersionNumber(), Pmt.getSectionNumber(), Pmt.getLastSectionNumber());
739 dbgpatpmt(" pcr = %d\n", Pmt.getPCRPid());
740 if (pmtVersion == Pmt.getVersionNumber())
741 return;
744 int NumApids = 0;
745 int NumDpids = 0;
746 int NumSpids = 0;
747 vpid = vtype = 0;
748 ppid = 0;
749 apids[0] = 0;
750 dpids[0] = 0;
751 spids[0] = 0;
752 atypes[0] = 0;
753 dtypes[0] = 0;
754 SI::PMT::Stream stream;
755 for (SI::Loop::Iterator it; Pmt.streamLoop.getNext(stream, it); ) {
756 dbgpatpmt(" stream type = %02X, pid = %d", stream.getStreamType(), stream.getPid());
757 switch (stream.getStreamType()) {
758 case 0x01: // STREAMTYPE_11172_VIDEO
759 case 0x02: // STREAMTYPE_13818_VIDEO
760 case 0x1B: // H.264
761 case 0x24: // H.265
762 vpid = stream.getPid();
763 vtype = stream.getStreamType();
764 ppid = Pmt.getPCRPid();
765 break;
766 case 0x03: // STREAMTYPE_11172_AUDIO
767 case 0x04: // STREAMTYPE_13818_AUDIO
768 case 0x0F: // ISO/IEC 13818-7 Audio with ADTS transport syntax
769 case 0x11: // ISO/IEC 14496-3 Audio with LATM transport syntax
770 {
771 if (NumApids < MAXAPIDS) {
772 apids[NumApids] = stream.getPid();
773 atypes[NumApids] = stream.getStreamType();
774 *alangs[NumApids] = 0;
776 for (SI::Loop::Iterator it; (d = stream.streamDescriptors.getNext(it)); ) {
777 switch (d->getDescriptorTag()) {
781 char *s = alangs[NumApids];
782 int n = 0;
783 for (SI::Loop::Iterator it; ld->languageLoop.getNext(l, it); ) {
784 if (*ld->languageCode != '-') { // some use "---" to indicate "none"
785 dbgpatpmt(" '%s'", l.languageCode);
786 if (n > 0)
787 *s++ = '+';
789 s += strlen(s);
790 if (n++ > 1)
791 break;
792 }
793 }
794 }
795 break;
796 default: ;
797 }
798 delete d;
799 }
801 cDevice::PrimaryDevice()->SetAvailableTrack(ttAudio, NumApids, apids[NumApids], alangs[NumApids]);
802 NumApids++;
803 apids[NumApids] = 0;
804 }
805 }
806 break;
807 case 0x06: // STREAMTYPE_13818_PES_PRIVATE
808 {
809 int dpid = 0;
810 int dtype = 0;
811 char lang[MAXLANGCODE1] = "";
813 for (SI::Loop::Iterator it; (d = stream.streamDescriptors.getNext(it)); ) {
814 switch (d->getDescriptorTag()) {
817 dbgpatpmt(" AC3");
818 dpid = stream.getPid();
819 dtype = d->getDescriptorTag();
820 break;
822 dbgpatpmt(" subtitling");
823 if (NumSpids < MAXSPIDS) {
824 spids[NumSpids] = stream.getPid();
825 *slangs[NumSpids] = 0;
826 subtitlingTypes[NumSpids] = 0;
827 compositionPageIds[NumSpids] = 0;
828 ancillaryPageIds[NumSpids] = 0;
831 char *s = slangs[NumSpids];
832 int n = 0;
833 for (SI::Loop::Iterator it; sd->subtitlingLoop.getNext(sub, it); ) {
834 if (sub.languageCode[0]) {
835 dbgpatpmt(" '%s'", sub.languageCode);
836 subtitlingTypes[NumSpids] = sub.getSubtitlingType();
838 ancillaryPageIds[NumSpids] = sub.getAncillaryPageId();
839 if (n > 0)
840 *s++ = '+';
842 s += strlen(s);
843 if (n++ > 1)
844 break;
845 }
846 }
848 cDevice::PrimaryDevice()->SetAvailableTrack(ttSubtitle, NumSpids, spids[NumSpids], slangs[NumSpids]);
849 NumSpids++;
850 spids[NumSpids] = 0;
851 }
852 break;
855 dbgpatpmt(" '%s'", ld->languageCode);
857 }
858 break;
859 default: ;
860 }
861 delete d;
862 }
863 if (dpid) {
864 if (NumDpids < MAXDPIDS) {
865 dpids[NumDpids] = dpid;
866 dtypes[NumDpids] = dtype;
867 strn0cpy(dlangs[NumDpids], lang, sizeof(dlangs[NumDpids]));
869 cDevice::PrimaryDevice()->SetAvailableTrack(ttDolby, NumDpids, dpid, lang);
870 NumDpids++;
871 dpids[NumDpids] = 0;
872 }
873 }
874 }
875 break;
876 case 0x81: // STREAMTYPE_USER_PRIVATE - AC3 audio for ATSC and BD
877 case 0x82: // STREAMTYPE_USER_PRIVATE - DTS audio for BD
878 case 0x87: // eac3
879 {
880 dbgpatpmt(" %s",
881 stream.getStreamType() == 0x81 ? "AC3" :
882 stream.getStreamType() == 0x87 ? "AC3" :
883 stream.getStreamType() == 0x82 ? "DTS" : "");
884 char lang[MAXLANGCODE1] = { 0 };
886 for (SI::Loop::Iterator it; (d = stream.streamDescriptors.getNext(it)); ) {
887 switch (d->getDescriptorTag()) {
890 dbgpatpmt(" '%s'", ld->languageCode);
892 }
893 break;
894 default: ;
895 }
896 delete d;
897 }
898 if (NumDpids < MAXDPIDS) {
899 dpids[NumDpids] = stream.getPid();
900 dtypes[NumDpids] = SI::AC3DescriptorTag;
901 strn0cpy(dlangs[NumDpids], lang, sizeof(dlangs[NumDpids]));
903 cDevice::PrimaryDevice()->SetAvailableTrack(ttDolby, NumDpids, stream.getPid(), lang);
904 NumDpids++;
905 dpids[NumDpids] = 0;
906 }
907 }
908 break;
909 case 0x90: // PGS subtitles for BD
910 {
911 dbgpatpmt(" subtitling");
912 char lang[MAXLANGCODE1] = { 0 };
914 for (SI::Loop::Iterator it; (d = stream.streamDescriptors.getNext(it)); ) {
915 switch (d->getDescriptorTag()) {
918 dbgpatpmt(" '%s'", ld->languageCode);
920 if (NumSpids < MAXSPIDS) {
921 spids[NumSpids] = stream.getPid();
922 *slangs[NumSpids] = 0;
923 subtitlingTypes[NumSpids] = 0;
924 compositionPageIds[NumSpids] = 0;
925 ancillaryPageIds[NumSpids] = 0;
927 cDevice::PrimaryDevice()->SetAvailableTrack(ttSubtitle, NumSpids, stream.getPid(), lang);
928 NumSpids++;
929 spids[NumSpids] = 0;
930 }
931 }
932 break;
933 default: ;
934 }
935 delete d;
936 }
937 }
938 break;
939 default: ;
940 }
941 dbgpatpmt("\n");
945 }
946 }
948 completed = true;
949 }
950 else
951 esyslog("ERROR: can't parse PMT");
952 pmtSize = 0;
953}
954
955bool cPatPmtParser::ParsePatPmt(const uchar *Data, int Length)
956{
957 while (Length >= TS_SIZE) {
958 if (*Data != TS_SYNC_BYTE)
959 break; // just for safety
960 int Pid = TsPid(Data);
961 if (Pid == PATPID)
962 ParsePat(Data, TS_SIZE);
963 else if (IsPmtPid(Pid)) {
964 ParsePmt(Data, TS_SIZE);
965 if (patVersion >= 0 && pmtVersion >= 0)
966 return true;
967 }
968 Data += TS_SIZE;
969 Length -= TS_SIZE;
970 }
971 return false;
972}
973
974bool cPatPmtParser::GetVersions(int &PatVersion, int &PmtVersion) const
975{
976 PatVersion = patVersion;
977 PmtVersion = pmtVersion;
978 return patVersion >= 0 && pmtVersion >= 0;
979}
980
981// --- cEitGenerator ---------------------------------------------------------
982
984{
985 counter = 0;
986 version = 0;
987 if (Sid)
988 Generate(Sid);
989}
990
991uint16_t cEitGenerator::YMDtoMJD(int Y, int M, int D)
992{
993 int L = (M < 3) ? 1 : 0;
994 return 14956 + D + int((Y - L) * 365.25) + int((M + 1 + L * 12) * 30.6001);
995}
996
998{
1000 *p++ = 0x04; // descriptor length
1001 *p++ = '9'; // country code "902" ("All countries") -> EN 300 468 / 6.2.28; www.dvbservices.com/country_codes/index.php
1002 *p++ = '0';
1003 *p++ = '2';
1004 *p++ = ParentalRating;
1005 return p;
1006}
1007
1009{
1010 uchar *PayloadStart;
1011 uchar *SectionStart;
1012 uchar *DescriptorsStart;
1013 memset(eit, 0xFF, sizeof(eit));
1014 struct tm tm_r;
1015 time_t t = time(NULL) - 3600; // let's have the event start one hour in the past
1016 tm *tm = localtime_r(&t, &tm_r);
1017 uint16_t MJD = YMDtoMJD(tm->tm_year, tm->tm_mon + 1, tm->tm_mday);
1018 uchar *p = eit;
1019 // TS header:
1020 *p++ = TS_SYNC_BYTE;
1021 *p++ = TS_PAYLOAD_START;
1022 *p++ = EITPID;
1023 *p++ = 0x10 | (counter++ & 0x0F); // continuity counter
1024 *p++ = 0x00; // pointer field (payload unit start indicator is set)
1025 // payload:
1026 PayloadStart = p;
1027 *p++ = 0x4E; // TID present/following event on this transponder
1028 *p++ = 0xF0;
1029 *p++ = 0x00; // section length
1030 SectionStart = p;
1031 *p++ = Sid >> 8;
1032 *p++ = Sid & 0xFF;
1033 *p++ = 0xC1 | (version << 1);
1034 *p++ = 0x00; // section number
1035 *p++ = 0x00; // last section number
1036 *p++ = 0x00; // transport stream id
1037 *p++ = 0x00; // ...
1038 *p++ = 0x00; // original network id
1039 *p++ = 0x00; // ...
1040 *p++ = 0x00; // segment last section number
1041 *p++ = 0x4E; // last table id
1042 *p++ = 0x00; // event id
1043 *p++ = 0x01; // ...
1044 *p++ = MJD >> 8; // start time
1045 *p++ = MJD & 0xFF; // ...
1046 *p++ = tm->tm_hour; // ...
1047 *p++ = tm->tm_min; // ...
1048 *p++ = tm->tm_sec; // ...
1049 *p++ = 0x24; // duration (one day, should cover everything)
1050 *p++ = 0x00; // ...
1051 *p++ = 0x00; // ...
1052 *p++ = 0x90; // running status, free/CA mode
1053 *p++ = 0x00; // descriptors loop length
1054 DescriptorsStart = p;
1056 // fill in lengths:
1057 *(SectionStart - 1) = p - SectionStart + 4; // +4 = length of CRC
1058 *(DescriptorsStart - 1) = p - DescriptorsStart;
1059 // checksum
1060 int crc = SI::CRC32::crc32((char *)PayloadStart, p - PayloadStart, 0xFFFFFFFF);
1061 *p++ = crc >> 24;
1062 *p++ = crc >> 16;
1063 *p++ = crc >> 8;
1064 *p++ = crc;
1065 return eit;
1066}
1067
1068// --- cTsToPes --------------------------------------------------------------
1069
1071{
1072 data = NULL;
1073 size = 0;
1074 Reset();
1075}
1076
1078{
1079 free(data);
1080}
1081
1082void cTsToPes::PutTs(const uchar *Data, int Length)
1083{
1084 if (TsError(Data)) {
1085 Reset();
1086 return; // ignore packets with TEI set, and drop any PES data collected so far
1087 }
1088 if (TsPayloadStart(Data))
1089 Reset();
1090 else if (!size)
1091 return; // skip everything before the first payload start
1092 Length = TsGetPayload(&Data);
1093 if (length + Length > size) {
1094 int NewSize = max(KILOBYTE(2), length + Length);
1095 if (uchar *NewData = (uchar *)realloc(data, NewSize)) {
1096 data = NewData;
1097 size = NewSize;
1098 }
1099 else {
1100 esyslog("ERROR: out of memory");
1101 Reset();
1102 return;
1103 }
1104 }
1105 memcpy(data + length, Data, Length);
1106 length += Length;
1107}
1108
1109#define MAXPESLENGTH 0xFFF0
1110
1111const uchar *cTsToPes::GetPes(int &Length)
1112{
1113 if (repeatLast) {
1114 repeatLast = false;
1115 Length = lastLength;
1116 return lastData;
1117 }
1118 if (offset < length && PesLongEnough(length)) {
1119 if (!PesHasLength(data)) // this is a video PES packet with undefined length
1120 offset = 6; // trigger setting PES length for initial slice
1121 if (offset) {
1122 uchar *p = data + offset - 6;
1123 if (p != data) {
1124 p -= 3;
1125 if (p < data) {
1126 Reset();
1127 return NULL;
1128 }
1129 memmove(p, data, 4);
1130 }
1131 int l = min(length - offset, MAXPESLENGTH);
1132 offset += l;
1133 if (p != data) {
1134 l += 3;
1135 p[6] = 0x80;
1136 p[7] = 0x00;
1137 p[8] = 0x00;
1138 }
1139 p[4] = l / 256;
1140 p[5] = l & 0xFF;
1141 Length = l + 6;
1142 lastLength = Length;
1143 lastData = p;
1144 return p;
1145 }
1146 else {
1147 Length = PesLength(data);
1148 if (Length <= length) {
1149 offset = Length; // to make sure we break out in case of garbage data
1150 lastLength = Length;
1151 lastData = data;
1152 return data;
1153 }
1154 }
1155 }
1156 return NULL;
1157}
1158
1160{
1161 repeatLast = true;
1162}
1163
1165{
1166 length = offset = 0;
1167 lastData = NULL;
1168 lastLength = 0;
1169 repeatLast = false;
1170}
1171
1172// --- Some helper functions for debugging -----------------------------------
1173
1174void BlockDump(const char *Name, const u_char *Data, int Length)
1175{
1176 printf("--- %s\n", Name);
1177 for (int i = 0; i < Length; i++) {
1178 if (i && (i % 16) == 0)
1179 printf("\n");
1180 printf(" %02X", Data[i]);
1181 }
1182 printf("\n");
1183}
1184
1185void TsDump(const char *Name, const u_char *Data, int Length)
1186{
1187 printf("%s: %04X", Name, Length);
1188 int n = min(Length, 20);
1189 for (int i = 0; i < n; i++)
1190 printf(" %02X", Data[i]);
1191 if (n < Length) {
1192 printf(" ...");
1193 n = max(n, Length - 10);
1194 for (n = max(n, Length - 10); n < Length; n++)
1195 printf(" %02X", Data[n]);
1196 }
1197 printf("\n");
1198}
1199
1200void PesDump(const char *Name, const u_char *Data, int Length)
1201{
1202 TsDump(Name, Data, Length);
1203}
1204
1205// --- cFrameParser ----------------------------------------------------------
1206
1208protected:
1209 bool debug;
1213 uint16_t frameWidth;
1214 uint16_t frameHeight;
1217public:
1218 cFrameParser(void);
1219 virtual ~cFrameParser() {};
1220 virtual int Parse(const uchar *Data, int Length, int Pid) = 0;
1227 void SetDebug(bool Debug) { debug = Debug; }
1228 bool NewFrame(void) { return newFrame; }
1229 bool IndependentFrame(void) { return independentFrame; }
1231 uint16_t FrameWidth(void) { return frameWidth; }
1232 uint16_t FrameHeight(void) { return frameHeight; }
1233 double FramesPerSecond(void) { return framesPerSecond; }
1234 bool Progressive(void) { return progressive; }
1235 };
1236
1238{
1239 debug = true;
1240 newFrame = false;
1241 independentFrame = false;
1243 frameWidth = 0;
1244 frameHeight = 0;
1245 framesPerSecond = 0.0;
1246 progressive = false;
1247}
1248
1249// --- cAudioParser ----------------------------------------------------------
1250
1252public:
1253 cAudioParser(void);
1254 virtual int Parse(const uchar *Data, int Length, int Pid);
1255 };
1256
1260
1261int cAudioParser::Parse(const uchar *Data, int Length, int Pid)
1262{
1263 if (TsPayloadStart(Data)) {
1264 newFrame = independentFrame = true;
1265 if (debug)
1266 dbgframes("/");
1267 }
1268 else
1269 newFrame = independentFrame = false;
1270 return TS_SIZE;
1271}
1272
1273// --- cMpeg2Parser ----------------------------------------------------------
1274
1276private:
1277 uint32_t scanner;
1281 const double frame_rate_table[9] = {
1282 0, // 0 forbidden
1283 24000./1001., // 1 23.976...
1284 24., // 2 24
1285 25., // 3 25
1286 30000./1001., // 4 29.97...
1287 30., // 5 30
1288 50., // 6 50
1289 60000./1001., // 7 59.94...
1290 60. // 8 60
1291 };
1292public:
1293 cMpeg2Parser(void);
1294 virtual int Parse(const uchar *Data, int Length, int Pid);
1295 };
1296
1298{
1300 seenIndependentFrame = false;
1301 lastIFrameTemporalReference = -1; // invalid
1302 seenScanType = false;
1303}
1304
1305int cMpeg2Parser::Parse(const uchar *Data, int Length, int Pid)
1306{
1307 newFrame = independentFrame = false;
1308 bool SeenPayloadStart = false;
1309 cTsPayload tsPayload(const_cast<uchar *>(Data), Length, Pid);
1310 if (TsPayloadStart(Data)) {
1311 SeenPayloadStart = true;
1312 tsPayload.SkipPesHeader();
1315 dbgframes("/");
1316 }
1317 uint32_t OldScanner = scanner; // need to remember it in case of multiple frames per payload
1318 for (;;) {
1319 if (!SeenPayloadStart && tsPayload.AtTsStart())
1320 OldScanner = scanner;
1321 scanner = (scanner << 8) | tsPayload.GetByte();
1322 if (scanner == 0x00000100) { // Picture Start Code
1323 if (!SeenPayloadStart && tsPayload.GetLastIndex() > TS_SIZE) {
1324 scanner = OldScanner;
1325 return tsPayload.Used() - TS_SIZE;
1326 }
1327 uchar b1 = tsPayload.GetByte();
1328 uchar b2 = tsPayload.GetByte();
1329 int TemporalReference = (b1 << 2 ) + ((b2 & 0xC0) >> 6);
1330 uchar FrameType = (b2 >> 3) & 0x07;
1331 if (tsPayload.Find(0x000001B5)) { // Extension start code
1332 if (((tsPayload.GetByte() & 0xF0) >> 4) == 0x08) { // Picture coding extension
1333 tsPayload.GetByte();
1334 uchar PictureStructure = tsPayload.GetByte() & 0x03;
1335 if (PictureStructure == 0x02) // bottom field
1336 break;
1337 }
1338 }
1339 newFrame = true;
1340 independentFrame = FrameType == 1; // I-Frame
1341 if (independentFrame) {
1344 lastIFrameTemporalReference = TemporalReference;
1345 }
1346 if (debug) {
1349 static const char FrameTypes[] = "?IPBD???";
1350 dbgframes("%c", FrameTypes[FrameType]);
1351 }
1352 }
1353 tsPayload.Statistics();
1354 break;
1355 }
1356 else if (frameWidth == 0 && scanner == 0x000001B3) { // Sequence header code
1357 frameWidth = tsPayload.GetByte() << 4;
1358 uchar b = tsPayload.GetByte(); // ignoring two MSB of width and height in sequence extension
1359 frameWidth |= b >> 4; // as 12 Bit = max 4095 should be sufficient for all available MPEG2 streams
1360 frameHeight = (b & 0x0F) << 8 | tsPayload.GetByte();
1361 b = tsPayload.GetByte();
1362 uchar frame_rate_value = b & 0x0F;
1363 if (frame_rate_value > 0 && frame_rate_value <= 8)
1364 framesPerSecond = frame_rate_table[frame_rate_value];
1365 }
1366 else if (!seenScanType && scanner == 0x000001B5) { // Extension start code
1367 if ((tsPayload.GetByte() & 0xF0) == 0x10) { // Sequence Extension
1368 progressive = (tsPayload.GetByte() & 0x40) != 0;
1369 seenScanType = true;
1370 if (debug) {
1371 cString s = cString::sprintf("MPEG2: %d x %d%c %.2f fps", frameWidth, frameHeight, progressive ? 'p' : 'i', framesPerSecond);
1372 dsyslog("%s", *s);
1373 dbgframes("\n%s", *s);
1374 }
1375 }
1376 }
1377 if (tsPayload.AtPayloadStart() // stop at a new payload start to have the buffer refilled if necessary
1378 || tsPayload.Eof()) // or if we're out of data
1379 break;
1380 }
1381 return tsPayload.Used();
1382}
1383
1384// --- cH264Parser -----------------------------------------------------------
1385
1387private:
1394 uchar byte; // holds the current byte value in case of bitwise access
1395 int bit; // the bit index into the current byte (-1 if we're not in bit reading mode)
1396 int zeroBytes; // the number of consecutive zero bytes (to detect 0x000003)
1397 // Identifiers written in '_' notation as in "ITU-T H.264":
1401protected:
1403 uint32_t scanner;
1406 uchar GetByte(bool Raw = false);
1410 uchar GetBit(void);
1411 uint32_t GetBits(int Bits);
1412 uint32_t GetGolombUe(void);
1413 int32_t GetGolombSe(void);
1414 void ParseAccessUnitDelimiter(void);
1415 void ParseSequenceParameterSet(void);
1416 void ParseSliceHeader(void);
1417public:
1418 cH264Parser(void);
1422 virtual int Parse(const uchar *Data, int Length, int Pid);
1423 };
1424
1426{
1427 byte = 0;
1428 bit = -1;
1429 zeroBytes = 0;
1433 frame_mbs_only_flag = false;
1434 gotAccessUnitDelimiter = false;
1436}
1437
1439{
1440 uchar b = tsPayload.GetByte();
1441 if (!Raw) {
1442 // If we encounter the byte sequence 0x000003, we need to skip the 0x03:
1443 if (b == 0x00)
1444 zeroBytes++;
1445 else {
1446 if (b == 0x03 && zeroBytes >= 2)
1447 b = tsPayload.GetByte();
1448 zeroBytes = b ? 0 : 1;
1449 }
1450 }
1451 else
1452 zeroBytes = 0;
1453 bit = -1;
1454 return b;
1455}
1456
1458{
1459 if (bit < 0) {
1460 byte = GetByte();
1461 bit = 7;
1462 }
1463 return (byte & (1 << bit--)) ? 1 : 0;
1464}
1465
1466uint32_t cH264Parser::GetBits(int Bits)
1467{
1468 uint32_t b = 0;
1469 while (Bits--)
1470 b |= GetBit() << Bits;
1471 return b;
1472}
1473
1475{
1476 int z = -1;
1477 for (int b = 0; !b && z < 32; z++) // limiting z to no get stuck if GetBit() always returns 0
1478 b = GetBit();
1479 return (1 << z) - 1 + GetBits(z);
1480}
1481
1483{
1484 uint32_t v = GetGolombUe();
1485 if (v) {
1486 if ((v & 0x01) != 0)
1487 return (v + 1) / 2; // fails for v == 0xFFFFFFFF, but that will probably never happen
1488 else
1489 return -int32_t(v / 2);
1490 }
1491 return v;
1492}
1493
1494int cH264Parser::Parse(const uchar *Data, int Length, int Pid)
1495{
1496 newFrame = independentFrame = false;
1497 tsPayload.Setup(const_cast<uchar *>(Data), Length, Pid);
1498 if (TsPayloadStart(Data)) {
1502 dbgframes("/");
1503 }
1504 }
1505 for (;;) {
1506 scanner = (scanner << 8) | GetByte(true);
1507 if ((scanner & 0xFFFFFF00) == 0x00000100) { // NAL unit start
1508 uchar NalUnitType = scanner & 0x1F;
1509 switch (NalUnitType) {
1512 break;
1516 }
1517 break;
1521 gotAccessUnitDelimiter = false;
1522 if (newFrame)
1524 return tsPayload.Used();
1525 }
1526 break;
1527 default: ;
1528 }
1529 }
1530 if (tsPayload.AtPayloadStart() // stop at a new payload start to have the buffer refilled if necessary
1531 || tsPayload.Eof()) // or if we're out of data
1532 break;
1533 }
1534 return tsPayload.Used();
1535}
1536
1538{
1540 dbgframes("A");
1541 GetByte(); // primary_pic_type
1542}
1543
1545{
1546 int chroma_format_idc = 0;
1547 int bitDepth = 0;
1548 uchar profile_idc = GetByte(); // profile_idc
1549 GetByte(); // constraint_set[0-5]_flags, reserved_zero_2bits
1550 GetByte(); // level_idc
1551 GetGolombUe(); // seq_parameter_set_id
1552 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) {
1553 chroma_format_idc = GetGolombUe(); // chroma_format_idc
1554 if (chroma_format_idc == 3)
1556 bitDepth = 8 + GetGolombUe(); // bit_depth_luma_minus8
1557 GetGolombUe(); // bit_depth_chroma_minus8
1558 GetBit(); // qpprime_y_zero_transform_bypass_flag
1559 if (GetBit()) { // seq_scaling_matrix_present_flag
1560 for (int i = 0; i < ((chroma_format_idc != 3) ? 8 : 12); i++) {
1561 if (GetBit()) { // seq_scaling_list_present_flag
1562 int SizeOfScalingList = (i < 6) ? 16 : 64;
1563 int LastScale = 8;
1564 int NextScale = 8;
1565 for (int j = 0; j < SizeOfScalingList; j++) {
1566 if (NextScale)
1567 NextScale = (LastScale + GetGolombSe() + 256) % 256; // delta_scale
1568 if (NextScale)
1569 LastScale = NextScale;
1570 }
1571 }
1572 }
1573 }
1574 }
1575 log2_max_frame_num = GetGolombUe() + 4; // log2_max_frame_num_minus4
1576 int pic_order_cnt_type = GetGolombUe(); // pic_order_cnt_type
1577 if (pic_order_cnt_type == 0)
1578 GetGolombUe(); // log2_max_pic_order_cnt_lsb_minus4
1579 else if (pic_order_cnt_type == 1) {
1580 GetBit(); // delta_pic_order_always_zero_flag
1581 GetGolombSe(); // offset_for_non_ref_pic
1582 GetGolombSe(); // offset_for_top_to_bottom_field
1583 for (int i = GetGolombUe(); i--; ) // num_ref_frames_in_pic_order_cnt_cycle
1584 GetGolombSe(); // offset_for_ref_frame
1585 }
1586 GetGolombUe(); // max_num_ref_frames
1587 GetBit(); // gaps_in_frame_num_value_allowed_flag
1588 uint16_t frame_Width = 16 * (1 + GetGolombUe()); // pic_width_in_mbs_minus1
1589 uint16_t frame_Height = 16 * (1 + GetGolombUe()); // pic_height_in_map_units_minus1
1590 frame_mbs_only_flag = GetBit(); // frame_mbs_only_flag
1591 if (frameWidth == 0) {
1593 if (!frame_mbs_only_flag) {
1594 GetBit(); // mb_adaptive_frame_field_flag
1595 frame_Height *= 2;
1596 }
1597 GetBit(); // direct_8x8_inference_flag
1598 bool frame_cropping_flag = GetBit(); // frame_cropping_flag
1599 if (frame_cropping_flag) {
1600 uint16_t frame_crop_left_offset = GetGolombUe(); // frame_crop_left_offset
1601 uint16_t frame_crop_right_offset = GetGolombUe(); // frame_crop_right_offset
1602 uint16_t frame_crop_top_offset = GetGolombUe(); // frame_crop_top_offset
1603 uint16_t frame_crop_bottom_offset = GetGolombUe(); // frame_crop_bottom_offset
1604 uint16_t CropUnitX = 1;
1605 uint16_t CropUnitY = frame_mbs_only_flag ? 1 : 2;
1606 if (!separate_colour_plane_flag && chroma_format_idc > 0) {
1607 if (chroma_format_idc == 1) {
1608 CropUnitX = 2;
1609 CropUnitY *= 2;
1610 }
1611 else if (chroma_format_idc == 2)
1612 CropUnitX = 2;
1613 }
1614 frame_Width -= CropUnitX * (frame_crop_left_offset + frame_crop_right_offset);
1615 frame_Height -= CropUnitY * (frame_crop_top_offset + frame_crop_bottom_offset);
1616 }
1617 frameWidth = frame_Width;
1618 frameHeight = frame_Height;
1619 // VUI parameters
1620 if (GetBit()) { // vui_parameters_present_flag
1621 if (GetBit()) { // aspect_ratio_info_present
1622 int aspect_ratio_idc = GetBits(8); // aspect_ratio_idc
1623 if (aspect_ratio_idc == 255)
1624 GetBits(32);
1625 }
1626 if (GetBit()) // overscan_info_present_flag
1627 GetBit(); // overscan_approriate_flag
1628 if (GetBit()) { // video_signal_type_present_flag
1629 GetBits(4); // video_format, video_full_range_flag
1630 if (GetBit()) // colour_description_present_flag
1631 GetBits(24); // colour_primaries, transfer_characteristics, matrix_coefficients
1632 }
1633 if (GetBit()) { // chroma_loc_info_present_flag
1634 GetGolombUe(); // chroma_sample_loc_type_top_field
1635 GetGolombUe(); // chroma_sample_loc_type_bottom_field
1636 }
1637 if (GetBit()) { // timing_info_present_flag
1638 uint32_t num_units_in_tick = GetBits(32); // num_units_in_tick
1639 uint32_t time_scale = GetBits(32); // time_scale
1640 if (num_units_in_tick > 0)
1641 framesPerSecond = double(time_scale) / (num_units_in_tick << 1);
1642 }
1643 }
1644 if (debug) {
1645 cString s = cString::sprintf("H.264: %d x %d%c %.2f fps %d Bit", frameWidth, frameHeight, progressive ? 'p':'i', framesPerSecond, bitDepth);
1646 dsyslog("%s", *s);
1647 dbgframes("\n%s", *s);
1648 }
1649 }
1650 if (debug) {
1652 dbgframes("A"); // just for completeness
1653 dbgframes(frame_mbs_only_flag ? "S" : "s");
1654 }
1655}
1656
1658{
1659 newFrame = true;
1660 GetGolombUe(); // first_mb_in_slice
1661 int slice_type = GetGolombUe(); // slice_type, 0 = P, 1 = B, 2 = I, 3 = SP, 4 = SI
1662 independentFrame = (slice_type % 5) == 2;
1663 if (debug) {
1664 static const char SliceTypes[] = "PBIpi";
1665 dbgframes("%c", SliceTypes[slice_type % 5]);
1666 }
1668 return; // don't need the rest - a frame is complete
1669 GetGolombUe(); // pic_parameter_set_id
1671 GetBits(2); // colour_plane_id
1672 GetBits(log2_max_frame_num); // frame_num
1673 if (!frame_mbs_only_flag) {
1674 if (GetBit()) // field_pic_flag
1675 newFrame = !GetBit(); // bottom_field_flag
1676 if (debug)
1677 dbgframes(newFrame ? "t" : "b");
1678 }
1679}
1680
1681// --- cH265Parser -----------------------------------------------------------
1682
1721
1723:cH264Parser()
1724{
1725}
1726
1727int cH265Parser::Parse(const uchar *Data, int Length, int Pid)
1728{
1729 newFrame = independentFrame = false;
1730 tsPayload.Setup(const_cast<uchar *>(Data), Length, Pid);
1731 if (TsPayloadStart(Data)) {
1734 }
1735 for (;;) {
1736 scanner = (scanner << 8) | GetByte(true);
1737 if ((scanner & 0xFFFFFF00) == 0x00000100) { // NAL unit start
1738 uchar NalUnitType = (scanner >> 1) & 0x3F;
1739 GetByte(); // nuh_layer_id + nuh_temporal_id_plus1
1740 if (NalUnitType <= nutSliceSegmentRASLR || (NalUnitType >= nutSliceSegmentBLAWLP && NalUnitType <= nutSliceSegmentCRANUT)) {
1741 if (NalUnitType == nutSliceSegmentIDRWRADL || NalUnitType == nutSliceSegmentIDRNLP || NalUnitType == nutSliceSegmentCRANUT)
1742 independentFrame = true;
1743 if (GetBit()) { // first_slice_segment_in_pic_flag
1744 newFrame = true;
1746 }
1747 break;
1748 }
1749 else if (frameWidth == 0 && NalUnitType == nutSequenceParameterSet) {
1752 }
1753 }
1754 if (tsPayload.AtPayloadStart() // stop at a new payload start to have the buffer refilled if necessary
1755 || tsPayload.Eof()) // or if we're out of data
1756 break;
1757 }
1758 return tsPayload.Used();
1759}
1760
1762{
1764 uint8_t sub_layer_profile_present_flag[8];
1765 uint8_t sub_layer_level_present_flag[8];
1766 GetBits(4); // sps_video_parameter_set_id
1767 int sps_max_sub_layers_minus1 = GetBits(3); // sps_max_sub_layers_minus1
1768 GetBit(); // sps_temporal_id_nesting_flag
1769 // begin profile_tier_level(1, sps_max_sub_layers_minus1)
1770 GetByte();
1771 GetByte();
1772 GetByte();
1773 GetByte();
1774 GetByte();
1775 bool general_progressive_source_flag = GetBit(); // general_progressive_source_flag
1776 progressive = general_progressive_source_flag;
1777 GetBit(); // general_interlaced_source_flag
1778 GetBits(6);
1779 GetByte();
1780 GetByte();
1781 GetByte();
1782 GetByte();
1783 GetByte();
1784 GetByte(); // general_level_idc
1785 for (int i = 0; i < sps_max_sub_layers_minus1; i++ ) {
1786 sub_layer_profile_present_flag[i] = GetBit(); // sub_layer_profile_present_flag[i]
1787 sub_layer_level_present_flag[i] = GetBit(); // sub_layer_level_present_flag[i]
1788 }
1789 if (sps_max_sub_layers_minus1 > 0) {
1790 for (int i = sps_max_sub_layers_minus1; i < 8; i++ )
1791 GetBits(2); // reserved_zero_2bits[i]
1792 }
1793 for (int i = 0; i < sps_max_sub_layers_minus1; i++ ) {
1794 if (sub_layer_profile_present_flag[i] )
1795 GetBits(88);
1796 if (sub_layer_level_present_flag[i])
1797 GetBits(8);
1798 }
1799 // end profile_tier_level
1800 GetGolombUe(); // sps_seq_parameter_set_id
1801 int chroma_format_idc = GetGolombUe(); // chroma_format_idc
1802 if (chroma_format_idc == 3)
1803 separate_colour_plane_flag = GetBit(); // separate_colour_plane_flag
1804 frameWidth = GetGolombUe(); // pic_width_in_luma_samples
1805 frameHeight = GetGolombUe(); // pic_height_in_luma_samples
1806 bool conformance_window_flag = GetBit(); // conformance_window_flag
1807 if (conformance_window_flag) {
1808 int conf_win_left_offset = GetGolombUe(); // conf_win_left_offset
1809 int conf_win_right_offset = GetGolombUe(); // conf_win_right_offset
1810 int conf_win_top_offset = GetGolombUe(); // conf_win_top_offset
1811 int conf_win_bottom_offset = GetGolombUe(); // conf_win_bottom_offset
1812 uint16_t SubWidthC = 1;
1813 uint16_t SubHeightC = 1;
1814 if (!separate_colour_plane_flag && chroma_format_idc > 0) {
1815 if (chroma_format_idc == 1) {
1816 SubWidthC = 2;
1817 SubHeightC = 2;
1818 }
1819 else if (chroma_format_idc == 2)
1820 SubWidthC = 2;
1821 }
1822 frameWidth -= SubWidthC * (conf_win_left_offset + conf_win_right_offset);
1823 frameHeight -= SubHeightC * (conf_win_top_offset + conf_win_bottom_offset);
1824 }
1825 int bitDepth = 8 + GetGolombUe(); // bit_depth_luma_minus8
1826 GetGolombUe(); // bit_depth_chroma_minus8
1827 int log2_max_pic_order_cnt_lsb_minus4 = GetGolombUe(); // log2_max_pic_order_cnt_lsb_minus4
1828 int sps_sub_layer_ordering_info_present_flag = GetBit(); // sps_sub_layer_ordering_info_present_flag
1829 for (int i = sps_sub_layer_ordering_info_present_flag ? 0 : sps_max_sub_layers_minus1; i <= sps_max_sub_layers_minus1; ++i) {
1830 GetGolombUe(); // sps_max_dec_pic_buffering_minus1[i]
1831 GetGolombUe(); // sps_max_num_reorder_pics[i]
1832 GetGolombUe(); // sps_max_latency_increase_plus1[i]
1833 }
1834 GetGolombUe(); // log2_min_luma_coding_block_size_minus3
1835 GetGolombUe(); // log2_diff_max_min_luma_coding_block_size
1836 GetGolombUe(); // log2_min_luma_transform_block_size_minus2
1837 GetGolombUe(); // log2_diff_max_min_luma_transform_block_size
1838 GetGolombUe(); // max_transform_hierarchy_depth_inter
1839 GetGolombUe(); // max_transform_hierarchy_depth_intra
1840 if (GetBit()) { // scaling_list_enabled_flag
1841 if (GetBit()) { // sps_scaling_list_data_present_flag
1842 // begin scaling_list_data
1843 for (int sizeId = 0; sizeId < 4; ++sizeId) {
1844 for (int matrixId = 0; matrixId < 6; matrixId += (sizeId == 3) ? 3 : 1) {
1845 if (!GetBit()) // scaling_list_pred_mode_flag[sizeId][matrixId]
1846 GetGolombUe(); // scaling_list_pred_matrix_id_delta[sizeId][matrixId]
1847 else {
1848 int coefNum = min(64, (1 << (4 + (sizeId << 1))));
1849 if (sizeId > 1)
1850 GetGolombSe(); // scaling_list_dc_coef_minus8[sizeId−2][matrixId]
1851 for (int i = 0; i < coefNum; ++i)
1852 GetGolombSe(); // scaling_list_delta_coef
1853 }
1854 }
1855 }
1856 }
1857 // end scaling_list_data
1858 }
1859 GetBits(2); // amp_enabled_flag, sample_adaptive_offset_enabled_flag
1860 if (GetBit()) { // pcm_enabled_flag
1861 GetBits(8); // pcm_sample_bit_depth_luma_minus1, pcm_sample_bit_depth_chroma_minus1
1862 GetGolombUe(); // log2_min_pcm_luma_coding_block_size_minus3
1863 GetGolombUe(); // log2_diff_max_min_pcm_luma_coding_block_size
1864 GetBit(); // pcm_loop_filter_disabled_flag
1865 }
1866 uint32_t num_short_term_ref_pic_sets = GetGolombUe(); // num_short_term_ref_pic_sets
1867 uint32_t NumDeltaPocs[num_short_term_ref_pic_sets];
1868 for (uint32_t stRpsIdx = 0; stRpsIdx < num_short_term_ref_pic_sets; ++stRpsIdx) {
1869 // start of st_ref_pic_set(stRpsIdx)
1870 bool inter_ref_pic_set_prediction_flag = false;
1871 if (stRpsIdx != 0)
1872 inter_ref_pic_set_prediction_flag = GetBit(); // inter_ref_pic_set_prediction_flag
1873 if (inter_ref_pic_set_prediction_flag) {
1874 uint32_t RefRpsIdx, delta_idx_minus1 = 0;
1875 if (stRpsIdx == num_short_term_ref_pic_sets)
1876 delta_idx_minus1 = GetGolombUe(); // delta_idx_minus1
1877 GetBit(); // delta_rps_sign
1878 GetGolombUe(); // abs_delta_rps_minus1
1879 RefRpsIdx = stRpsIdx - (delta_idx_minus1 + 1);
1880 NumDeltaPocs[stRpsIdx] = 0;
1881 for (uint32_t j = 0; j <= NumDeltaPocs[RefRpsIdx]; ++j) {
1882 if (!GetBit()) { // used_by_curr_pic_flag[j]
1883 if (GetBit()) // use_delta_flag[j]
1884 NumDeltaPocs[stRpsIdx]++;
1885 }
1886 else
1887 NumDeltaPocs[stRpsIdx]++;
1888 }
1889 }
1890 else {
1891 uint32_t num_negative_pics = GetGolombUe(); // num_negative_pics
1892 uint32_t num_positive_pics = GetGolombUe(); // num_positive_pics
1893 for (uint32_t j = 0; j < num_negative_pics; ++j) {
1894 GetGolombUe(); // delta_poc_s0_minus1[i]
1895 GetBit(); // used_by_curr_pic_s0_flag[i]
1896 }
1897 for (uint32_t j = 0; j < num_positive_pics; ++j) {
1898 GetGolombUe(); // delta_poc_s1_minus1[i]
1899 GetBit(); // delta_poc_s1_minus1[i]
1900 }
1901 NumDeltaPocs[stRpsIdx] = num_negative_pics + num_positive_pics;
1902 }
1903 // end of st_ref_pic_set(stRpsIdx)
1904 }
1905 if (GetBit()) { // long_term_ref_pics_present_flag
1906 uint32_t num_long_term_ref_pics_sps = GetGolombUe(); // num_long_term_ref_pics_sps
1907 for (uint32_t i = 0; i < num_long_term_ref_pics_sps; ++i) {
1908 GetBits(log2_max_pic_order_cnt_lsb_minus4 + 4); // lt_ref_pic_poc_lsb_sps[i]
1909 GetBit(); // used_by_curr_pic_lt_sps_flag[i]
1910 }
1911 }
1912 GetBits(2); // sps_temporal_mvp_enabled_flag, strong_intra_smoothing_enabled_flag
1913 if (GetBit()) { // vui_parameters_present_flag
1914 // begin of vui_parameters()
1915 if (GetBit()) { // aspect_ratio_info_present_flag
1916 int aspect_ratio_idc = GetBits(8); // aspect_ratio_idc
1917 if (aspect_ratio_idc == 255) // EXTENDED_SAR
1918 GetBits(32); // sar_width, sar_height
1919 }
1920 if (GetBit()) // overscan_info_present_flag
1921 GetBit(); // overscan_appropriate_flag
1922 if (GetBit()) { // video_signal_type_present_flag
1923 GetBits(4); // video_format, video_full_range_flag
1924 if (GetBit()) // colour_description_present_flag
1925 GetBits(24); // colour_primaries, transfer_characteristics, matrix_coeffs
1926 }
1927 if (GetBit()) { // chroma_loc_info_present_flag
1928 GetGolombUe(); // chroma_sample_loc_type_top_field
1929 GetGolombUe(); // chroma_sample_loc_type_bottom_field
1930 }
1931 GetBits(3); // neutral_chroma_indication_flag, field_seq_flag, frame_field_info_present_flag
1932 if (GetBit()) { // default_display_window_flag
1933 GetGolombUe(); // def_disp_win_left_offset
1934 GetGolombUe(); // def_disp_win_right_offset
1935 GetGolombUe(); // def_disp_win_top_offset
1936 GetGolombUe(); // def_disp_win_bottom_offset
1937 }
1938 if (GetBit()) { // vui_timing_info_present_flag
1939 uint32_t vui_num_units_in_tick = GetBits(32); // vui_num_units_in_tick
1940 uint32_t vui_time_scale = GetBits(32); // vui_time_scale
1941 if (vui_num_units_in_tick > 0)
1942 framesPerSecond = (double)vui_time_scale / vui_num_units_in_tick;
1943 }
1944 }
1945 if (debug) {
1946 cString s = cString::sprintf("H.265: %d x %d%c %.2f fps %d Bit", frameWidth, frameHeight, progressive ? 'p':'i', framesPerSecond, bitDepth);
1947 dsyslog("%s", *s);
1948 dbgframes("\n%s", *s);
1949 }
1950}
1951
1952// --- cFrameDetector --------------------------------------------------------
1953
1955{
1956 parser = NULL;
1957 SetPid(Pid, Type);
1958 synced = false;
1959 newFrame = independentFrame = false;
1960 numPtsValues = 0;
1961 numIFrames = 0;
1962 framesPerSecond = 0;
1964 scanning = false;
1965}
1966
1967static int CmpUint32(const void *p1, const void *p2)
1968{
1969 if (*(uint32_t *)p1 < *(uint32_t *)p2) return -1;
1970 if (*(uint32_t *)p1 > *(uint32_t *)p2) return 1;
1971 return 0;
1972}
1973
1974void cFrameDetector::SetPid(int Pid, int Type)
1975{
1976 pid = Pid;
1977 type = Type;
1978 isVideo = type == 0x01 || type == 0x02 || type == 0x1B || type == 0x24; // MPEG 1, 2, H.264 or H.265
1979 delete parser;
1980 parser = NULL;
1981 if (type == 0x01 || type == 0x02)
1982 parser = new cMpeg2Parser;
1983 else if (type == 0x1B)
1984 parser = new cH264Parser;
1985 else if (type == 0x24)
1986 parser = new cH265Parser;
1987 else if (type == 0x03 || type == 0x04 || type == 0x06) // MPEG audio or AC3 audio
1988 parser = new cAudioParser;
1989 else if (type != 0)
1990 esyslog("ERROR: unknown stream type %d (PID %d) in frame detector", type, pid);
1991}
1992
1993int cFrameDetector::Analyze(const uchar *Data, int Length)
1994{
1995 if (!parser)
1996 return 0;
1997 int Processed = 0;
1998 newFrame = independentFrame = false;
1999 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
2000 // Sync on TS packet borders:
2001 if (int Skipped = TS_SYNC(Data, Length))
2002 return Processed + Skipped;
2003 // Handle one TS packet:
2004 int Handled = TS_SIZE;
2005 if (TsHasPayload(Data) && !TsIsScrambled(Data)) {
2006 int Pid = TsPid(Data);
2007 if (Pid == pid) {
2008 if (Processed)
2009 return Processed;
2010 if (TsPayloadStart(Data))
2011 scanning = true;
2012 if (scanning) {
2013 // Detect the beginning of a new frame:
2014 if (TsPayloadStart(Data)) {
2017 }
2018 int n = parser->Parse(Data, Length, pid);
2019 if (n > 0) {
2020 if (parser->NewFrame()) {
2021 newFrame = true;
2023 if (synced) {
2024 if (framesPerPayloadUnit <= 1)
2025 scanning = false;
2026 }
2027 else {
2028 if (parser->FramesPerSecond() > 0.0) {
2030 synced = true;
2031 parser->SetDebug(false);
2032 }
2034 if (independentFrame)
2035 numIFrames++;
2036 }
2037 }
2038 Handled = n;
2039 }
2040 }
2041 if (TsPayloadStart(Data)) {
2042 // Determine the frame rate from the PTS values in the PES headers:
2043 if (framesPerSecond <= 0.0) {
2044 // frame rate unknown, so collect a sequence of PTS values:
2045 if (numPtsValues < 2 || numPtsValues < MaxPtsValues && numIFrames < 2) { // collect a sequence containing at least two I-frames
2046 if (newFrame) { // only take PTS values at the beginning of a frame (in case if fields!)
2047 const uchar *Pes = Data + TsPayloadOffset(Data);
2048 if (numIFrames && PesHasPts(Pes)) {
2050 // check for rollover:
2051 if (numPtsValues && ptsValues[numPtsValues - 1] > 0xF0000000 && ptsValues[numPtsValues] < 0x10000000) {
2052 dbgframes("#");
2053 numPtsValues = 0;
2054 numIFrames = 0;
2055 }
2056 else
2057 numPtsValues++;
2058 }
2059 }
2060 }
2061 if (numPtsValues >= 2 && numIFrames >= 2) {
2062 // find the smallest PTS delta:
2063 qsort(ptsValues, numPtsValues, sizeof(uint32_t), CmpUint32);
2064 numPtsValues--;
2065 for (int i = 0; i < numPtsValues; i++)
2066 ptsValues[i] = ptsValues[i + 1] - ptsValues[i];
2067 qsort(ptsValues, numPtsValues, sizeof(uint32_t), CmpUint32);
2068 int Div = framesPerPayloadUnit;
2069 if (framesPerPayloadUnit > 1)
2071 if (Div <= 0)
2072 Div = 1;
2073 int Delta = ptsValues[0] / Div;
2074 // determine frame info:
2075 if (isVideo) {
2076 if (Delta == 3753)
2077 framesPerSecond = 24.0 / 1.001;
2078 else if (abs(Delta - 3600) <= 1)
2079 framesPerSecond = 25.0;
2080 else if (Delta % 3003 == 0)
2081 framesPerSecond = 30.0 / 1.001;
2082 else if (abs(Delta - 1800) <= 1)
2083 framesPerSecond = 50.0;
2084 else if (Delta == 1501)
2085 framesPerSecond = 60.0 / 1.001;
2086 else {
2088 dsyslog("unknown frame delta (%d), assuming %5.2f fps", Delta, DEFAULTFRAMESPERSECOND);
2089 }
2090 }
2091 else // audio
2092 framesPerSecond = double(PTSTICKS) / Delta; // PTS of audio frames is always increasing
2093 dbgframes("\nDelta = %d FPS = %5.2f FPPU = %d NF = %d TRO = %d\n", Delta, framesPerSecond, framesPerPayloadUnit, numPtsValues + 1, parser->IFrameTemporalReferenceOffset());
2094 synced = true;
2095 parser->SetDebug(false);
2096 }
2097 }
2098 }
2099 }
2100 else if (Pid == PATPID && synced && Processed)
2101 return Processed; // allow the caller to see any PAT packets
2102 }
2103 Data += Handled;
2104 Length -= Handled;
2105 Processed += Handled;
2106 if (newFrame)
2107 break;
2108 }
2109 return Processed;
2110}
2111
2112// --- cNaluDumper ---------------------------------------------------------
2113
2115{
2117 reset();
2118}
2119
2121{
2123 ContinuityOffset = 0;
2124 PesId = -1;
2125 PesOffset = 0;
2127 NaluOffset = 0;
2128 History = 0xffffffff;
2129 DropAllPayload = false;
2130}
2131
2132void cNaluDumper::ProcessPayload(unsigned char *Payload, int size, bool PayloadStart, sPayloadInfo &Info)
2133{
2134 Info.DropPayloadStartBytes = 0;
2135 Info.DropPayloadEndBytes = 0;
2136 int LastKeepByte = -1;
2137
2138 if (PayloadStart)
2139 {
2140 History = 0xffffffff;
2141 PesId = -1;
2143 }
2144
2145 for (int i=0; i<size; i++) {
2146 History = (History << 8) | Payload[i];
2147
2148 PesOffset++;
2149 NaluOffset++;
2150
2151 bool DropByte = false;
2152
2153 if (History >= 0x00000180 && History <= 0x000001FF)
2154 {
2155 // Start of PES packet
2156 PesId = History & 0xff;
2157 PesOffset = 0;
2159 }
2160 else if (PesId >= 0xe0 && PesId <= 0xef // video stream
2161 && History >= 0x00000100 && History <= 0x0000017F) // NALU start code
2162 {
2163 int NaluId = History & 0xff;
2164 NaluOffset = 0;
2165 NaluFillState = ((NaluId & 0x1f) == 0x0c) ? NALU_FILL : NALU_NONE;
2166 }
2167
2168 if (PesId >= 0xe0 && PesId <= 0xef // video stream
2169 && PesOffset >= 1 && PesOffset <= 2)
2170 {
2171 Payload[i] = 0; // Zero out PES length field
2172 }
2173
2174 if (NaluFillState == NALU_FILL && NaluOffset > 0) // Within NALU fill data
2175 {
2176 // We expect a series of 0xff bytes terminated by a single 0x80 byte.
2177
2178 if (Payload[i] == 0xFF)
2179 {
2180 DropByte = true;
2181 }
2182 else if (Payload[i] == 0x80)
2183 {
2184 NaluFillState = NALU_TERM; // Last byte of NALU fill, next byte sets NaluFillEnd=true
2185 DropByte = true;
2186 }
2187 else // Invalid NALU fill
2188 {
2189 dsyslog("cNaluDumper: Unexpected NALU fill data: %02x", Payload[i]);
2191 if (LastKeepByte == -1)
2192 {
2193 // Nalu fill from beginning of packet until last byte
2194 // packet start needs to be dropped
2195 Info.DropPayloadStartBytes = i;
2196 }
2197 }
2198 }
2199 else if (NaluFillState == NALU_TERM) // Within NALU fill data
2200 {
2201 // We are after the terminating 0x80 byte
2203 if (LastKeepByte == -1)
2204 {
2205 // Nalu fill from beginning of packet until last byte
2206 // packet start needs to be dropped
2207 Info.DropPayloadStartBytes = i;
2208 }
2209 }
2210
2211 if (!DropByte)
2212 LastKeepByte = i; // Last useful byte
2213 }
2214
2215 Info.DropAllPayloadBytes = (LastKeepByte == -1);
2216 Info.DropPayloadEndBytes = size-1-LastKeepByte;
2217}
2218
2219bool cNaluDumper::ProcessTSPacket(unsigned char *Packet)
2220{
2221 bool HasAdaption = TsHasAdaptationField(Packet);
2222 bool HasPayload = TsHasPayload(Packet);
2223
2224 // Check continuity:
2225 int ContinuityInput = TsContinuityCounter(Packet);
2226 if (LastContinuityInput >= 0)
2227 {
2228 int NewContinuityInput = HasPayload ? (LastContinuityInput + 1) & TS_CONT_CNT_MASK : LastContinuityInput;
2229 int Offset = (NewContinuityInput - ContinuityInput) & TS_CONT_CNT_MASK;
2230 if (Offset > 0)
2231 dsyslog("cNaluDumper: TS continuity offset %i", Offset);
2232 if (Offset > ContinuityOffset)
2233 ContinuityOffset = Offset; // max if packets get dropped, otherwise always the current one.
2234 }
2235 LastContinuityInput = ContinuityInput;
2236
2237 if (HasPayload) {
2238 sPayloadInfo Info;
2239 int Offset = TsPayloadOffset(Packet);
2240 ProcessPayload(Packet + Offset, TS_SIZE - Offset, TsPayloadStart(Packet), Info);
2241
2243 {
2244 // Return from drop packet mode to normal mode
2245 DropAllPayload = false;
2246
2247 // Does the packet start with some remaining NALU fill data?
2248 if (Info.DropPayloadStartBytes > 0)
2249 {
2250 // Add these bytes as stuffing to the adaption field.
2251
2252 // Sample payload layout:
2253 // FF FF FF FF FF 80 00 00 01 xx xx xx xx
2254 // ^DropPayloadStartBytes
2255
2256 TsExtendAdaptionField(Packet, Offset - 4 + Info.DropPayloadStartBytes);
2257 }
2258 }
2259
2260 bool DropThisPayload = DropAllPayload;
2261
2262 if (!DropAllPayload && Info.DropPayloadEndBytes > 0) // Payload ends with 0xff NALU Fill
2263 {
2264 // Last packet of useful data
2265 // Do early termination of NALU fill data
2266 Packet[TS_SIZE-1] = 0x80;
2267 DropAllPayload = true;
2268 // Drop all packets AFTER this one
2269
2270 // Since we already wrote the 0x80, we have to make sure that
2271 // as soon as we stop dropping packets, any beginning NALU fill of next
2272 // packet gets dumped. (see DropPayloadStartBytes above)
2273 }
2274
2275 if (DropThisPayload && HasAdaption)
2276 {
2277 // Drop payload data, but keep adaption field data
2278 TsExtendAdaptionField(Packet, TS_SIZE-4);
2279 DropThisPayload = false;
2280 }
2281
2282 if (DropThisPayload)
2283 {
2284 return true; // Drop packet
2285 }
2286 }
2287
2288 // Fix Continuity Counter and reproduce incoming offsets:
2289 int NewContinuityOutput = TsHasPayload(Packet) ? (LastContinuityOutput + 1) & TS_CONT_CNT_MASK : LastContinuityOutput;
2290 NewContinuityOutput = (NewContinuityOutput + ContinuityOffset) & TS_CONT_CNT_MASK;
2291 TsSetContinuityCounter(Packet, NewContinuityOutput);
2292 LastContinuityOutput = NewContinuityOutput;
2293 ContinuityOffset = 0;
2294
2295 return false; // Keep packet
2296}
2297
2298// --- cNaluStreamProcessor ---------------------------------------------------------
2299
2301{
2302 pPatPmtParser = NULL;
2303 vpid = -1;
2304 data = NULL;
2305 length = 0;
2306 tempLength = 0;
2307 tempLengthAtEnd = false;
2308 TotalPackets = 0;
2309 DroppedPackets = 0;
2310}
2311
2313{
2314 if (length > 0)
2315 esyslog("cNaluStreamProcessor::PutBuffer: New data before old data was processed!");
2316
2317 data = Data;
2318 length = Length;
2319}
2320
2322{
2323 if (length <= 0)
2324 {
2325 // Need more data - quick exit
2326 OutLength = 0;
2327 return NULL;
2328 }
2329 if (tempLength > 0) // Data in temp buffer?
2330 {
2331 if (tempLengthAtEnd) // Data is at end, copy to beginning
2332 {
2333 // Overlapping src and dst!
2334 for (int i=0; i<tempLength; i++)
2336 }
2337 // Normalize TempBuffer fill
2338 if (tempLength < TS_SIZE && length > 0)
2339 {
2340 int Size = min(TS_SIZE-tempLength, length);
2341 memcpy(tempBuffer+tempLength, data, Size);
2342 data += Size;
2343 length -= Size;
2344 tempLength += Size;
2345 }
2346 if (tempLength < TS_SIZE)
2347 {
2348 // All incoming data buffered, but need more data
2349 tempLengthAtEnd = false;
2350 OutLength = 0;
2351 return NULL;
2352 }
2353 // Now: TempLength==TS_SIZE
2354 if (tempBuffer[0] != TS_SYNC_BYTE)
2355 {
2356 // Need to sync on TS within temp buffer
2357 int Skipped = 1;
2358 while (Skipped < TS_SIZE && (tempBuffer[Skipped] != TS_SYNC_BYTE || (Skipped < length && data[Skipped] != TS_SYNC_BYTE)))
2359 Skipped++;
2360 esyslog("ERROR: skipped %d bytes to sync on start of TS packet", Skipped);
2361 // Pass through skipped bytes
2362 tempLengthAtEnd = true;
2363 tempLength = TS_SIZE - Skipped; // may be 0, thats ok
2364 OutLength = Skipped;
2365 return tempBuffer;
2366 }
2367 // Now: TempBuffer is a TS packet
2368 int Pid = TsPid(tempBuffer);
2369 if (pPatPmtParser)
2370 {
2371 if (Pid == 0)
2373 else if (pPatPmtParser->IsPmtPid(Pid))
2375 }
2376
2377 TotalPackets++;
2378 bool Drop = false;
2379 if (Pid == vpid || (pPatPmtParser && Pid == pPatPmtParser->Vpid() && pPatPmtParser->Vtype() == 0x1B))
2381 if (!Drop)
2382 {
2383 // Keep this packet, then continue with new data
2384 tempLength = 0;
2385 OutLength = TS_SIZE;
2386 return tempBuffer;
2387 }
2388 // Drop TempBuffer
2390 tempLength = 0;
2391 }
2392 // Now: TempLength==0, just process data/length
2393
2394 // Pointer to processed data / length:
2395 uchar *Out = data;
2396 uchar *OutEnd = Out;
2397
2398 while (length >= TS_SIZE)
2399 {
2400 if (data[0] != TS_SYNC_BYTE) {
2401 int Skipped = 1;
2402 while (Skipped < length && (data[Skipped] != TS_SYNC_BYTE || (length - Skipped > TS_SIZE && data[Skipped + TS_SIZE] != TS_SYNC_BYTE)))
2403 Skipped++;
2404 esyslog("ERROR: skipped %d bytes to sync on start of TS packet", Skipped);
2405
2406 // Pass through skipped bytes
2407 if (OutEnd != data)
2408 memcpy(OutEnd, data, Skipped);
2409 OutEnd += Skipped;
2410 continue;
2411 }
2412 // Now: Data starts with complete TS packet
2413
2414 int Pid = TsPid(data);
2415 if (pPatPmtParser)
2416 {
2417 if (Pid == 0)
2419 else if (pPatPmtParser->IsPmtPid(Pid))
2421 }
2422
2423 TotalPackets++;
2424 bool Drop = false;
2425 if (Pid == vpid || (pPatPmtParser && Pid == pPatPmtParser->Vpid() && pPatPmtParser->Vtype() == 0x1B))
2427 if (!Drop)
2428 {
2429 if (OutEnd != data)
2430 memcpy(OutEnd, data, TS_SIZE);
2431 OutEnd += TS_SIZE;
2432 }
2433 else
2434 {
2436 }
2437 data += TS_SIZE;
2438 length -= TS_SIZE;
2439 }
2440 // Now: Less than a packet remains.
2441 if (length > 0)
2442 {
2443 // copy remains into temp buffer
2444 memcpy(tempBuffer, data, length);
2446 tempLengthAtEnd = false;
2447 length = 0;
2448 }
2449 OutLength = (OutEnd - Out);
2450 return OutLength > 0 ? Out : NULL;
2451}
#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:1261
cAudioParser(void)
Definition remux.c:1257
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:440
cEitGenerator(int Sid=0)
Definition remux.c:983
int counter
Definition remux.h:441
uchar * AddParentalRatingDescriptor(uchar *p, uchar ParentalRating=0)
Definition remux.c:997
uint16_t YMDtoMJD(int Y, int M, int D)
Definition remux.c:991
uchar * Generate(int Sid)
Definition remux.c:1008
int version
Definition remux.h:442
uint32_t ptsValues[MaxPtsValues]
Definition remux.h:521
bool synced
Definition remux.h:518
bool scanning
Definition remux.h:529
int framesPerPayloadUnit
Definition remux.h:527
double framesPerSecond
Definition remux.h:525
int framesInPayloadUnit
Definition remux.h:526
int numIFrames
Definition remux.h:523
bool independentFrame
Definition remux.h:520
cFrameDetector(int Pid=0, int Type=0)
Sets up a frame detector for the given Pid and stream Type.
Definition remux.c:1954
bool newFrame
Definition remux.h:519
cFrameParser * parser
Definition remux.h:530
int numPtsValues
Definition remux.h:522
int Analyze(const uchar *Data, int Length)
Analyzes the TS packets pointed to by Data.
Definition remux.c:1993
bool isVideo
Definition remux.h:524
void SetPid(int Pid, int Type)
Sets the Pid and stream Type to detect frames for.
Definition remux.c:1974
uint16_t FrameWidth(void)
Definition remux.c:1231
bool progressive
Definition remux.c:1216
void SetDebug(bool Debug)
Definition remux.c:1227
bool NewFrame(void)
Definition remux.c:1228
double FramesPerSecond(void)
Definition remux.c:1233
bool IndependentFrame(void)
Definition remux.c:1229
bool newFrame
Definition remux.c:1210
int iFrameTemporalReferenceOffset
Definition remux.c:1212
double framesPerSecond
Definition remux.c:1215
bool independentFrame
Definition remux.c:1211
virtual ~cFrameParser()
Definition remux.c:1219
uint16_t frameHeight
Definition remux.c:1214
bool debug
Definition remux.c:1209
bool Progressive(void)
Definition remux.c:1234
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.
uint16_t FrameHeight(void)
Definition remux.c:1232
int IFrameTemporalReferenceOffset(void)
Definition remux.c:1230
uint16_t frameWidth
Definition remux.c:1213
cFrameParser(void)
Definition remux.c:1237
uint32_t GetBits(int Bits)
Definition remux.c:1466
cTsPayload tsPayload
Definition remux.c:1402
void ParseAccessUnitDelimiter(void)
Definition remux.c:1537
@ nutSequenceParameterSet
Definition remux.c:1391
@ nutCodedSliceNonIdr
Definition remux.c:1389
@ nutAccessUnitDelimiter
Definition remux.c:1392
@ nutCodedSliceIdr
Definition remux.c:1390
bool separate_colour_plane_flag
Definition remux.c:1398
bool gotAccessUnitDelimiter
Definition remux.c:1404
int zeroBytes
Definition remux.c:1396
bool frame_mbs_only_flag
Definition remux.c:1400
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:1494
int log2_max_frame_num
Definition remux.c:1399
uint32_t GetGolombUe(void)
Definition remux.c:1474
uchar GetByte(bool Raw=false)
Gets the next data byte.
Definition remux.c:1438
void ParseSliceHeader(void)
Definition remux.c:1657
void ParseSequenceParameterSet(void)
Definition remux.c:1544
uchar byte
Definition remux.c:1394
uint32_t scanner
Definition remux.c:1403
bool gotSequenceParameterSet
Definition remux.c:1405
int32_t GetGolombSe(void)
Definition remux.c:1482
cH264Parser(void)
Sets up a new H.264 parser.
Definition remux.c:1425
uchar GetBit(void)
Definition remux.c:1457
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:1727
cH265Parser(void)
Definition remux.c:1722
@ nutSliceSegmentIDRWRADL
Definition remux.c:1699
@ nutUnspecified0
Definition remux.c:1713
@ nutSliceSegmentSTSAN
Definition remux.c:1690
@ nutSliceSegmentRADLN
Definition remux.c:1692
@ nutSliceSegmentIDRNLP
Definition remux.c:1700
@ nutPrefixSEI
Definition remux.c:1709
@ nutAccessUnitDelimiter
Definition remux.c:1705
@ nutUnspecified7
Definition remux.c:1714
@ nutSliceSegmentBLAWRADL
Definition remux.c:1697
@ nutSliceSegmentTSAR
Definition remux.c:1689
@ nutSliceSegmentRADLR
Definition remux.c:1693
@ nutSliceSegmentTrailingR
Definition remux.c:1687
@ nutVideoParameterSet
Definition remux.c:1702
@ nutSequenceParameterSet
Definition remux.c:1703
@ nutSliceSegmentTSAN
Definition remux.c:1688
@ nutSliceSegmentRASLN
Definition remux.c:1694
@ nutSuffixSEI
Definition remux.c:1710
@ nutSliceSegmentBLAWLP
Definition remux.c:1696
@ nutEndOfBitstream
Definition remux.c:1707
@ nutSliceSegmentBLANLP
Definition remux.c:1698
@ nutSliceSegmentRASLR
Definition remux.c:1695
@ nutPictureParameterSet
Definition remux.c:1704
@ nutNonVCLRes3
Definition remux.c:1712
@ nutSliceSegmentCRANUT
Definition remux.c:1701
@ nutSliceSegmentTrailingN
Definition remux.c:1686
@ nutNonVCLRes0
Definition remux.c:1711
@ nutFillerData
Definition remux.c:1708
@ nutSliceSegmentSTSAR
Definition remux.c:1691
@ nutEndOfSequence
Definition remux.c:1706
void ParseSequenceParameterSet(void)
Definition remux.c:1761
bool seenIndependentFrame
Definition remux.c:1278
cMpeg2Parser(void)
Definition remux.c:1297
bool seenScanType
Definition remux.c:1280
int lastIFrameTemporalReference
Definition remux.c:1279
uint32_t scanner
Definition remux.c:1277
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:1305
const double frame_rate_table[9]
Definition remux.c:1281
void reset()
Definition remux.c:2120
int LastContinuityInput
Definition remux.h:564
int PesId
Definition remux.h:570
void ProcessPayload(unsigned char *Payload, int size, bool PayloadStart, sPayloadInfo &Info)
Definition remux.c:2132
bool DropAllPayload
Definition remux.h:568
@ NALU_TERM
Definition remux.h:578
@ NALU_NONE
Definition remux.h:576
@ NALU_FILL
Definition remux.h:577
unsigned int History
Definition remux.h:562
int PesOffset
Definition remux.h:571
eNaluFillState NaluFillState
Definition remux.h:582
bool ProcessTSPacket(unsigned char *Packet)
Definition remux.c:2219
cNaluDumper()
Definition remux.c:2114
int NaluOffset
Definition remux.h:573
int ContinuityOffset
Definition remux.h:566
int LastContinuityOutput
Definition remux.h:565
cPatPmtParser * pPatPmtParser
Definition remux.h:610
long long int DroppedPackets
Definition remux.h:614
long long int TotalPackets
Definition remux.h:613
uchar tempBuffer[TS_SIZE]
Definition remux.h:607
cNaluDumper NaluDumper
Definition remux.h:611
void PutBuffer(uchar *Data, int Length)
Definition remux.c:2312
uchar * GetBuffer(int &OutLength)
Definition remux.c:2321
int MakeCRC(uchar *Target, const uchar *Data, int Length)
Definition remux.c:487
uchar * GetPmt(int &Index)
Returns a pointer to the Index'th TS packet of the PMT section.
Definition remux.c:636
void SetChannel(const cChannel *Channel)
Sets the Channel for which the PAT/PMT shall be generated.
Definition remux.c:621
void IncEsInfoLength(int Length)
Definition remux.c:420
void IncCounter(int &Counter, uchar *TsPacket)
Definition remux.c:407
cPatPmtGenerator(const cChannel *Channel=NULL)
Definition remux.c:397
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:615
int numPmtPackets
Definition remux.h:308
uchar * esInfoLength
Definition remux.h:314
uchar pat[TS_SIZE]
Definition remux.h:306
int MakeAC3Descriptor(uchar *Target, uchar Type)
Definition remux.c:441
void GeneratePat(void)
Generates a PAT section for later use with GetPat().
Definition remux.c:517
uchar * GetPat(void)
Returns a pointer to the PAT section, which consists of exactly one TS packet.
Definition remux.c:630
uchar pmt[MAX_PMT_TS][TS_SIZE]
Definition remux.h:307
int MakeLanguageDescriptor(uchar *Target, const char *Language)
Definition remux.c:468
void GeneratePmt(const cChannel *Channel)
Generates a PMT section for the given Channel, for later use with GetPmt().
Definition remux.c:546
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:502
int MakeStream(uchar *Target, uchar Type, int Pid)
Definition remux.c:429
int MakeSubtitlingDescriptor(uchar *Target, const char *Language, uchar SubtitlingType, uint16_t CompositionPageId, uint16_t AncillaryPageId)
Definition remux.c:451
void IncVersion(int &Version)
Definition remux.c:414
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:974
int Vtype(void) const
Returns the video stream type as defined by the current PMT, or 0 if no video stream type has been de...
Definition remux.h:415
int dpids[MAXDPIDS+1]
Definition remux.h:372
uchar pmt[MAX_SECTION_SIZE]
Definition remux.h:361
int apids[MAXAPIDS+1]
Definition remux.h:369
cPatPmtParser(bool UpdatePrimaryDevice=false)
Definition remux.c:647
void Reset(void)
Resets the parser.
Definition remux.c:653
void ParsePat(const uchar *Data, int Length)
Parses the PAT data from the single TS packet in Data.
Definition remux.c:663
int pmtSize
Definition remux.h:362
char dlangs[MAXDPIDS][MAXLANGCODE2]
Definition remux.h:374
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:955
int patVersion
Definition remux.h:363
int pmtPids[MAX_PMT_PIDS+1]
Definition remux.h:365
uchar subtitlingTypes[MAXSPIDS]
Definition remux.h:377
int dtypes[MAXDPIDS+1]
Definition remux.h:373
uint16_t ancillaryPageIds[MAXSPIDS]
Definition remux.h:379
int SectionLength(const uchar *Data, int Length)
Definition remux.h:383
void ParsePmt(const uchar *Data, int Length)
Parses the PMT data from the single TS packet in Data.
Definition remux.c:695
bool completed
Definition remux.h:381
bool IsPmtPid(int Pid) const
Returns true if Pid the one of the PMT pids as defined by the current PAT.
Definition remux.h:406
uint16_t compositionPageIds[MAXSPIDS]
Definition remux.h:378
char alangs[MAXAPIDS][MAXLANGCODE2]
Definition remux.h:371
int spids[MAXSPIDS+1]
Definition remux.h:375
int pmtVersion
Definition remux.h:364
bool updatePrimaryDevice
Definition remux.h:380
int Vpid(void) const
Returns the video pid as defined by the current PMT, or 0 if no video pid has been detected,...
Definition remux.h:409
char slangs[MAXSPIDS][MAXLANGCODE2]
Definition remux.h:376
int atypes[MAXAPIDS+1]
Definition remux.h:370
static void SetBrokenLink(uchar *Data, int Length)
Definition remux.c:102
int UseDolbyDigital
Definition config.h:326
static cString sprintf(const char *fmt,...) __attribute__((format(printf
Definition tools.c:1149
int numPacketsPid
Definition remux.h:238
int pid
Definition remux.h:236
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:258
int Used(void)
Returns the number of raw bytes that have already been used (e.g.
Definition remux.h:264
bool Eof(void) const
Returns true if all available bytes of the TS payload have been processed.
Definition remux.h:268
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:255
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:237
int numPacketsOther
Definition remux.h:239
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:235
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:234
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:463
bool repeatLast
Definition remux.h:464
uchar * lastData
Definition remux.h:462
uchar * data
Definition remux.h:458
void PutTs(const uchar *Data, int Length)
Puts the payload data of the single TS packet at Data into the converter.
Definition remux.c:1082
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:1159
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:1111
cTsToPes(void)
Definition remux.c:1070
int length
Definition remux.h:460
~cTsToPes()
Definition remux.c:1077
void Reset(void)
Resets the converter.
Definition remux.c:1164
int offset
Definition remux.h:461
int size
Definition remux.h:459
cSetup Setup
Definition config.c:372
@ ttSubtitle
Definition device.h:70
@ ttDolby
Definition device.h:67
@ ttAudio
Definition device.h:64
const char * I18nNormalizeLanguageCode(const char *Code)
Returns a 3 letter language code that may not be zero terminated.
Definition i18n.c:286
@ EnhancedAC3DescriptorTag
Definition si.h:136
@ SubtitlingDescriptorTag
Definition si.h:102
@ ISO639LanguageDescriptorTag
Definition si.h:60
@ ParentalRatingDescriptorTag
Definition si.h:98
@ AC3DescriptorTag
Definition si.h:119
#define DEFAULTFRAMESPERSECOND
Definition recording.h: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:1200
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:1109
#define P_PMT_PID
Definition remux.c:499
void TsHidePayload(uchar *p)
Definition remux.c:121
static int CmpUint32(const void *p1, const void *p2)
Definition remux.c:1967
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 TsExtendAdaptionField(unsigned char *Packet, int ToLength)
Definition remux.c:359
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:1174
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:498
void TsDump(const char *Name, const u_char *Data, int Length)
Definition remux.c:1185
#define MAX_TS_PACKETS_FOR_VIDEO_FRAME_DETECTION
Definition remux.c:26
bool TsError(const uchar *p)
Definition remux.h:82
#define TS_ADAPT_PCR
Definition remux.h:46
int TsPid(const uchar *p)
Definition remux.h:87
bool TsHasPayload(const uchar *p)
Definition remux.h:62
#define MAX33BIT
Definition remux.h:59
#define MAX_PMT_PIDS
Definition remux.h:357
int PesPayloadOffset(const uchar *p)
Definition remux.h:184
#define PATPID
Definition remux.h:52
bool TsIsScrambled(const uchar *p)
Definition remux.h:98
void TsSetContinuityCounter(uchar *p, uchar Counter)
Definition remux.h:108
uchar TsContinuityCounter(const uchar *p)
Definition remux.h:103
int TsGetPayload(const uchar **p)
Definition remux.h:119
bool PesHasPts(const uchar *p)
Definition remux.h:189
bool PesLongEnough(int Length)
Definition remux.h:169
#define TS_SIZE
Definition remux.h:34
#define MAX_SECTION_SIZE
Definition remux.h:301
int64_t PesGetDts(const uchar *p)
Definition remux.h:208
#define TS_ADAPT_FIELD_EXISTS
Definition remux.h:40
int64_t PesGetPts(const uchar *p)
Definition remux.h:199
bool TsPayloadStart(const uchar *p)
Definition remux.h:77
#define TS_SYNC(Data, Length)
Definition remux.h:154
int TsPayloadOffset(const uchar *p)
Definition remux.h:113
#define MAXPID
Definition remux.h:55
bool PesHasDts(const uchar *p)
Definition remux.h:194
#define PCRFACTOR
Definition remux.h:58
#define TS_SYNC_BYTE
Definition remux.h:33
bool PesHasLength(const uchar *p)
Definition remux.h:174
bool TsHasAdaptationField(const uchar *p)
Definition remux.h:72
void TsExtendAdaptionField(unsigned char *Packet, int ToLength)
Definition remux.c:359
#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:509
int PesLength(const uchar *p)
Definition remux.h:179
ePesHeader
Definition remux.h:16
@ phMPEG2
Definition remux.h:20
@ phNeedMoreData
Definition remux.h:17
@ phInvalid
Definition remux.h:18
@ phMPEG1
Definition remux.h:19
#define EITPID
Definition remux.h:54
#define TS_CONT_CNT_MASK
Definition remux.h:42
#define TS_PAYLOAD_START
Definition remux.h:36
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