mistserver/src/analysers/dtsc_analyser.cpp

128 lines
5.2 KiB
C++

/// \file dtsc_analyser.cpp
/// Reads an DTSC file and prints all readable data about it
#include <string>
#include <iostream>
#include <sstream>
#include <mist/dtsc.h>
#include <mist/json.h>
#include <mist/config.h>
#include <mist/defines.h>
#include <mist/h264.h>
///\brief Holds everything unique to the analysers.
namespace Analysers {
///\brief Debugging tool for DTSC data.
///
/// Expects DTSC data in a file given on the command line, outputs human-readable information to stderr.
///\param conf The configuration parsed from the commandline.
///\return The return code of the analyser.
int analyseDTSC(Util::Config conf){
DTSC::File F(conf.getString("filename"));
if (!F){
std::cerr << "Not a valid DTSC file" << std::endl;
return 1;
}
if (conf.getBool("compact")){
bool hasH264 = false;
bool hasAAC = false;
JSON::Value result;
std::stringstream issues;
for (std::map<unsigned int, DTSC::Track>::iterator it = F.getMeta().tracks.begin(); it != F.getMeta().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->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) && F.getMeta().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();
return 0;
}
if (F.getMeta().vod || F.getMeta().live){
F.getMeta().toPrettyString(std::cout,0, 0x03);
}
int bPos = 0;
F.seek_bpos(0);
F.parseNext();
while (F.getPacket()){
switch (F.getPacket().getVersion()){
case DTSC::DTSC_V1: {
std::cout << "DTSCv1 packet: " << F.getPacket().getScan().toPrettyString() << std::endl;
break;
}
case DTSC::DTSC_V2: {
std::cout << "DTSCv2 packet (Track " << F.getPacket().getTrackId() << ", time " << F.getPacket().getTime() << "): " << F.getPacket().getScan().toPrettyString() << std::endl;
break;
}
case DTSC::DTSC_HEAD: {
std::cout << "DTSC header: " << F.getPacket().getScan().toPrettyString() << std::endl;
break;
}
case DTSC::DTCM: {
std::cout << "DTCM command: " << F.getPacket().getScan().toPrettyString() << std::endl;
break;
}
default:
DEBUG_MSG(DLVL_WARN,"Invalid dtsc packet @ bpos %d", bPos);
break;
}
bPos = F.getBytePos();
F.parseNext();
}
return 0;
}
}
/// Reads an DTSC file and prints all readable data about it
int main(int argc, char ** argv){
Util::Config conf = Util::Config(argv[0]);
conf.addOption("filename", JSON::fromString("{\"arg_num\":1, \"arg\":\"string\", \"help\":\"Filename of the DTSC file to analyse.\"}"));
conf.addOption("compact", JSON::fromString("{\"short\": \"c\", \"long\": \"compact\", \"help\":\"Filename of the DTSC file to analyse.\"}"));
conf.parseArgs(argc, argv);
return Analysers::analyseDTSC(conf);
} //main