diff --git a/CMakeLists.txt b/CMakeLists.txt index 180eb911..a9472bc1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -383,6 +383,10 @@ makeOutput(RTSP rtsp)#LTS makeOutput(TSPush ts_push ts)#LTS makeOutput(DASH dash_mp4 http)#LTS +if (DEFINED WITH_SANITY ) + makeOutput(SanityCheck sanitycheck)#LTS +endif() + add_executable(MistOutHTTP src/output/mist_out.cpp src/output/output.cpp diff --git a/src/output/output_sanitycheck.cpp b/src/output/output_sanitycheck.cpp new file mode 100644 index 00000000..2de554be --- /dev/null +++ b/src/output/output_sanitycheck.cpp @@ -0,0 +1,91 @@ +#include +#include +#include +#include "output_sanitycheck.h" + +namespace Mist { + OutSanityCheck::OutSanityCheck(Socket::Connection & conn) : Output(conn){ + streamName = config->getString("streamname"); + parseData = true; + wantRequest = false; + initialize(); + initialSeek(); + sortSet.clear(); + for (std::set::iterator subIt = selectedTracks.begin(); subIt != selectedTracks.end(); subIt++) { + keyPart temp; + temp.trackID = *subIt; + temp.time = myMeta.tracks[*subIt].firstms;//timeplace of frame + temp.endTime = myMeta.tracks[*subIt].firstms + myMeta.tracks[*subIt].parts[0].getDuration(); + temp.size = myMeta.tracks[*subIt].parts[0].getSize();//bytesize of frame (alle parts all together) + temp.index = 0; + sortSet.insert(temp); + } + realTime = 0; + + if (config->getInteger("seek")){ + uint64_t seekPoint = config->getInteger("seek"); + + while (!sortSet.empty() && sortSet.begin()->time < seekPoint) { + keyPart temp; + temp.index = sortSet.begin()->index + 1; + temp.trackID = sortSet.begin()->trackID; + if (temp.index < myMeta.tracks[temp.trackID].parts.size()) { //only insert when there are parts left + temp.time = sortSet.begin()->endTime;//timeplace of frame + temp.endTime = sortSet.begin()->endTime + myMeta.tracks[temp.trackID].parts[temp.index].getDuration(); + temp.size = myMeta.tracks[temp.trackID].parts[temp.index].getSize();//bytesize of frame + sortSet.insert(temp); + } + //remove highest keyPart + sortSet.erase(sortSet.begin()); + } + seek(seekPoint); + } + + + } + + void OutSanityCheck::init(Util::Config * cfg) { + Output::init(cfg); + capa["name"] = "SanityCheck"; + capa["desc"] = "Does sanity check on a stream"; + capa["codecs"][0u][0u].append("*"); + cfg->addOption("streamname", JSON::fromString("{\"arg\":\"string\",\"short\":\"s\",\"long\":\"stream\",\"help\":\"The name of the stream that this connector will transmit.\"}")); + cfg->addOption("seek", JSON::fromString("{\"arg\":\"string\",\"short\":\"S\",\"long\":\"seek\",\"help\":\"Time in ms to check from - by default start of stream\"}")); + cfg->addBasicConnectorOptions(capa); + config = cfg; + } + + void OutSanityCheck::sendNext() { + if ((unsigned long)thisPacket.getTrackId() != sortSet.begin()->trackID || thisPacket.getTime() != sortSet.begin()->time) { + while (packets.size()){ + std::cout << packets.front() << std::endl; + packets.pop_front(); + } + std::cout << "Input is inconsistent! Expected " << sortSet.begin()->trackID << ":" << sortSet.begin()->time << " but got " << thisPacket.getTrackId() << ":" << thisPacket.getTime() << " (part " << sortSet.begin()->index << " in " << myMeta.tracks[sortSet.begin()->trackID].codec << " track)" << std::endl; + myConn.close(); + return; + } + + //Packet is normally sent here + packets.push_back(thisPacket.toSummary()); + while (packets.size() > 10){packets.pop_front();} + + //keep track of where we are + if (!sortSet.empty()) { + keyPart temp; + temp.index = sortSet.begin()->index + 1; + temp.trackID = sortSet.begin()->trackID; + if (temp.index < myMeta.tracks[temp.trackID].parts.size()) { //only insert when there are parts left + temp.time = sortSet.begin()->endTime;//timeplace of frame + temp.endTime = sortSet.begin()->endTime + myMeta.tracks[temp.trackID].parts[temp.index].getDuration(); + temp.size = myMeta.tracks[temp.trackID].parts[temp.index].getSize();//bytesize of frame + sortSet.insert(temp); + } + //remove highest keyPart + sortSet.erase(sortSet.begin()); + } + + } + +} + diff --git a/src/output/output_sanitycheck.h b/src/output/output_sanitycheck.h new file mode 100644 index 00000000..bdc7aa50 --- /dev/null +++ b/src/output/output_sanitycheck.h @@ -0,0 +1,43 @@ +#include "output.h" +#include + +namespace Mist { + struct keyPart{ + public: + bool operator < (const keyPart& rhs) const { + if (time < rhs.time){ + return true; + } + if (time == rhs.time){ + if (trackID < rhs.trackID){ + return true; + } + if (trackID == rhs.trackID){ + return index < rhs.index; + } + } + return false; + } + long unsigned int trackID; + long unsigned int size; + long long unsigned int time; + long long unsigned int endTime; + long long unsigned int byteOffset;//added for MP4 fragmented + long int timeOffset;//added for MP4 fragmented + long unsigned int duration;//added for MP4 fragmented + long unsigned int index; + }; + + class OutSanityCheck : public Output { + public: + OutSanityCheck(Socket::Connection & conn); + static void init(Util::Config * cfg); + void sendNext(); + static bool listenMode(){return false;} + protected: + std::deque packets; + std::set sortSet;//needed for unfragmented MP4, remembers the order of keyparts + }; +} + +typedef Mist::OutSanityCheck mistOut;