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();
373 TsPacket[3] = (TsPacket[3] & 0xF0) | Counter;
374 if (++Counter > 0x0F)
380 if (++Version > 0x1F)
397 Target[i++] = 0xE0 | (Pid >> 8);
420 Target[i++] = *Language++;
421 Target[i++] = *Language++;
422 Target[i++] = *Language++;
423 Target[i++] = SubtitlingType;
424 Target[i++] = CompositionPageId >> 8;
425 Target[i++] = CompositionPageId & 0xFF;
426 Target[i++] = AncillaryPageId >> 8;
427 Target[i++] = AncillaryPageId & 0xFF;
437 Target[Length] = 0x00;
438 for (
const char *End = Language + strlen(Language); Language < End; ) {
439 Target[i++] = *Language++;
440 Target[i++] = *Language++;
441 Target[i++] = *Language++;
443 Target[Length] += 0x04;
444 if (*Language ==
'+')
455 Target[i++] = crc >> 24;
456 Target[i++] = crc >> 16;
457 Target[i++] = crc >> 8;
462 #define P_TSID 0x8008 // pseudo TS ID
463 #define P_PMT_PID 0x0084 // pseudo PMT pid
464 #define MAXPID 0x2000 // the maximum possible number of pids
468 bool Used[
MAXPID] = {
false };
469 #define SETPID(p) { if ((p) >= 0 && (p) < MAXPID) Used[p] = true; }
470 #define SETPIDS(l) { const int *p = l; while (*p) { SETPID(*p); p++; } }
483 memset(
pat, 0xFF,
sizeof(
pat));
491 int PayloadStart = i;
494 int SectionLength = i;
503 p[i++] = 0xE0 | (
pmtPid >> 8);
505 pat[SectionLength] = i - SectionLength - 1 + 4;
514 memset(buf, 0xFF,
sizeof(buf));
517 int Vpid = Channel->
Vpid();
518 int Ppid = Channel->
Ppid();
522 int SectionLength = i;
530 p[i++] = 0xE0 | (Ppid >> 8);
537 for (
int n = 0; Channel->
Apid(n); n++) {
539 const char *Alang = Channel->
Alang(n);
542 for (
int n = 0; Channel->
Dpid(n); n++) {
547 for (
int n = 0; Channel->
Spid(n); n++) {
552 int sl = i - SectionLength - 2 + 4;
553 buf[SectionLength] |= (sl >> 8) & 0x0F;
554 buf[SectionLength + 1] = sl;
631 Data += PayloadOffset;
632 Length -= PayloadOffset;
634 if ((Length -= Data[0] + 1) <= 0)
656 esyslog(
"ERROR: can't parse PAT");
664 Data += PayloadOffset;
665 Length -= PayloadOffset;
669 if ((Length -= Data[0] + 1) <= 0)
673 if (Length <=
int(
sizeof(
pmt))) {
674 memcpy(
pmt, Data, Length);
678 esyslog(
"ERROR: PMT packet length too big (%d byte)!", Length);
690 esyslog(
"ERROR: PMT section length too big (%d byte)!",
pmtSize + Length);
745 char *s =
alangs[NumApids];
795 char *s =
slangs[NumSpids];
829 dpids[NumDpids] = dpid;
915 esyslog(
"ERROR: can't parse PMT");
924 int Pid =
TsPid(Data);
957 int L = (M < 3) ? 1 : 0;
958 return 14956 + D + int((Y - L) * 365.25) + int((M + 1 + L * 12) * 30.6001);
968 *p++ = ParentalRating;
976 uchar *DescriptorsStart;
977 memset(
eit, 0xFF,
sizeof(
eit));
979 time_t t = time(NULL) - 3600;
980 tm *tm = localtime_r(&t, &tm_r);
981 uint16_t MJD =
YMDtoMJD(tm->tm_year, tm->tm_mon + 1, tm->tm_mday);
987 *p++ = 0x10 | (
counter++ & 0x0F);
1018 DescriptorsStart = p;
1021 *(SectionStart - 1) = p - SectionStart + 4;
1022 *(DescriptorsStart - 1) = p - DescriptorsStart;
1024 int crc =
SI::CRC32::crc32((
char *)PayloadStart, p - PayloadStart, 0xFFFFFFFF);
1064 esyslog(
"ERROR: out of memory");
1073 #define MAXPESLENGTH 0xFFF0
1093 memmove(p,
data, 4);
1140 printf(
"--- %s\n", Name);
1141 for (
int i = 0; i < Length; i++) {
1142 if (i && (i % 16) == 0)
1144 printf(
" %02X", Data[i]);
1151 printf(
"%s: %04X", Name, Length);
1152 int n =
min(Length, 20);
1153 for (
int i = 0; i < n; i++)
1154 printf(
" %02X", Data[i]);
1157 n =
max(n, Length - 10);
1158 for (n =
max(n, Length - 10); n < Length; n++)
1159 printf(
" %02X", Data[n]);
1166 TsDump(Name, Data, Length);
1206 virtual int Parse(
const uchar *Data,
int Length,
int Pid);
1234 virtual int Parse(
const uchar *Data,
int Length,
int Pid);
1247 bool SeenPayloadStart =
false;
1250 SeenPayloadStart =
true;
1256 uint32_t OldScanner =
scanner;
1258 if (!SeenPayloadStart && tsPayload.
AtTsStart())
1268 int TemporalReference = (b1 << 2 ) + ((b2 & 0xC0) >> 6);
1269 uchar FrameType = (b2 >> 3) & 0x07;
1270 if (tsPayload.
Find(0x000001B5)) {
1271 if (((tsPayload.
GetByte() & 0xF0) >> 4) == 0x08) {
1274 if (PictureStructure == 0x02)
1288 static const char FrameTypes[] =
"?IPBD???";
1299 return tsPayload.
Used();
1340 virtual int Parse(
const uchar *Data,
int Length,
int Pid);
1381 return (
byte & (1 <<
bit--)) ? 1 : 0;
1395 for (
int b = 0; !b && z < 32; z++)
1397 return (1 << z) - 1 +
GetBits(z);
1404 if ((v & 0x01) != 0)
1407 return -int32_t(v / 2);
1425 if ((
scanner & 0xFFFFFF00) == 0x00000100) {
1427 switch (NalUnitType) {
1468 if (profile_idc == 100 || profile_idc == 110 || profile_idc == 122 || profile_idc == 244 || profile_idc == 44 || profile_idc == 83 || profile_idc == 86 || profile_idc ==118 || profile_idc == 128) {
1470 if (chroma_format_idc == 3)
1476 for (
int i = 0; i < ((chroma_format_idc != 3) ? 8 : 12); i++) {
1478 int SizeOfScalingList = (i < 6) ? 16 : 64;
1481 for (
int j = 0; j < SizeOfScalingList; j++) {
1483 NextScale = (LastScale +
GetGolombSe() + 256) % 256;
1485 LastScale = NextScale;
1493 if (pic_order_cnt_type == 0)
1495 else if (pic_order_cnt_type == 1) {
1521 static const char SliceTypes[] =
"PBIpi";
1522 dbgframes(
"%c", SliceTypes[slice_type % 5]);
1575 virtual int Parse(
const uchar *Data,
int Length,
int Pid);
1593 if ((
scanner & 0xFFFFFF00) == 0x00000100) {
1630 if (*(uint32_t *)p1 < *(uint32_t *)p2)
return -1;
1631 if (*(uint32_t *)p1 > *(uint32_t *)p2)
return 1;
1644 else if (
type == 0x1B)
1646 else if (
type == 0x24)
1651 esyslog(
"ERROR: unknown stream type %d (PID %d) in frame detector",
type,
pid);
1662 if (
int Skipped =
TS_SYNC(Data, Length))
1663 return Processed + Skipped;
1667 int Pid =
TsPid(Data);
1734 else if (abs(Delta - 3600) <= 1)
1736 else if (Delta % 3003 == 0)
1738 else if (abs(Delta - 1800) <= 1)
1740 else if (Delta == 1501)
1761 Processed += Handled;
#define TS_SYNC(Data, Length)
int64_t TsGetDts(const uchar *p, int l)
bool IsPmtPid(int Pid) const
Returns true if Pid the one of the PMT pids as defined by the current PAT.
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
void EnsureSubtitleTrack(void)
Makes sure one of the preferred language subtitle tracks is selected.
bool separate_colour_plane_flag
uchar SubtitlingType(int i) const
bool AtPayloadStart(void)
Returns true if this payload handler is currently pointing to the first byte of a TS packet that star...
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 EnsureAudioTrack(bool Force=false)
Makes sure an audio track is selected that is actually available.
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)
static cDevice * PrimaryDevice(void)
Returns the primary device.
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 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
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
int Used(void)
Returns the number of raw bytes that have already been used (e.g.
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
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)
bool Eof(void) const
Returns true if all available bytes of the TS payload have been processed.
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 ParseSliceHeader(void)
int lastIFrameTemporalReference
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 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)
bool AtTsStart(void)
Returns true if this payload handler is currently pointing to first byte of a TS packet.
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]
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)
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.
int MakeAC3Descriptor(uchar *Target, uchar Type)
void Reset(void)
Resets the converter.
#define TS_PAYLOAD_EXISTS
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...
void ClrAvailableTracks(bool DescriptionsOnly=false, bool IdsOnly=false)
Clears the list of currently available tracks.
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)
const int * Apids(void) const
#define WRN_TS_PACKETS_FOR_FRAME_DETECTOR