/// \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(){ strBuf.reserve(188); 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{ strBuf = Data.substr(0, 188); Data.erase(0, 188); } 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){ strBuf[1] = (strBuf[1] & 0xE0) + ((NewPID & 0x1F00) >> 8); strBuf[2] = (NewPID & 0x00FF); } /// Gets the PID of a single TS::Packet. /// \return The value of the PID. int TS::Packet::PID(){ return ((strBuf[1] & 0x1F) << 8) + strBuf[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){ strBuf[3] = (strBuf[3] & 0xF0) + (NewContinuity & 0x0F); } /// Gets the Continuity Counter of a single TS::Packet. /// \return The value of the Continuity Counter. int TS::Packet::ContinuityCounter(){ return (strBuf[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 188 - strBuf.size(); } /// Clears a TS::Packet. void TS::Packet::Clear(){ strBuf.resize(4); strBuf[0] = 0x47; strBuf[1] = 0x00; strBuf[2] = 0x00; strBuf[3] = 0x10; } /// 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){ strBuf[3] = (strBuf[3] & 0xCF) + ((NewSelector & 0x03) << 4); if (NewSelector & 0x02){ strBuf[4] = 0x00; }else{ strBuf.resize(4); } } /// 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 ((strBuf[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){ if (strBuf.size() < 12){ strBuf.resize(12); } AdaptationField(3); strBuf[4] = 0x07; strBuf[5] = (strBuf[5] | 0x10); int64_t TmpVal = NewVal / 300; strBuf[6] = (((TmpVal >> 1) >> 24) & 0xFF); strBuf[7] = (((TmpVal >> 1) >> 16) & 0xFF); strBuf[8] = (((TmpVal >> 1) >> 8) & 0xFF); strBuf[9] = ((TmpVal >> 1) & 0xFF); int Remainder = NewVal % 300; strBuf[10] = 0x7E + ((TmpVal & 0x01) << 7) + ((Remainder & 0x0100) >> 8); strBuf[11] = (Remainder & 0x00FF); } /// 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 ( !(strBuf[5] & 0x10)){ return -1; } int64_t Result = 0; Result = (((strBuf[6] << 24) + (strBuf[7] << 16) + (strBuf[8] << 8) + strBuf[9]) << 1) + (strBuf[10] & 0x80 >> 7); Result = Result * 300; Result += ((strBuf[10] & 0x01) << 8 + strBuf[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)strBuf[4]; } /// Prints a packet to stdout, for analyser purposes. void TS::Packet::Print(){ std::cout << "TS Packet: " << (strBuf[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 (strBuf[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){ strBuf[1] |= 0x40; }else{ strBuf[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 (strBuf[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() == 3){ if (strBuf.size() < 6){ strBuf.resize(6); } if ( !strBuf[4]){ strBuf[4] = 1; } if (NewVal){ strBuf[5] |= 0x40; }else{ strBuf[5] &= 0xBF; } }else{ if (strBuf.size() < 6){ strBuf.resize(6); } AdaptationField(3); strBuf[4] = 1; if (NewVal){ strBuf[5] = 0x40; }else{ strBuf[5] = 0x00; } } } /// Transforms the TS::Packet into a standard Program Association Table void TS::Packet::DefaultPAT(){ static int MyCntr = 0; strBuf = std::string(TS::PAT, 188); ContinuityCounter(MyCntr); MyCntr = ((MyCntr + 1) % 0x10); } /// Transforms the TS::Packet into a standard Program Mapping Table void TS::Packet::DefaultPMT(){ static int MyCntr = 0; strBuf = std::string(TS::PMT, 188); ContinuityCounter(MyCntr); MyCntr = ((MyCntr + 1) % 0x10); } /// Generates a string from the contents of the TS::Packet /// \return A string representation of the packet. const char* TS::Packet::ToString(){ if (strBuf.size() != 188){ std::cerr << "Error: Size invalid (" << strBuf.size() << ") Invalid data from this point on." << std::endl; } return strBuf.c_str(); } /// 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, long long unsigned int PTS){ NewLen += (PTS == 1 ? 9 : 14); strBuf += (char)0x00; //PacketStartCodePrefix strBuf += (char)0x00; //PacketStartCodePrefix (Cont) strBuf += (char)0x01; //PacketStartCodePrefix (Cont) strBuf += (char)0xe0; //StreamType Video strBuf += (char)((NewLen & 0xFF00) >> 8); //PES PacketLength strBuf += (char)(NewLen & 0x00FF); //PES PacketLength (Cont) strBuf += (char)0x80; //Reserved + Flags if (PTS != 1){ strBuf += (char)0x80; //PTSOnlyFlag + Flags strBuf += (char)0x05; //PESHeaderDataLength strBuf += (char)(0x20 + ((PTS & 0x1C0000000LL) >> 29) + 1); //PTS strBuf += (char)((PTS & 0x03FC00000LL) >> 22); //PTS (Cont) strBuf += (char)(((PTS & 0x0003F8000LL) >> 14) + 1); //PTS (Cont) strBuf += (char)((PTS & 0x000007F80LL) >> 7); //PTS (Cont) strBuf += (char)(((PTS & 0x00000007FLL) << 1) + 1); //PTS (Cont) }else{ strBuf += (char)0x00; //PTSOnlyFlag + Flags strBuf += (char)0x00; //PESHeaderDataLength } //PesPacket-Wise Prepended Data strBuf += (char)0x00; //NALU StartCode strBuf += (char)0x00; //NALU StartCode (Cont) strBuf += (char)0x00; //NALU StartCode (Cont) strBuf += (char)0x01; //NALU StartCode (Cont) strBuf += (char)0x09; //NALU EndOfPacket (Einde Vorige Packet) strBuf += (char)0xF0; //NALU EndOfPacket (Cont) } /// 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; strBuf += (char)0x00; //PacketStartCodePrefix strBuf += (char)0x00; //PacketStartCodePrefix (Cont) strBuf += (char)0x01; //PacketStartCodePrefix (Cont) strBuf += (char)0xc0; //StreamType Audio strBuf += (char)((NewLen & 0xFF00) >> 8); //PES PacketLength strBuf += (char)(NewLen & 0x00FF); //PES PacketLength (Cont) strBuf += (char)0x80; //Reserved + Flags strBuf += (char)0x80; //PTSOnlyFlag + Flags strBuf += (char)0x05; //PESHeaderDataLength strBuf += (char)(0x20 + ((PTS & 0x1C0000000LL) >> 29) + 1); //PTS strBuf += (char)((PTS & 0x03FC00000LL) >> 22); //PTS (Cont) strBuf += (char)(((PTS & 0x0003F8000LL) >> 14) + 1); //PTS (Cont) strBuf += (char)((PTS & 0x000007F80LL) >> 7); //PTS (Cont) strBuf += (char)(((PTS & 0x00000007FLL) << 1) + 1); //PTS (Cont) } /// 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 toWrite = 188 - strBuf.size(); strBuf += NewVal.substr(0, toWrite); NewVal.erase(0, toWrite); } /// 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 = strBuf[4]; strBuf[4] = Offset + NumBytes - 1; strBuf.resize(5 + Offset + NumBytes - 2); for (int i = 0; i < (NumBytes - 2); i++){ strBuf[5 + Offset + i] = 0xFF; } }else{ AdaptationField(3); strBuf.resize(6); strBuf[4] = (char)(NumBytes - 1); strBuf[5] = (char)0x00; for (int i = 0; i < (NumBytes - 2); i++){ strBuf += (char)0xFF; } } }