Restyle
This commit is contained in:
parent
5b79f296d6
commit
fccf66fba2
280 changed files with 56975 additions and 71885 deletions
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
@ -38,4 +38,3 @@ protected:
|
|||
uint64_t finTime; ///< Unix time of last packet received
|
||||
bool *isActive; ///< Pointer to is_active bool from config
|
||||
};
|
||||
|
||||
|
|
|
@ -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> ¤tPos) {
|
||||
bool parseAdaptationSet(std::string &data, std::set<seekPos> ¤tPos){
|
||||
// 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> ¤tPos) {
|
|||
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> ¤tPos) {
|
|||
|
||||
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> ¤tPos) {
|
|||
|
||||
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> ¤tPos) {
|
|||
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> ¤tPos) {
|
|||
// 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> ¤tPos) {
|
|||
|
||||
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> ¤tPos, std::vector<StreamData> &streamData) {
|
||||
bool parseXML(std::string &body, std::set<seekPos> ¤tPos, 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> ¤tPos, 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> ¤tPos, 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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -14,4 +14,3 @@ private:
|
|||
Socket::Connection conn;
|
||||
uint64_t totalBytes;
|
||||
};
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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.
|
||||
};
|
||||
|
||||
|
|
|
@ -37,4 +37,3 @@ bool AnalyserFLV::parsePacket(){
|
|||
mediaTime = flvData.tagTime();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -11,4 +11,3 @@ private:
|
|||
FLV::Tag flvData;
|
||||
long long filter;
|
||||
};
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -12,4 +12,3 @@ private:
|
|||
uint64_t neededBytes();
|
||||
bool sizePrepended;
|
||||
};
|
||||
|
||||
|
|
|
@ -132,4 +132,3 @@ bool AnalyserHLS::parsePacket(){
|
|||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
|
@ -42,4 +42,3 @@ uint64_t AnalyserMP4::neededBytes(){
|
|||
size += ntohl(((int *)mp4Buffer.data())[3]);
|
||||
return size;
|
||||
}
|
||||
|
||||
|
|
|
@ -14,4 +14,3 @@ private:
|
|||
uint64_t curPos;
|
||||
uint64_t prePos;
|
||||
};
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -13,4 +13,3 @@ private:
|
|||
OGG::Page oggPage;
|
||||
int kfgshift;
|
||||
};
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -12,4 +12,3 @@ private:
|
|||
uint64_t curPos;
|
||||
uint64_t prePos;
|
||||
};
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
};
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -21,4 +21,3 @@ private:
|
|||
DTSC::Meta myMeta;
|
||||
SDP::State sdpState;
|
||||
};
|
||||
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
|
@ -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> ¤tPos){
|
||||
//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> ¤tPos){
|
||||
// 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> ¤tPos, 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> ¤tPos, 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;
|
||||
}
|
||||
|
|
|
@ -15,4 +15,3 @@ int main(int argc, char *argv[]){
|
|||
return 2;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue