Go to the documentation of this file.
23 #define dbgpatpmt(a...) if (DebugPatPmt) fprintf(stderr, a)
24 #define dbgframes(a...) if (DebugFrames) fprintf(stderr, a)
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)
30 #define EMPTY_SCANNER (0xFFFFFFFF)
37 if ((Data[6] & 0xC0) == 0x80) {
45 if (ContinuationHeader)
46 *ContinuationHeader = ((Data[6] == 0x80) && !Data[7] && !Data[8]);
55 for (
int i = 0; i < 16; i++) {
71 if (ContinuationHeader)
72 *ContinuationHeader =
false;
86 if (ContinuationHeader)
87 *ContinuationHeader =
true;
98 #define VIDEO_STREAM_S 0xE0
107 if (Data[i] == 0 && Data[i + 1] == 0 && Data[i + 2] == 1 && Data[i + 3] == 0xB8) {
108 if (!(Data[i + 7] & 0x40))
113 dsyslog(
"SetBrokenLink: no GOP header found in video packet");
116 dsyslog(
"SetBrokenLink: no video packet in frame");
128 memset(p + 6, 0xFF,
TS_SIZE - 6);
141 p[10] = (b << 7) | (p[10] & 0x7E) | ((e >> 8) & 0x01);
147 int TsSync(
const uchar *Data,
int Length,
const char *File,
const char *Function,
int Line)
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);
218 p[ 9] = ((Pts >> 29) & 0x0E) | (p[9] & 0xF1);
220 p[11] = ((Pts >> 14) & 0xFE) | 0x01;
222 p[13] = ((Pts << 1) & 0xFE) | 0x01;
227 p[14] = ((Dts >> 29) & 0x0E) | (p[14] & 0xF1);
229 p[16] = ((Dts >> 14) & 0xFE) | 0x01;
231 p[18] = ((Dts << 1) & 0xFE) | 0x01;
236 int64_t d = Pts2 - Pts1;
256 Setup(Data, Length, Pid);
330 if (Index >= 0 && Index <
length)
336 int OldIndex =
index;
341 Scanner = (Scanner << 8) |
GetByte();
387 if (Offset == 4 && Offset < NewPayload)
389 if (Offset == 5 && Offset < NewPayload)
390 Packet[Offset++] = 0;
391 while (Offset < NewPayload)
392 Packet[Offset++] = 0xff;
409 TsPacket[3] = (TsPacket[3] & 0xF0) | Counter;
410 if (++Counter > 0x0F)
416 if (++Version > 0x1F)
433 Target[i++] = 0xE0 | (Pid >> 8);
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;
473 Target[Length] = 0x00;
474 for (
const char *End = Language + strlen(Language); Language < End; ) {
475 Target[i++] = *Language++;
476 Target[i++] = *Language++;
477 Target[i++] = *Language++;
479 Target[Length] += 0x04;
480 if (*Language ==
'+')
491 Target[i++] = crc >> 24;
492 Target[i++] = crc >> 16;
493 Target[i++] = crc >> 8;
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
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++; } }
519 memset(
pat, 0xFF,
sizeof(
pat));
527 int PayloadStart = i;
530 int SectionLength = i;
539 p[i++] = 0xE0 | (
pmtPid >> 8);
541 pat[SectionLength] = i - SectionLength - 1 + 4;
550 memset(buf, 0xFF,
sizeof(buf));
553 int Vpid = Channel->
Vpid();
554 int Ppid = Channel->
Ppid();
558 int SectionLength = i;
566 p[i++] = 0xE0 | (Ppid >> 8);
573 for (
int n = 0; Channel->
Apid(n); n++) {
575 const char *Alang = Channel->
Alang(n);
578 for (
int n = 0; Channel->
Dpid(n); n++) {
583 for (
int n = 0; Channel->
Spid(n); n++) {
588 int sl = i - SectionLength - 2 + 4;
589 buf[SectionLength] |= (sl >> 8) & 0x0F;
590 buf[SectionLength + 1] = sl;
667 Data += PayloadOffset;
668 Length -= PayloadOffset;
670 if ((Length -= Data[0] + 1) <= 0)
692 esyslog(
"ERROR: can't parse PAT");
700 Data += PayloadOffset;
701 Length -= PayloadOffset;
705 if ((Length -= Data[0] + 1) <= 0)
709 if (Length <=
int(
sizeof(
pmt))) {
710 memcpy(
pmt, Data, Length);
714 esyslog(
"ERROR: PMT packet length too big (%d byte)!", Length);
726 esyslog(
"ERROR: PMT section length too big (%d byte)!",
pmtSize + Length);
743 cDevice::PrimaryDevice()->ClrAvailableTracks(
false,
true);
781 char *s =
alangs[NumApids];
801 cDevice::PrimaryDevice()->SetAvailableTrack(
ttAudio, NumApids,
apids[NumApids],
alangs[NumApids]);
831 char *s =
slangs[NumSpids];
848 cDevice::PrimaryDevice()->SetAvailableTrack(
ttSubtitle, NumSpids,
spids[NumSpids],
slangs[NumSpids]);
865 dpids[NumDpids] = dpid;
869 cDevice::PrimaryDevice()->SetAvailableTrack(
ttDolby, NumDpids, dpid, lang);
903 cDevice::PrimaryDevice()->SetAvailableTrack(
ttDolby, NumDpids, stream.
getPid(), lang);
927 cDevice::PrimaryDevice()->SetAvailableTrack(
ttSubtitle, NumSpids, stream.
getPid(), lang);
943 cDevice::PrimaryDevice()->EnsureAudioTrack(
true);
944 cDevice::PrimaryDevice()->EnsureSubtitleTrack();
951 esyslog(
"ERROR: can't parse PMT");
960 int Pid =
TsPid(Data);
963 else if (IsPmtPid(Pid)) {
993 int L = (M < 3) ? 1 : 0;
994 return 14956 + D + int((Y - L) * 365.25) + int((M + 1 + L * 12) * 30.6001);
1004 *p++ = ParentalRating;
1010 uchar *PayloadStart;
1011 uchar *SectionStart;
1012 uchar *DescriptorsStart;
1013 memset(
eit, 0xFF,
sizeof(
eit));
1015 time_t t = time(NULL) - 3600;
1016 tm *tm = localtime_r(&t, &tm_r);
1017 uint16_t MJD =
YMDtoMJD(tm->tm_year, tm->tm_mon + 1, tm->tm_mday);
1023 *p++ = 0x10 | (
counter++ & 0x0F);
1054 DescriptorsStart = p;
1057 *(SectionStart - 1) = p - SectionStart + 4;
1058 *(DescriptorsStart - 1) = p - DescriptorsStart;
1060 int crc =
SI::CRC32::crc32((
char *)PayloadStart, p - PayloadStart, 0xFFFFFFFF);
1100 esyslog(
"ERROR: out of memory");
1109 #define MAXPESLENGTH 0xFFF0
1129 memmove(p,
data, 4);
1176 printf(
"--- %s\n", Name);
1177 for (
int i = 0; i < Length; i++) {
1178 if (i && (i % 16) == 0)
1180 printf(
" %02X", Data[i]);
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]);
1193 n =
max(n, Length - 10);
1194 for (n =
max(n, Length - 10); n < Length; n++)
1195 printf(
" %02X", Data[n]);
1202 TsDump(Name, Data, Length);
1216 virtual int Parse(
const uchar *Data,
int Length,
int Pid) = 0;
1242 virtual int Parse(
const uchar *Data,
int Length,
int Pid);
1270 virtual int Parse(
const uchar *Data,
int Length,
int Pid);
1283 bool SeenPayloadStart =
false;
1286 SeenPayloadStart =
true;
1292 uint32_t OldScanner =
scanner;
1294 if (!SeenPayloadStart && tsPayload.AtTsStart())
1300 return tsPayload.Used() -
TS_SIZE;
1304 int TemporalReference = (b1 << 2 ) + ((b2 & 0xC0) >> 6);
1305 uchar FrameType = (b2 >> 3) & 0x07;
1306 if (tsPayload.
Find(0x000001B5)) {
1307 if (((tsPayload.
GetByte() & 0xF0) >> 4) == 0x08) {
1310 if (PictureStructure == 0x02)
1324 static const char FrameTypes[] =
"?IPBD???";
1331 if (tsPayload.AtPayloadStart()
1335 return tsPayload.Used();
1376 virtual int Parse(
const uchar *Data,
int Length,
int Pid);
1417 return (
byte & (1 <<
bit--)) ? 1 : 0;
1431 for (
int b = 0; !b && z < 32; z++)
1433 return (1 << z) - 1 +
GetBits(z);
1440 if ((v & 0x01) != 0)
1443 return -int32_t(v / 2);
1461 if ((
scanner & 0xFFFFFF00) == 0x00000100) {
1463 switch (NalUnitType) {
1504 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) {
1506 if (chroma_format_idc == 3)
1512 for (
int i = 0; i < ((chroma_format_idc != 3) ? 8 : 12); i++) {
1514 int SizeOfScalingList = (i < 6) ? 16 : 64;
1517 for (
int j = 0; j < SizeOfScalingList; j++) {
1519 NextScale = (LastScale +
GetGolombSe() + 256) % 256;
1521 LastScale = NextScale;
1529 if (pic_order_cnt_type == 0)
1531 else if (pic_order_cnt_type == 1) {
1557 static const char SliceTypes[] =
"PBIpi";
1558 dbgframes(
"%c", SliceTypes[slice_type % 5]);
1611 virtual int Parse(
const uchar *Data,
int Length,
int Pid);
1629 if ((
scanner & 0xFFFFFF00) == 0x00000100) {
1666 if (*(uint32_t *)p1 < *(uint32_t *)p2)
return -1;
1667 if (*(uint32_t *)p1 > *(uint32_t *)p2)
return 1;
1680 else if (
type == 0x1B)
1682 else if (
type == 0x24)
1687 esyslog(
"ERROR: unknown stream type %d (PID %d) in frame detector",
type,
pid);
1698 if (
int Skipped =
TS_SYNC(Data, Length))
1699 return Processed + Skipped;
1703 int Pid =
TsPid(Data);
1770 else if (abs(Delta - 3600) <= 1)
1772 else if (Delta % 3003 == 0)
1774 else if (abs(Delta - 1800) <= 1)
1776 else if (Delta == 1501)
1797 Processed += Handled;
1828 int LastKeepByte = -1;
1837 for (
int i=0; i<size; i++) {
1843 bool DropByte =
false;
1870 if (Payload[i] == 0xFF)
1874 else if (Payload[i] == 0x80)
1881 dsyslog(
"cNaluDumper: Unexpected NALU fill data: %02x", Payload[i]);
1883 if (LastKeepByte == -1)
1895 if (LastKeepByte == -1)
1923 dsyslog(
"cNaluDumper: TS continuity offset %i", Offset);
1967 if (DropThisPayload && HasAdaption)
1971 DropThisPayload =
false;
1974 if (DropThisPayload)
2007 esyslog(
"cNaluStreamProcessor::PutBuffer: New data before old data was processed!");
2030 if (tempLength < TS_SIZE && length > 0)
2052 esyslog(
"ERROR: skipped %d bytes to sync on start of TS packet", Skipped);
2056 OutLength = Skipped;
2088 uchar *OutEnd = Out;
2096 esyslog(
"ERROR: skipped %d bytes to sync on start of TS packet", Skipped);
2100 memcpy(OutEnd,
data, Skipped);
2141 OutLength = (OutEnd - Out);
2142 return OutLength > 0 ? Out : NULL;
cPatPmtParser * pPatPmtParser
#define TS_SYNC(Data, Length)
int64_t TsGetDts(const uchar *p, int l)
bool PesLongEnough(int Length)
int TsGetPayload(const uchar **p)
void SetPid(int Pid, int Type)
Sets the Pid and stream Type to detect frames for.
void GeneratePmt(const cChannel *Channel)
Generates a PMT section for the given Channel, for later use with GetPmt().
static u_int32_t crc32(const char *d, int len, u_int32_t CRCvalue)
uchar * GetPmt(int &Index)
Returns a pointer to the Index'th TS packet of the PMT section.
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...
@ nutSliceSegmentIDRWRADL
int getCompositionPageId() const
bool separate_colour_plane_flag
uchar SubtitlingType(int i) const
int getStreamType() const
#define WRN_TS_PACKETS_FOR_VIDEO_FRAME_DETECTION
virtual int Parse(const uchar *Data, int Length, int Pid)
Parses the given Data, which is a sequence of Length bytes of TS packets.
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...
void TsHidePayload(uchar *p)
const char * Alang(int i) const
int getAncillaryPageId() const
void PesSetDts(uchar *p, int64_t Dts)
#define TS_ADAPT_FIELD_EXISTS
void TsSetPts(uchar *p, int l, int64_t Pts)
bool gotAccessUnitDelimiter
int Analyze(const uchar *Data, int Length)
Analyzes the TS packets pointed to by Data.
char alangs[MAXAPIDS][MAXLANGCODE2]
#define MIN_TS_PACKETS_FOR_FRAME_DETECTOR
bool TsError(const uchar *p)
bool getCurrentNextIndicator() const
@ nutSliceSegmentTrailingR
bool TsHasAdaptationField(const uchar *p)
uchar GetByte(bool Raw=false)
Gets the next data byte.
cH264Parser(void)
Sets up a new H.264 parser.
uint16_t AncillaryPageId(int i) const
int getLastSectionNumber() const
StructureLoop< Stream > streamLoop
cFrameDetector(int Pid=0, int Type=0)
Sets up a frame detector for the given Pid and stream Type.
int64_t PesGetDts(const uchar *p)
char dlangs[MAXDPIDS][MAXLANGCODE2]
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...
void TsExtendAdaptionField(unsigned char *Packet, int ToLength)
void ParsePat(const uchar *Data, int Length)
Parses the PAT data from the single TS packet in Data.
uchar pmt[MAX_SECTION_SIZE]
int getSectionNumber() const
int getTransportStreamId() const
long long int TotalPackets
bool ParsePatPmt(const uchar *Data, int Length)
Parses the given Data (which may consist of several TS packets, typically an entire frame) and extrac...
#define MAX_TS_PACKETS_FOR_VIDEO_FRAME_DETECTION
int TsPayloadOffset(const uchar *p)
virtual int Parse(const uchar *Data, int Length, int Pid)
Parses the given Data, which is a sequence of Length bytes of TS packets.
int TsPid(const uchar *p)
@ ParentalRatingDescriptorTag
@ EnhancedAC3DescriptorTag
void IncVersion(int &Version)
const int * Dpids(void) const
virtual int Parse(const uchar *Data, int Length, int Pid)
Parses the given Data, which is a sequence of Length bytes of TS packets.
void SetDebug(bool Debug)
uchar GetByte(void)
Gets the next byte of the TS payload, skipping any intermediate TS header data.
@ nutSliceSegmentBLAWRADL
uint32_t ptsValues[MaxPtsValues]
int getSubtitlingType() const
int DropPayloadStartBytes
bool PesHasLength(const uchar *p)
StructureLoop< Subtitling > subtitlingLoop
void ParseSequenceParameterSet(void)
bool Find(uint32_t Code)
Searches for the four byte sequence given in Code and returns true if it was found within the payload...
void PesDump(const char *Name, const u_char *Data, int Length)
const char * Dlang(int i) const
bool seenIndependentFrame
DescriptorTag getDescriptorTag() const
int PesLength(const uchar *p)
bool TsHasPayload(const uchar *p)
static void SetBrokenLink(uchar *Data, int Length)
bool TsIsScrambled(const uchar *p)
@ ISO639LanguageDescriptorTag
uchar * GetPat(void)
Returns a pointer to the PAT section, which consists of exactly one TS packet.
DescriptorLoop streamDescriptors
void ProcessPayload(unsigned char *Payload, int size, bool PayloadStart, sPayloadInfo &Info)
void ParseSliceHeader(void)
int lastIFrameTemporalReference
bool ProcessTSPacket(unsigned char *Packet)
int GetLastIndex(void)
Returns the index into the TS data of the payload byte that has most recently been read.
#define DEFAULTFRAMESPERSECOND
void IncCounter(int &Counter, uchar *TsPacket)
uint16_t CompositionPageId(int i) const
void ParseAccessUnitDelimiter(void)
bool PesHasDts(const uchar *p)
int32_t GetGolombSe(void)
virtual int Parse(const uchar *Data, int Length, int Pid)
Parses the given Data, which is a sequence of Length bytes of TS packets.
void BlockDump(const char *Name, const u_char *Data, int Length)
bool TsPayloadStart(const uchar *p)
void SetVersions(int PatVersion, int PmtVersion)
Sets the version numbers for the generated PAT and PMT, in case this generator is used to,...
int MakeLanguageDescriptor(uchar *Target, const char *Language)
uint16_t ancillaryPageIds[MAXSPIDS]
uint16_t YMDtoMJD(int Y, int M, int D)
uchar * Generate(int Sid)
uchar * AddParentalRatingDescriptor(uchar *p, uchar ParentalRating=0)
void Reset(void)
Resets the parser.
const char * I18nNormalizeLanguageCode(const char *Code)
Returns a 3 letter language code that may not be zero terminated.
int SectionLength(const uchar *Data, int Length)
uchar * GetBuffer(int &OutLength)
uchar TsContinuityCounter(const uchar *p)
void PutTs(const uchar *Data, int Length)
Puts the payload data of the single TS packet at Data into the converter.
static int CmpUint32(const void *p1, const void *p2)
@ SubtitlingDescriptorTag
bool gotSequenceParameterSet
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.
StructureLoop< Association > associationLoop
int IFrameTemporalReferenceOffset(void)
void PesSetPts(uchar *p, int64_t Pts)
int MakeCRC(uchar *Target, const uchar *Data, int Length)
void SetChannel(const cChannel *Channel)
Sets the Channel for which the PAT/PMT shall be generated.
const char * Slang(int i) const
int MakeSubtitlingDescriptor(uchar *Target, const char *Language, uchar SubtitlingType, uint16_t CompositionPageId, uint16_t AncillaryPageId)
void GeneratePmtPid(const cChannel *Channel)
Generates a PMT pid that doesn't collide with any of the actual pids of the Channel.
StructureLoop< Language > languageLoop
uchar subtitlingTypes[MAXSPIDS]
void SetByte(uchar Byte, int Index)
Sets the TS data byte at the given Index to the value Byte.
uint16_t compositionPageIds[MAXSPIDS]
eNaluFillState NaluFillState
int pmtPids[MAX_PMT_PIDS+1]
void GeneratePat(void)
Generates a PAT section for later use with GetPat().
void ParsePmt(const uchar *Data, int Length)
Parses the PMT data from the single TS packet in Data.
void IncEsInfoLength(int Length)
Descriptor * getNext(Iterator &it)
void TsSetPcr(uchar *p, int64_t Pcr)
void TsSetContinuityCounter(uchar *p, uchar Counter)
int64_t PtsDiff(int64_t Pts1, int64_t Pts2)
Returns the difference between two PTS values.
uint32_t GetBits(int Bits)
cPatPmtParser(bool UpdatePrimaryDevice=false)
int iFrameTemporalReferenceOffset
@ nutSliceSegmentTrailingN
ePesHeader AnalyzePesHeader(const uchar *Data, int Count, int &PesPayloadOffset, bool *ContinuationHeader)
void TsDump(const char *Name, const u_char *Data, int Length)
cPatPmtGenerator(const cChannel *Channel=NULL)
const int * Spids(void) const
bool SkipBytes(int Bytes)
Skips the given number of bytes in the payload and returns true if there is still data left to read.
long long int DroppedPackets
int MakeAC3Descriptor(uchar *Target, uchar Type)
void Reset(void)
Resets the converter.
#define TS_PAYLOAD_EXISTS
uchar tempBuffer[TS_SIZE]
uchar pmt[MAX_PMT_TS][TS_SIZE]
int MakeStream(uchar *Target, uchar Type, int Pid)
void SetRepeatLast(void)
Makes the next call to GetPes() return exactly the same data as the last one (provided there was no c...
char slangs[MAXSPIDS][MAXLANGCODE2]
int64_t PesGetPts(const uchar *p)
uint32_t GetGolombUe(void)
int PesPayloadOffset(const uchar *p)
int64_t TsGetPts(const uchar *p, int l)
const uchar * GetPes(int &Length)
Gets a pointer to the complete PES packet, or NULL if the packet is not complete yet.
@ nutSequenceParameterSet
int getVersionNumber() const
@ nutSequenceParameterSet
void TsSetDts(uchar *p, int l, int64_t Dts)
bool SkipPesHeader(void)
Skips all bytes belonging to the PES header of the payload.
bool IndependentFrame(void)
bool PesHasPts(const uchar *p)
int TsSync(const uchar *Data, int Length, const char *File, const char *Function, int Line)
void PutBuffer(uchar *Data, int Length)
const int * Apids(void) const
#define WRN_TS_PACKETS_FOR_FRAME_DETECTOR