/// \file dtsc_analyser.cpp /// Reads an DTSC file and prints all readable data about it #include #include #include #include #include #include #include #include ///\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::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::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