TS::Packet classes no longer rely on global PMT tracking

This commit is contained in:
Thulinma 2020-08-29 00:54:28 +02:00
parent 7423868de4
commit 3baa8d1524
5 changed files with 63 additions and 36 deletions

View file

@ -27,9 +27,6 @@
"tortor commodo neque, vitae hendrerit nunc sem ut odio." "tortor commodo neque, vitae hendrerit nunc sem ut odio."
#endif #endif
std::set<unsigned int> pmt_pids;
std::map<unsigned int, std::string> stream_pids;
/// A standard Program Association Table, as generated by FFMPEG. /// A standard Program Association Table, as generated by FFMPEG.
/// Seems to be independent of the stream. /// Seems to be independent of the stream.
// 0x47 = sync byte // 0x47 = sync byte
@ -47,6 +44,8 @@ std::map<unsigned int, std::string> stream_pids;
// 0x2AB104B2 = CRC32 // 0x2AB104B2 = CRC32
namespace TS{ namespace TS{
std::map<unsigned int, std::string> stream_pids;
char PAT[188] ={ char PAT[188] ={
0x47, 0x40, 0x00, 0x10, 0x00, 0x00, 0xB0, 0x0D, 0x00, 0x01, 0xC1, 0x00, 0x00, 0x00, 0x01, 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, 0xF0, 0x00, 0x2A, 0xB1, 0x04, 0xB2, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
@ -276,7 +275,7 @@ namespace TS{
/// Prints a packet to stdout, for analyser purposes. /// Prints a packet to stdout, for analyser purposes.
/// If detail level contains bitmask 64, prints raw bytes after packet. /// If detail level contains bitmask 64, prints raw bytes after packet.
std::string Packet::toPrettyString(size_t indent, int detailLevel) const{ std::string Packet::toPrettyString(const std::set<unsigned int> &pidlist, size_t indent, int detailLevel) const{
if (!(*this)){return "[Invalid packet - no sync byte]";} if (!(*this)){return "[Invalid packet - no sync byte]";}
std::stringstream output; std::stringstream output;
output << std::string(indent, ' ') << "[PID " << getPID() << "|" << std::hex output << std::string(indent, ' ') << "[PID " << getPID() << "|" << std::hex
@ -288,7 +287,7 @@ namespace TS{
case 17: output << "SDT"; break; case 17: output << "SDT"; break;
case 0x1FFF: output << "Null"; break; case 0x1FFF: output << "Null"; break;
default: default:
if (isPMT()){ if (isPMT(pidlist)){
output << "PMT"; output << "PMT";
}else{ }else{
if (isStream()){ if (isStream()){
@ -315,7 +314,7 @@ namespace TS{
return output.str(); return output.str();
} }
if (pmt_pids.count(getPID())){ if (pidlist.count(getPID())){
// PMT // PMT
output << ((ProgramMappingTable *)this)->toPrettyString(indent + 2); output << ((ProgramMappingTable *)this)->toPrettyString(indent + 2);
return output.str(); return output.str();
@ -349,7 +348,7 @@ namespace TS{
/// Returns true if this PID contains a PMT. /// Returns true if this PID contains a PMT.
/// Important caveat: only works if the corresponding PAT has been pretty-printed or had parsePIDs() called on it! /// Important caveat: only works if the corresponding PAT has been pretty-printed or had parsePIDs() called on it!
bool Packet::isPMT() const{return pmt_pids.count(getPID());} bool Packet::isPMT(const std::set<unsigned int> & pidList) const{return pidList.count(getPID());}
/// Returns true if this PID contains a stream known from a PMT. /// Returns true if this PID contains a stream known from a PMT.
/// Important caveat: only works if the corresponding PMT was pretty-printed or had parseStreams() called on it! /// Important caveat: only works if the corresponding PMT was pretty-printed or had parseStreams() called on it!
@ -834,8 +833,8 @@ namespace TS{
((int)(strBuf[loc + 2]) << 8) | strBuf[loc + 3]; ((int)(strBuf[loc + 2]) << 8) | strBuf[loc + 3];
} }
void ProgramAssociationTable::parsePIDs(){ void ProgramAssociationTable::parsePIDs(std::set<unsigned int> & pidlist){
for (int i = 0; i < getProgramCount(); i++){pmt_pids.insert(getProgramPID(i));} for (int i = 0; i < getProgramCount(); i++){pidlist.insert(getProgramPID(i));}
} }
/// This function prints a program association table, /// This function prints a program association table,

View file

@ -17,6 +17,8 @@
/// Holds all TS processing related code. /// Holds all TS processing related code.
namespace TS{ namespace TS{
extern std::map<unsigned int, std::string> stream_pids;
/// Class for reading and writing TS Streams. The class is capable of analyzing a packet of 188 /// Class for reading and writing TS Streams. The class is capable of analyzing a packet of 188
/// bytes and calculating key values /// bytes and calculating key values
class Packet{ class Packet{
@ -60,7 +62,7 @@ namespace TS{
// Helper functions // Helper functions
operator bool() const; operator bool() const;
bool isPMT() const; bool isPMT(const std::set<unsigned int> & pidList) const;
bool isStream() const; bool isStream() const;
void clear(); void clear();
void setDefaultPAT(); void setDefaultPAT();
@ -82,7 +84,7 @@ namespace TS{
static std::string &getPESPS1LeadIn(unsigned int len, unsigned long long PTS, uint64_t bps = 0); static std::string &getPESPS1LeadIn(unsigned int len, unsigned long long PTS, uint64_t bps = 0);
// Printers and writers // Printers and writers
std::string toPrettyString(size_t indent = 0, int detailLevel = 3) const; std::string toPrettyString(const std::set<unsigned int> & pidlist, size_t indent = 0, int detailLevel = 3) const;
const char *getPayload() const; const char *getPayload() const;
int getPayloadLength() const; int getPayloadLength() const;
const char *checkAndGetBuffer() const; const char *checkAndGetBuffer() const;
@ -107,7 +109,7 @@ namespace TS{
short getProgramNumber(short index) const; short getProgramNumber(short index) const;
short getProgramPID(short index) const; short getProgramPID(short index) const;
int getCRC() const; int getCRC() const;
void parsePIDs(); void parsePIDs(std::set<unsigned int> & pidlist);
std::string toPrettyString(size_t indent) const; std::string toPrettyString(size_t indent) const;
}; };

View file

@ -15,7 +15,7 @@ tthread::recursive_mutex tMutex;
namespace TS{ namespace TS{
bool Assembler::assemble(Stream & TSStrm, char * ptr, size_t len){ bool Assembler::assemble(Stream & TSStrm, char * ptr, size_t len, bool parse){
bool ret = false; bool ret = false;
size_t offset = 0; size_t offset = 0;
size_t amount = 188-leftData.size(); size_t amount = 188-leftData.size();
@ -26,9 +26,13 @@ namespace TS{
//Success! //Success!
leftData.append(ptr, amount); leftData.append(ptr, amount);
tsBuf.FromPointer(leftData); tsBuf.FromPointer(leftData);
TSStrm.add(tsBuf); if (!ret && tsBuf.getUnitStart()){ret = true;}
ret = true; if (parse){
if (!TSStrm.isDataTrack(tsBuf.getPID())){TSStrm.parse(tsBuf.getPID());} TSStrm.parse(tsBuf, 0);
}else{
TSStrm.add(tsBuf);
if (!TSStrm.isDataTrack(tsBuf.getPID())){TSStrm.parse(tsBuf.getPID());}
}
offset = amount; offset = amount;
leftData.assign(0,0); leftData.assign(0,0);
} }
@ -45,9 +49,13 @@ namespace TS{
} }
if (offset + 188 <= len){ if (offset + 188 <= len){
tsBuf.FromPointer(ptr + offset); tsBuf.FromPointer(ptr + offset);
TSStrm.add(tsBuf); if (!ret && tsBuf.getUnitStart()){ret = true;}
if (!TSStrm.isDataTrack(tsBuf.getPID())){TSStrm.parse(tsBuf.getPID());} if (parse){
ret = true; TSStrm.parse(tsBuf, 0);
}else{
TSStrm.add(tsBuf);
if (!TSStrm.isDataTrack(tsBuf.getPID())){TSStrm.parse(tsBuf.getPID());}
}
}else{ }else{
leftData.assign(ptr + offset, len - offset); leftData.assign(ptr + offset, len - offset);
} }
@ -182,7 +190,7 @@ namespace TS{
uint32_t tid = newPack.getPID(); uint32_t tid = newPack.getPID();
bool unitStart = newPack.getUnitStart(); bool unitStart = newPack.getUnitStart();
static uint32_t wantPrev = 0; static uint32_t wantPrev = 0;
bool wantTrack = ((wantPrev == tid) || (tid == 0 || newPack.isPMT() || pidToCodec.count(tid))); bool wantTrack = ((wantPrev == tid) || (tid == 0 || newPack.isPMT(pmtTracks) || pidToCodec.count(tid)));
if (!wantTrack){return;} if (!wantTrack){return;}
if (psCacheTid != tid || !psCache){ if (psCacheTid != tid || !psCache){
psCache = &(pesStreams[tid]); psCache = &(pesStreams[tid]);
@ -217,14 +225,9 @@ namespace TS{
// Handle PAT packets // Handle PAT packets
if (tid == 0){ if (tid == 0){
///\todo Keep track of updates in PAT instead of keeping only the last PAT as a reference ///\todo Keep track of updates in PAT instead of keeping only the last PAT as a reference
associationTable = psCache->back(); associationTable = psCache->back();
associationTable.parsePIDs();
lastPAT = Util::bootSecs(); lastPAT = Util::bootSecs();
associationTable.parsePIDs(pmtTracks);
size_t pmtCount = associationTable.getProgramCount();
for (size_t i = 0; i < pmtCount; i++){pmtTracks.insert(associationTable.getProgramPID(i));}
pesStreams.erase(0); pesStreams.erase(0);
psCacheTid = 0; psCacheTid = 0;
psCache = 0; psCache = 0;
@ -285,7 +288,8 @@ namespace TS{
void Stream::parse(Packet &newPack, uint64_t bytePos){ void Stream::parse(Packet &newPack, uint64_t bytePos){
add(newPack, bytePos); add(newPack, bytePos);
if (newPack.getUnitStart()){parse(newPack.getPID());} unsigned int pid = newPack.getPID();
if (!pid || newPack.getUnitStart()){parse(pid);}
} }
bool Stream::hasPacketOnEachTrack() const{ bool Stream::hasPacketOnEachTrack() const{
@ -335,7 +339,9 @@ namespace TS{
} }
for (std::map<size_t, uint32_t>::const_iterator i = seenUnitStart.begin(); i != seenUnitStart.end(); i++){ for (std::map<size_t, uint32_t>::const_iterator i = seenUnitStart.begin(); i != seenUnitStart.end(); i++){
if (pidToCodec.count(i->first) && i->second > 1){return true;} if (pidToCodec.count(i->first) && i->second > 1){
return true;
}
} }
return false; return false;
@ -907,7 +913,21 @@ namespace TS{
} }
} }
if (packTrack){getPacket(packTrack, pack);} if (packTrack){
getPacket(packTrack, pack);
return;
}
//Nothing yet...? Let's see if we can parse something.
for (std::map<size_t, uint32_t>::const_iterator i = seenUnitStart.begin(); i != seenUnitStart.end(); i++){
if (pidToCodec.count(i->first) && i->second > 1){
parse(i->first);
if (hasPacket(i->first)){
getPacket(packTrack, pack);
return;
}
}
}
} }
void Stream::initializeMetadata(DTSC::Meta &meta, size_t tid, size_t mappingId){ void Stream::initializeMetadata(DTSC::Meta &meta, size_t tid, size_t mappingId){

View file

@ -45,7 +45,10 @@ namespace TS{
void clear(); void clear();
}; };
class Assembler;
class Stream{ class Stream{
friend class Assembler;
public: public:
Stream(); Stream();
~Stream(); ~Stream();
@ -78,6 +81,8 @@ namespace TS{
ProgramAssociationTable associationTable; ProgramAssociationTable associationTable;
std::map<size_t, ADTSRemainder> remainders; std::map<size_t, ADTSRemainder> remainders;
std::set<unsigned int> pmtTracks;
std::map<size_t, uint64_t> lastPMT; std::map<size_t, uint64_t> lastPMT;
std::map<size_t, ProgramMappingTable> mappingTable; std::map<size_t, ProgramMappingTable> mappingTable;
@ -102,14 +107,12 @@ namespace TS{
std::map<size_t, size_t> rolloverCount; std::map<size_t, size_t> rolloverCount;
std::map<size_t, unsigned long long> lastms; std::map<size_t, unsigned long long> lastms;
std::set<size_t> pmtTracks;
void parsePES(size_t tid, bool finished = false); void parsePES(size_t tid, bool finished = false);
}; };
class Assembler{ class Assembler{
public: public:
bool assemble(Stream & TSStrm, char * ptr, size_t len); bool assemble(Stream & TSStrm, char * ptr, size_t len, bool parse = false);
private: private:
Util::ResizeablePointer leftData; Util::ResizeablePointer leftData;
TS::Packet tsBuf; TS::Packet tsBuf;

View file

@ -17,6 +17,9 @@
#include <string> #include <string>
#include <unistd.h> #include <unistd.h>
std::set<unsigned int> pmtTracks;
void AnalyserTS::init(Util::Config &conf){ void AnalyserTS::init(Util::Config &conf){
Analyser::init(conf); Analyser::init(conf);
JSON::Value opt; JSON::Value opt;
@ -68,13 +71,13 @@ bool AnalyserTS::parsePacket(){
} }
payloads.erase(packet.getPID()); payloads.erase(packet.getPID());
} }
if (packet.getPID() == 0){((TS::ProgramAssociationTable *)&packet)->parsePIDs();} if (packet.getPID() == 0){((TS::ProgramAssociationTable *)&packet)->parsePIDs(pmtTracks);}
if (packet.isPMT()){((TS::ProgramMappingTable *)&packet)->parseStreams();} if (packet.isPMT(pmtTracks)){((TS::ProgramMappingTable *)&packet)->parseStreams();}
if ((((detail & 2) && !packet.isStream()) || ((detail & 4) && packet.isStream())) && if ((((detail & 2) && !packet.isStream()) || ((detail & 4) && packet.isStream())) &&
(!pidOnly || packet.getPID() == pidOnly)){ (!pidOnly || packet.getPID() == pidOnly)){
std::cout << packet.toPrettyString(0, detail); std::cout << packet.toPrettyString(pmtTracks, 0, detail);
} }
if (packet.getPID() >= 0x10 && !packet.isPMT() && packet.getPID() != 17 && if (packet.getPID() >= 0x10 && !packet.isPMT(pmtTracks) && packet.getPID() != 17 &&
(payloads[packet.getPID()].size() || packet.getUnitStart())){ (payloads[packet.getPID()].size() || packet.getUnitStart())){
payloads[packet.getPID()].append(packet.getPayload(), packet.getPayloadLength()); payloads[packet.getPID()].append(packet.getPayload(), packet.getPayloadLength());
} }