319 lines
9.9 KiB
C++
319 lines
9.9 KiB
C++
/// \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;
|
|
}
|
|
}
|
|
}
|