mistserver/src/analysers/analyser_dtsc.cpp

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;
}