TS::Packet classes no longer rely on global PMT tracking
This commit is contained in:
parent
7423868de4
commit
3baa8d1524
5 changed files with 63 additions and 36 deletions
|
@ -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,
|
||||||
|
|
|
@ -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;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -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){
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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());
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue