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;
913 esyslog(
"ERROR: can't parse PMT");
922 int Pid =
TsPid(Data);
955 int L = (M < 3) ? 1 : 0;
956 return 14956 + D + int((Y - L) * 365.25) + int((M + 1 + L * 12) * 30.6001);
966 *p++ = ParentalRating;
974 uchar *DescriptorsStart;
975 memset(
eit, 0xFF,
sizeof(
eit));
977 time_t t = time(NULL) - 3600;
978 tm *tm = localtime_r(&t, &tm_r);
979 uint16_t MJD =
YMDtoMJD(tm->tm_year, tm->tm_mon + 1, tm->tm_mday);
985 *p++ = 0x10 | (
counter++ & 0x0F);
1016 DescriptorsStart = p;
1019 *(SectionStart - 1) = p - SectionStart + 4;
1020 *(DescriptorsStart - 1) = p - DescriptorsStart;
1022 int crc =
SI::CRC32::crc32((
char *)PayloadStart, p - PayloadStart, 0xFFFFFFFF);
1062 esyslog(
"ERROR: out of memory");
1071 #define MAXPESLENGTH 0xFFF0 1091 memmove(p,
data, 4);
1138 printf(
"--- %s\n", Name);
1139 for (
int i = 0; i < Length; i++) {
1140 if (i && (i % 16) == 0)
1142 printf(
" %02X", Data[i]);
1149 printf(
"%s: %04X", Name, Length);
1150 int n =
min(Length, 20);
1151 for (
int i = 0; i < n; i++)
1152 printf(
" %02X", Data[i]);
1155 n =
max(n, Length - 10);
1156 for (n =
max(n, Length - 10); n < Length; n++)
1157 printf(
" %02X", Data[n]);
1164 TsDump(Name, Data, Length);
1178 virtual int Parse(
const uchar *Data,
int Length,
int Pid) = 0;
1204 virtual int Parse(
const uchar *Data,
int Length,
int Pid);
1232 virtual int Parse(
const uchar *Data,
int Length,
int Pid);
1245 bool SeenPayloadStart =
false;
1246 cTsPayload tsPayload(const_cast<uchar *>(Data), Length, Pid);
1248 SeenPayloadStart =
true;
1254 uint32_t OldScanner =
scanner;
1256 if (!SeenPayloadStart && tsPayload.
AtTsStart())
1266 int TemporalReference = (b1 << 2 ) + ((b2 & 0xC0) >> 6);
1267 uchar FrameType = (b2 >> 3) & 0x07;
1268 if (tsPayload.
Find(0x000001B5)) {
1269 if (((tsPayload.
GetByte() & 0xF0) >> 4) == 0x08) {
1272 if (PictureStructure == 0x02)
1286 static const char FrameTypes[] =
"?IPBD???";
1297 return tsPayload.
Used();
1338 virtual int Parse(
const uchar *Data,
int Length,
int Pid);
1379 return (
byte & (1 <<
bit--)) ? 1 : 0;
1393 for (
int b = 0; !b && z < 32; z++)
1395 return (1 << z) - 1 +
GetBits(z);
1402 if ((v & 0x01) != 0)
1405 return -int32_t(v / 2);
1423 if ((
scanner & 0xFFFFFF00) == 0x00000100) {
1425 switch (NalUnitType) {
1466 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) {
1468 if (chroma_format_idc == 3)
1474 for (
int i = 0; i < ((chroma_format_idc != 3) ? 8 : 12); i++) {
1476 int SizeOfScalingList = (i < 6) ? 16 : 64;
1479 for (
int j = 0; j < SizeOfScalingList; j++) {
1481 NextScale = (LastScale +
GetGolombSe() + 256) % 256;
1483 LastScale = NextScale;
1491 if (pic_order_cnt_type == 0)
1493 else if (pic_order_cnt_type == 1) {
1519 static const char SliceTypes[] =
"PBIpi";
1520 dbgframes(
"%c", SliceTypes[slice_type % 5]);
1573 virtual int Parse(
const uchar *Data,
int Length,
int Pid);
1591 if ((
scanner & 0xFFFFFF00) == 0x00000100) {
1628 if (*(uint32_t *)p1 < *(uint32_t *)p2)
return -1;
1629 if (*(uint32_t *)p1 > *(uint32_t *)p2)
return 1;
1642 else if (
type == 0x1B)
1644 else if (
type == 0x24)
1649 esyslog(
"ERROR: unknown stream type %d (PID %d) in frame detector",
type,
pid);
1660 if (
int Skipped =
TS_SYNC(Data, Length))
1661 return Processed + Skipped;
1665 int Pid =
TsPid(Data);
1732 else if (abs((int32_t)Delta - 3600) <= 1)
1734 else if (Delta % 3003 == 0)
1736 else if (abs((int32_t)Delta - 1800) <= 1)
1738 else if (Delta == 1501)
1759 Processed += Handled;
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.
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,...
int getVersionNumber() const
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)
void ParsePmt(const uchar *Data, int Length)
Parses the PMT data from the single TS packet in Data.
uint16_t ancillaryPageIds[MAXSPIDS]
virtual int Parse(const uchar *Data, int Length, int Pid)
Parses the given Data, which is a sequence of Length bytes of TS packets.
char alangs[MAXAPIDS][MAXLANGCODE2]
bool IndependentFrame(void)
bool getCurrentNextIndicator() const
bool TsPayloadStart(const uchar *p)
bool gotAccessUnitDelimiter
int MakeLanguageDescriptor(uchar *Target, const char *Language)
bool IsPmtPid(int Pid) const
Returns true if Pid the one of the PMT pids as defined by the current PAT.
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)
bool TsHasPayload(const uchar *p)
StructureLoop< Association > associationLoop
const char * Alang(int i) const
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 getStreamType() const
#define WRN_TS_PACKETS_FOR_FRAME_DETECTOR
const char * Slang(int i) const
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)
const int * Spids(void) 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...
StructureLoop< Subtitling > subtitlingLoop
void ParseSequenceParameterSet(void)
const char * Dlang(int i) const
int64_t TsGetDts(const uchar *p, int l)
int getAncillaryPageId() const
int MakeAC3Descriptor(uchar *Target, uchar Type)
int getSubtitlingType() const
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
uchar pmt[MAX_PMT_TS][TS_SIZE]
bool PesLongEnough(int Length)
const int * Apids(void) const
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 PesLength(const uchar *p)
void PesSetPts(uchar *p, int64_t Pts)
void ParseAccessUnitDelimiter(void)
int lastIFrameTemporalReference
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...
cH264Parser(void)
Sets up a new H.264 parser.
char dlangs[MAXDPIDS][MAXLANGCODE2]
const int * Dpids(void) const
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.
uchar * Generate(int Sid)
StructureLoop< Language > languageLoop
bool Eof(void) const
Returns true if all available bytes of the TS payload have been processed.
#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]
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.
uint16_t CompositionPageId(int i) const
int getSectionNumber() const
uint32_t GetBits(int Bits)
static void SetBrokenLink(uchar *Data, int Length)
uchar SubtitlingType(int i) const
bool seenIndependentFrame
#define MIN_TS_PACKETS_FOR_FRAME_DETECTOR
void EnsureAudioTrack(bool Force=false)
Makes sure an audio track is selected that is actually available.
int getTransportStreamId() const
static cDevice * PrimaryDevice(void)
Returns the primary device.
bool PesHasLength(const uchar *p)
#define TS_SYNC(Data, Length)
int64_t TsGetPts(const uchar *p, int l)
uchar * AddParentalRatingDescriptor(uchar *p, uchar ParentalRating=0)
bool TsIsScrambled(const uchar *p)
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.
DescriptorLoop streamDescriptors
bool gotSequenceParameterSet
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...
uint16_t AncillaryPageId(int i) const
DescriptorTag getDescriptorTag() const
void IncVersion(int &Version)
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)
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.
int getCompositionPageId() const
int getLastSectionNumber() const
bool SkipPesHeader(void)
Skips all bytes belonging to the PES header of the payload.