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);
205 p[ 9] = ((Pts >> 29) & 0x0E) | (p[9] & 0xF1);
207 p[11] = ((Pts >> 14) & 0xFE) | 0x01;
209 p[13] = ((Pts << 1) & 0xFE) | 0x01;
214 p[14] = ((Dts >> 29) & 0x0E) | (p[14] & 0xF1);
216 p[16] = ((Dts >> 14) & 0xFE) | 0x01;
218 p[18] = ((Dts << 1) & 0xFE) | 0x01;
223 int64_t d = Pts2 - Pts1;
243 Setup(Data, Length, Pid);
317 if (Index >= 0 && Index <
length)
323 int OldIndex =
index;
328 Scanner = (Scanner << 8) |
GetByte();
360 TsPacket[3] = (TsPacket[3] & 0xF0) | Counter;
361 if (++Counter > 0x0F)
367 if (++Version > 0x1F)
384 Target[i++] = 0xE0 | (Pid >> 8);
407 Target[i++] = *Language++;
408 Target[i++] = *Language++;
409 Target[i++] = *Language++;
410 Target[i++] = SubtitlingType;
411 Target[i++] = CompositionPageId >> 8;
412 Target[i++] = CompositionPageId & 0xFF;
413 Target[i++] = AncillaryPageId >> 8;
414 Target[i++] = AncillaryPageId & 0xFF;
424 Target[Length] = 0x00;
425 for (
const char *End = Language + strlen(Language); Language < End; ) {
426 Target[i++] = *Language++;
427 Target[i++] = *Language++;
428 Target[i++] = *Language++;
430 Target[Length] += 0x04;
431 if (*Language ==
'+')
442 Target[i++] = crc >> 24;
443 Target[i++] = crc >> 16;
444 Target[i++] = crc >> 8;
449 #define P_TSID 0x8008 // pseudo TS ID
450 #define P_PMT_PID 0x0084 // pseudo PMT pid
451 #define MAXPID 0x2000 // the maximum possible number of pids
455 bool Used[
MAXPID] = {
false };
456 #define SETPID(p) { if ((p) >= 0 && (p) < MAXPID) Used[p] = true; }
457 #define SETPIDS(l) { const int *p = l; while (*p) { SETPID(*p); p++; } }
470 memset(
pat, 0xFF,
sizeof(
pat));
478 int PayloadStart = i;
481 int SectionLength = i;
490 p[i++] = 0xE0 | (
pmtPid >> 8);
492 pat[SectionLength] = i - SectionLength - 1 + 4;
501 memset(buf, 0xFF,
sizeof(buf));
504 int Vpid = Channel->
Vpid();
505 int Ppid = Channel->
Ppid();
509 int SectionLength = i;
517 p[i++] = 0xE0 | (Ppid >> 8);
524 for (
int n = 0; Channel->
Apid(n); n++) {
526 const char *Alang = Channel->
Alang(n);
529 for (
int n = 0; Channel->
Dpid(n); n++) {
534 for (
int n = 0; Channel->
Spid(n); n++) {
539 int sl = i - SectionLength - 2 + 4;
540 buf[SectionLength] |= (sl >> 8) & 0x0F;
541 buf[SectionLength + 1] = sl;
617 Data += PayloadOffset;
618 Length -= PayloadOffset;
620 if ((Length -= Data[0] + 1) <= 0)
642 esyslog(
"ERROR: can't parse PAT");
650 Data += PayloadOffset;
651 Length -= PayloadOffset;
655 if ((Length -= Data[0] + 1) <= 0)
659 if (Length <=
int(
sizeof(
pmt))) {
660 memcpy(
pmt, Data, Length);
664 esyslog(
"ERROR: PMT packet length too big (%d byte)!", Length);
676 esyslog(
"ERROR: PMT section length too big (%d byte)!",
pmtSize + Length);
730 char *s =
alangs[NumApids];
780 char *s =
slangs[NumSpids];
814 dpids[NumDpids] = dpid;
864 esyslog(
"ERROR: can't parse PMT");
873 int Pid =
TsPid(Data);
926 esyslog(
"ERROR: out of memory");
935 #define MAXPESLENGTH 0xFFF0
1002 printf(
"--- %s\n", Name);
1003 for (
int i = 0; i < Length; i++) {
1004 if (i && (i % 16) == 0)
1006 printf(
" %02X", Data[i]);
1013 printf(
"%s: %04X", Name, Length);
1014 int n =
min(Length, 20);
1015 for (
int i = 0; i < n; i++)
1016 printf(
" %02X", Data[i]);
1019 n =
max(n, Length - 10);
1020 for (n =
max(n, Length - 10); n < Length; n++)
1021 printf(
" %02X", Data[n]);
1028 TsDump(Name, Data, Length);
1042 virtual int Parse(
const uchar *Data,
int Length,
int Pid) = 0;
1068 virtual int Parse(
const uchar *Data,
int Length,
int Pid);
1096 virtual int Parse(
const uchar *Data,
int Length,
int Pid);
1109 bool SeenPayloadStart =
false;
1110 cTsPayload tsPayload(const_cast<uchar *>(Data), Length, Pid);
1112 SeenPayloadStart =
true;
1118 uint32_t OldScanner =
scanner;
1120 if (!SeenPayloadStart && tsPayload.
AtTsStart())
1130 int TemporalReference = (b1 << 2 ) + ((b2 & 0xC0) >> 6);
1131 uchar FrameType = (b2 >> 3) & 0x07;
1132 if (tsPayload.
Find(0x000001B5)) {
1133 if (((tsPayload.
GetByte() & 0xF0) >> 4) == 0x08) {
1136 if (PictureStructure == 0x02)
1145 lastIFrameTemporalReference = TemporalReference;
1150 static const char FrameTypes[] =
"?IPBD???";
1161 return tsPayload.
Used();
1202 virtual int Parse(
const uchar *Data,
int Length,
int Pid);
1243 return (
byte & (1 <<
bit--)) ? 1 : 0;
1257 for (
int b = 0; !b && z < 32; z++)
1259 return (1 << z) - 1 +
GetBits(z);
1266 if ((v & 0x01) != 0)
1269 return -int32_t(v / 2);
1287 if ((
scanner & 0xFFFFFF00) == 0x00000100) {
1289 switch (NalUnitType) {
1330 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) {
1332 if (chroma_format_idc == 3)
1338 for (
int i = 0; i < ((chroma_format_idc != 3) ? 8 : 12); i++) {
1340 int SizeOfScalingList = (i < 6) ? 16 : 64;
1343 for (
int j = 0; j < SizeOfScalingList; j++) {
1345 NextScale = (LastScale +
GetGolombSe() + 256) % 256;
1347 LastScale = NextScale;
1355 if (pic_order_cnt_type == 0)
1357 else if (pic_order_cnt_type == 1) {
1383 static const char SliceTypes[] =
"PBIpi";
1384 dbgframes(
"%c", SliceTypes[slice_type % 5]);
1417 if (*(uint32_t *)p1 < *(uint32_t *)p2)
return -1;
1418 if (*(uint32_t *)p1 > *(uint32_t *)p2)
return 1;
1431 else if (
type == 0x1B)
1433 else if (
type == 0x04 ||
type == 0x06)
1436 esyslog(
"ERROR: unknown stream type %d (PID %d) in frame detector",
type,
pid);
1449 while (Skipped < Length && (Data[Skipped] !=
TS_SYNC_BYTE || Length - Skipped > TS_SIZE && Data[Skipped + TS_SIZE] !=
TS_SYNC_BYTE))
1451 esyslog(
"ERROR: skipped %d bytes to sync on start of TS packet", Skipped);
1452 return Processed + Skipped;
1457 int Pid =
TsPid(Data);
1517 if (abs(Delta - 3600) <= 1)
1519 else if (Delta % 3003 == 0)
1521 else if (abs(Delta - 1800) <= 1)
1523 else if (Delta == 1501)
1544 Processed += Handled;
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.
static unsigned char buf(long p)
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.
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.
#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)
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.
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
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 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.
int getSubtitlingType() const
StructureLoop< Language > languageLoop
#define WRN_TS_PACKETS_FOR_VIDEO_FRAME_DETECTION
int TsGetPayload(const uchar **p)
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]
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
#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)
int64_t TsGetPts(const uchar *p, int l)
uint16_t CompositionPageId(int i) const
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
bool gotSequenceParameterSet
const char * Slang(int i) const
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 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.
bool SkipPesHeader(void)
Skips all bytes belonging to the PES header of the payload.