diff --git a/lib/timing.cpp b/lib/timing.cpp index 3d7673a1..b4a7974f 100644 --- a/lib/timing.cpp +++ b/lib/timing.cpp @@ -4,6 +4,8 @@ #include "timing.h" #include //for gettimeofday #include //for time and nanosleep +#include +#include //emulate clock_gettime() for OSX compatibility #if defined(__APPLE__) || defined(__MACH__) @@ -97,3 +99,16 @@ long long unsigned int Util::getMicros(long long unsigned int previous) { long long int Util::epoch() { return time(0); } + +std::string Util::getUTCString(){ + time_t rawtime; + struct tm * ptm; + + time ( &rawtime ); + + ptm = gmtime ( &rawtime ); + + char result[20]; + snprintf(result, 20, "%0.4d-%0.2d-%0.2dT%0.2d:%0.2d:%0.2d", ptm->tm_year, ptm->tm_mon, ptm->tm_mday, ptm->tm_hour, ptm->tm_min, ptm->tm_sec); + return std::string(result); +} diff --git a/lib/timing.h b/lib/timing.h index 0c027a45..9e8a40f6 100644 --- a/lib/timing.h +++ b/lib/timing.h @@ -1,5 +1,6 @@ /// \file timing.h /// Utilities for handling time and timestamps. +#include #pragma once @@ -12,4 +13,5 @@ namespace Util { long long unsigned int getMicros(long long unsigned int previous);/// #include #include +#include namespace Mist { OutDashMP4::OutDashMP4(Socket::Connection & conn) : HTTPOutput(conn){realTime = 0;} @@ -199,6 +200,7 @@ namespace Mist { } std::string OutDashMP4::buildSidx(unsigned int tid){ + fragmentSizes[tid].clear(); MP4::AVCC avccBox; MP4::HVCC hvccBox; if (myMeta.tracks[tid].codec == "H264"){ @@ -376,6 +378,7 @@ namespace Mist { } void OutDashMP4::buildMdat(unsigned int tid, unsigned int keyNum){ + buildSidx(tid);//Nasty hack for updating fragment sizes... MP4::AVCC avccBox; avccBox.setPayload(myMeta.tracks[tid].init); std::stringstream r; @@ -424,10 +427,32 @@ namespace Mist { } return; } + + std::string OutDashMP4::h264init(const std::string & initData) { + std::stringstream r; + MP4::AVCC avccBox; + avccBox.setPayload(initData); + r << std::hex << std::setw(2) << std::setfill('0') << (int)avccBox.getSPS()[0] << std::dec; + r << std::hex << std::setw(2) << std::setfill('0') << (int)avccBox.getSPS()[1] << std::dec; + r << std::hex << std::setw(2) << std::setfill('0') << (int)avccBox.getSPS()[2] << std::dec; + return r.str(); + } + + std::string OutDashMP4::h265init(const std::string & initData) { + std::stringstream r; + r << std::hex << std::setw(2) << std::setfill('0') << (int)initData[1] << std::dec; + r << std::hex << std::setw(2) << std::setfill('0') << (int)initData[6] << std::dec; + r << std::hex << std::setw(2) << std::setfill('0') << (int)initData[7] << std::dec; + r << std::hex << std::setw(2) << std::setfill('0') << (int)initData[8] << std::dec; + r << std::hex << std::setw(2) << std::setfill('0') << (int)initData[9] << std::dec; + r << std::hex << std::setw(2) << std::setfill('0') << (int)initData[10] << std::dec; + r << std::hex << std::setw(2) << std::setfill('0') << (int)initData[11] << std::dec; + r << std::hex << std::setw(2) << std::setfill('0') << (int)initData[12] << std::dec; + return r.str(); + } std::string OutDashMP4::buildManifest(){ initialize(); - int lastTime = 0; int lastVidTime = 0; int vidKeys = 0; int vidInitTrack = 0; @@ -436,15 +461,7 @@ namespace Mist { int audInitTrack = 0; ///\todo Dash automatically selects the last audio and video track for manifest, maybe make this expandable/selectable? for (std::map::iterator it = myMeta.tracks.begin(); it != myMeta.tracks.end(); it ++){ - if (it->second.lastms > lastTime){ - lastTime = it->second.lastms; - } - if (it->second.codec == "H264" && it->second.lastms > lastVidTime){ - lastVidTime = it->second.lastms; - vidKeys = it->second.keys.size(); - vidInitTrack = it->first; - } - if (it->second.codec == "HEVC" && it->second.lastms > lastVidTime){ + if ((it->second.codec == "H264" || it->second.codec == "HEVC") && it->second.lastms > lastVidTime){ lastVidTime = it->second.lastms; vidKeys = it->second.keys.size(); vidInitTrack = it->first; @@ -457,47 +474,48 @@ namespace Mist { } std::stringstream r; r << "" << std::endl; - r << "" << std::endl; + r << "second.lastms - myMeta.tracks.begin()->second.firstms; + r << "timeShiftBufferDepth=\"PT" << bufferTime / 1000 << "." << bufferTime % 1000 << "S\" suggestedPresentationDelay=\"PT15.0S\" minBufferTime=\"PT6.0S\""; + } + r << " >" << std::endl; r << " " << streamName << "" << std::endl; - r << " " << std::endl; + r << " " << std::endl; if (vidInitTrack){ - r << " " << std::endl; + DTSC::Track & trackRef = myMeta.tracks[vidInitTrack]; + r << " " << std::endl; r << " " << std::endl; r << " " << std::endl; - for (int i = 0; i < myMeta.tracks[vidInitTrack].keys.size() - 1; i++){ - r << " " << std::endl; + r <<" " << std::endl; + for (int i = 1; i < trackRef.keys.size() - 1; i++){ + r << " " << std::endl; + } + if (myMeta.vod){ + int lastDur = trackRef.lastms - trackRef.keys.rbegin()->getTime(); + r << " " << std::endl; } - int lastDur = myMeta.tracks[vidInitTrack].lastms - myMeta.tracks[vidInitTrack].keys.rbegin()->getTime(); - r << " " << std::endl; r << " " << std::endl; r << " " << std::endl; for (std::map::iterator it = myMeta.tracks.begin(); it != myMeta.tracks.end(); it++){ if (it->second.codec == "H264"){ - MP4::AVCC avccBox; - avccBox.setPayload(it->second.init); r << " first << "\" "; - r << "codecs=\"avc1."; - r << std::hex << std::setw(2) << std::setfill('0') << (int)avccBox.getSPS()[0] << std::dec; - r << std::hex << std::setw(2) << std::setfill('0') << (int)avccBox.getSPS()[1] << std::dec; - r << std::hex << std::setw(2) << std::setfill('0') << (int)avccBox.getSPS()[2] << std::dec; - r << "\" "; + r << "codecs=\"avc1." << h264init(it->second.init) << "\" "; r << "bandwidth=\"" << it->second.bps << "\" "; r << "/>" << std::endl; } if (it->second.codec == "HEVC"){ r << " first << "\" "; - r << "codecs=\"hev1."; - r << std::hex << std::setw(2) << std::setfill('0') << (int)it->second.init[1] << std::dec; - r << std::hex << std::setw(2) << std::setfill('0') << (int)it->second.init[6] << std::dec; - r << std::hex << std::setw(2) << std::setfill('0') << (int)it->second.init[7] << std::dec; - r << std::hex << std::setw(2) << std::setfill('0') << (int)it->second.init[8] << std::dec; - r << std::hex << std::setw(2) << std::setfill('0') << (int)it->second.init[9] << std::dec; - r << std::hex << std::setw(2) << std::setfill('0') << (int)it->second.init[10] << std::dec; - r << std::hex << std::setw(2) << std::setfill('0') << (int)it->second.init[11] << std::dec; - r << std::hex << std::setw(2) << std::setfill('0') << (int)it->second.init[12] << std::dec; - r << "\" "; + r << "codecs=\"hev1." << h265init(it->second.init) << "\" "; r << "bandwidth=\"" << it->second.bps << "\" "; r << "/>" << std::endl; } @@ -505,16 +523,20 @@ namespace Mist { r << " " << std::endl; } if (audInitTrack){ + DTSC::Track & trackRef = myMeta.tracks[audInitTrack]; r << " " << std::endl; r << " " << std::endl; r << " " << std::endl; r << " " << std::endl; - for (int i = 0; i < myMeta.tracks[audInitTrack].keys.size() - 1; i++){ - r << " " << std::endl; + r <<" " << std::endl; + for (int i = 1; i < trackRef.keys.size() - 1; i++){ + r << " " << std::endl; + } + if (myMeta.vod){ + int lastDur = trackRef.lastms - trackRef.keys.rbegin()->getTime(); + r << " " << std::endl; } - int lastDur = myMeta.tracks[audInitTrack].lastms - myMeta.tracks[audInitTrack].keys.rbegin()->getTime(); - r << " " << std::endl; r << " " << std::endl; r << " " << std::endl; @@ -599,6 +621,9 @@ namespace Mist { void OutDashMP4::onHTTP(){ initialize(); + if (myMeta.live){ + updateMeta(); + } std::string url = H.url; if (H.method == "OPTIONS"){ H.Clean(); diff --git a/src/output/output_dash_mp4.h b/src/output/output_dash_mp4.h index 97fbeee4..67b366db 100644 --- a/src/output/output_dash_mp4.h +++ b/src/output/output_dash_mp4.h @@ -27,6 +27,9 @@ namespace Mist { void parseRange(std::string header, long long & byteStart, long long & byteEnd); int getKeyFromRange(unsigned int tid, long long int byteStart); std::map moovBoxes; + + std::string h264init(const std::string & initData); + std::string h265init(const std::string & initData); }; }