From 6813f00b093aa563226045131611778d4bab231c Mon Sep 17 00:00:00 2001 From: Erik Zandvliet Date: Mon, 22 Oct 2012 15:09:24 +0200 Subject: [PATCH] Initial commit --- lib/Makefile.am | 2 +- lib/nal.cpp | 71 ++++++++++ lib/nal.h | 14 ++ lib/ts_packet.cpp | 349 ++++++++++++++++++++++++++++++++++++++++++++++ lib/ts_packet.h | 147 +++++++++++++++++++ 5 files changed, 582 insertions(+), 1 deletion(-) create mode 100644 lib/nal.cpp create mode 100644 lib/nal.h create mode 100644 lib/ts_packet.cpp create mode 100644 lib/ts_packet.h diff --git a/lib/Makefile.am b/lib/Makefile.am index d3c0bfc6..9d92098f 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -9,4 +9,4 @@ pkgconfigdir = $(libdir)/pkgconfig pkgconfig_DATA = mist-1.0.pc library_includedir=$(includedir)/mist-1.0/mist -library_include_HEADERS = amf.h auth.h base64.h config.h dtsc.h flv_tag.h http_parser.h json.h procs.h rtmpchunks.h socket.h mp4.h ftp.h filesystem.h stream.h timing.h +library_include_HEADERS = amf.h auth.h base64.h config.h dtsc.h flv_tag.h http_parser.h json.h procs.h rtmpchunks.h socket.h mp4.h ftp.h filesystem.h stream.h timing.h nal.h ts_packet.h diff --git a/lib/nal.cpp b/lib/nal.cpp new file mode 100644 index 00000000..dfbc34b4 --- /dev/null +++ b/lib/nal.cpp @@ -0,0 +1,71 @@ +#include "nal.h" + +NAL_Unit::NAL_Unit( ) { + +} + +NAL_Unit::NAL_Unit( std::string & InputData ) { + ReadData( InputData ); +} + +bool NAL_Unit::ReadData( std::string & InputData ) { + std::string FullAnnexB; + FullAnnexB += (char)0x00; + FullAnnexB += (char)0x00; + FullAnnexB += (char)0x00; + FullAnnexB += (char)0x01; + std::string ShortAnnexB; + ShortAnnexB += (char)0x00; + ShortAnnexB += (char)0x00; + ShortAnnexB += (char)0x01; +// fprintf( stderr, "NAL_Unit::ReadData --- DataSize: %d\n", InputData.size() ); + if( InputData.size() < 3 ) { return false; } + bool AnnexB = false; + if( InputData.substr(0,3) == ShortAnnexB ) { AnnexB = true; } + if( InputData.substr(0,4) == FullAnnexB ) { InputData.erase(0,1); AnnexB = true; } + if( AnnexB ) { + MyData = ""; + InputData.erase(0,3);//Intro Bytes + bool FinalByteRead = false; + int Location = std::min( InputData.find( ShortAnnexB ), InputData.find( FullAnnexB ) ); + MyData = InputData.substr(0,Location); + InputData.erase(0,Location); + } else { + if( InputData.size() < 4 ) { return false; } + int UnitLen = (InputData[0] << 24) + (InputData[1] << 16) + (InputData[2] << 8) + InputData[3]; + if( InputData.size() < 4+UnitLen ) { return false; } + InputData.erase(0,4);//Remove Length + MyData = InputData.substr(0,UnitLen); + InputData.erase(0,UnitLen);//Remove this unit from the string + } + return true; +} + +std::string NAL_Unit::AnnexB( bool LongIntro ) { + std::string Result; + if( MyData.size() ) { + if( LongIntro ) { Result += (char)0x00; } + Result += (char)0x00; + Result += (char)0x00; + Result += (char)0x01;//Annex B Lead-In + Result += MyData; + } + return Result; +} + +std::string NAL_Unit::SizePrepended( ) { + std::string Result; + if( MyData.size() ) { + int DataSize = MyData.size(); + Result += (char)( ( DataSize & 0xFF000000 ) >> 24 ); + Result += (char)( ( DataSize & 0x00FF0000 ) >> 16 ); + Result += (char)( ( DataSize & 0x0000FF00 ) >> 8 ); + Result += (char)( DataSize & 0x000000FF );//Size Lead-In + Result += MyData; + } + return Result; +} + +int NAL_Unit::Type( ) { + return ( MyData[0] & 0x1F ); +} diff --git a/lib/nal.h b/lib/nal.h new file mode 100644 index 00000000..b129f479 --- /dev/null +++ b/lib/nal.h @@ -0,0 +1,14 @@ +#include +#include + +class NAL_Unit { + public: + NAL_Unit( ); + NAL_Unit( std::string & InputData ); + bool ReadData( std::string & InputData ); + std::string AnnexB( bool LongIntro = false ); + std::string SizePrepended( ); + int Type( ); + private: + std::string MyData; +};//NAL_Unit class diff --git a/lib/ts_packet.cpp b/lib/ts_packet.cpp new file mode 100644 index 00000000..bdec17ce --- /dev/null +++ b/lib/ts_packet.cpp @@ -0,0 +1,349 @@ +/// \file ts_packet.cpp +/// Holds all code for the TS namespace. + +#include "ts_packet.h" + +/// This constructor creates an empty TS::Packet, ready for use for either reading or writing. +/// All this constructor does is call TS::Packet::Clear(). +TS::Packet::Packet() { Clear( ); } + +/// This function fills a TS::Packet from provided Data. +/// It fills the content with the first 188 bytes of Data. +/// \param Data The data to be read into the packet. +/// \return true if it was possible to read in a full packet, false otherwise. +bool TS::Packet::FromString( std::string & Data ) { + if( Data.size() < 188 ) { + return false; + } else { + for( int i = 0; i < 188; i++ ) { Buffer[i] = Data[i]; } + Data.erase(0,188); + Free = 0; + } + return true; +} + +/// The deconstructor deletes all space that may be occupied by a TS::Packet. +TS::Packet::~Packet() { } + +/// Sets the PID of a single TS::Packet. +/// \param NewPID The new PID of the packet. +void TS::Packet::PID( int NewPID ) { + Buffer[1] = (Buffer[1] & 0xE0) + ((NewPID & 0x1F00) >> 8 ); + Buffer[2] = (NewPID & 0x00FF); + Free = std::min( Free, 184 ); +} + +/// Gets the PID of a single TS::Packet. +/// \return The value of the PID. +int TS::Packet::PID() { + return (( Buffer[1] & 0x1F ) << 8 ) + Buffer[2]; +} + +/// Sets the Continuity Counter of a single TS::Packet. +/// \param NewContinuity The new Continuity Counter of the packet. +void TS::Packet::ContinuityCounter( int NewContinuity ) { + Buffer[3] = ( Buffer[3] & 0xF0 ) + ( NewContinuity & 0x0F ); + Free = std::min( Free, 184 ); +} + +/// Gets the Continuity Counter of a single TS::Packet. +/// \return The value of the Continuity Counter. +int TS::Packet::ContinuityCounter() { + return ( Buffer[3] & 0x0F ); +} + +/// Gets the amount of bytes that are not written yet in a TS::Packet. +/// \return The amount of bytes that can still be written to this packet. +int TS::Packet::BytesFree( ) { + return Free; +} + +/// Clears a TS::Packet. +void TS::Packet::Clear( ) { + Free = 184; + Buffer[0] = 0x47; + for( int i = 1; i < 188; i++ ) { Buffer[i] = 0x00; } + AdaptationField( 1 ); +} + +/// Sets the selection value for an adaptationfield of a TS::Packet. +/// \param NewSelector The new value of the selection bits. +/// - 1: No AdaptationField. +/// - 2: AdaptationField Only. +/// - 3: AdaptationField followed by Data. +void TS::Packet::AdaptationField( int NewSelector ) { + Buffer[3] = ( Buffer[3] & 0xCF ) + ((NewSelector & 0x03) << 4); + Buffer[4] = 0; + Free = std::min( Free, 184 ); +} + +/// Gets whether a TS::Packet contains an adaptationfield. +/// \return The existence of an adaptationfield. +/// - 0: No adaptationfield present. +/// - 1: Adaptationfield is present. +int TS::Packet::AdaptationField( ) { + return ((Buffer[3] & 0x30) >> 4 ); +} + +/// Sets the PCR (Program Clock Reference) of a TS::Packet. +/// \param NewVal The new PCR Value. +void TS::Packet::PCR( int64_t NewVal ) { + AdaptationField( 3 ); + Buffer[4] = 7; + Buffer[5] = (Buffer[5] | 0x10 ); + int64_t TmpVal = NewVal / 300; + fprintf( stderr, "\tSetting PCR_Base: %d\n", TmpVal ); + Buffer[6] = (((TmpVal>>1)>>24) & 0xFF); + Buffer[7] = (((TmpVal>>1)>>16) & 0xFF); + Buffer[8] = (((TmpVal>>1)>>8) & 0xFF); + Buffer[9] = ((TmpVal>>1) & 0xFF); + int Remainder = NewVal % 300; + Buffer[10] = 0x7E + ((TmpVal & 0x01)<<7) + ((Remainder & 0x0100) >> 8 ); + Buffer[11] = (Remainder & 0x00FF); + Free = std::min( Free, 176 ); +}; + +/// Gets the PCR (Program Clock Reference) of a TS::Packet. +/// \return The value of the PCR. +int64_t TS::Packet::PCR( ) { + if( !AdaptationField() ) { + return -1; + } + if( !(Buffer[5] & 0x10 ) ) { + return -1; + } + int64_t Result = 0; + Result = (((((((Buffer[6] << 8) + Buffer[7]) << 8) + Buffer[8]) << 8) + Buffer[9]) << 1) + ( Buffer[10] & 0x80 ); + Result = Result * 300; + Result += ((Buffer[10] & 0x01) << 8 + Buffer[11]); + return Result; +} + +/// Gets the current length of the adaptationfield. +/// \return The length of the adaptationfield. +int TS::Packet::AdaptationFieldLen( ) { + if( !AdaptationField() ) { + return -1; + } + return (int)Buffer[4]; +} + +/// Prints a packet to stdout, for analyser purposes. +void TS::Packet::Print( ) { + std::cout << "TS Packet: " << (Buffer[0] == 0x47) + << "\n\tNewUnit: " << UnitStart() + << "\n\tPID: " << PID() + << "\n\tContinuity Counter: " << ContinuityCounter() + << "\n\tAdaption Field: " << AdaptationField() << "\n"; + if( AdaptationField() ) { + std::cout << "\t\tAdaption Field Length: " << AdaptationFieldLen() << "\n"; + if( AdaptationFieldLen() ) { + std::cout << "\t\tRandom Access: " << RandomAccess() << "\n"; + } + if( PCR() != -1 ) { + std::cout << "\t\tPCR: " << PCR() << "( " << (double)PCR() / 27000000 << " s )\n"; + } + } +} + +/// Gets whether a new unit starts in this TS::Packet. +/// \return The start of a new unit. +int TS::Packet::UnitStart( ) { + return ( Buffer[1] & 0x40) >> 6; +} + +/// Sets the start of a new unit in this TS::Packet. +/// \param NewVal The new value for the start of a unit. +void TS::Packet::UnitStart( int NewVal ) { + if( NewVal ) { + Buffer[1] = (Buffer[1] | 0x40); + } else { + Buffer[1] = (Buffer[1] & 0xBF); + } +} + +/// Gets whether this TS::Packet can be accessed at random (indicates keyframe). +/// \return Whether or not this TS::Packet contains a keyframe. +int TS::Packet::RandomAccess( ) { + if( AdaptationField() < 2 ) { + return -1; + } + return ( Buffer[5] & 0x40) >> 6; +} + +/// Sets whether this TS::Packet contains a keyframe +/// \param NewVal Whether or not this TS::Packet contains a keyframe. +void TS::Packet::RandomAccess( int NewVal ) { + if( AdaptationField() ) { + if( Buffer[4] == 0 ) { + Buffer[4] = 1; + } + if( NewVal ) { + Buffer[5] = (Buffer[5] | 0x40); + } else { + Buffer[5] = (Buffer[5] & 0xBF); + } + } else { + AdaptationField( 3 ); + Buffer[4] = 1; + if( NewVal ) { + Buffer[5] = 0x40; + } else { + Buffer[5] = 0x00; + } + + } + Free = std::min( Free, 182 ); +} + +/// Transforms the TS::Packet into a standard Program Association Table +void TS::Packet::DefaultPAT( ) { + static int MyCntr = 0; + std::copy( TS::PAT, TS::PAT + 188, Buffer ); + ContinuityCounter( MyCntr ); + Free = 0; + MyCntr = ( (MyCntr + 1) % 0x10); +} + +/// Transforms the TS::Packet into a standard Program Mapping Table +void TS::Packet::DefaultPMT( ) { + static int MyCntr = 0; + std::copy( TS::PMT, TS::PMT + 188, Buffer ); + ContinuityCounter( MyCntr ); + Free = 0; + MyCntr = ( (MyCntr + 1) % 0x10); +} + +/// Generates a string from the contents of the TS::Packet +/// \return A string representation of the packet. +char* TS::Packet::ToString( ) { + return Buffer; +} + +/// Generates a PES Lead-in for a video frame. +/// Starts at the first Free byte. +/// \param NewLen The length of this video frame. +void TS::Packet::PESVideoLeadIn( int NewLen ) { + static int PTS = 126000; + NewLen += 14; + int Offset = ( 188 - Free ); + Buffer[Offset] = 0x00;//PacketStartCodePrefix + Buffer[Offset+1] = 0x00;//PacketStartCodePrefix (Cont) + Buffer[Offset+2] = 0x01;//PacketStartCodePrefix (Cont) + Buffer[Offset+3] = 0xe0;//StreamType Video + Buffer[Offset+4] = (NewLen & 0xFF00) >> 8;//PES PacketLength + Buffer[Offset+5] = (NewLen & 0x00FF);//PES PacketLength (Cont) + Buffer[Offset+6] = 0x80;//Reserved + Flags + Buffer[Offset+7] = 0x80;//PTSOnlyFlag + Flags + Buffer[Offset+8] = 0x05;//PESHeaderDataLength + Buffer[Offset+9] = 0x20 + ((PTS & 0x1C0000000) >> 29 ) + 1;//PTS + Buffer[Offset+10] = 0x00 + ((PTS & 0x03FC00000) >> 22 );//PTS (Cont) + Buffer[Offset+11] = 0x00 + ((PTS & 0x0003F8000) >> 14 ) + 1;//PTS (Cont) + Buffer[Offset+12] = 0x00 + ((PTS & 0x000007F80) >> 7 );//PTS (Cont) + Buffer[Offset+13] = 0x00 + ((PTS & 0x00000007F) << 1) + 1;//PTS (Cont) + + //PesPacket-Wise Prepended Data + + Buffer[Offset+14] = 0x00;//NALU StartCode + Buffer[Offset+15] = 0x00;//NALU StartCode (Cont) + Buffer[Offset+16] = 0x00;//NALU StartCode (Cont) + Buffer[Offset+17] = 0x01;//NALU StartCode (Cont) + Buffer[Offset+18] = 0x09;//NALU EndOfPacket (Einde Vorige Packet) + Buffer[Offset+19] = 0xF0;//NALU EndOfPacket (Cont) + Free = Free - 20; + PTS += 3003; +} + +/// Generates a PES Lead-in for an audio frame. +/// Starts at the first Free byte. +/// \param NewLen The length of this audio frame. +/// \param PTS The timestamp of the audio frame. +void TS::Packet::PESAudioLeadIn( int NewLen, uint64_t PTS ) { + NewLen += 8; + int Offset = ( 188 - Free ) - 2; + Buffer[Offset] = 0x00;//PacketStartCodePrefix + Buffer[Offset+1] = 0x00;//PacketStartCodePrefix (Cont) + Buffer[Offset+2] = 0x01;//PacketStartCodePrefix (Cont) + Buffer[Offset+3] = 0xc0;//StreamType Video + + Buffer[Offset+4] = (NewLen & 0xFF00) >> 8;//PES PacketLength + Buffer[Offset+5] = (NewLen & 0x00FF);//PES PacketLength (Cont) + Buffer[Offset+6] = 0x80;//Reserved + Flags + Buffer[Offset+7] = 0x80;//PTSOnlyFlag + Flags + Buffer[Offset+8] = 0x05;//PESHeaderDataLength + Buffer[Offset+9] = 0x20 + ((PTS & 0x1C0000000) >> 29 ) + 1;//PTS + Buffer[Offset+10] = 0x00 + ((PTS & 0x03FC00000) >> 22 );//PTS (Cont) + Buffer[Offset+11] = 0x00 + ((PTS & 0x0003F8000) >> 14 ) + 1;//PTS (Cont) + Buffer[Offset+12] = 0x00 + ((PTS & 0x000007F80) >> 7 );//PTS (Cont) + Buffer[Offset+13] = 0x00 + ((PTS & 0x00000007F) << 1) + 1;//PTS (Cont) + Free = Free - 12; +} + +/// Fills the free bytes of the TS::Packet. +/// Stores as many bytes from NewVal as possible in the packet. +/// \param NewVal The data to store in the packet. +void TS::Packet::FillFree( std::string & NewVal ) { + int Offset = 188 - Free; + std::copy( NewVal.begin(), NewVal.begin() + Free, Buffer + Offset ); + NewVal.erase(0,Free); + Free = 0; +} + +/// Adds NumBytes of stuffing to the TS::Packet. +/// \param NumBytes the amount of stuffing bytes. +void TS::Packet::AddStuffing( int NumBytes ) { + if( NumBytes <= 0 ) { return; } + if( AdaptationField( ) == 3 ) { + int Offset = Buffer[4]; + Buffer[4] = Offset + NumBytes - 1; + for( int i = 0; i < ( NumBytes -2 ); i ++ ) { + Buffer[6+Offset+i] = 0xFF; + } + Free -= NumBytes; + } else { + AdaptationField( 3 ); + Buffer[4] = NumBytes - 1; + Buffer[5] = 0x00; + for( int i = 0; i < ( NumBytes -2 ); i ++ ) { + Buffer[6+i] = 0xFF; + } + Free -= NumBytes; + } +} + + +/// Transforms this TS::Packet into a standard Service Description Table +void TS::Packet::FFMpegHeader( ) { + static int MyCntr = 0; + std::copy( TS::SDT, TS::SDT + 188, Buffer ); + ContinuityCounter( MyCntr ); + Free = 0; + MyCntr = ( (MyCntr + 1) % 0x10); +} + +int TS::Packet::PESTimeStamp( ) { + if( !UnitStart( ) ) { return -1; } + int PesOffset = 4; + if( AdaptationField( ) >= 2 ) { PesOffset += 1 + AdaptationFieldLen( ); } + fprintf( stderr, "PES Offset: %d\n", PesOffset ); + fprintf( stderr, "PES StartCode: %0.2X %0.2X %0.2X\n", Buffer[PesOffset], Buffer[PesOffset+1], Buffer[PesOffset+2] ); + int MyTimestamp = (Buffer[PesOffset+9] & 0x0F) >> 1; + MyTimestamp = (MyTimestamp << 8) + Buffer[PesOffset+10]; + MyTimestamp = (MyTimestamp << 7) + ((Buffer[PesOffset+11]) >> 1); + MyTimestamp = (MyTimestamp << 8) + Buffer[PesOffset+12]; + MyTimestamp = (MyTimestamp << 7) + ((Buffer[PesOffset+13]) >> 1); + fprintf( stderr, "PES Timestamp: %d\n", MyTimestamp ); + return MyTimestamp; +} + +int TS::Packet::GetDataOffset( ) { + int Offset = 4; + if( AdaptationField( ) >= 2 ) { + Offset += 1 + AdaptationFieldLen( ); + } + if( UnitStart() ) { + Offset += 8;//Default Header + Flag Bytes + Offset += 1 + Buffer[Offset];//HeaderLengthByte + HeaderLength + } + return Offset; +} diff --git a/lib/ts_packet.h b/lib/ts_packet.h new file mode 100644 index 00000000..0fdc42f7 --- /dev/null +++ b/lib/ts_packet.h @@ -0,0 +1,147 @@ +/// \file ts_packet.h +/// Holds all headers for the TS Namespace. + +#pragma once +#include +#include +#include //for uint64_t +#include +#include +#include +#include + +#include "dtsc.h" + +/// Holds all TS processing related code. +namespace TS { + /// Class for reading and writing TS Streams + class Packet { + public: + Packet(); + ~Packet(); + bool FromString( std::string & Data ); + void PID( int NewPID ); + int PID(); + void ContinuityCounter( int NewContinuity ); + int ContinuityCounter(); + void Clear(); + void PCR( int64_t NewVal ); + int64_t PCR(); + void AdaptationField( int NewVal ); + int AdaptationField( ); + int AdaptationFieldLen( ); + void DefaultPAT(); + void DefaultPMT(); + int UnitStart( ); + void UnitStart( int NewVal ); + int RandomAccess( ); + void RandomAccess( int NewVal ); + int BytesFree(); + + void Print(); + char* ToString(); + void PESVideoLeadIn( int NewLen ); + void PESAudioLeadIn( int NewLen, uint64_t PTS = 0 ); + void FillFree( std::string & PackageData ); + void AddStuffing( int NumBytes ); + void FFMpegHeader( ); + + int PESTimeStamp( ); + int GetDataOffset( ); + private: + int Free; + char Buffer[188];///< The actual data + };//TS::Packet class + + /// Constructs an audio header to be used on each audio frame. + /// The length of this header will ALWAYS be 7 bytes, and has to be + /// prepended on each audio frame. + /// \param FrameLen the length of the current audio frame. + static inline std::string GetAudioHeader( int FrameLen ) { + char StandardHeader[7] = {0xFF,0xF1,0x4C,0x80,0x00,0x1F,0xFC}; + FrameLen += 7; + StandardHeader[3] = ( StandardHeader[3] & 0xFC ) + ( ( FrameLen & 0x00001800 ) >> 11 ); + StandardHeader[4] = ( ( FrameLen & 0x000007F8 ) >> 3 ); + StandardHeader[5] = ( StandardHeader[5] & 0x3F ) + ( ( FrameLen & 0x00000007 ) << 5 ); + return std::string(StandardHeader,7); + } + + /// A standard Program Association Table, as generated by FFMPEG. + /// Seems to be independent of the stream. + static char PAT[188] = { + 0x47,0x40,0x00,0x10, 0x00,0x00,0xB0,0x0D, 0x00,0x01,0xC1,0x00, 0x00,0x00,0x01,0xF0, + 0x00,0x2A,0xB1,0x04, 0xB2,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF, + 0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF, + 0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF, + 0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF, + 0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF, + 0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF, + 0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF, + 0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF, + 0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF, + 0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF, + 0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF + }; + + /// A standard Program Mapping Table, as generated by FFMPEG. + /// Contains both Audio and Video mappings, works also on video- or audio-only streams. + static char PMT[188] = { + 0x47,0x50,0x00,0x10, 0x00,0x02,0xB0,0x1D, 0x00,0x01,0xC1,0x00, 0x00,0xE1,0x00,0xF0, + 0x00,0x1B,0xE1,0x00, 0xF0,0x00,0x0F,0xE1, 0x01,0xF0,0x06,0x0A, 0x04,0x65,0x6E,0x67, + 0x00,0x8D,0x82,0x9A, 0x07,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF, + 0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF, + 0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF, + 0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF, + 0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF, + 0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF, + 0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF, + 0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF, + 0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF, + 0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF + }; + + /// A standard Sevice Description Table, as generated by FFMPEG. + /// Not used in our connector, provided for compatibility means + static char SDT[188] = { + 0x47,0x40,0x11,0x10, 0x00,0x42,0xF0,0x25, 0x00,0x01,0xC1,0x00, 0x00,0x00,0x01,0xFF, + 0x00,0x01,0xFC,0x80, 0x14,0x48,0x12,0x01, 0x06,0x46,0x46,0x6D, 0x70,0x65,0x67,0x09, + 0x53,0x65,0x72,0x76, 0x69,0x63,0x65,0x30, 0x31,0xA7,0x79,0xA0, 0x03,0xFF,0xFF,0xFF, + 0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF, + 0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF, + 0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF, + 0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF, + 0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF, + 0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF, + 0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF, + 0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF, + 0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF + }; + + /// A standard Picture Parameter Set, as generated by FFMPEG. + /// Seems to be stream-independent. + static char PPS[24] = { + 0x00,0x00,0x00,0x01, + 0x27,0x4D,0x40,0x1F, + 0xA9,0x18,0x0A,0x00, + 0xB7,0x60,0x0D,0x40, + 0x40,0x40,0x4C,0x2B, + 0x5E,0xF7,0xC0,0x40 + }; + + /// A standard Sequence Parameter Set, as generated by FFMPEG. + /// Seems to be stream-independent. + static char SPS[8] = { + 0x00,0x00,0x00,0x01, + 0x28,0xCE,0x09,0xC8 + }; + + /// The full Bytesteam Nal-Header. + static char NalHeader[4] = { + 0x00,0x00,0x00,0x01 + }; + + /// The shortened Bytesteam Nal-Header. + static char ShortNalHeader[3] = { + 0x00,0x00,0x01 + }; +};//TS namespace