diff --git a/src/output/output.cpp b/src/output/output.cpp index 70809c10..7b484ea6 100644 --- a/src/output/output.cpp +++ b/src/output/output.cpp @@ -105,6 +105,14 @@ namespace Mist{ INFO_MSG("Not modifying target (%s), no options present", tgt.c_str()); } } + if (targetParams.count("rate")){ + long long int multiplier = JSON::Value(targetParams["rate"]).asInt(); + if (multiplier){ + realTime = 1000 / multiplier; + }else{ + realTime = 0; + } + } /*LTS-END*/ } @@ -994,7 +1002,7 @@ namespace Mist{ } /*LTS-START*/ if (isRecordingToFile){ - if (myMeta.live && targetParams.count("recstartunix") || targetParams.count("recstopunix")){ + if (myMeta.live && (targetParams.count("recstartunix") || targetParams.count("recstopunix"))){ uint64_t unixStreamBegin = Util::epoch() - (liveTime() / 1000); if (targetParams.count("recstartunix")){ long long startUnix = atoll(targetParams["recstartunix"].c_str()); @@ -1054,6 +1062,69 @@ namespace Mist{ INFO_MSG("Recording will start at %lld", startRec); seekPos = startRec; } + }else{ + if (myMeta.live && (targetParams.count("startunix") || targetParams.count("stopunix"))){ + uint64_t unixStreamBegin = Util::epoch() - (liveTime() / 1000); + if (targetParams.count("startunix")){ + long long startUnix = atoll(targetParams["startunix"].c_str()); + if (startUnix < 0){startUnix += Util::epoch();} + if (startUnix < unixStreamBegin){ + WARN_MSG("Start time is earlier than stream begin - starting earliest possible"); + targetParams["start"] = "-1"; + }else{ + targetParams["start"] = JSON::Value((long long)((startUnix - unixStreamBegin)*1000)).asString(); + } + } + if (targetParams.count("stopunix")){ + long long stopUnix = atoll(targetParams["stopunix"].c_str()); + if (stopUnix < 0){stopUnix += Util::epoch();} + if (stopUnix < unixStreamBegin){ + FAIL_MSG("Stop time is earlier than stream begin - aborting"); + onFail(); + return; + }else{ + targetParams["stop"] = JSON::Value((long long)((stopUnix - unixStreamBegin)*1000)).asString(); + } + } + } + if (targetParams.count("stop")){ + long long endRec = atoll(targetParams["stop"].c_str()); + if (endRec < 0 || endRec < startTime()){ + FAIL_MSG("Entire range is in the past"); + onFail(); + return; + } + INFO_MSG("Playback will stop at %lld", endRec); + } + if (targetParams.count("start") && atoll(targetParams["start"].c_str()) != 0){ + unsigned long int mainTrack = getMainSelectedTrack(); + long long startRec = atoll(targetParams["start"].c_str()); + if (startRec > 0 && startRec > myMeta.tracks[mainTrack].lastms){ + if (myMeta.vod){ + FAIL_MSG("Playback start past end of non-live source"); + onFail(); + return; + } + INFO_MSG("Waiting for stream to reach playback starting point"); + long unsigned int streamAvail = myMeta.tracks[mainTrack].lastms; + long unsigned int lastUpdated = Util::getMS(); + while (Util::getMS() - lastUpdated < 5000 && startRec > streamAvail && keepGoing()){ + Util::sleep(500); + updateMeta(); + if (myMeta.tracks[mainTrack].lastms > streamAvail){ + stats(); + streamAvail = myMeta.tracks[mainTrack].lastms; + lastUpdated = Util::getMS(); + } + } + } + if (startRec < 0 || startRec < startTime()){ + WARN_MSG("Playback begin at %llu ms not available, starting at %llu ms instead", startRec, startTime()); + startRec = startTime(); + } + INFO_MSG("Playback will start at %lld", startRec); + seekPos = startRec; + } } /*LTS-END*/ MEDIUM_MSG("Initial seek to %llums", seekPos); @@ -1244,6 +1315,11 @@ namespace Mist{ if (!onFinish()){ break; } + }else if (targetParams.count("stop") && atoll(targetParams["stop"].c_str()) < lastPacketTime){ + INFO_MSG("End of planned playback reached, shutting down"); + if (!onFinish()){ + break; + } } sendNext(); }else{ diff --git a/src/output/output_http.cpp b/src/output/output_http.cpp index 91f77d21..6a82e57a 100644 --- a/src/output/output_http.cpp +++ b/src/output/output_http.cpp @@ -267,6 +267,28 @@ namespace Mist { if (H.GetVar("audio") != ""){targetParams["audio"] = H.GetVar("audio");} if (H.GetVar("video") != ""){targetParams["video"] = H.GetVar("video");} if (H.GetVar("subtitle") != ""){targetParams["subtitle"] = H.GetVar("subtitle");} + if (H.GetVar("start") != ""){targetParams["start"] = H.GetVar("start");} + if (H.GetVar("stop") != ""){targetParams["stop"] = H.GetVar("stop");} + if (H.GetVar("startunix") != ""){targetParams["startunix"] = H.GetVar("startunix");} + if (H.GetVar("stopunix") != ""){targetParams["stopunix"] = H.GetVar("stopunix");} + //allow setting of play back rate through buffer variable. + //play back rate is set in MS per second, but the variable is a simple multiplier. + if (H.GetVar("rate") != ""){ + long long int multiplier = JSON::Value(H.GetVar("rate")).asInt(); + if (multiplier){ + realTime = 1000 / multiplier; + }else{ + realTime = 0; + } + } + if (H.GetHeader("X-Mist-Rate") != ""){ + long long int multiplier = JSON::Value(H.GetHeader("X-Mist-Rate")).asInt(); + if (multiplier){ + realTime = 1000 / multiplier; + }else{ + realTime = 0; + } + } //Handle upgrade to websocket if the output supports it if (doesWebsockets() && H.GetHeader("Upgrade") == "websocket"){ INFO_MSG("Switching to Websocket mode"); diff --git a/src/output/output_progressive_mp4.cpp b/src/output/output_progressive_mp4.cpp index 20e47083..afcaa312 100644 --- a/src/output/output_progressive_mp4.cpp +++ b/src/output/output_progressive_mp4.cpp @@ -747,24 +747,6 @@ namespace Mist{ if (H.GetVar("buffer") != ""){ maxSkipAhead = JSON::Value(H.GetVar("buffer")).asInt() * 1000; } - //allow setting of play back rate through buffer variable. - //play back rate is set in MS per second, but the variable is a simple multiplier. - if (H.GetVar("rate") != ""){ - long long int multiplier = JSON::Value(H.GetVar("rate")).asInt(); - if (multiplier){ - realTime = 1000 / multiplier; - }else{ - realTime = 0; - } - } - if (H.GetHeader("X-Mist-Rate") != ""){ - long long int multiplier = JSON::Value(H.GetHeader("X-Mist-Rate")).asInt(); - if (multiplier){ - realTime = 1000 / multiplier; - }else{ - realTime = 0; - } - } //Set mode to key frames only for video tracks keysOnly = atoi(H.GetVar("keysonly").c_str());