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) {
41 PesPayloadOffset = 6 + 3 + Data[8];
42 if (Count < PesPayloadOffset)
45 if (ContinuationHeader)
46 *ContinuationHeader = ((Data[6] == 0x80) && !Data[7] && !Data[8]);
55 for (
int i = 0; i < 16; i++) {
56 if (Data[PesPayloadOffset] != 0xFF)
59 if (Count <= ++PesPayloadOffset)
64 if ((Data[PesPayloadOffset] & 0xC0) == 0x40) {
65 PesPayloadOffset += 2;
67 if (Count <= PesPayloadOffset)
71 if (ContinuationHeader)
72 *ContinuationHeader =
false;
74 if ((Data[PesPayloadOffset] & 0xF0) == 0x20) {
76 PesPayloadOffset += 5;
78 else if ((Data[PesPayloadOffset] & 0xF0) == 0x30) {
80 PesPayloadOffset += 10;
82 else if (Data[PesPayloadOffset] == 0x0F) {
86 if (ContinuationHeader)
87 *ContinuationHeader =
true;
92 if (Count < PesPayloadOffset)
98 #define VIDEO_STREAM_S 0xE0
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))
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);
781 char *s =
alangs[NumApids];
831 char *s =
slangs[NumSpids];
865 dpids[NumDpids] = dpid;
949 esyslog(
"ERROR: can't parse PMT");
958 int Pid =
TsPid(Data);
991 int L = (M < 3) ? 1 : 0;
992 return 14956 + D + int((Y - L) * 365.25) + int((M + 1 + L * 12) * 30.6001);
1002 *p++ = ParentalRating;
1008 uchar *PayloadStart;
1009 uchar *SectionStart;
1010 uchar *DescriptorsStart;
1011 memset(
eit, 0xFF,
sizeof(
eit));
1013 time_t t = time(NULL) - 3600;
1014 tm *tm = localtime_r(&t, &tm_r);
1015 uint16_t MJD =
YMDtoMJD(tm->tm_year, tm->tm_mon + 1, tm->tm_mday);
1021 *p++ = 0x10 | (
counter++ & 0x0F);
1052 DescriptorsStart = p;
1055 *(SectionStart - 1) = p - SectionStart + 4;
1056 *(DescriptorsStart - 1) = p - DescriptorsStart;
1058 int crc =
SI::CRC32::crc32((
char *)PayloadStart, p - PayloadStart, 0xFFFFFFFF);
1098 esyslog(
"ERROR: out of memory");
1107 #define MAXPESLENGTH 0xFFF0
1127 memmove(p,
data, 4);
1174 printf(
"--- %s\n", Name);
1175 for (
int i = 0; i < Length; i++) {
1176 if (i && (i % 16) == 0)
1178 printf(
" %02X", Data[i]);
1185 printf(
"%s: %04X", Name, Length);
1186 int n =
min(Length, 20);
1187 for (
int i = 0; i < n; i++)
1188 printf(
" %02X", Data[i]);
1191 n =
max(n, Length - 10);
1192 for (n =
max(n, Length - 10); n < Length; n++)
1193 printf(
" %02X", Data[n]);
1200 TsDump(Name, Data, Length);
1214 virtual int Parse(
const uchar *Data,
int Length,
int Pid) = 0;
1240 virtual int Parse(
const uchar *Data,
int Length,
int Pid);
1268 virtual int Parse(
const uchar *Data,
int Length,
int Pid);
1281 bool SeenPayloadStart =
false;
1282 cTsPayload tsPayload(const_cast<uchar *>(Data), Length, Pid);
1284 SeenPayloadStart =
true;
1290 uint32_t OldScanner =
scanner;
1292 if (!SeenPayloadStart && tsPayload.
AtTsStart())
1302 int TemporalReference = (b1 << 2 ) + ((b2 & 0xC0) >> 6);
1303 uchar FrameType = (b2 >> 3) & 0x07;
1304 if (tsPayload.
Find(0x000001B5)) {
1305 if (((tsPayload.
GetByte() & 0xF0) >> 4) == 0x08) {
1308 if (PictureStructure == 0x02)
1317 lastIFrameTemporalReference = TemporalReference;
1322 static const char FrameTypes[] =
"?IPBD???";
1333 return tsPayload.
Used();
1374 virtual int Parse(
const uchar *Data,
int Length,
int Pid);
1415 return (
byte & (1 <<
bit--)) ? 1 : 0;
1429 for (
int b = 0; !b && z < 32; z++)
1431 return (1 << z) - 1 +
GetBits(z);
1438 if ((v & 0x01) != 0)
1441 return -int32_t(v / 2);
1459 if ((
scanner & 0xFFFFFF00) == 0x00000100) {
1461 switch (NalUnitType) {
1502 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) {
1504 if (chroma_format_idc == 3)
1510 for (
int i = 0; i < ((chroma_format_idc != 3) ? 8 : 12); i++) {
1512 int SizeOfScalingList = (i < 6) ? 16 : 64;
1515 for (
int j = 0; j < SizeOfScalingList; j++) {
1517 NextScale = (LastScale +
GetGolombSe() + 256) % 256;
1519 LastScale = NextScale;
1527 if (pic_order_cnt_type == 0)
1529 else if (pic_order_cnt_type == 1) {
1555 static const char SliceTypes[] =
"PBIpi";
1556 dbgframes(
"%c", SliceTypes[slice_type % 5]);
1609 virtual int Parse(
const uchar *Data,
int Length,
int Pid);
1627 if ((
scanner & 0xFFFFFF00) == 0x00000100) {
1664 if (*(uint32_t *)p1 < *(uint32_t *)p2)
return -1;
1665 if (*(uint32_t *)p1 > *(uint32_t *)p2)
return 1;
1678 else if (
type == 0x1B)
1680 else if (
type == 0x24)
1685 esyslog(
"ERROR: unknown stream type %d (PID %d) in frame detector",
type,
pid);
1696 if (
int Skipped =
TS_SYNC(Data, Length))
1697 return Processed + Skipped;
1701 int Pid =
TsPid(Data);
1768 else if (abs(Delta - 3600) <= 1)
1770 else if (Delta % 3003 == 0)
1772 else if (abs(Delta - 1800) <= 1)
1774 else if (Delta == 1501)
1795 Processed += Handled;
1826 int LastKeepByte = -1;
1835 for (
int i=0; i<size; i++) {
1841 bool DropByte =
false;
1868 if (Payload[i] == 0xFF)
1872 else if (Payload[i] == 0x80)
1879 dsyslog(
"cNaluDumper: Unexpected NALU fill data: %02x", Payload[i]);
1881 if (LastKeepByte == -1)
1893 if (LastKeepByte == -1)
1921 dsyslog(
"cNaluDumper: TS continuity offset %i", Offset);
1965 if (DropThisPayload && HasAdaption)
1969 DropThisPayload =
false;
1972 if (DropThisPayload)
2005 esyslog(
"cNaluStreamProcessor::PutBuffer: New data before old data was processed!");
2028 if (tempLength < TS_SIZE && length > 0)
2050 esyslog(
"ERROR: skipped %d bytes to sync on start of TS packet", Skipped);
2054 OutLength = Skipped;
2086 uchar *OutEnd = Out;
2094 esyslog(
"ERROR: skipped %d bytes to sync on start of TS packet", Skipped);
2098 memcpy(OutEnd,
data, Skipped);
2139 OutLength = (OutEnd - Out);
2140 return OutLength > 0 ? Out : NULL;
uint16_t AncillaryPageId(int i) const
bool ParsePatPmt(const uchar *Data, int Length)
Parses the given Data (which may consist of several TS packets, typically an entire frame) and extrac...
void ParsePat(const uchar *Data, int Length)
Parses the PAT data from the single TS packet in Data.
int Used(void)
Returns the number of raw bytes that have already been used (e.g.
bool separate_colour_plane_flag
uchar GetByte(void)
Gets the next byte of the TS payload, skipping any intermediate TS header data.
const int * Dpids(void) const
uchar subtitlingTypes[MAXSPIDS]
void SetVersions(int PatVersion, int PmtVersion)
Sets the version numbers for the generated PAT and PMT, in case this generator is used to...
bool TsError(const uchar *p)
void SetPid(int Pid, int Type)
Sets the Pid and stream Type to detect frames for.
#define MAX_TS_PACKETS_FOR_VIDEO_FRAME_DETECTION
#define DEFAULTFRAMESPERSECOND
int PesPayloadOffset(const uchar *p)
void IncCounter(int &Counter, uchar *TsPacket)
bool SkipBytes(int Bytes)
Skips the given number of bytes in the payload and returns true if there is still data left to read...
bool TsHasAdaptationField(const uchar *p)
bool getCurrentNextIndicator() const
void ParsePmt(const uchar *Data, int Length)
Parses the PMT data from the single TS packet in Data.
uint16_t ancillaryPageIds[MAXSPIDS]
bool IsPmtPid(int Pid) const
Returns true if Pid the one of the PMT pids as defined by the current PAT.
virtual int Parse(const uchar *Data, int Length, int Pid)
Parses the given Data, which is a sequence of Length bytes of TS packets.
uchar SubtitlingType(int i) const
char alangs[MAXAPIDS][MAXLANGCODE2]
bool IndependentFrame(void)
bool TsPayloadStart(const uchar *p)
bool gotAccessUnitDelimiter
int MakeLanguageDescriptor(uchar *Target, const char *Language)
void GeneratePmtPid(const cChannel *Channel)
Generates a PMT pid that doesn't collide with any of the actual pids of the Channel.
int64_t PesGetPts(const uchar *p)
int Analyze(const uchar *Data, int Length)
Analyzes the TS packets pointed to by Data.
uint16_t YMDtoMJD(int Y, int M, int D)
int getCompositionPageId() const
bool TsHasPayload(const uchar *p)
StructureLoop< Association > associationLoop
uint32_t ptsValues[MaxPtsValues]
StructureLoop< Stream > streamLoop
char slangs[MAXSPIDS][MAXLANGCODE2]
#define TS_ADAPT_FIELD_EXISTS
static u_int32_t crc32(const char *d, int len, u_int32_t CRCvalue)
void IncEsInfoLength(int Length)
int MakeCRC(uchar *Target, const uchar *Data, int Length)
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.
int Vpid(void) const
Returns the video pid as defined by the current PMT, or 0 if no video pid has been detected...
#define WRN_TS_PACKETS_FOR_FRAME_DETECTOR
void SetChannel(const cChannel *Channel)
Sets the Channel for which the PAT/PMT shall be generated.
bool AtPayloadStart(void)
Returns true if this payload handler is currently pointing to the first byte of a TS packet that star...
bool PesHasPts(const uchar *p)
cPatPmtGenerator(const cChannel *Channel=NULL)
int MakeSubtitlingDescriptor(uchar *Target, const char *Language, uchar SubtitlingType, uint16_t CompositionPageId, uint16_t AncillaryPageId)
DescriptorTag getDescriptorTag() const
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...
const char * Dlang(int i) const
StructureLoop< Subtitling > subtitlingLoop
void ParseSequenceParameterSet(void)
int64_t TsGetDts(const uchar *p, int l)
void TsExtendAdaptionField(unsigned char *Packet, int ToLength)
cPatPmtParser * pPatPmtParser
int MakeAC3Descriptor(uchar *Target, uchar Type)
void GeneratePat(void)
Generates a PAT section for later use with GetPat().
bool Find(uint32_t Code)
Searches for the four byte sequence given in Code and returns true if it was found within the payload...
int SectionLength(const uchar *Data, int Length)
int MakeStream(uchar *Target, uchar Type, int Pid)
uchar GetByte(bool Raw=false)
Gets the next data byte.
int iFrameTemporalReferenceOffset
bool Eof(void) const
Returns true if all available bytes of the TS payload have been processed.
uchar pmt[MAX_PMT_TS][TS_SIZE]
const char * Alang(int i) const
bool PesLongEnough(int Length)
void TsSetPcr(uchar *p, int64_t Pcr)
int TsPid(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.
long long int DroppedPackets
cFrameDetector(int Pid=0, int Type=0)
Sets up a frame detector for the given Pid and stream Type.
void ParseSliceHeader(void)
void EnsureSubtitleTrack(void)
Makes sure one of the preferred language subtitle tracks is selected.
#define TS_PAYLOAD_EXISTS
int getSectionNumber() const
int PesLength(const uchar *p)
void PesSetPts(uchar *p, int64_t Pts)
void ParseAccessUnitDelimiter(void)
int lastIFrameTemporalReference
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...
cH264Parser(void)
Sets up a new H.264 parser.
char dlangs[MAXDPIDS][MAXLANGCODE2]
void Reset(void)
Resets the converter.
bool PesHasDts(const uchar *p)
void PesSetDts(uchar *p, int64_t Dts)
void BlockDump(const char *Name, const u_char *Data, int Length)
void TsSetDts(uchar *p, int l, int64_t Dts)
cPatPmtParser(bool UpdatePrimaryDevice=false)
int TsSync(const uchar *Data, int Length, const char *File, const char *Function, int Line)
int GetLastIndex(void)
Returns the index into the TS data of the payload byte that has most recently been read...
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.
void TsDump(const char *Name, const u_char *Data, int Length)
virtual int Parse(const uchar *Data, int Length, int Pid)
Parses the given Data, which is a sequence of Length bytes of TS packets.
int64_t PtsDiff(int64_t Pts1, int64_t Pts2)
Returns the difference between two PTS values.
void PutTs(const uchar *Data, int Length)
Puts the payload data of the single TS packet at Data into the converter.
void ClrAvailableTracks(bool DescriptionsOnly=false, bool IdsOnly=false)
Clears the list of currently available tracks.
ePesHeader AnalyzePesHeader(const uchar *Data, int Count, int &PesPayloadOffset, bool *ContinuationHeader)
int IFrameTemporalReferenceOffset(void)
uchar * GetPmt(int &Index)
Returns a pointer to the Index'th TS packet of the PMT section.
void TsSetContinuityCounter(uchar *p, uchar Counter)
void ProcessPayload(unsigned char *Payload, int size, bool PayloadStart, sPayloadInfo &Info)
uchar * Generate(int Sid)
int getSubtitlingType() const
StructureLoop< Language > languageLoop
#define WRN_TS_PACKETS_FOR_VIDEO_FRAME_DETECTION
int TsGetPayload(const uchar **p)
long long int TotalPackets
void GeneratePmt(const cChannel *Channel)
Generates a PMT section for the given Channel, for later use with GetPmt().
uchar pmt[MAX_SECTION_SIZE]
int32_t GetGolombSe(void)
void TsHidePayload(uchar *p)
uint16_t compositionPageIds[MAXSPIDS]
int getStreamType() const
void PesDump(const char *Name, const u_char *Data, int Length)
int pmtPids[MAX_PMT_PIDS+1]
virtual int Parse(const uchar *Data, int Length, int Pid)
Parses the given Data, which is a sequence of Length bytes of TS packets.
uint32_t GetBits(int Bits)
static void SetBrokenLink(uchar *Data, int Length)
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...
bool seenIndependentFrame
const int * Apids(void) const
bool ProcessTSPacket(unsigned char *Packet)
#define MIN_TS_PACKETS_FOR_FRAME_DETECTOR
void EnsureAudioTrack(bool Force=false)
Makes sure an audio track is selected that is actually available.
static cDevice * PrimaryDevice(void)
Returns the primary device.
int getVersionNumber() const
bool PesHasLength(const uchar *p)
#define TS_SYNC(Data, Length)
int64_t TsGetPts(const uchar *p, int l)
uint16_t CompositionPageId(int i) const
uchar * AddParentalRatingDescriptor(uchar *p, uchar ParentalRating=0)
int getLastSectionNumber() const
bool TsIsScrambled(const uchar *p)
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...
int64_t PesGetDts(const uchar *p)
void SetByte(uchar Byte, int Index)
Sets the TS data byte at the given Index to the value Byte.
int getTransportStreamId() const
DescriptorLoop streamDescriptors
int DropPayloadStartBytes
eNaluFillState NaluFillState
bool gotSequenceParameterSet
const char * Slang(int i) const
uchar TsContinuityCounter(const uchar *p)
void IncVersion(int &Version)
const int * Spids(void) const
const uchar * GetPes(int &Length)
Gets a pointer to the complete PES packet, or NULL if the packet is not complete yet.
uint32_t GetGolombUe(void)
int getAncillaryPageId() const
void SetDebug(bool Debug)
int TsPayloadOffset(const uchar *p)
void SetRepeatLast(void)
Makes the next call to GetPes() return exactly the same data as the last one (provided there was no c...
bool AtTsStart(void)
Returns true if this payload handler is currently pointing to first byte of a TS packet.
void TsSetPts(uchar *p, int l, int64_t Pts)
const char * I18nNormalizeLanguageCode(const char *Code)
Returns a 3 letter language code that may not be zero terminated.
static int CmpUint32(const void *p1, const void *p2)
void PutBuffer(uchar *Data, int Length)
void Reset(void)
Resets the parser.
Descriptor * getNext(Iterator &it)
uchar * GetPat(void)
Returns a pointer to the PAT section, which consists of exactly one TS packet.
uchar * GetBuffer(int &OutLength)
bool SkipPesHeader(void)
Skips all bytes belonging to the PES header of the payload.
uchar tempBuffer[TS_SIZE]