This commit is contained in:
DDVTech 2021-09-10 23:44:31 +02:00 committed by Thulinma
parent 5b79f296d6
commit fccf66fba2
280 changed files with 56975 additions and 71885 deletions

View file

@ -12,8 +12,8 @@ Analyser::Analyser(Util::Config &conf){
isActive = &conf.is_active;
}
///Opens the filename. Supports stdin and plain files.
bool Analyser::open(const std::string & filename){
/// Opens the filename. Supports stdin and plain files.
bool Analyser::open(const std::string &filename){
if (filename.size() && filename != "-"){
int fp = ::open(filename.c_str(), O_RDONLY);
if (fp <= 0){
@ -37,10 +37,12 @@ void Analyser::stop(){
/// Prints validation message if needed
Analyser::~Analyser(){
if (validate){std::cout << upTime << ", " << finTime << ", " << (finTime - upTime) << ", " << mediaTime << std::endl;}
if (validate){
std::cout << upTime << ", " << finTime << ", " << (finTime - upTime) << ", " << mediaTime << std::endl;
}
}
///Checks if standard input is still valid.
/// Checks if standard input is still valid.
bool Analyser::isOpen(){
return (*isActive) && std::cin.good();
}
@ -48,9 +50,7 @@ bool Analyser::isOpen(){
/// Main loop for all analysers. Reads packets while not interrupted, parsing and/or printing them.
int Analyser::run(Util::Config &conf){
isActive = &conf.is_active;
if (!open(conf.getString("filename"))){
return 1;
}
if (!open(conf.getString("filename"))){return 1;}
while (conf.is_active && isOpen()){
if (!parsePacket()){
if (isOpen()){
@ -63,7 +63,7 @@ int Analyser::run(Util::Config &conf){
if (validate){
finTime = Util::bootSecs();
//slow down to realtime + 10s
// slow down to realtime + 10s
if (validate && ((finTime - upTime + 10) * 1000 < mediaTime)){
uint32_t sleepMs = mediaTime - (Util::bootSecs() - upTime + 10) * 1000;
if ((finTime - upTime + sleepMs / 1000) >= timeOut){
@ -122,4 +122,3 @@ void Analyser::init(Util::Config &conf){
conf.addOption("detail", opt);
opt.null();
}

View file

@ -38,4 +38,3 @@ protected:
uint64_t finTime; ///< Unix time of last packet received
bool *isActive; ///< Pointer to is_active bool from config
};

View file

@ -21,9 +21,9 @@
StreamData tempSD; // temp global
bool getDelimBlock(std::string &data, std::string name, size_t &blockStart, size_t &blockEnd, std::string delim) {
bool getDelimBlock(std::string &data, std::string name, size_t &blockStart, size_t &blockEnd, std::string delim){
size_t offset = data.find(name);
if (offset == std::string::npos) {
if (offset == std::string::npos){
return false; // name string not found.
}
// expected: delim character BEFORE blockstart.
@ -35,18 +35,18 @@ bool getDelimBlock(std::string &data, std::string name, size_t &blockStart, size
blockEnd = data.find(delim, offset);
// DEBUG_MSG(DLVL_INFO, "offset: %i blockEnd: %i ", offset, blockEnd);
if (blockStart == std::string::npos || blockEnd == std::string::npos) {
if (blockStart == std::string::npos || blockEnd == std::string::npos){
return false; // no start/end quotes found
}
blockEnd++; // include delim
// DEBUG_MSG(DLVL_INFO, "getDelimPos: data.size() %i start %i end %i num %i", data.size(), blockStart,blockEnd,(blockEnd-blockStart) );
// DEBUG_MSG(DLVL_INFO, "getDelimPos: data.size() %i start %i end %i num %i", data.size(), blockStart,blockEnd,(blockEnd-blockStart) );
return true;
}
bool getValueBlock(std::string &data, std::string name, size_t &blockStart, size_t &blockEnd, std::string delim) {
bool getValueBlock(std::string &data, std::string name, size_t &blockStart, size_t &blockEnd, std::string delim){
size_t offset = data.find(name);
if (offset == std::string::npos) {
if (offset == std::string::npos){
return false; // name string not found.
}
blockStart = data.find(delim, offset);
@ -55,31 +55,31 @@ bool getValueBlock(std::string &data, std::string name, size_t &blockStart, size
offset = blockStart; // skip single character!
blockEnd = data.find(delim, offset);
// DEBUG_MSG(DLVL_INFO, "offset: %i blockEnd: %i ", offset, blockEnd);
if (blockStart == std::string::npos || blockEnd == std::string::npos) {
if (blockStart == std::string::npos || blockEnd == std::string::npos){
return false; // no start/end quotes found
}
// DEBUG_MSG(DLVL_INFO, "getValueBlock: data.size() %i start %i end %i num %i", data.size(), blockStart,blockEnd,(blockEnd-blockStart) );
// DEBUG_MSG(DLVL_INFO, "getValueBlock: data.size() %i start %i end %i num %i", data.size(), blockStart,blockEnd,(blockEnd-blockStart) );
return true;
}
bool getString(std::string &data, std::string name, std::string &output) {
bool getString(std::string &data, std::string name, std::string &output){
size_t blockStart = 0;
size_t blockEnd = 0;
if (!getValueBlock(data, name, blockStart, blockEnd, "\"")) {
if (!getValueBlock(data, name, blockStart, blockEnd, "\"")){
// DEBUG_MSG(DLVL_FAIL, "could not find \"%s\" in data block", name.c_str());
return false; // could not find value in this data block.
}
// DEBUG_MSG(DLVL_INFO, "data.size() %i start %i end %i num %i", data.size(), blockStart,blockEnd,(blockEnd-blockStart) )
// DEBUG_MSG(DLVL_INFO, "data.size() %i start %i end %i num %i", data.size(), blockStart,blockEnd,(blockEnd-blockStart) )
output = data.substr(blockStart, (blockEnd - blockStart));
// looks like this function is working as expected
// DEBUG_MSG(DLVL_INFO, "data in getstring %s", (data.substr(blockStart,(blockEnd-blockStart))).c_str());
return true;
}
bool getLong(std::string &data, std::string name, long &output) {
bool getLong(std::string &data, std::string name, long &output){
size_t blockStart, blockEnd;
if (!getValueBlock(data, name, blockStart, blockEnd, "\"")) {
if (!getValueBlock(data, name, blockStart, blockEnd, "\"")){
// DEBUG_MSG(DLVL_FAIL, "could not find \"%s\" in data block", name.c_str());
return false; // could not find value in this data block.
}
@ -89,32 +89,32 @@ bool getLong(std::string &data, std::string name, long &output) {
}
// block expecting separate name and /name occurence, or name and /> before another occurence of <.
bool getBlock(std::string &data, std::string name, int offset, size_t &blockStart, size_t &blockEnd) {
bool getBlock(std::string &data, std::string name, int offset, size_t &blockStart, size_t &blockEnd){
blockStart = data.find("<" + name + ">", offset);
if (blockStart == std::string::npos) {
if (blockStart == std::string::npos){
blockStart = data.find("<" + name + " ", offset); // this considers both valid situations <name> and <name bla="bla"/>
}
if (blockStart == std::string::npos) {
if (blockStart == std::string::npos){
DEBUG_MSG(DLVL_INFO, "no block start found for name: %s at offset: %i", name.c_str(), offset);
return false;
}
blockEnd = data.find("/" + name + ">", blockStart);
if (blockEnd == std::string::npos) {
if (blockEnd == std::string::npos){
blockEnd = data.find("/>", blockStart);
if (blockEnd == std::string::npos) {
if (blockEnd == std::string::npos){
DEBUG_MSG(DLVL_INFO, "no block end found.");
return false;
}
size_t temp = data.find("<", blockStart + 1, (blockEnd - blockStart - 1)); // the +1 is to avoid re-interpreting the starting < //TODO!!
if (temp != std::string::npos) { // all info is epxected between <name ... />
if (temp != std::string::npos){// all info is epxected between <name ... />
DEBUG_MSG(DLVL_FAIL, "block start found before block end. offset: %lu block: %s", temp, data.c_str());
return false;
}
// DEBUG_MSG(DLVL_FAIL, "special block end found");
blockEnd += 2; // position after />
} else {
}else{
blockEnd += name.size() + 2; // position after /name>
}
@ -122,31 +122,33 @@ bool getBlock(std::string &data, std::string name, int offset, size_t &blockStar
return true;
}
bool parseAdaptationSet(std::string &data, std::set<seekPos> &currentPos) {
bool parseAdaptationSet(std::string &data, std::set<seekPos> &currentPos){
// DEBUG_MSG(DLVL_INFO, "Parsing adaptationSet: %s", data.c_str());
size_t offset = 0;
size_t blockStart, blockEnd;
tempSD.trackType = OTHER;
// get value: mimetype //todo: handle this!
std::string mimeType;
if (!getString(data, "mimeType", mimeType)) { // get first occurence of mimeType. --> this will break if multiple mimetypes should be read from
// this block because no offset is provided. solution: use this on a substring containing the
// desired information.
if (!getString(
data, "mimeType",
mimeType)){// get first occurence of mimeType. --> this will break if multiple mimetypes
// should be read from this block because no offset is provided. solution:
// use this on a substring containing the desired information.
DEBUG_MSG(DLVL_FAIL, "mimeType not found");
return false;
}
DEBUG_MSG(DLVL_INFO, "mimeType: %s", mimeType.c_str()); // checked, OK
if (mimeType.find("video") != std::string::npos) { tempSD.trackType = VIDEO; }
if (mimeType.find("audio") != std::string::npos) { tempSD.trackType = AUDIO; }
if (tempSD.trackType == OTHER) {
if (mimeType.find("video") != std::string::npos){tempSD.trackType = VIDEO;}
if (mimeType.find("audio") != std::string::npos){tempSD.trackType = AUDIO;}
if (tempSD.trackType == OTHER){
DEBUG_MSG(DLVL_FAIL, "no audio or video type found. giving up.");
return false;
}
// find an ID within this adaptationSet block.
if (!getBlock(data, (std::string) "Representation", offset, blockStart, blockEnd)) {
if (!getBlock(data, (std::string) "Representation", offset, blockStart, blockEnd)){
DEBUG_MSG(DLVL_FAIL, "Representation not found");
return false;
}
@ -157,7 +159,7 @@ bool parseAdaptationSet(std::string &data, std::set<seekPos> &currentPos) {
DEBUG_MSG(DLVL_INFO, "Representation block: %s", block.c_str());
// check if block is not junk?
if (!getLong(block, "id", tempSD.trackID)) {
if (!getLong(block, "id", tempSD.trackID)){
DEBUG_MSG(DLVL_FAIL, "Representation id not found in block %s", block.c_str());
return false;
}
@ -165,7 +167,7 @@ bool parseAdaptationSet(std::string &data, std::set<seekPos> &currentPos) {
offset = 0;
// get values from SegmentTemplate
if (!getBlock(data, (std::string) "SegmentTemplate", offset, blockStart, blockEnd)) {
if (!getBlock(data, (std::string) "SegmentTemplate", offset, blockStart, blockEnd)){
DEBUG_MSG(DLVL_FAIL, "SegmentTemplate not found");
return false;
}
@ -178,27 +180,28 @@ bool parseAdaptationSet(std::string &data, std::set<seekPos> &currentPos) {
size_t tmpBlockStart = 0;
size_t tmpBlockEnd = 0;
if (!getDelimBlock(tempSD.media, "RepresentationID", tmpBlockStart, tmpBlockEnd, "$")) {
if (!getDelimBlock(tempSD.media, "RepresentationID", tmpBlockStart, tmpBlockEnd, "$")){
DEBUG_MSG(DLVL_FAIL, "Failed to find and replace $RepresentationID$ in %s", tempSD.media.c_str());
return false;
}
tempSD.media.replace(tmpBlockStart, (tmpBlockEnd - tmpBlockStart), "%d");
if (!getDelimBlock(tempSD.media, "Time", tmpBlockStart, tmpBlockEnd, "$")) {
if (!getDelimBlock(tempSD.media, "Time", tmpBlockStart, tmpBlockEnd, "$")){
DEBUG_MSG(DLVL_FAIL, "Failed to find and replace $Time$ in %s", tempSD.media.c_str());
return false;
}
tempSD.media.replace(tmpBlockStart, (tmpBlockEnd - tmpBlockStart), "%d");
if (!getDelimBlock(tempSD.initialization, "RepresentationID", tmpBlockStart, tmpBlockEnd, "$")) {
DEBUG_MSG(DLVL_FAIL, "Failed to find and replace $RepresentationID$ in %s", tempSD.initialization.c_str());
if (!getDelimBlock(tempSD.initialization, "RepresentationID", tmpBlockStart, tmpBlockEnd, "$")){
DEBUG_MSG(DLVL_FAIL, "Failed to find and replace $RepresentationID$ in %s",
tempSD.initialization.c_str());
return false;
}
tempSD.initialization.replace(tmpBlockStart, (tmpBlockEnd - tmpBlockStart), "%d");
// get segment timeline block from within segment template:
size_t blockOffset = 0; // offset should be 0 because this is a new block
if (!getBlock(block, "SegmentTimeline", blockOffset, blockStart, blockEnd)) {
if (!getBlock(block, "SegmentTimeline", blockOffset, blockStart, blockEnd)){
DEBUG_MSG(DLVL_FAIL, "SegmentTimeline block not found");
return false;
}
@ -210,12 +213,12 @@ bool parseAdaptationSet(std::string &data, std::set<seekPos> &currentPos) {
offset = 0;
long long unsigned int totalDuration = 0;
long timeValue;
while (1) {
if (!getBlock(block2, "S", offset, blockStart, blockEnd)) {
if (numS == 0) {
while (1){
if (!getBlock(block2, "S", offset, blockStart, blockEnd)){
if (numS == 0){
DEBUG_MSG(DLVL_FAIL, "no S found within SegmentTimeline");
return false;
} else {
}else{
DEBUG_MSG(DLVL_INFO, "all S found within SegmentTimeline %i", numS);
return true; // break; //escape from while loop (to return true)
}
@ -225,10 +228,10 @@ bool parseAdaptationSet(std::string &data, std::set<seekPos> &currentPos) {
// searching for t(start position)
std::string sBlock = block2.substr(blockStart, (blockEnd - blockStart));
// DEBUG_MSG(DLVL_INFO, "S found. offset: %i blockStart: %i blockend: %i block: %s",offset,blockStart, blockEnd, sBlock.c_str()); //OK!
if (getLong(sBlock, "t", timeValue)) {
if (getLong(sBlock, "t", timeValue)){
totalDuration = timeValue; // reset totalDuration to value of t
}
if (!getLong(sBlock, "d", timeValue)) { // expected duration in every S.
if (!getLong(sBlock, "d", timeValue)){// expected duration in every S.
DEBUG_MSG(DLVL_FAIL, "no d found within S");
return false;
}
@ -250,12 +253,12 @@ bool parseAdaptationSet(std::string &data, std::set<seekPos> &currentPos) {
currentPos.insert(thisPos); // assumes insert copies all data in seekPos struct.
totalDuration += timeValue; // update totalDuration
offset = blockEnd; // blockEnd and blockStart are absolute values within string, offset is not relevant.
offset = blockEnd; // blockEnd and blockStart are absolute values within string, offset is not relevant.
}
return true;
}
bool parseXML(std::string &body, std::set<seekPos> &currentPos, std::vector<StreamData> &streamData) {
bool parseXML(std::string &body, std::set<seekPos> &currentPos, std::vector<StreamData> &streamData){
// for all adaptation sets
// representation ID
int numAdaptationSet = 0;
@ -264,24 +267,24 @@ bool parseXML(std::string &body, std::set<seekPos> &currentPos, std::vector<Stre
size_t adaptationSetEnd;
// DEBUG_MSG(DLVL_INFO, "body received: %s", body.c_str());
while (getBlock(body, "AdaptationSet", currentOffset, adaptationSetStart, adaptationSetEnd)) {
while (getBlock(body, "AdaptationSet", currentOffset, adaptationSetStart, adaptationSetEnd)){
tempSD.adaptationSet = numAdaptationSet;
numAdaptationSet++;
DEBUG_MSG(DLVL_INFO, "adaptationSet found. start: %lu end: %lu num: %lu ", adaptationSetStart, adaptationSetEnd,
(adaptationSetEnd - adaptationSetStart));
DEBUG_MSG(DLVL_INFO, "adaptationSet found. start: %lu end: %lu num: %lu ", adaptationSetStart,
adaptationSetEnd, (adaptationSetEnd - adaptationSetStart));
// get substring: from <adaptationSet... to /adaptationSet>
std::string adaptationSet = body.substr(adaptationSetStart, (adaptationSetEnd - adaptationSetStart));
// function was verified: output as expected.
if (!parseAdaptationSet(adaptationSet, currentPos)) {
if (!parseAdaptationSet(adaptationSet, currentPos)){
DEBUG_MSG(DLVL_FAIL, "parseAdaptationSet returned false."); // this also happens in the case of OTHER mimetype. in that case it might be
// desirable to continue searching for valid data instead of quitting.
return false;
}
streamData.push_back(tempSD); // put temp values into adaptation set vector
streamData.push_back(tempSD); // put temp values into adaptation set vector
currentOffset = adaptationSetEnd; // the getblock function should make sure End is at the correct offset.
}
if (numAdaptationSet == 0) {
if (numAdaptationSet == 0){
DEBUG_MSG(DLVL_FAIL, "no adaptationSet found.");
return false;
}
@ -289,44 +292,38 @@ bool parseXML(std::string &body, std::set<seekPos> &currentPos, std::vector<Stre
return true;
}
dashAnalyser::dashAnalyser(Util::Config conf) : analysers(conf) {
dashAnalyser::dashAnalyser(Util::Config conf) : analysers(conf){
port = 80;
url = conf.getString("url");
if (url.substr(0, 7) != "http://") {
if (url.substr(0, 7) != "http://"){
DEBUG_MSG(DLVL_FAIL, "The URL must start with http://");
// return -1;
exit(1);
}
url = url.substr(7); // found problem if url is to short!! it gives out of range when entering http://meh.meh
if((url.find('/') == std::string::npos) || (url.find(".mpd") == std::string::npos))
{
std::cout << "incorrect url"<<std::endl;
if ((url.find('/') == std::string::npos) || (url.find(".mpd") == std::string::npos)){
std::cout << "incorrect url" << std::endl;
mayExecute = false;
return;
}
server = url.substr(0, url.find('/'));
url = url.substr(url.find('/'));
if (server.find(':') != std::string::npos) {
if (server.find(':') != std::string::npos){
port = atoi(server.substr(server.find(':') + 1).c_str());
server = server.substr(0, server.find(':'));
}
startTime = Util::bootSecs();
abortTime = conf.getInteger("abort");
conn.open(server, port, false);
if(!conn.connected())
{
if (!conn.connected()){
mayExecute = false;
return;
}
@ -335,9 +332,7 @@ dashAnalyser::dashAnalyser(Util::Config conf) : analysers(conf) {
DEBUG_MSG(DLVL_INFO, "url %s server: %s port: %d", url.c_str(), server.c_str(), port);
urlPrependStuff = url.substr(0, url.rfind("/") + 1);
DEBUG_MSG(DLVL_INFO, "prepend stuff: %s", urlPrependStuff.c_str());
if (!conn) {
conn.open(server, port, false);
}
if (!conn){conn.open(server, port, false);}
pos = 0;
HTTP::Parser H;
@ -345,7 +340,7 @@ dashAnalyser::dashAnalyser(Util::Config conf) : analysers(conf) {
H.SetHeader("Host", server + ":" + JSON::Value((long long)port).toString());
H.SendRequest(conn);
H.Clean();
while (conn && (!conn.spool() || !H.Read(conn))) {}
while (conn && (!conn.spool() || !H.Read(conn))){}
H.BuildResponse();
currentPos;
@ -356,9 +351,9 @@ dashAnalyser::dashAnalyser(Util::Config conf) : analysers(conf) {
// DEBUG_MSG(DLVL_INFO, "url %s ", url.c_str());
// std::ifstream in(url.c_str());
// std::string s((std::istreambuf_iterator<char>(in)), std::istreambuf_iterator<char>());
if (!parseXML(H.body, currentPos, streamData)) {
if (!parseXML(H.body, currentPos, streamData)){
DEBUG_MSG(DLVL_FAIL, "Manifest parsing failed. body: \n %s", H.body.c_str());
if (conf.getString("mode") == "validate") {
if (conf.getString("mode") == "validate"){
long long int endTime = Util::bootSecs();
std::cout << startTime << ", " << endTime << ", " << (endTime - startTime) << ", " << pos << std::endl;
}
@ -372,7 +367,7 @@ dashAnalyser::dashAnalyser(Util::Config conf) : analysers(conf) {
DEBUG_MSG(DLVL_INFO, "*********");
DEBUG_MSG(DLVL_INFO, "num streams: %lu", streamData.size());
for (unsigned int i = 0; i < streamData.size(); i++) {
for (unsigned int i = 0; i < streamData.size(); i++){
DEBUG_MSG(DLVL_INFO, "");
DEBUG_MSG(DLVL_INFO, "ID in vector %d", i);
DEBUG_MSG(DLVL_INFO, "trackID %ld", streamData[i].trackID);
@ -385,75 +380,74 @@ dashAnalyser::dashAnalyser(Util::Config conf) : analysers(conf) {
DEBUG_MSG(DLVL_INFO, "");
for (unsigned int i = 0; i < streamData.size(); i++) { // get init url
for (unsigned int i = 0; i < streamData.size(); i++){// get init url
static char charBuf[512];
snprintf(charBuf, 512, streamData[i].initialization.c_str(), streamData[i].trackID);
streamData[i].initURL.assign(charBuf);
DEBUG_MSG(DLVL_INFO, "init url for adaptationSet %d trackID %ld: %s ", streamData[i].adaptationSet, streamData[i].trackID,
streamData[i].initURL.c_str());
DEBUG_MSG(DLVL_INFO, "init url for adaptationSet %d trackID %ld: %s ",
streamData[i].adaptationSet, streamData[i].trackID, streamData[i].initURL.c_str());
}
}
bool dashAnalyser::hasInput() {
bool dashAnalyser::hasInput(){
return currentPos.size();
}
bool dashAnalyser::packetReady() {
bool dashAnalyser::packetReady(){
return (abortTime <= 0 || Util::bootSecs() < startTime + abortTime) && (currentPos.size() > 0);
}
dashAnalyser::~dashAnalyser() {
dashAnalyser::~dashAnalyser(){
INFO_MSG("stopped");
}
int dashAnalyser::doAnalyse() {
int dashAnalyser::doAnalyse(){
// DEBUG_MSG(DLVL_INFO, "next url: %s", currentPos.begin()->url.c_str());
// match adaptation set and track id?
int tempID = 0;
for (unsigned int i = 0; i < streamData.size(); i++) {
if (streamData[i].trackID == currentPos.begin()->trackID && streamData[i].adaptationSet == currentPos.begin()->adaptationSet) tempID = i;
for (unsigned int i = 0; i < streamData.size(); i++){
if (streamData[i].trackID == currentPos.begin()->trackID &&
streamData[i].adaptationSet == currentPos.begin()->adaptationSet)
tempID = i;
}
if (!conn) { conn.open(server, port, false); }
if (!conn){conn.open(server, port, false);}
HTTP::Parser H;
H.url = urlPrependStuff;
H.url.append(currentPos.begin()->url);
DEBUG_MSG(DLVL_INFO, "Retrieving segment: %s (%llu-%llu)", H.url.c_str(), currentPos.begin()->seekTime,
currentPos.begin()->seekTime + currentPos.begin()->duration);
DEBUG_MSG(DLVL_INFO, "Retrieving segment: %s (%llu-%llu)", H.url.c_str(),
currentPos.begin()->seekTime, currentPos.begin()->seekTime + currentPos.begin()->duration);
H.SetHeader("Host", server + ":" + JSON::Value((long long)port).toString()); // wut?
H.SendRequest(conn);
// TODO: get response?
H.Clean();
while (conn && (!conn.spool() || !H.Read(conn))) {} // ehm...
while (conn && (!conn.spool() || !H.Read(conn))){}// ehm...
// std::cout << "leh vomi: "<<H.body <<std::endl;
// DEBUG_MSG(DLVL_INFO, "zut: %s", H.body.c_str());
// strBuf[tempID].append(H.body);
if (!H.body.size()) {
if (!H.body.size()){
DEBUG_MSG(DLVL_FAIL, "No data downloaded from %s", H.url.c_str());
// break;
return 0;
}
size_t beforeParse = H.body.size();
MP4::Box mp4Data;
bool mdatSeen = false;
while (mp4Data.read(H.body)) {
if (mp4Data.isType("mdat")) { mdatSeen = true; }
while (mp4Data.read(H.body)){
if (mp4Data.isType("mdat")){mdatSeen = true;}
}
if (!mdatSeen) {
if (!mdatSeen){
DEBUG_MSG(DLVL_FAIL, "No mdat present. Sadface. :-(");
// break;
return 0;
}
if (H.body.size()) {
if (H.body.size()){
DEBUG_MSG(DLVL_FAIL, "%lu bytes left in body. Assuming horrible things...", H.body.size()); //,H.body.c_str());
std::cerr << H.body << std::endl;
if (beforeParse == H.body.size()) {
if (beforeParse == H.body.size()){
// break;
return 0;
}
@ -462,7 +456,7 @@ int dashAnalyser::doAnalyse() {
pos = 1000 * (currentPos.begin()->seekTime + currentPos.begin()->duration) / streamData[tempID].timeScale;
if (conf.getString("mode") == "validate" && (Util::bootSecs() - startTime + 5) * 1000 < pos) {
if (conf.getString("mode") == "validate" && (Util::bootSecs() - startTime + 5) * 1000 < pos){
Util::wait(pos - (Util::bootSecs() - startTime + 5) * 1000);
}
@ -472,18 +466,25 @@ int dashAnalyser::doAnalyse() {
return pos;
}
int main(int argc, char **argv) {
int main(int argc, char **argv){
Util::Config conf = Util::Config(argv[0]);
conf.addOption("mode", JSON::fromString("{\"long\":\"mode\", \"arg\":\"string\", \"short\":\"m\", \"default\":\"analyse\", \"help\":\"What to "
"do with the stream. Valid modes are 'analyse', 'validate', 'output'.\"}"));
conf.addOption("url", JSON::fromString("{\"arg_num\":1, \"arg\":\"string\", \"help\":\"URL to HLS stream index file to retrieve.\"}"));
conf.addOption("abort", JSON::fromString("{\"long\":\"abort\", \"short\":\"a\", \"arg\":\"integer\", \"default\":-1, \"help\":\"Abort after "
"this many seconds of downloading. Negative values mean unlimited, which is the default.\"}"));
conf.addOption(
"detail",
JSON::fromString("{\"long\":\"detail\", \"short\":\"D\", \"arg\":\"num\", \"default\":2, \"help\":\"Detail level of analysis. \"}"));
"mode",
JSON::fromString("{\"long\":\"mode\", \"arg\":\"string\", \"short\":\"m\", "
"\"default\":\"analyse\", \"help\":\"What to "
"do with the stream. Valid modes are 'analyse', 'validate', 'output'.\"}"));
conf.addOption("url", JSON::fromString("{\"arg_num\":1, \"arg\":\"string\", \"help\":\"URL to "
"HLS stream index file to retrieve.\"}"));
conf.addOption("abort",
JSON::fromString("{\"long\":\"abort\", \"short\":\"a\", \"arg\":\"integer\", "
"\"default\":-1, \"help\":\"Abort after "
"this many seconds of downloading. Negative values mean "
"unlimited, which is the default.\"}"));
conf.addOption("detail",
JSON::fromString("{\"long\":\"detail\", \"short\":\"D\", \"arg\":\"num\", "
"\"default\":2, \"help\":\"Detail level of analysis. \"}"));
conf.parseArgs(argc, argv);
conf.activate();
@ -494,20 +495,27 @@ int main(int argc, char **argv) {
return 0;
}
int main2(int argc, char **argv) {
int main2(int argc, char **argv){
Util::Config conf = Util::Config(argv[0]);
conf.addOption("mode", JSON::fromString("{\"long\":\"mode\", \"arg\":\"string\", \"short\":\"m\", \"default\":\"analyse\", \"help\":\"What to "
"do with the stream. Valid modes are 'analyse', 'validate', 'output'.\"}"));
conf.addOption("url", JSON::fromString("{\"arg_num\":1, \"arg\":\"string\", \"help\":\"URL to HLS stream index file to retrieve.\"}"));
conf.addOption("abort", JSON::fromString("{\"long\":\"abort\", \"short\":\"a\", \"arg\":\"integer\", \"default\":-1, \"help\":\"Abort after "
"this many seconds of downloading. Negative values mean unlimited, which is the default.\"}"));
conf.addOption(
"mode",
JSON::fromString("{\"long\":\"mode\", \"arg\":\"string\", \"short\":\"m\", "
"\"default\":\"analyse\", \"help\":\"What to "
"do with the stream. Valid modes are 'analyse', 'validate', 'output'.\"}"));
conf.addOption("url", JSON::fromString("{\"arg_num\":1, \"arg\":\"string\", \"help\":\"URL to "
"HLS stream index file to retrieve.\"}"));
conf.addOption("abort",
JSON::fromString("{\"long\":\"abort\", \"short\":\"a\", \"arg\":\"integer\", "
"\"default\":-1, \"help\":\"Abort after "
"this many seconds of downloading. Negative values mean "
"unlimited, which is the default.\"}"));
conf.parseArgs(argc, argv);
conf.activate();
unsigned int port = 80;
std::string url = conf.getString("url");
if (url.substr(0, 7) != "http://") {
if (url.substr(0, 7) != "http://"){
DEBUG_MSG(DLVL_FAIL, "The URL must start with http://");
return -1;
}
@ -516,7 +524,7 @@ int main2(int argc, char **argv) {
std::string server = url.substr(0, url.find('/'));
url = url.substr(url.find('/'));
if (server.find(':') != std::string::npos) {
if (server.find(':') != std::string::npos){
port = atoi(server.substr(server.find(':') + 1).c_str());
server = server.substr(0, server.find(':'));
}
@ -530,14 +538,14 @@ int main2(int argc, char **argv) {
DEBUG_MSG(DLVL_INFO, "url %s server: %s port: %d", url.c_str(), server.c_str(), port);
std::string urlPrependStuff = url.substr(0, url.rfind("/") + 1);
DEBUG_MSG(DLVL_INFO, "prepend stuff: %s", urlPrependStuff.c_str());
if (!conn) { conn.open(server, port, false); }
if (!conn){conn.open(server, port, false);}
unsigned int pos = 0;
HTTP::Parser H;
H.url = url;
H.SetHeader("Host", server + ":" + JSON::Value((long long)port).toString());
H.SendRequest(conn);
H.Clean();
while (conn && (!conn.spool() || !H.Read(conn))) {}
while (conn && (!conn.spool() || !H.Read(conn))){}
H.BuildResponse();
std::set<seekPos> currentPos;
@ -548,9 +556,9 @@ int main2(int argc, char **argv) {
// DEBUG_MSG(DLVL_INFO, "url %s ", url.c_str());
// std::ifstream in(url.c_str());
// std::string s((std::istreambuf_iterator<char>(in)), std::istreambuf_iterator<char>());
if (!parseXML(H.body, currentPos, streamData)) {
if (!parseXML(H.body, currentPos, streamData)){
DEBUG_MSG(DLVL_FAIL, "Manifest parsing failed. body: \n %s", H.body.c_str());
if (conf.getString("mode") == "validate") {
if (conf.getString("mode") == "validate"){
long long int endTime = Util::bootSecs();
std::cout << startTime << ", " << endTime << ", " << (endTime - startTime) << ", " << pos << std::endl;
}
@ -563,7 +571,7 @@ int main2(int argc, char **argv) {
DEBUG_MSG(DLVL_INFO, "*********");
DEBUG_MSG(DLVL_INFO, "num streams: %lu", streamData.size());
for (unsigned int i = 0; i < streamData.size(); i++) {
for (unsigned int i = 0; i < streamData.size(); i++){
DEBUG_MSG(DLVL_INFO, "");
DEBUG_MSG(DLVL_INFO, "ID in vector %d", i);
DEBUG_MSG(DLVL_INFO, "trackID %ld", streamData[i].trackID);
@ -576,67 +584,69 @@ int main2(int argc, char **argv) {
DEBUG_MSG(DLVL_INFO, "");
for (unsigned int i = 0; i < streamData.size(); i++) { // get init url
for (unsigned int i = 0; i < streamData.size(); i++){// get init url
static char charBuf[512];
snprintf(charBuf, 512, streamData[i].initialization.c_str(), streamData[i].trackID);
streamData[i].initURL.assign(charBuf);
DEBUG_MSG(DLVL_INFO, "init url for adaptationSet %d trackID %ld: %s ", streamData[i].adaptationSet, streamData[i].trackID,
streamData[i].initURL.c_str());
DEBUG_MSG(DLVL_INFO, "init url for adaptationSet %d trackID %ld: %s ",
streamData[i].adaptationSet, streamData[i].trackID, streamData[i].initURL.c_str());
}
while (currentPos.size() && (abortTime <= 0 || Util::bootSecs() < startTime + abortTime)) {
while (currentPos.size() && (abortTime <= 0 || Util::bootSecs() < startTime + abortTime)){
// DEBUG_MSG(DLVL_INFO, "next url: %s", currentPos.begin()->url.c_str());
std::cout << "blaa" << std::endl;
// match adaptation set and track id?
int tempID = 0;
for (unsigned int i = 0; i < streamData.size(); i++) {
if (streamData[i].trackID == currentPos.begin()->trackID && streamData[i].adaptationSet == currentPos.begin()->adaptationSet) tempID = i;
for (unsigned int i = 0; i < streamData.size(); i++){
if (streamData[i].trackID == currentPos.begin()->trackID &&
streamData[i].adaptationSet == currentPos.begin()->adaptationSet)
tempID = i;
}
if (!conn) { conn.open(server, port, false); }
if (!conn){conn.open(server, port, false);}
HTTP::Parser H;
H.url = urlPrependStuff;
H.url.append(currentPos.begin()->url);
DEBUG_MSG(DLVL_INFO, "Retrieving segment: %s (%llu-%llu)", H.url.c_str(), currentPos.begin()->seekTime,
currentPos.begin()->seekTime + currentPos.begin()->duration);
DEBUG_MSG(DLVL_INFO, "Retrieving segment: %s (%llu-%llu)", H.url.c_str(),
currentPos.begin()->seekTime, currentPos.begin()->seekTime + currentPos.begin()->duration);
H.SetHeader("Host", server + ":" + JSON::Value((long long)port).toString()); // wut?
H.SendRequest(conn);
// TODO: get response?
H.Clean();
while (conn && (!conn.spool() || !H.Read(conn))) {} // ehm...
while (conn && (!conn.spool() || !H.Read(conn))){}// ehm...
// std::cout << "leh vomi: "<<H.body <<std::endl;
// DEBUG_MSG(DLVL_INFO, "zut: %s", H.body.c_str());
// strBuf[tempID].append(H.body);
if (!H.body.size()) {
if (!H.body.size()){
DEBUG_MSG(DLVL_FAIL, "No data downloaded from %s", H.url.c_str());
break;
}
size_t beforeParse = H.body.size();
MP4::Box mp4Data;
bool mdatSeen = false;
while (mp4Data.read(H.body)) {
if (mp4Data.isType("mdat")) { mdatSeen = true; }
while (mp4Data.read(H.body)){
if (mp4Data.isType("mdat")){mdatSeen = true;}
}
if (!mdatSeen) {
if (!mdatSeen){
DEBUG_MSG(DLVL_FAIL, "No mdat present. Sadface. :-(");
break;
}
if (H.body.size()) {
if (H.body.size()){
DEBUG_MSG(DLVL_FAIL, "%lu bytes left in body. Assuming horrible things...", H.body.size()); //,H.body.c_str());
std::cerr << H.body << std::endl;
if (beforeParse == H.body.size()) { break; }
if (beforeParse == H.body.size()){break;}
}
H.Clean();
pos = 1000 * (currentPos.begin()->seekTime + currentPos.begin()->duration) / streamData[tempID].timeScale;
if (conf.getString("mode") == "validate" && (Util::bootSecs() - startTime + 5) * 1000 < pos) {
if (conf.getString("mode") == "validate" && (Util::bootSecs() - startTime + 5) * 1000 < pos){
Util::wait(pos - (Util::bootSecs() - startTime + 5) * 1000);
}
currentPos.erase(currentPos.begin());
}
if (conf.getString("mode") == "validate") {
if (conf.getString("mode") == "validate"){
long long int endTime = Util::bootSecs();
std::cout << startTime << ", " << endTime << ", " << (endTime - startTime) << ", " << pos << std::endl;
}

View file

@ -1,5 +1,5 @@
#include <mist/config.h>
#include "analyser.h"
#include <mist/config.h>
#include <set>
struct StreamData{
@ -7,72 +7,62 @@ struct StreamData{
std::string media;
std::string initialization;
std::string initURL;
long trackID;
long trackID;
unsigned int adaptationSet;
unsigned char trackType;
unsigned char trackType;
};
struct seekPos {
struct seekPos{
///\brief Less-than comparison for seekPos structures.
///\param rhs The seekPos to compare with.
///\return Whether this object is smaller than rhs.
bool operator < (const seekPos & rhs) const {
if ((seekTime*rhs.timeScale) < (rhs.seekTime*timeScale)) {
bool operator<(const seekPos &rhs) const{
if ((seekTime * rhs.timeScale) < (rhs.seekTime * timeScale)){
return true;
} else {
if ( (seekTime*rhs.timeScale) == (rhs.seekTime*timeScale)){
}else{
if ((seekTime * rhs.timeScale) == (rhs.seekTime * timeScale)){
if (adaptationSet < rhs.adaptationSet){
return true;
} else if (adaptationSet == rhs.adaptationSet){
if (trackID < rhs.trackID) {
return true;
}
}
}else if (adaptationSet == rhs.adaptationSet){
if (trackID < rhs.trackID){return true;}
}
}
}
return false;
}
long timeScale;
long long unsigned int bytePos; /// ?
long long unsigned int seekTime; ///start
long long unsigned int duration; ///duration
unsigned int trackID; ///stores representation ID
unsigned int adaptationSet; ///stores type
unsigned char trackType; ///stores type
long long unsigned int bytePos; /// ?
long long unsigned int seekTime; /// start
long long unsigned int duration; /// duration
unsigned int trackID; /// stores representation ID
unsigned int adaptationSet; /// stores type
unsigned char trackType; /// stores type
std::string url;
};
class dashAnalyser : public analysers
{
public:
dashAnalyser(Util::Config config);
~dashAnalyser();
bool packetReady();
void PreProcessing();
//int Analyse();
int doAnalyse();
// void doValidate();
bool hasInput();
void PostProcessing();
private:
unsigned int port;
std::string url;
std::string server;
long long int startTime;
long long int abortTime;
Socket::Connection conn;
std::string urlPrependStuff;
unsigned int pos;
std::set<seekPos> currentPos;
std::vector<StreamData> streamData;
class dashAnalyser : public analysers{
public:
dashAnalyser(Util::Config config);
~dashAnalyser();
bool packetReady();
void PreProcessing();
// int Analyse();
int doAnalyse();
// void doValidate();
bool hasInput();
void PostProcessing();
private:
unsigned int port;
std::string url;
std::string server;
long long int startTime;
long long int abortTime;
Socket::Connection conn;
std::string urlPrependStuff;
unsigned int pos;
std::set<seekPos> currentPos;
std::vector<StreamData> streamData;
};

View file

@ -1,6 +1,6 @@
#include "analyser_dtsc.h"
#include <mist/h264.h>
#include <iomanip>
#include <mist/h264.h>
void AnalyserDTSC::init(Util::Config &conf){
Analyser::init(conf);
@ -29,7 +29,7 @@ bool AnalyserDTSC::parsePacket(){
if (!conn.spool()){Util::sleep(50);}
}
std::string dataBuf = conn.Received().remove(conn.Received().bytes(0xFFFFFFFFul));
DTSC::Scan S((char*)dataBuf.data(), dataBuf.size());
DTSC::Scan S((char *)dataBuf.data(), dataBuf.size());
std::cout << S.toPrettyString() << std::endl;
return false;
}
@ -57,7 +57,7 @@ bool AnalyserDTSC::parsePacket(){
<< "): " << P.getScan().toPrettyString() << std::endl;
}
if (detail >= 8){
char * payDat;
char *payDat;
size_t payLen;
P.getString("data", payDat, payLen);
for (uint64_t i = 0; i < payLen; ++i){
@ -70,7 +70,8 @@ bool AnalyserDTSC::parsePacket(){
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))));
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){
@ -79,8 +80,7 @@ bool AnalyserDTSC::parsePacket(){
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++){
for (std::map<unsigned int, DTSC::Track>::iterator it = M.tracks.begin(); it != M.tracks.end(); it++){
JSON::Value track;
track["kbits"] = (uint64_t)((double)it->second.bps * 8 / 1024);
track["codec"] = it->second.codec;
@ -90,8 +90,7 @@ bool AnalyserDTSC::parsePacket(){
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++){
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();}
@ -113,12 +112,10 @@ bool AnalyserDTSC::parsePacket(){
track["keys"]["frames_min"] = shrtest_cnt;
track["keys"]["frames_max"] = longest_cnt;
if (longest_prt > 500){
issues << "unstable connection (" << longest_prt << "ms " << it->second.codec
<< " frame)! ";
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)! ";
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;}
@ -156,4 +153,3 @@ bool AnalyserDTSC::parsePacket(){
totalBytes += P.getDataLen();
return true;
}

View file

@ -14,4 +14,3 @@ private:
Socket::Connection conn;
uint64_t totalBytes;
};

View file

@ -17,7 +17,7 @@ bool AnalyserEBML::parsePacket(){
// Read in smart bursts until we have enough data
while (isOpen() && dataBuffer.size() < neededBytes()){
uint64_t needed = neededBytes();
if (needed > 1024*1024){
if (needed > 1024 * 1024){
dataBuffer.erase(0, 1);
continue;
}
@ -38,38 +38,29 @@ bool AnalyserEBML::parsePacket(){
HIGH_MSG("Read an element at position %d", prePos);
if (detail >= 2){std::cout << E.toPrettyString(depthStash.size() * 2, detail);}
switch (E.getID()){
case EBML::EID_SEGMENT:
segmentOffset = prePos + E.getHeaderLen();
std::cout << "[OFFSET INFORMATION] Segment offset is " << segmentOffset << std::endl;
break;
case EBML::EID_CLUSTER:
std::cout << "[OFFSET INFORMATION] Cluster at " << (prePos-segmentOffset) << std::endl;
break;
case EBML::EID_SEEKID:
lastSeekId = E.getValUInt();
break;
case EBML::EID_SEEKPOSITION:
lastSeekPos = E.getValUInt();
break;
case EBML::EID_INFO:
case EBML::EID_TRACKS:
case EBML::EID_TAGS:
case EBML::EID_CUES:
{
uint32_t sID = E.getID();
std::cout << "Encountered " << sID << std::endl;
if (seekChecks.count(sID)){
std::cout << "[OFFSET INFORMATION] Segment " << EBML::Element::getIDString(sID) << " is at " << prePos << ", expected was " << seekChecks[sID] << std::endl;
}
}
break;
}
if (depthStash.size()){
depthStash.front() -= E.getOuterLen();
}
if (E.getType() == EBML::ELEM_MASTER){
depthStash.push_front(E.getPayloadLen());
case EBML::EID_SEGMENT:
segmentOffset = prePos + E.getHeaderLen();
std::cout << "[OFFSET INFORMATION] Segment offset is " << segmentOffset << std::endl;
break;
case EBML::EID_CLUSTER:
std::cout << "[OFFSET INFORMATION] Cluster at " << (prePos - segmentOffset) << std::endl;
break;
case EBML::EID_SEEKID: lastSeekId = E.getValUInt(); break;
case EBML::EID_SEEKPOSITION: lastSeekPos = E.getValUInt(); break;
case EBML::EID_INFO:
case EBML::EID_TRACKS:
case EBML::EID_TAGS:
case EBML::EID_CUES:{
uint32_t sID = E.getID();
std::cout << "Encountered " << sID << std::endl;
if (seekChecks.count(sID)){
std::cout << "[OFFSET INFORMATION] Segment " << EBML::Element::getIDString(sID) << " is at "
<< prePos << ", expected was " << seekChecks[sID] << std::endl;
}
}break;
}
if (depthStash.size()){depthStash.front() -= E.getOuterLen();}
if (E.getType() == EBML::ELEM_MASTER){depthStash.push_front(E.getPayloadLen());}
while (depthStash.size() && !depthStash.front()){
depthStash.pop_front();
if (lastSeekId){
@ -86,8 +77,9 @@ bool AnalyserEBML::parsePacket(){
}
}
}
seekChecks[lastSeekId] = segmentOffset+lastSeekPos;
std::cout << "[OFFSET INFORMATION] Segment offset for " << EBML::Element::getIDString(lastSeekId) << " (" << lastSeekId << ") is " << (segmentOffset+lastSeekPos) << std::endl;
seekChecks[lastSeekId] = segmentOffset + lastSeekPos;
std::cout << "[OFFSET INFORMATION] Segment offset for " << EBML::Element::getIDString(lastSeekId)
<< " (" << lastSeekId << ") is " << (segmentOffset + lastSeekPos) << std::endl;
lastSeekId = 0;
lastSeekPos = 0;
}
@ -101,4 +93,3 @@ bool AnalyserEBML::parsePacket(){
uint64_t AnalyserEBML::neededBytes(){
return EBML::Element::needBytes(dataBuffer.data(), dataBuffer.size(), true);
}

View file

@ -16,6 +16,5 @@ private:
uint32_t lastSeekId;
uint64_t lastSeekPos;
std::map<uint32_t, uint64_t> seekChecks;
std::deque<uint64_t> depthStash;///<Contains bytes to read to go up a level in the element depth.
std::deque<uint64_t> depthStash; ///< Contains bytes to read to go up a level in the element depth.
};

View file

@ -37,4 +37,3 @@ bool AnalyserFLV::parsePacket(){
mediaTime = flvData.tagTime();
return true;
}

View file

@ -11,4 +11,3 @@ private:
FLV::Tag flvData;
long long filter;
};

View file

@ -35,7 +35,7 @@ bool AnalyserH264::parsePacket(){
size_t size = 0;
h264::nalUnit *nalPtr;
do {
do{
size = 0;
nalPtr = h264::nalFactory(dataBuffer.data(), dataBuffer.size(), size, !sizePrepended);
if (nalPtr){
@ -44,8 +44,8 @@ bool AnalyserH264::parsePacket(){
dataBuffer.erase(0, size); // erase the NAL unit we just read
prePos += size;
}
///\TODO update mediaTime with current timestamp
} while(nalPtr);
///\TODO update mediaTime with current timestamp
}while (nalPtr);
if (!nalPtr){
FAIL_MSG("Could not read a NAL unit at position %llu", prePos);
return false;
@ -58,6 +58,5 @@ uint64_t AnalyserH264::neededBytes(){
if (!sizePrepended){return 1024 * 1024;}
// otherwise, buffer the exact size needed
if (dataBuffer.size() < 4){return 4;}
return Bit::btohl(dataBuffer.data())+4;
return Bit::btohl(dataBuffer.data()) + 4;
}

View file

@ -12,4 +12,3 @@ private:
uint64_t neededBytes();
bool sizePrepended;
};

View file

@ -132,4 +132,3 @@ bool AnalyserHLS::parsePacket(){
}
return false;
}

View file

@ -1,7 +1,7 @@
#include "analyser.h"
#include <fstream>
#include <mist/http_parser.h>
#include <mist/downloader.h>
#include <mist/http_parser.h>
class HLSPart{
public:
@ -30,4 +30,3 @@ private:
std::ofstream reconstruct;
HTTP::Downloader DL;
};

View file

@ -42,4 +42,3 @@ uint64_t AnalyserMP4::neededBytes(){
size += ntohl(((int *)mp4Buffer.data())[3]);
return size;
}

View file

@ -14,4 +14,3 @@ private:
uint64_t curPos;
uint64_t prePos;
};

View file

@ -36,9 +36,7 @@ bool AnalyserOGG::parsePacket(){
}
if (sn2Codec[oggPage.getBitstreamSerialNumber()] == "Theora"){
if (detail >= 2){
std::cout << " Theora data" << std::endl;
}
if (detail >= 2){std::cout << " Theora data" << std::endl;}
static unsigned int numParts = 0;
static unsigned int keyCount = 0;
for (unsigned int i = 0; i < oggPage.getAllSegments().size(); i++){
@ -46,33 +44,27 @@ bool AnalyserOGG::parsePacket(){
if (tmpHeader.isHeader()){
if (tmpHeader.getHeaderType() == 0){kfgshift = tmpHeader.getKFGShift();}
}else{
if (!(oggPage.getHeaderType() == OGG::Continued) &&
tmpHeader.getFTYPE() == 0){// if keyframe
if (!(oggPage.getHeaderType() == OGG::Continued) && tmpHeader.getFTYPE() == 0){// if keyframe
if (detail >= 3){
std::cout << "keyframe " << keyCount << " has " << numParts << " parts and granule " << (oggPage.getGranulePosition() >> kfgshift) << std::endl;
std::cout << "keyframe " << keyCount << " has " << numParts << " parts and granule "
<< (oggPage.getGranulePosition() >> kfgshift) << std::endl;
}
numParts = 0;
keyCount++;
}
if (oggPage.getHeaderType() != OGG::Continued || i){numParts++;}
}
if (detail >= 2){
std::cout << tmpHeader.toPrettyString(4);
}
if (detail >= 2){std::cout << tmpHeader.toPrettyString(4);}
}
}else if (sn2Codec[oggPage.getBitstreamSerialNumber()] == "Vorbis"){
if (detail >= 2){
std::cout << " Vorbis data" << std::endl;
}
if (detail >= 2){std::cout << " Vorbis data" << std::endl;}
for (unsigned int i = 0; i < oggPage.getAllSegments().size(); i++){
int len = oggPage.getAllSegments()[i].size();
vorbis::header tmpHeader((char *)oggPage.getSegment(i), len);
if (tmpHeader.isHeader() && detail >= 2){std::cout << tmpHeader.toPrettyString(4);}
}
}else if (sn2Codec[oggPage.getBitstreamSerialNumber()] == "Opus"){
if (detail >= 2){
std::cout << " Opus data" << std::endl;
}
if (detail >= 2){std::cout << " Opus data" << std::endl;}
int offset = 0;
for (unsigned int i = 0; i < oggPage.getAllSegments().size(); i++){
int len = oggPage.getAllSegments()[i].size();
@ -83,8 +75,7 @@ bool AnalyserOGG::parsePacket(){
std::cout << " Channels: " << (int)(part[9]) << std::endl;
std::cout << " Pre-skip: " << (int)(part[10] + (part[11] << 8)) << std::endl;
std::cout << " Orig. sample rate: "
<< (int)(part[12] + (part[13] << 8) + (part[14] << 16) + (part[15] << 24))
<< std::endl;
<< (int)(part[12] + (part[13] << 8) + (part[14] << 16) + (part[15] << 24)) << std::endl;
std::cout << " Gain: " << (int)(part[16] + (part[17] << 8)) << std::endl;
std::cout << " Channel map: " << (int)(part[18]) << std::endl;
if (part[18] > 0){
@ -96,8 +87,7 @@ bool AnalyserOGG::parsePacket(){
unsigned int vendor_len = part[8] + (part[9] << 8) + (part[10] << 16) + (part[11] << 24);
std::cout << " Vendor: " << std::string(part + 12, vendor_len) << std::endl;
const char *str_data = part + 12 + vendor_len;
unsigned int strings =
str_data[0] + (str_data[1] << 8) + (str_data[2] << 16) + (str_data[3] << 24);
unsigned int strings = str_data[0] + (str_data[1] << 8) + (str_data[2] << 16) + (str_data[3] << 24);
std::cout << " Tags: (" << strings << ")" << std::endl;
str_data += 4;
for (unsigned int j = 0; j < strings; j++){
@ -109,13 +99,10 @@ bool AnalyserOGG::parsePacket(){
}
}
}else{
if (detail >= 4){
std::cout << " " << Opus::Opus_prettyPacket(part, len) << std::endl;
}
if (detail >= 4){std::cout << " " << Opus::Opus_prettyPacket(part, len) << std::endl;}
}
offset += len;
}
}
return true;
}

View file

@ -13,4 +13,3 @@ private:
OGG::Page oggPage;
int kfgshift;
};

View file

@ -30,7 +30,7 @@ bool AnalyserRIFF::parsePacket(){
if (detail >= 2){C.toPrettyString(std::cout);}
///\TODO update mediaTime with the current timestamp
if (C){
dataBuffer.erase(0, C.getPayloadSize()+8);
dataBuffer.erase(0, C.getPayloadSize() + 8);
return true;
}
return false;
@ -39,6 +39,5 @@ bool AnalyserRIFF::parsePacket(){
/// Calculates how many bytes we need to read a whole box.
uint64_t AnalyserRIFF::neededBytes(){
if (dataBuffer.size() < 8){return 8;}
return RIFF::Chunk(dataBuffer.data()).getPayloadSize()+8;
return RIFF::Chunk(dataBuffer.data()).getPayloadSize() + 8;
}

View file

@ -12,4 +12,3 @@ private:
uint64_t curPos;
uint64_t prePos;
};

View file

@ -25,7 +25,7 @@ AnalyserRTMP::AnalyserRTMP(Util::Config &conf) : Analyser(conf){
}
}
bool AnalyserRTMP::open(const std::string & filename){
bool AnalyserRTMP::open(const std::string &filename){
if (!Analyser::open(filename)){return false;}
// Skip the 3073 byte handshake - there is no (truly) useful data in this.
MEDIUM_MSG("Skipping handshake...");
@ -63,8 +63,7 @@ bool AnalyserRTMP::parsePacket(){
// We now know for sure that we've parsed a packet
DETAIL_HI("Chunk info: [%#2X] CS ID %u, timestamp %u, len %u, type ID %u, Stream ID %u",
next.headertype, next.cs_id, next.timestamp, next.len, next.msg_type_id,
next.msg_stream_id);
next.headertype, next.cs_id, next.timestamp, next.len, next.msg_type_id, next.msg_stream_id);
switch (next.msg_type_id){
case 0: // does not exist
DETAIL_LOW("Error chunk @ %lu - CS%i, T%i, L%i, LL%i, MID%i", read_in - strbuf.size(),
@ -91,12 +90,10 @@ bool AnalyserRTMP::parsePacket(){
ntohl(*(unsigned int *)(next.data.c_str() + 2)));
break;
case 1:
DETAIL_MED("CTRL: User control message: stream EOF %u",
ntohl(*(unsigned int *)(next.data.c_str() + 2)));
DETAIL_MED("CTRL: User control message: stream EOF %u", ntohl(*(unsigned int *)(next.data.c_str() + 2)));
break;
case 2:
DETAIL_MED("CTRL: User control message: stream dry %u",
ntohl(*(unsigned int *)(next.data.c_str() + 2)));
DETAIL_MED("CTRL: User control message: stream dry %u", ntohl(*(unsigned int *)(next.data.c_str() + 2)));
break;
case 3:
DETAIL_MED("CTRL: User control message: setbufferlen %u",
@ -183,4 +180,3 @@ bool AnalyserRTMP::parsePacket(){
}// switch for type of chunk
return true;
}

View file

@ -5,18 +5,17 @@
class AnalyserRTMP : public Analyser{
private:
RTMPStream::Chunk next; ///< Holds the most recently parsed RTMP chunk
FLV::Tag F;///< Holds the most recently created FLV packet
unsigned int read_in; ///< Amounts of bytes read to fill 'strbuf' so far
Socket::Buffer strbuf;///< Internal buffer from where 'next' is filled
AMF::Object amfdata;///< Last read AMF object
AMF::Object3 amf3data;///<Last read AMF3 object
std::ofstream reconstruct;///< If reconstructing, a valid file handle
RTMPStream::Chunk next; ///< Holds the most recently parsed RTMP chunk
FLV::Tag F; ///< Holds the most recently created FLV packet
unsigned int read_in; ///< Amounts of bytes read to fill 'strbuf' so far
Socket::Buffer strbuf; ///< Internal buffer from where 'next' is filled
AMF::Object amfdata; ///< Last read AMF object
AMF::Object3 amf3data; ///< Last read AMF3 object
std::ofstream reconstruct; ///< If reconstructing, a valid file handle
public:
AnalyserRTMP(Util::Config & conf);
static void init(Util::Config & conf);
AnalyserRTMP(Util::Config &conf);
static void init(Util::Config &conf);
bool parsePacket();
virtual bool open(const std::string &filename);
};

View file

@ -1,23 +1,23 @@
#include <cstdlib>
#include <iostream>
#include <fstream>
#include <iomanip>
#include <string>
#include <string.h>
#include <vector>
#include <sstream>
#include <mist/socket.h>
#include <iostream>
#include <mist/config.h>
#include <mist/rtp.h>
#include <mist/http_parser.h>
#include <mist/rtp.h>
#include <mist/socket.h>
#include <sstream>
#include <string.h>
#include <string>
#include <vector>
//rtsp://krabs:1935/vod/gear1.mp4
// rtsp://krabs:1935/vod/gear1.mp4
namespace Analysers {
namespace Analysers{
int analyseRTP(){
Socket::Connection conn("localhost", 554, true);
//Socket::Connection conn("krabs", 1935, true);
HTTP::Parser HTTP_R, HTTP_S;//HTTP Receiver en HTTP Sender.
// Socket::Connection conn("krabs", 1935, true);
HTTP::Parser HTTP_R, HTTP_S; // HTTP Receiver en HTTP Sender.
int step = 0;
/*1 = sent describe
2 = recd describe
@ -28,61 +28,62 @@ namespace Analysers {
std::vector<Socket::UDPConnection> connections;
unsigned int trackIt = 0;
while (conn.connected()){
// std::cerr << "loopy" << std::endl;
if(step == 0){
// std::cerr << "loopy" << std::endl;
if (step == 0){
HTTP_S.protocol = "RTSP/1.0";
HTTP_S.method = "DESCRIBE";
//rtsp://krabs:1935/vod/gear1.mp4
//rtsp://localhost/g1
// rtsp://krabs:1935/vod/gear1.mp4
// rtsp://localhost/g1
HTTP_S.url = "rtsp://localhost/steers";
//HTTP_S.url = "rtsp://krabs:1935/vod/steers.mp4";
HTTP_S.SetHeader("CSeq",1);
HTTP_S.SendRequest(conn);
// HTTP_S.url = "rtsp://krabs:1935/vod/steers.mp4";
HTTP_S.SetHeader("CSeq", 1);
HTTP_S.SendRequest(conn);
step++;
}else if(step == 2){
std::cerr <<"setup " << tracks[trackIt] << std::endl;
}else if (step == 2){
std::cerr << "setup " << tracks[trackIt] << std::endl;
HTTP_S.method = "SETUP";
HTTP_S.url = "rtsp://localhost/steers/" + tracks[trackIt];
//HTTP_S.url = "rtsp://krabs:1935/vod/steers.mp4/" + tracks[trackIt];
HTTP_S.SetHeader("CSeq",2+trackIt);
// HTTP_S.url = "rtsp://krabs:1935/vod/steers.mp4/" + tracks[trackIt];
HTTP_S.SetHeader("CSeq", 2 + trackIt);
std::stringstream ss;
ss << "RTP/steersVP;unicast;client_port="<< 20000 + 2*trackIt<<"-"<< 20001 + 2*trackIt;
HTTP_S.SetHeader("Transport",ss.str());//make client ports, 4200 + 2*offset
ss << "RTP/steersVP;unicast;client_port=" << 20000 + 2 * trackIt << "-" << 20001 + 2 * trackIt;
HTTP_S.SetHeader("Transport", ss.str()); // make client ports, 4200 + 2*offset
trackIt++;
step++;
HTTP_S.SendRequest(conn);
std::cerr << "step " << step << "/\\"<< ss.str()<<std::endl;
}else if(step == 4){
std::cerr << "step " << step << "/\\" << ss.str() << std::endl;
}else if (step == 4){
std::cerr << "Play!!!1" << std::endl;
HTTP_S.method = "PLAY";
HTTP_S.url = "rtsp://localhost/steers";
//HTTP_S.url = "rtsp://krabs:1935/vod/steers.mp4";
HTTP_S.SetHeader("Range","npt=0.000-");
// HTTP_S.url = "rtsp://krabs:1935/vod/steers.mp4";
HTTP_S.SetHeader("Range", "npt=0.000-");
HTTP_S.SendRequest(conn);
step++;
std::cerr << "step for play.." << step << std::endl;
}
if (conn.Received().size() || conn.spool()){
}
if (conn.Received().size() || conn.spool()){
if (HTTP_R.Read(conn)){
if(step == 1){
std::cerr << "recvd desc" << std::endl;
for(size_t ml = HTTP_R.body.find("a=control:",HTTP_R.body.find("m=")); ml != std::string::npos; ml = HTTP_R.body.find("a=control:",ml+1)){
if (step == 1){
std::cerr << "recvd desc" << std::endl;
for (size_t ml = HTTP_R.body.find("a=control:", HTTP_R.body.find("m="));
ml != std::string::npos; ml = HTTP_R.body.find("a=control:", ml + 1)){
std::cerr << "found trekk" << std::endl;
tracks.push_back(HTTP_R.body.substr(ml+10,HTTP_R.body.find_first_of("\r\n",ml)-(ml+10)));
tracks.push_back(HTTP_R.body.substr(ml + 10, HTTP_R.body.find_first_of("\r\n", ml) - (ml + 10)));
connections.push_back(Socket::UDPConnection());
}
for(unsigned int x = 0; x < connections.size();x++){
connections[x].SetDestination("127.0.0.1",666);
connections[x].bind(20000+2*x);
for (unsigned int x = 0; x < connections.size(); x++){
connections[x].SetDestination("127.0.0.1", 666);
connections[x].bind(20000 + 2 * x);
connections[x].setBlocking(true);
}
step++;
}else if(step == 3){
}else if (step == 3){
std::cerr << "recvd setup" << std::endl;
std::cerr << "trackIt: " << trackIt << " size " << tracks.size() << std::endl;
if(trackIt < tracks.size())
if (trackIt < tracks.size())
step--;
else
step++;
@ -91,12 +92,12 @@ namespace Analysers {
HTTP_R.Clean();
}
}//!
if(step == 5){
if (step == 5){
for(unsigned int cx = 0; cx < connections.size(); cx++){
// std::cerr <<"PLAY MF" << std::endl;
if(connections[cx].Receive()){
RTP::Packet* pakketje = new RTP::Packet(connections[cx].data, connections[cx].data_len);
for (unsigned int cx = 0; cx < connections.size(); cx++){
// std::cerr <<"PLAY MF" << std::endl;
if (connections[cx].Receive()){
RTP::Packet *pakketje = new RTP::Packet(connections[cx].data, connections[cx].data_len);
/*std::cout << "Version = " << pakketje->getVersion() << std::endl;
std::cout << "Padding = " << pakketje->getPadding() << std::endl;
std::cout << "Extension = " << pakketje->getExtension() << std::endl;
@ -106,103 +107,95 @@ namespace Analysers {
std::cout << "Sequence = " << pakketje->getSequence() << std::endl;
std::cout << "Timestamp = " << pakketje->getTimeStamp() << std::endl;
std::cout << "SSRC = " << pakketje->getSSRC() << std::endl;
std::cout << "datalen: " << connections[cx].data_len << std::endl;
std::cout << "datalen: " << connections[cx].data_len << std::endl;
std::cout << "payload:" << std::endl;*/
if(pakketje->getPayloadType() == 97){
if (pakketje->getPayloadType() == 97){
int h264type = (int)(connections[cx].data[12] & 0x1f);
std::cout << h264type << " - ";
if(h264type == 0){
if (h264type == 0){
std::cout << "unspecified - ";
}else if(h264type == 1){
}else if (h264type == 1){
std::cout << "Coded slice of a non-IDR picture - ";
}else if(h264type == 2){
}else if (h264type == 2){
std::cout << "Coded slice data partition A - ";
}else if(h264type == 3){
}else if (h264type == 3){
std::cout << "Coded slice data partition B - ";
}else if(h264type == 4){
}else if (h264type == 4){
std::cout << "Coded slice data partition C - ";
}else if(h264type == 5){
}else if (h264type == 5){
std::cout << "Coded slice of an IDR picture - ";
}else if(h264type == 6){
}else if (h264type == 6){
std::cout << "Supplemental enhancement information (SEI) - ";
}else if(h264type == 7){
}else if (h264type == 7){
std::cout << "Sequence parameter set - ";
}else if(h264type == 8){
}else if (h264type == 8){
std::cout << "Picture parameter set - ";
}else if(h264type == 9){
}else if (h264type == 9){
std::cout << "Access unit delimiter - ";
}else if(h264type == 10){
}else if (h264type == 10){
std::cout << "End of sequence - ";
}else if(h264type == 11){
}else if (h264type == 11){
std::cout << "End of stream - ";
}else if(h264type == 12){
}else if (h264type == 12){
std::cout << "Filler data - ";
}else if(h264type == 13){
}else if (h264type == 13){
std::cout << "Sequence parameter set extension - ";
}else if(h264type == 14){
}else if (h264type == 14){
std::cout << "Prefix NAL unit - ";
}else if(h264type == 15){
}else if (h264type == 15){
std::cout << "Subset sequence parameter set - ";
}else if(h264type == 16){
}else if (h264type == 16){
std::cout << "Reserved - ";
}else if(h264type == 17){
}else if (h264type == 17){
std::cout << "Reserved - ";
}else if(h264type == 18){
}else if (h264type == 18){
std::cout << "Reserved - ";
}else if(h264type == 19){
}else if (h264type == 19){
std::cout << "Coded slice of an auxiliary coded picture without partitioning - ";
}else if(h264type == 20){
}else if (h264type == 20){
std::cout << "Coded slice extension - ";
}else if(h264type == 21){
}else if (h264type == 21){
std::cout << "Reserved - ";
}else if(h264type == 22){
}else if (h264type == 22){
std::cout << "Reserved - ";
}else if(h264type == 23){
}else if (h264type == 23){
std::cout << "Reserved - ";
}else if(h264type == 24){
}else if (h264type == 24){
std::cout << "stap a - ";
}else if(h264type == 25){
}else if (h264type == 25){
std::cout << "stap b - ";
}else if(h264type == 26){
}else if (h264type == 26){
std::cout << "mtap16 - ";
}else if(h264type == 27){
}else if (h264type == 27){
std::cout << "mtap24 - ";
}else if(h264type == 28){
}else if (h264type == 28){
std::cout << "fu a - ";
}else if(h264type == 29){
}else if (h264type == 29){
std::cout << "fu b - ";
}else if(h264type == 30){
}else if (h264type == 30){
std::cout << "Unspecified - ";
}else if(h264type == 31){
}else if (h264type == 31){
std::cout << "Unspecified - ";
}
for(unsigned int i = 13 ; i < connections[cx].data_len;i++){
std::cout << std::hex <<std::setw(2) << std::setfill('0') << (int)connections[cx].data[i]<< std::dec;
for (unsigned int i = 13; i < connections[cx].data_len; i++){
std::cout << std::hex << std::setw(2) << std::setfill('0')
<< (int)connections[cx].data[i] << std::dec;
}
std::cout << std::endl<<std::endl;
std::cout << std::endl << std::endl;
}
delete pakketje;
}
delete pakketje;
}
}
}
}
return 666;
}
}// namespace Analysers
}
int main(int argc, char ** argv){
int main(int argc, char **argv){
Util::Config conf = Util::Config(argv[0]);
conf.parseArgs(argc, argv);
return Analysers::analyseRTP();

View file

@ -14,7 +14,8 @@ void AnalyserRTSP::incoming(const DTSC::Packet &pkt){
char *dataPtr;
size_t dataSize;
pkt.getString("data", dataPtr, dataSize);
DETAIL_MED("Received %ub %sfor track %lu (%s) @ %llums", dataSize, pkt.getFlag("keyframe")?"keyframe ":"", pkt.getTrackId(),
DETAIL_MED("Received %ub %sfor track %lu (%s) @ %llums", dataSize,
pkt.getFlag("keyframe") ? "keyframe " : "", pkt.getTrackId(),
myMeta.tracks[pkt.getTrackId()].getIdentifier().c_str(), pkt.getTime());
if (detail >= 8){
for (uint32_t i = 0; i < dataSize; ++i){
@ -99,9 +100,7 @@ bool AnalyserRTSP::parsePacket(){
if (!trackNo && (chan % 2) != 1){
DETAIL_MED("Received packet for unknown track number on channel %u", chan);
}
if (trackNo){
sdpState.tracks[trackNo].sorter.rtpSeq = pkt.getSequence();
}
if (trackNo){sdpState.tracks[trackNo].sorter.rtpSeq = pkt.getSequence();}
if (detail >= 10){
char *pl = pkt.getPayload();
@ -120,4 +119,3 @@ bool AnalyserRTSP::parsePacket(){
}while (isOpen());
return false;
}

View file

@ -21,4 +21,3 @@ private:
DTSC::Meta myMeta;
SDP::State sdpState;
};

View file

@ -1,5 +1,5 @@
#include "analyser_ts.h"
#include "analyser.h"
#include "analyser_ts.h"
#include <cstdio>
#include <cstdlib>
#include <fcntl.h>
@ -50,8 +50,7 @@ bool AnalyserTS::parsePacket(){
bytes += 188;
if (!packet.FromPointer(packetPtr)){return false;}
if (detail){
if (packet.getUnitStart() && payloads.count(packet.getPID()) &&
payloads[packet.getPID()] != ""){
if (packet.getUnitStart() && payloads.count(packet.getPID()) && payloads[packet.getPID()] != ""){
if ((detail & 1) && (!pidOnly || packet.getPID() == pidOnly)){
std::cout << printPES(payloads[packet.getPID()], packet.getPID());
}
@ -75,8 +74,7 @@ bool AnalyserTS::parsePacket(){
}
AnalyserTS::~AnalyserTS(){
for (std::map<unsigned long long, std::string>::iterator it = payloads.begin();
it != payloads.end(); it++){
for (std::map<unsigned long long, std::string>::iterator it = payloads.begin(); it != payloads.end(); it++){
if ((detail & 1) && (!pidOnly || it->first == pidOnly)){
std::cout << printPES(it->second, it->first);
}
@ -98,8 +96,7 @@ std::string AnalyserTS::printPES(const std::string &d, unsigned long PID){
}
if (!known){res << " [Unknown stream ID: " << (int)d[3] << "]";}
if (d[0] != 0 || d[1] != 0 || d[2] != 1){
res << " [!!! INVALID START CODE: " << (int)d[0] << " " << (int)d[1] << " " << (int)d[2]
<< " ]";
res << " [!!! INVALID START CODE: " << (int)d[0] << " " << (int)d[1] << " " << (int)d[2] << " ]";
}
unsigned int padding = 0;
if (known){
@ -164,7 +161,8 @@ std::string AnalyserTS::printPES(const std::string &d, unsigned long PID){
}
}
if ((((int)d[4]) << 8 | d[5]) != (d.size() - 6)){
res << " [Size " << (((int)d[4]) << 8 | d[5]) + 6 << " => " << (d.size()) << "] [Payload " << (d.size() - 9 - headSize) << "]";
res << " [Size " << (((int)d[4]) << 8 | d[5]) + 6 << " => " << (d.size()) << "] [Payload "
<< (d.size() - 9 - headSize) << "]";
}else{
res << " [Size " << (d.size()) << "] [Payload " << (d.size() - 9 - headSize) << "]";
}
@ -185,4 +183,3 @@ std::string AnalyserTS::printPES(const std::string &d, unsigned long PID){
}
return res.str();
}

View file

@ -9,10 +9,10 @@ public:
bool parsePacket();
static void init(Util::Config &conf);
std::string printPES(const std::string &d, unsigned long PID);
private:
std::map<unsigned long long, std::string> payloads;
uint32_t pidOnly;
TS::Packet packet;
uint64_t bytes;
};

View file

@ -2,409 +2,407 @@
/// Contains the code for the DASH Analysing tool.
/// Currently, only mp4 is supported, and the xml parser assumes a representation id tag exists
#include <fstream>
#include <iostream>
#include <mist/config.h>
#include <mist/timing.h>
#include <mist/defines.h>
#include <mist/http_parser.h>
#include <iostream>
#include <fstream>
#include <set>
#include <mist/mp4.h>
#include <mist/mp4_generic.h>
#include <mist/timing.h>
#include <set>
#define OTHER 0x00
#define VIDEO 0x01
#define AUDIO 0x02
///\brief simple struct for storage of stream-specific data
struct StreamData{
long timeScale;
std::string media;
std::string initialization;
std::string initURL;
long trackID;
long trackID;
unsigned int adaptationSet;
unsigned char trackType;
unsigned char trackType;
};
StreamData tempSD; //temp global
StreamData tempSD; // temp global
///\brief another simple structure used for ordering byte seek positions.
struct seekPos {
struct seekPos{
///\brief Less-than comparison for seekPos structures.
///\param rhs The seekPos to compare with.
///\return Whether this object is smaller than rhs.
bool operator < (const seekPos & rhs) const {
if ((seekTime*rhs.timeScale) < (rhs.seekTime*timeScale)) {
bool operator<(const seekPos &rhs) const{
if ((seekTime * rhs.timeScale) < (rhs.seekTime * timeScale)){
return true;
} else {
if ( (seekTime*rhs.timeScale) == (rhs.seekTime*timeScale)){
}else{
if ((seekTime * rhs.timeScale) == (rhs.seekTime * timeScale)){
if (adaptationSet < rhs.adaptationSet){
return true;
} else if (adaptationSet == rhs.adaptationSet){
if (trackID < rhs.trackID) {
return true;
}
}
}else if (adaptationSet == rhs.adaptationSet){
if (trackID < rhs.trackID){return true;}
}
}
}
return false;
}
long timeScale;
long long unsigned int bytePos; /// ?
long long unsigned int seekTime; ///start
long long unsigned int duration; ///duration
unsigned int trackID; ///stores representation ID
unsigned int adaptationSet; ///stores type
unsigned char trackType; ///stores type
long long unsigned int bytePos; /// ?
long long unsigned int seekTime; /// start
long long unsigned int duration; /// duration
unsigned int trackID; /// stores representation ID
unsigned int adaptationSet; /// stores type
unsigned char trackType; /// stores type
std::string url;
};
bool getDelimBlock(std::string & data, std::string name, size_t &blockStart, size_t &blockEnd, std::string delim){
size_t offset=data.find(name);
if(offset==std::string::npos){
return false; //name string not found.
}
//expected: delim character BEFORE blockstart.
offset--;
blockStart=data.find(delim,offset);
//DEBUG_MSG(DLVL_INFO, "offset: %i blockStart: %i ", offset, blockStart);
offset=blockStart+1;//skip single character!
blockEnd=data.find(delim,offset);
//DEBUG_MSG(DLVL_INFO, "offset: %i blockEnd: %i ", offset, blockEnd);
if(blockStart==std::string::npos || blockEnd==std::string::npos){
return false; //no start/end quotes found
bool getDelimBlock(std::string &data, std::string name, size_t &blockStart, size_t &blockEnd, std::string delim){
size_t offset = data.find(name);
if (offset == std::string::npos){
return false; // name string not found.
}
blockEnd++; //include delim
//DEBUG_MSG(DLVL_INFO, "getDelimPos: data.size() %i start %i end %i num %i", data.size(), blockStart,blockEnd,(blockEnd-blockStart) );
// expected: delim character BEFORE blockstart.
offset--;
blockStart = data.find(delim, offset);
// DEBUG_MSG(DLVL_INFO, "offset: %i blockStart: %i ", offset, blockStart);
offset = blockStart + 1; // skip single character!
blockEnd = data.find(delim, offset);
// DEBUG_MSG(DLVL_INFO, "offset: %i blockEnd: %i ", offset, blockEnd);
if (blockStart == std::string::npos || blockEnd == std::string::npos){
return false; // no start/end quotes found
}
blockEnd++; // include delim
// DEBUG_MSG(DLVL_INFO, "getDelimPos: data.size() %i start %i end %i num %i", data.size(), blockStart,blockEnd,(blockEnd-blockStart) );
return true;
}
bool getValueBlock(std::string & data, std::string name, size_t &blockStart, size_t &blockEnd, std::string delim){
size_t offset=data.find(name);
if(offset==std::string::npos){
return false; //name string not found.
}
blockStart=data.find(delim,offset);
//DEBUG_MSG(DLVL_INFO, "offset: %i blockStart: %i ", offset, blockStart);
blockStart++; //clip off quote characters
offset=blockStart;//skip single character!
blockEnd=data.find(delim,offset);
//DEBUG_MSG(DLVL_INFO, "offset: %i blockEnd: %i ", offset, blockEnd);
if(blockStart==std::string::npos || blockEnd==std::string::npos){
return false; //no start/end quotes found
}
//DEBUG_MSG(DLVL_INFO, "getValueBlock: data.size() %i start %i end %i num %i", data.size(), blockStart,blockEnd,(blockEnd-blockStart) );
bool getValueBlock(std::string &data, std::string name, size_t &blockStart, size_t &blockEnd, std::string delim){
size_t offset = data.find(name);
if (offset == std::string::npos){
return false; // name string not found.
}
blockStart = data.find(delim, offset);
// DEBUG_MSG(DLVL_INFO, "offset: %i blockStart: %i ", offset, blockStart);
blockStart++; // clip off quote characters
offset = blockStart; // skip single character!
blockEnd = data.find(delim, offset);
// DEBUG_MSG(DLVL_INFO, "offset: %i blockEnd: %i ", offset, blockEnd);
if (blockStart == std::string::npos || blockEnd == std::string::npos){
return false; // no start/end quotes found
}
// DEBUG_MSG(DLVL_INFO, "getValueBlock: data.size() %i start %i end %i num %i", data.size(), blockStart,blockEnd,(blockEnd-blockStart) );
return true;
}
bool getString(std::string &data, std::string name, std::string &output){
size_t blockStart=0;
size_t blockEnd=0;
if(!getValueBlock(data, name, blockStart,blockEnd, "\"")){
//DEBUG_MSG(DLVL_FAIL, "could not find \"%s\" in data block", name.c_str());
return false; //could not find value in this data block.
}
//DEBUG_MSG(DLVL_INFO, "data.size() %i start %i end %i num %i", data.size(), blockStart,blockEnd,(blockEnd-blockStart) )
output=data.substr(blockStart,(blockEnd-blockStart));
//looks like this function is working as expected
//DEBUG_MSG(DLVL_INFO, "data in getstring %s", (data.substr(blockStart,(blockEnd-blockStart))).c_str());
size_t blockStart = 0;
size_t blockEnd = 0;
if (!getValueBlock(data, name, blockStart, blockEnd, "\"")){
// DEBUG_MSG(DLVL_FAIL, "could not find \"%s\" in data block", name.c_str());
return false; // could not find value in this data block.
}
// DEBUG_MSG(DLVL_INFO, "data.size() %i start %i end %i num %i", data.size(), blockStart,blockEnd,(blockEnd-blockStart) )
output = data.substr(blockStart, (blockEnd - blockStart));
// looks like this function is working as expected
// DEBUG_MSG(DLVL_INFO, "data in getstring %s", (data.substr(blockStart,(blockEnd-blockStart))).c_str());
return true;
}
bool getLong(std::string &data, std::string name, long &output){
size_t blockStart, blockEnd;
if(!getValueBlock(data, name, blockStart,blockEnd, "\"")){
//DEBUG_MSG(DLVL_FAIL, "could not find \"%s\" in data block", name.c_str());
return false; //could not find value in this data block.
}
//DEBUG_MSG(DLVL_INFO, "name: %s data in atol %s",name.c_str(), (data.substr(blockStart,(blockEnd-blockStart))).c_str());
output=atol( (data.substr(blockStart,(blockEnd-blockStart))).c_str() );
if (!getValueBlock(data, name, blockStart, blockEnd, "\"")){
// DEBUG_MSG(DLVL_FAIL, "could not find \"%s\" in data block", name.c_str());
return false; // could not find value in this data block.
}
// DEBUG_MSG(DLVL_INFO, "name: %s data in atol %s",name.c_str(), (data.substr(blockStart,(blockEnd-blockStart))).c_str());
output = atol((data.substr(blockStart, (blockEnd - blockStart))).c_str());
return true;
}
//block expecting separate name and /name occurence, or name and /> before another occurence of <.
bool getBlock(std::string & data, std::string name, int offset, size_t &blockStart, size_t &blockEnd){
blockStart=data.find("<"+name+">",offset);
if(blockStart==std::string::npos){
blockStart=data.find("<"+name+" ",offset); //this considers both valid situations <name> and <name bla="bla"/>
}
if(blockStart==std::string::npos){
DEBUG_MSG(DLVL_INFO, "no block start found for name: %s at offset: %i",name.c_str(), offset);
return false;
}
// block expecting separate name and /name occurence, or name and /> before another occurence of <.
bool getBlock(std::string &data, std::string name, int offset, size_t &blockStart, size_t &blockEnd){
blockStart = data.find("<" + name + ">", offset);
if (blockStart == std::string::npos){
blockStart = data.find("<" + name + " ", offset); // this considers both valid situations <name> and <name bla="bla"/>
}
blockEnd=data.find("/" + name+ ">", blockStart);
if(blockEnd==std::string::npos){
blockEnd=data.find("/>", blockStart);
if(blockEnd==std::string::npos){
if (blockStart == std::string::npos){
DEBUG_MSG(DLVL_INFO, "no block start found for name: %s at offset: %i", name.c_str(), offset);
return false;
}
blockEnd = data.find("/" + name + ">", blockStart);
if (blockEnd == std::string::npos){
blockEnd = data.find("/>", blockStart);
if (blockEnd == std::string::npos){
DEBUG_MSG(DLVL_INFO, "no block end found.");
return false;
}
size_t temp=data.find("<", blockStart+1, (blockEnd-blockStart-1)); //the +1 is to avoid re-interpreting the starting < //TODO!!
if(temp!=std::string::npos){ //all info is epxected between <name ... />
size_t temp = data.find("<", blockStart + 1, (blockEnd - blockStart - 1)); // the +1 is to avoid re-interpreting the starting < //TODO!!
if (temp != std::string::npos){// all info is epxected between <name ... />
DEBUG_MSG(DLVL_FAIL, "block start found before block end. offset: %lu block: %s", temp, data.c_str());
return false;
}
//DEBUG_MSG(DLVL_FAIL, "special block end found");
blockEnd+=2; //position after />
} else {
blockEnd += name.size()+2; //position after /name>
}
//DEBUG_MSG(DLVL_INFO, "getBlock: start: %i end: %i",blockStart,blockEnd);
// DEBUG_MSG(DLVL_FAIL, "special block end found");
blockEnd += 2; // position after />
}else{
blockEnd += name.size() + 2; // position after /name>
}
// DEBUG_MSG(DLVL_INFO, "getBlock: start: %i end: %i",blockStart,blockEnd);
return true;
}
bool parseAdaptationSet(std::string & data, std::set<seekPos> &currentPos){
//DEBUG_MSG(DLVL_INFO, "Parsing adaptationSet: %s", data.c_str());
size_t offset =0;
size_t blockStart, blockEnd;
tempSD.trackType=OTHER;
//get value: mimetype //todo: handle this!
bool parseAdaptationSet(std::string &data, std::set<seekPos> &currentPos){
// DEBUG_MSG(DLVL_INFO, "Parsing adaptationSet: %s", data.c_str());
size_t offset = 0;
size_t blockStart, blockEnd;
tempSD.trackType = OTHER;
// get value: mimetype //todo: handle this!
std::string mimeType;
if(!getString(data,"mimeType", mimeType)){ //get first occurence of mimeType. --> this will break if multiple mimetypes should be read from this block because no offset is provided. solution: use this on a substring containing the desired information.
if (!getString(data, "mimeType", mimeType)){// get first occurence of mimeType. --> this will break
// if multiple mimetypes should be read from this block
// because no offset is provided. solution: use this on a substring containing the desired information.
DEBUG_MSG(DLVL_FAIL, "mimeType not found");
return false;
}
DEBUG_MSG(DLVL_INFO, "mimeType: %s",mimeType.c_str()); //checked, OK
DEBUG_MSG(DLVL_INFO, "mimeType: %s", mimeType.c_str()); // checked, OK
if(mimeType.find("video")!=std::string::npos){tempSD.trackType=VIDEO;}
if(mimeType.find("audio")!=std::string::npos){tempSD.trackType=AUDIO;}
if(tempSD.trackType==OTHER){
if (mimeType.find("video") != std::string::npos){tempSD.trackType = VIDEO;}
if (mimeType.find("audio") != std::string::npos){tempSD.trackType = AUDIO;}
if (tempSD.trackType == OTHER){
DEBUG_MSG(DLVL_FAIL, "no audio or video type found. giving up.");
return false;
}
//find an ID within this adaptationSet block.
if(!getBlock(data,(std::string)"Representation", offset, blockStart, blockEnd)){
// find an ID within this adaptationSet block.
if (!getBlock(data, (std::string) "Representation", offset, blockStart, blockEnd)){
DEBUG_MSG(DLVL_FAIL, "Representation not found");
return false;
}
//representation string
std::string block=data.substr(blockStart,(blockEnd-blockStart));
DEBUG_MSG(DLVL_INFO, "Representation block: %s",block.c_str());
//check if block is not junk?
if(!getLong(block,"id", tempSD.trackID) ){
DEBUG_MSG(DLVL_FAIL, "Representation id not found in block %s",block.c_str());
// representation string
std::string block = data.substr(blockStart, (blockEnd - blockStart));
DEBUG_MSG(DLVL_INFO, "Representation block: %s", block.c_str());
// check if block is not junk?
if (!getLong(block, "id", tempSD.trackID)){
DEBUG_MSG(DLVL_FAIL, "Representation id not found in block %s", block.c_str());
return false;
}
DEBUG_MSG(DLVL_INFO, "Representation/id: %li",tempSD.trackID); //checked, OK
DEBUG_MSG(DLVL_INFO, "Representation/id: %li", tempSD.trackID); // checked, OK
offset =0;
//get values from SegmentTemplate
if(!getBlock(data,(std::string)"SegmentTemplate", offset, blockStart, blockEnd)){
offset = 0;
// get values from SegmentTemplate
if (!getBlock(data, (std::string) "SegmentTemplate", offset, blockStart, blockEnd)){
DEBUG_MSG(DLVL_FAIL, "SegmentTemplate not found");
return false;
}
block=data.substr(blockStart,(blockEnd-blockStart));
//DEBUG_MSG(DLVL_INFO, "SegmentTemplate block: %s",block.c_str()); //OK
block = data.substr(blockStart, (blockEnd - blockStart));
// DEBUG_MSG(DLVL_INFO, "SegmentTemplate block: %s",block.c_str()); //OK
getLong(block,"timescale", tempSD.timeScale);
getString(block,"media", tempSD.media);
getString(block,"initialization", tempSD.initialization);
size_t tmpBlockStart=0;
size_t tmpBlockEnd=0;
if(!getDelimBlock(tempSD.media,"RepresentationID",tmpBlockStart,tmpBlockEnd, "$")){
DEBUG_MSG(DLVL_FAIL, "Failed to find and replace $RepresentationID$ in %s",tempSD.media.c_str());
return false;
}
tempSD.media.replace(tmpBlockStart,(tmpBlockEnd-tmpBlockStart),"%d");
getLong(block, "timescale", tempSD.timeScale);
getString(block, "media", tempSD.media);
getString(block, "initialization", tempSD.initialization);
if(!getDelimBlock(tempSD.media,"Time",tmpBlockStart,tmpBlockEnd, "$")){
DEBUG_MSG(DLVL_FAIL, "Failed to find and replace $Time$ in %s",tempSD.media.c_str());
size_t tmpBlockStart = 0;
size_t tmpBlockEnd = 0;
if (!getDelimBlock(tempSD.media, "RepresentationID", tmpBlockStart, tmpBlockEnd, "$")){
DEBUG_MSG(DLVL_FAIL, "Failed to find and replace $RepresentationID$ in %s", tempSD.media.c_str());
return false;
}
tempSD.media.replace(tmpBlockStart,(tmpBlockEnd-tmpBlockStart),"%d");
if(!getDelimBlock(tempSD.initialization,"RepresentationID",tmpBlockStart,tmpBlockEnd, "$")){
DEBUG_MSG(DLVL_FAIL, "Failed to find and replace $RepresentationID$ in %s",tempSD.initialization.c_str());
return false;
}
tempSD.initialization.replace(tmpBlockStart,(tmpBlockEnd-tmpBlockStart),"%d");
}
tempSD.media.replace(tmpBlockStart, (tmpBlockEnd - tmpBlockStart), "%d");
//get segment timeline block from within segment template:
size_t blockOffset=0; //offset should be 0 because this is a new block
if(!getBlock(block,"SegmentTimeline", blockOffset, blockStart, blockEnd)){
if (!getDelimBlock(tempSD.media, "Time", tmpBlockStart, tmpBlockEnd, "$")){
DEBUG_MSG(DLVL_FAIL, "Failed to find and replace $Time$ in %s", tempSD.media.c_str());
return false;
}
tempSD.media.replace(tmpBlockStart, (tmpBlockEnd - tmpBlockStart), "%d");
if (!getDelimBlock(tempSD.initialization, "RepresentationID", tmpBlockStart, tmpBlockEnd, "$")){
DEBUG_MSG(DLVL_FAIL, "Failed to find and replace $RepresentationID$ in %s",
tempSD.initialization.c_str());
return false;
}
tempSD.initialization.replace(tmpBlockStart, (tmpBlockEnd - tmpBlockStart), "%d");
// get segment timeline block from within segment template:
size_t blockOffset = 0; // offset should be 0 because this is a new block
if (!getBlock(block, "SegmentTimeline", blockOffset, blockStart, blockEnd)){
DEBUG_MSG(DLVL_FAIL, "SegmentTimeline block not found");
return false;
}
std::string block2=block.substr(blockStart,(blockEnd-blockStart)); //overwrites previous block (takes just the segmentTimeline part
//DEBUG_MSG(DLVL_INFO, "SegmentTimeline block: %s",block2.c_str()); //OK
int numS=0;
offset=0;
long long unsigned int totalDuration=0;
}
std::string block2 = block.substr(blockStart, (blockEnd - blockStart)); // overwrites previous block (takes just the segmentTimeline part
// DEBUG_MSG(DLVL_INFO, "SegmentTimeline block: %s",block2.c_str()); //OK
int numS = 0;
offset = 0;
long long unsigned int totalDuration = 0;
long timeValue;
while(1){
if(!getBlock(block2,"S",offset, blockStart, blockEnd)){
if(numS==0){
while (1){
if (!getBlock(block2, "S", offset, blockStart, blockEnd)){
if (numS == 0){
DEBUG_MSG(DLVL_FAIL, "no S found within SegmentTimeline");
return false;
} else {
}else{
DEBUG_MSG(DLVL_INFO, "all S found within SegmentTimeline %i", numS);
return true; //break; //escape from while loop (to return true)
return true; // break; //escape from while loop (to return true)
}
}
numS++;
//stuff S data into: currentPos
//searching for t(start position)
std::string sBlock=block2.substr(blockStart,(blockEnd-blockStart));
//DEBUG_MSG(DLVL_INFO, "S found. offset: %i blockStart: %i blockend: %i block: %s",offset,blockStart, blockEnd, sBlock.c_str()); //OK!
if(getLong(sBlock,"t", timeValue)){
totalDuration=timeValue; //reset totalDuration to value of t
}
if(!getLong(sBlock,"d", timeValue)){ //expected duration in every S.
numS++;
// stuff S data into: currentPos
// searching for t(start position)
std::string sBlock = block2.substr(blockStart, (blockEnd - blockStart));
// DEBUG_MSG(DLVL_INFO, "S found. offset: %i blockStart: %i blockend: %i block: %s",offset,blockStart, blockEnd, sBlock.c_str()); //OK!
if (getLong(sBlock, "t", timeValue)){
totalDuration = timeValue; // reset totalDuration to value of t
}
if (!getLong(sBlock, "d", timeValue)){// expected duration in every S.
DEBUG_MSG(DLVL_FAIL, "no d found within S");
return false;
}
//stuff data with old value (start of block)
//DEBUG_MSG(DLVL_INFO, "stuffing info from S into set");
// stuff data with old value (start of block)
// DEBUG_MSG(DLVL_INFO, "stuffing info from S into set");
seekPos thisPos;
thisPos.trackType=tempSD.trackType;
thisPos.trackID=tempSD.trackID;
thisPos.adaptationSet=tempSD.adaptationSet;
//thisPos.trackID=id;
thisPos.seekTime=totalDuration; //previous total duration is start time of this S.
thisPos.duration=timeValue;
thisPos.timeScale=tempSD.timeScale;
thisPos.trackType = tempSD.trackType;
thisPos.trackID = tempSD.trackID;
thisPos.adaptationSet = tempSD.adaptationSet;
// thisPos.trackID=id;
thisPos.seekTime = totalDuration; // previous total duration is start time of this S.
thisPos.duration = timeValue;
thisPos.timeScale = tempSD.timeScale;
static char charBuf[512];
snprintf(charBuf, 512, tempSD.media.c_str(), tempSD.trackID, totalDuration);
thisPos.url.assign(charBuf);
//DEBUG_MSG(DLVL_INFO, "media url (from rep.ID %d, startTime %d): %s", tempSD.trackID, totalDuration,thisPos.url.c_str());
currentPos.insert(thisPos); //assumes insert copies all data in seekPos struct.
totalDuration+=timeValue;//update totalDuration
offset=blockEnd; //blockEnd and blockStart are absolute values within string, offset is not relevant.
}
// DEBUG_MSG(DLVL_INFO, "media url (from rep.ID %d, startTime %d): %s", tempSD.trackID, totalDuration,thisPos.url.c_str());
currentPos.insert(thisPos); // assumes insert copies all data in seekPos struct.
totalDuration += timeValue; // update totalDuration
offset = blockEnd; // blockEnd and blockStart are absolute values within string, offset is not relevant.
}
return true;
}
bool parseXML(std::string & body, std::set<seekPos> &currentPos, std::vector<StreamData> &streamData){
//for all adaptation sets
//representation ID
int numAdaptationSet=0;
size_t currentOffset=0;
bool parseXML(std::string &body, std::set<seekPos> &currentPos, std::vector<StreamData> &streamData){
// for all adaptation sets
// representation ID
int numAdaptationSet = 0;
size_t currentOffset = 0;
size_t adaptationSetStart;
size_t adaptationSetEnd;
//DEBUG_MSG(DLVL_INFO, "body received: %s", body.c_str());
while(getBlock(body,"AdaptationSet",currentOffset, adaptationSetStart, adaptationSetEnd)){
tempSD.adaptationSet=numAdaptationSet;
numAdaptationSet++;
DEBUG_MSG(DLVL_INFO, "adaptationSet found. start: %lu end: %lu num: %lu ",adaptationSetStart,adaptationSetEnd,(adaptationSetEnd-adaptationSetStart));
//get substring: from <adaptationSet... to /adaptationSet>
std::string adaptationSet=body.substr(adaptationSetStart,(adaptationSetEnd-adaptationSetStart));
//function was verified: output as expected.
if(!parseAdaptationSet(adaptationSet, currentPos)){
DEBUG_MSG(DLVL_FAIL, "parseAdaptationSet returned false."); //this also happens in the case of OTHER mimetype. in that case it might be desirable to continue searching for valid data instead of quitting.
return false;
size_t adaptationSetEnd;
// DEBUG_MSG(DLVL_INFO, "body received: %s", body.c_str());
while (getBlock(body, "AdaptationSet", currentOffset, adaptationSetStart, adaptationSetEnd)){
tempSD.adaptationSet = numAdaptationSet;
numAdaptationSet++;
DEBUG_MSG(DLVL_INFO, "adaptationSet found. start: %lu end: %lu num: %lu ", adaptationSetStart,
adaptationSetEnd, (adaptationSetEnd - adaptationSetStart));
// get substring: from <adaptationSet... to /adaptationSet>
std::string adaptationSet = body.substr(adaptationSetStart, (adaptationSetEnd - adaptationSetStart));
// function was verified: output as expected.
if (!parseAdaptationSet(adaptationSet, currentPos)){
DEBUG_MSG(DLVL_FAIL, "parseAdaptationSet returned false."); // this also happens in the case
// of OTHER mimetype. in that case it might be desirable to continue searching for valid data instead of quitting.
return false;
}
streamData.push_back(tempSD); //put temp values into adaptation set vector
currentOffset=adaptationSetEnd;//the getblock function should make sure End is at the correct offset.
streamData.push_back(tempSD); // put temp values into adaptation set vector
currentOffset = adaptationSetEnd; // the getblock function should make sure End is at the correct offset.
}
if(numAdaptationSet==0){
if (numAdaptationSet == 0){
DEBUG_MSG(DLVL_FAIL, "no adaptationSet found.");
return false;
}
DEBUG_MSG(DLVL_INFO, "all adaptation sets found. total: %i", numAdaptationSet);
}
DEBUG_MSG(DLVL_INFO, "all adaptation sets found. total: %i", numAdaptationSet);
return true;
}
int main(int argc, char ** argv) {
int main(int argc, char **argv){
Util::Config conf = Util::Config(argv[0]);
conf.addOption("mode", JSON::fromString("{\"long\":\"mode\", \"arg\":\"string\", \"short\":\"m\", \"default\":\"analyse\", \"help\":\"What to do with the stream. Valid modes are 'analyse', 'validate', 'output'.\"}"));
conf.addOption("url", JSON::fromString("{\"arg_num\":1, \"arg\":\"string\", \"help\":\"URL to HLS stream index file to retrieve.\"}"));
conf.addOption("abort", JSON::fromString("{\"long\":\"abort\", \"short\":\"a\", \"arg\":\"integer\", \"default\":-1, \"help\":\"Abort after this many seconds of downloading. Negative values mean unlimited, which is the default.\"}"));
conf.addOption("mode",
JSON::fromString("{\"long\":\"mode\", \"arg\":\"string\", \"short\":\"m\", "
"\"default\":\"analyse\", \"help\":\"What to do with the stream. "
"Valid modes are 'analyse', 'validate', 'output'.\"}"));
conf.addOption("url", JSON::fromString("{\"arg_num\":1, \"arg\":\"string\", \"help\":\"URL to "
"HLS stream index file to retrieve.\"}"));
conf.addOption("abort", JSON::fromString("{\"long\":\"abort\", \"short\":\"a\", "
"\"arg\":\"integer\", \"default\":-1, \"help\":\"Abort "
"after this many seconds of downloading. Negative "
"values mean unlimited, which is the default.\"}"));
conf.parseArgs(argc, argv);
conf.activate();
unsigned int port = 80;
std::string url = conf.getString("url");
if (url.substr(0, 7) != "http://") {
if (url.substr(0, 7) != "http://"){
DEBUG_MSG(DLVL_FAIL, "The URL must start with http://");
return -1;
}
url = url.substr(7); //found problem if url is to short!! it gives out of range when entering http://meh.meh
url = url.substr(7); // found problem if url is to short!! it gives out of range when entering http://meh.meh
std::string server = url.substr(0, url.find('/'));
url = url.substr(url.find('/'));
if (server.find(':') != std::string::npos) {
if (server.find(':') != std::string::npos){
port = atoi(server.substr(server.find(':') + 1).c_str());
server = server.substr(0, server.find(':'));
}
long long int startTime = Util::bootSecs();
long long int abortTime = conf.getInteger("abort");
Socket::Connection conn(server, port, false);
//url:
// url:
DEBUG_MSG(DLVL_INFO, "url %s server: %s port: %d", url.c_str(), server.c_str(), port);
std::string urlPrependStuff= url.substr(0, url.rfind("/")+1);
std::string urlPrependStuff = url.substr(0, url.rfind("/") + 1);
DEBUG_MSG(DLVL_INFO, "prepend stuff: %s", urlPrependStuff.c_str());
if (!conn) {
conn.open(server, port, false);
}
if (!conn){conn.open(server, port, false);}
unsigned int pos = 0;
HTTP::Parser H;
H.url = url;
H.SetHeader("Host", server + ":" + JSON::Value((long long)port).toString());
H.SendRequest(conn);
H.Clean();
while (conn && (!conn.spool() || !H.Read(conn))) {}
while (conn && (!conn.spool() || !H.Read(conn))){}
H.BuildResponse();
std::set<seekPos> currentPos;
std::vector<StreamData> streamData;
//DEBUG_MSG(DLVL_INFO, "body received: %s", H.body.c_str()); //keeps giving empty stuff :(
// DEBUG_MSG(DLVL_INFO, "url %s ", url.c_str());
//std::ifstream in(url.c_str());
//std::string s((std::istreambuf_iterator<char>(in)), std::istreambuf_iterator<char>());
if(!parseXML(H.body, currentPos,streamData)){
DEBUG_MSG(DLVL_FAIL, "Manifest parsing failed. body: \n %s", H.body.c_str());
if (conf.getString("mode") == "validate") {
std::vector<StreamData> streamData;
// DEBUG_MSG(DLVL_INFO, "body received: %s", H.body.c_str()); //keeps giving empty stuff :(
// DEBUG_MSG(DLVL_INFO, "url %s ", url.c_str());
// std::ifstream in(url.c_str());
// std::string s((std::istreambuf_iterator<char>(in)), std::istreambuf_iterator<char>());
if (!parseXML(H.body, currentPos, streamData)){
DEBUG_MSG(DLVL_FAIL, "Manifest parsing failed. body: \n %s", H.body.c_str());
if (conf.getString("mode") == "validate"){
long long int endTime = Util::bootSecs();
std::cout << startTime << ", " << endTime << ", " << (endTime - startTime) << ", " << pos << std::endl;
}
return -1;
}
H.Clean();
DEBUG_MSG(DLVL_INFO, "*********");
DEBUG_MSG(DLVL_INFO, "*SUMMARY*");
DEBUG_MSG(DLVL_INFO, "*********");
DEBUG_MSG(DLVL_INFO, "num streams: %lu", streamData.size());
for(unsigned int i=0; i<streamData.size();i++){
for (unsigned int i = 0; i < streamData.size(); i++){
DEBUG_MSG(DLVL_INFO, "");
DEBUG_MSG(DLVL_INFO, "ID in vector %d", i);
DEBUG_MSG(DLVL_INFO, "trackID %ld", streamData[i].trackID);
@ -414,77 +412,74 @@ int main(int argc, char ** argv) {
DEBUG_MSG(DLVL_INFO, "Media string %s", streamData[i].media.c_str());
DEBUG_MSG(DLVL_INFO, "Init string %s", streamData[i].initialization.c_str());
}
DEBUG_MSG(DLVL_INFO, "");
for(unsigned int i=0; i<streamData.size();i++){ //get init url
DEBUG_MSG(DLVL_INFO, "");
for (unsigned int i = 0; i < streamData.size(); i++){// get init url
static char charBuf[512];
snprintf(charBuf, 512, streamData[i].initialization.c_str(), streamData[i].trackID);
streamData[i].initURL.assign(charBuf);
DEBUG_MSG(DLVL_INFO, "init url for adaptationSet %d trackID %ld: %s ", streamData[i].adaptationSet, streamData[i].trackID, streamData[i].initURL.c_str());
DEBUG_MSG(DLVL_INFO, "init url for adaptationSet %d trackID %ld: %s ",
streamData[i].adaptationSet, streamData[i].trackID, streamData[i].initURL.c_str());
}
while(currentPos.size() && (abortTime <= 0 || Util::bootSecs() < startTime + abortTime)){
//DEBUG_MSG(DLVL_INFO, "next url: %s", currentPos.begin()->url.c_str());
//match adaptation set and track id?
int tempID=0;
for(unsigned int i=0; i<streamData.size();i++){
if( streamData[i].trackID == currentPos.begin()->trackID && streamData[i].adaptationSet == currentPos.begin()->adaptationSet ) tempID=i;
}
if (!conn) {
conn.open(server,port, false);
while (currentPos.size() && (abortTime <= 0 || Util::bootSecs() < startTime + abortTime)){
// DEBUG_MSG(DLVL_INFO, "next url: %s", currentPos.begin()->url.c_str());
// match adaptation set and track id?
int tempID = 0;
for (unsigned int i = 0; i < streamData.size(); i++){
if (streamData[i].trackID == currentPos.begin()->trackID &&
streamData[i].adaptationSet == currentPos.begin()->adaptationSet)
tempID = i;
}
if (!conn){conn.open(server, port, false);}
HTTP::Parser H;
H.url = urlPrependStuff;
H.url.append(currentPos.begin()->url);
DEBUG_MSG(DLVL_INFO, "Retrieving segment: %s (%llu-%llu)", H.url.c_str(),currentPos.begin()->seekTime, currentPos.begin()->seekTime+currentPos.begin()->duration);
H.SetHeader("Host", server + ":" + JSON::Value((long long)port).toString()); //wut?
H.url.append(currentPos.begin()->url);
DEBUG_MSG(DLVL_INFO, "Retrieving segment: %s (%llu-%llu)", H.url.c_str(),
currentPos.begin()->seekTime, currentPos.begin()->seekTime + currentPos.begin()->duration);
H.SetHeader("Host", server + ":" + JSON::Value((long long)port).toString()); // wut?
H.SendRequest(conn);
//TODO: get response?
// TODO: get response?
H.Clean();
while (conn && (!conn.spool() || !H.Read(conn))) {} //ehm...
//std::cout << "leh vomi: "<<H.body <<std::endl;
//DEBUG_MSG(DLVL_INFO, "zut: %s", H.body.c_str());
//strBuf[tempID].append(H.body);
if(!H.body.size()){
DEBUG_MSG(DLVL_FAIL, "No data downloaded from %s",H.url.c_str());
while (conn && (!conn.spool() || !H.Read(conn))){}// ehm...
// std::cout << "leh vomi: "<<H.body <<std::endl;
// DEBUG_MSG(DLVL_INFO, "zut: %s", H.body.c_str());
// strBuf[tempID].append(H.body);
if (!H.body.size()){
DEBUG_MSG(DLVL_FAIL, "No data downloaded from %s", H.url.c_str());
break;
}
size_t beforeParse = H.body.size();
MP4::Box mp4Data;
bool mdatSeen = false;
while(mp4Data.read(H.body)){
if (mp4Data.isType("mdat")){
mdatSeen = true;
}
while (mp4Data.read(H.body)){
if (mp4Data.isType("mdat")){mdatSeen = true;}
}
if (!mdatSeen){
DEBUG_MSG(DLVL_FAIL, "No mdat present. Sadface. :-(");
break;
}
if(H.body.size()){
DEBUG_MSG(DLVL_FAIL, "%lu bytes left in body. Assuming horrible things...", H.body.size());//,H.body.c_str());
if (H.body.size()){
DEBUG_MSG(DLVL_FAIL, "%lu bytes left in body. Assuming horrible things...", H.body.size()); //,H.body.c_str());
std::cerr << H.body << std::endl;
if (beforeParse == H.body.size()){
break;
}
}
H.Clean();
pos = 1000*(currentPos.begin()->seekTime+currentPos.begin()->duration)/streamData[tempID].timeScale;
if (conf.getString("mode") == "validate" && (Util::bootSecs()-startTime+5)*1000 < pos) {
Util::wait(pos - (Util::bootSecs()-startTime+5)*1000);
if (beforeParse == H.body.size()){break;}
}
H.Clean();
pos = 1000 * (currentPos.begin()->seekTime + currentPos.begin()->duration) / streamData[tempID].timeScale;
if (conf.getString("mode") == "validate" && (Util::bootSecs() - startTime + 5) * 1000 < pos){
Util::wait(pos - (Util::bootSecs() - startTime + 5) * 1000);
}
currentPos.erase(currentPos.begin());
}
if (conf.getString("mode") == "validate") {
if (conf.getString("mode") == "validate"){
long long int endTime = Util::bootSecs();
std::cout << startTime << ", " << endTime << ", " << (endTime - startTime) << ", " << pos << std::endl;
}
return 0;
}

View file

@ -15,4 +15,3 @@ int main(int argc, char *argv[]){
return 2;
}
}