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;
897 esyslog(
"ERROR: can't parse PMT");
906 int Pid =
TsPid(Data);
959 esyslog(
"ERROR: out of memory");
968 #define MAXPESLENGTH 0xFFF0
1035 printf(
"--- %s\n", Name);
1036 for (
int i = 0; i < Length; i++) {
1037 if (i && (i % 16) == 0)
1039 printf(
" %02X", Data[i]);
1046 printf(
"%s: %04X", Name, Length);
1047 int n =
min(Length, 20);
1048 for (
int i = 0; i < n; i++)
1049 printf(
" %02X", Data[i]);
1052 n =
max(n, Length - 10);
1053 for (n =
max(n, Length - 10); n < Length; n++)
1054 printf(
" %02X", Data[n]);
1061 TsDump(Name, Data, Length);
1075 virtual int Parse(
const uchar *Data,
int Length,
int Pid) = 0;
1101 virtual int Parse(
const uchar *Data,
int Length,
int Pid);
1129 virtual int Parse(
const uchar *Data,
int Length,
int Pid);
1142 bool SeenPayloadStart =
false;
1143 cTsPayload tsPayload(const_cast<uchar *>(Data), Length, Pid);
1145 SeenPayloadStart =
true;
1151 uint32_t OldScanner =
scanner;
1153 if (!SeenPayloadStart && tsPayload.
AtTsStart())
1163 int TemporalReference = (b1 << 2 ) + ((b2 & 0xC0) >> 6);
1164 uchar FrameType = (b2 >> 3) & 0x07;
1165 if (tsPayload.
Find(0x000001B5)) {
1166 if (((tsPayload.
GetByte() & 0xF0) >> 4) == 0x08) {
1169 if (PictureStructure == 0x02)
1178 lastIFrameTemporalReference = TemporalReference;
1183 static const char FrameTypes[] =
"?IPBD???";
1194 return tsPayload.
Used();
1235 virtual int Parse(
const uchar *Data,
int Length,
int Pid);
1276 return (
byte & (1 <<
bit--)) ? 1 : 0;
1290 for (
int b = 0; !b && z < 32; z++)
1292 return (1 << z) - 1 +
GetBits(z);
1299 if ((v & 0x01) != 0)
1302 return -int32_t(v / 2);
1320 if ((
scanner & 0xFFFFFF00) == 0x00000100) {
1322 switch (NalUnitType) {
1363 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) {
1365 if (chroma_format_idc == 3)
1371 for (
int i = 0; i < ((chroma_format_idc != 3) ? 8 : 12); i++) {
1373 int SizeOfScalingList = (i < 6) ? 16 : 64;
1376 for (
int j = 0; j < SizeOfScalingList; j++) {
1378 NextScale = (LastScale +
GetGolombSe() + 256) % 256;
1380 LastScale = NextScale;
1388 if (pic_order_cnt_type == 0)
1390 else if (pic_order_cnt_type == 1) {
1416 static const char SliceTypes[] =
"PBIpi";
1417 dbgframes(
"%c", SliceTypes[slice_type % 5]);
1450 if (*(uint32_t *)p1 < *(uint32_t *)p2)
return -1;
1451 if (*(uint32_t *)p1 > *(uint32_t *)p2)
return 1;
1464 else if (
type == 0x1B)
1466 else if (
type == 0x04 ||
type == 0x06)
1469 esyslog(
"ERROR: unknown stream type %d (PID %d) in frame detector",
type,
pid);
1482 while (Skipped < Length && (Data[Skipped] !=
TS_SYNC_BYTE || Length - Skipped > TS_SIZE && Data[Skipped + TS_SIZE] !=
TS_SYNC_BYTE))
1484 esyslog(
"ERROR: skipped %d bytes to sync on start of TS packet", Skipped);
1485 return Processed + Skipped;
1490 int Pid =
TsPid(Data);
1555 if (abs(Delta - 3600) <= 1)
1557 else if (Delta % 3003 == 0)
1559 else if (abs(Delta - 1800) <= 1)
1561 else if (Delta == 1501)
1582 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.
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.