154 lines
5.4 KiB
C++
154 lines
5.4 KiB
C++
#include "analyser_dtsc.h"
|
|
#include <mist/h264.h>
|
|
#include <iomanip>
|
|
|
|
void AnalyserDTSC::init(Util::Config &conf){
|
|
Analyser::init(conf);
|
|
JSON::Value opt;
|
|
opt["long"] = "headless";
|
|
opt["short"] = "H";
|
|
opt["help"] = "Parse entire file or streams as a single headless DTSC packet";
|
|
conf.addOption("headless", opt);
|
|
opt.null();
|
|
}
|
|
|
|
AnalyserDTSC::AnalyserDTSC(Util::Config &conf) : Analyser(conf){
|
|
conn = Socket::Connection(1, 0);
|
|
totalBytes = 0;
|
|
headLess = conf.getBool("headless");
|
|
}
|
|
|
|
bool AnalyserDTSC::parsePacket(){
|
|
if (headLess){
|
|
while (conn){
|
|
if (!conn.spool()){Util::sleep(50);}
|
|
}
|
|
std::string dataBuf = conn.Received().remove(conn.Received().bytes(0xFFFFFFFFul));
|
|
DTSC::Scan S((char*)dataBuf.data(), dataBuf.size());
|
|
std::cout << S.toPrettyString() << std::endl;
|
|
return false;
|
|
}
|
|
P.reInit(conn);
|
|
if (conn && !P){
|
|
FAIL_MSG("Invalid DTSC packet @ byte %llu", totalBytes)
|
|
return false;
|
|
}
|
|
if (!conn && !P){
|
|
stop();
|
|
return false;
|
|
}
|
|
|
|
switch (P.getVersion()){
|
|
case DTSC::DTSC_V1:{
|
|
if (detail >= 2){
|
|
std::cout << "DTSCv1 packet: " << P.getScan().toPrettyString() << std::endl;
|
|
}
|
|
break;
|
|
}
|
|
case DTSC::DTSC_V2:{
|
|
mediaTime = P.getTime();
|
|
if (detail >= 2){
|
|
std::cout << "DTSCv2 packet (Track " << P.getTrackId() << ", time " << P.getTime()
|
|
<< "): " << P.getScan().toPrettyString() << std::endl;
|
|
}
|
|
if (detail >= 8){
|
|
char * payDat;
|
|
size_t payLen;
|
|
P.getString("data", payDat, payLen);
|
|
for (uint64_t i = 0; i < payLen; ++i){
|
|
if ((i % 32) == 0){std::cout << std::endl;}
|
|
std::cout << std::hex << std::setw(2) << std::setfill('0') << (unsigned int)payDat[i];
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case DTSC::DTSC_HEAD:{
|
|
if (detail >= 3){
|
|
std::cout << "DTSC header: ";
|
|
DTSC::Meta(P).toPrettyString(std::cout, 0, (detail == 3 ? 0 : (detail == 4 ? 0x01 : (detail == 5 ? 0x03 : 0x07))));
|
|
}
|
|
if (detail == 2){std::cout << "DTSC header: " << P.getScan().toPrettyString() << std::endl;}
|
|
if (detail == 1){
|
|
bool hasH264 = false;
|
|
bool hasAAC = false;
|
|
JSON::Value result;
|
|
std::stringstream issues;
|
|
DTSC::Meta M(P);
|
|
for (std::map<unsigned int, DTSC::Track>::iterator it = M.tracks.begin();
|
|
it != M.tracks.end(); it++){
|
|
JSON::Value track;
|
|
track["kbits"] = (long long)((double)it->second.bps * 8 / 1024);
|
|
track["codec"] = it->second.codec;
|
|
uint32_t shrtest_key = 0xFFFFFFFFul;
|
|
uint32_t longest_key = 0;
|
|
uint32_t shrtest_prt = 0xFFFFFFFFul;
|
|
uint32_t longest_prt = 0;
|
|
uint32_t shrtest_cnt = 0xFFFFFFFFul;
|
|
uint32_t longest_cnt = 0;
|
|
for (std::deque<DTSC::Key>::iterator k = it->second.keys.begin();
|
|
k != it->second.keys.end(); k++){
|
|
if (!k->getLength()){continue;}
|
|
if (k->getLength() > longest_key){longest_key = k->getLength();}
|
|
if (k->getLength() < shrtest_key){shrtest_key = k->getLength();}
|
|
if (k->getParts() > longest_cnt){longest_cnt = k->getParts();}
|
|
if (k->getParts() < shrtest_cnt){shrtest_cnt = k->getParts();}
|
|
if (k->getParts()){
|
|
if ((k->getLength() / k->getParts()) > longest_prt){
|
|
longest_prt = (k->getLength() / k->getParts());
|
|
}
|
|
if ((k->getLength() / k->getParts()) < shrtest_prt){
|
|
shrtest_prt = (k->getLength() / k->getParts());
|
|
}
|
|
}
|
|
}
|
|
track["keys"]["ms_min"] = (long long)shrtest_key;
|
|
track["keys"]["ms_max"] = (long long)longest_key;
|
|
track["keys"]["frame_ms_min"] = (long long)shrtest_prt;
|
|
track["keys"]["frame_ms_max"] = (long long)longest_prt;
|
|
track["keys"]["frames_min"] = (long long)shrtest_cnt;
|
|
track["keys"]["frames_max"] = (long long)longest_cnt;
|
|
if (longest_prt > 500){
|
|
issues << "unstable connection (" << longest_prt << "ms " << it->second.codec
|
|
<< " frame)! ";
|
|
}
|
|
if (shrtest_cnt < 6){
|
|
issues << "unstable connection (" << shrtest_cnt << " " << it->second.codec
|
|
<< " frames in key)! ";
|
|
}
|
|
if (it->second.codec == "AAC"){hasAAC = true;}
|
|
if (it->second.codec == "H264"){hasH264 = true;}
|
|
if (it->second.type == "video"){
|
|
track["width"] = (long long)it->second.width;
|
|
track["height"] = (long long)it->second.height;
|
|
track["fpks"] = it->second.fpks;
|
|
if (it->second.codec == "H264"){
|
|
h264::sequenceParameterSet sps;
|
|
sps.fromDTSCInit(it->second.init);
|
|
h264::SPSMeta spsData = sps.getCharacteristics();
|
|
track["h264"]["profile"] = spsData.profile;
|
|
track["h264"]["level"] = spsData.level;
|
|
}
|
|
}
|
|
result[it->second.getWritableIdentifier()] = track;
|
|
}
|
|
if ((hasAAC || hasH264) && M.tracks.size() > 1){
|
|
if (!hasAAC){issues << "HLS no audio!";}
|
|
if (!hasH264){issues << "HLS no video!";}
|
|
}
|
|
if (issues.str().size()){result["issues"] = issues.str();}
|
|
std::cout << result.toString() << std::endl;
|
|
stop();
|
|
}
|
|
break;
|
|
}
|
|
case DTSC::DTCM:{
|
|
if (detail >= 2){std::cout << "DTCM command: " << P.getScan().toPrettyString() << std::endl;}
|
|
break;
|
|
}
|
|
default: FAIL_MSG("Invalid DTSC packet @ byte %llu", totalBytes); break;
|
|
}
|
|
|
|
totalBytes += P.getDataLen();
|
|
return true;
|
|
}
|
|
|