diff --git a/src/output/output.cpp b/src/output/output.cpp index 7b62be17..4f82a1f0 100644 --- a/src/output/output.cpp +++ b/src/output/output.cpp @@ -786,6 +786,53 @@ namespace Mist{ seek(seekPos); } + /// This function attempts to forward playback in live streams to a more live point. + /// It seeks to the last sync'ed keyframe of the main track, no closer than needsLookAhead+minKeepAway ms from the end. + /// Aborts if not live, there is no main track or it has no keyframes. + bool Output::liveSeek(){ + unsigned long long seekPos = 0; + if (!myMeta.live){return false;} + long unsigned int mainTrack = getMainSelectedTrack(); + //cancel if there are no keys in the main track + if (!myMeta.tracks.count(mainTrack)){return false;} + DTSC::Track & mainTrk = myMeta.tracks[mainTrack]; + if (!mainTrk.keys.size()){return false;} + uint32_t minKeepAway = mainTrk.minKeepAway; + + //Only skip forward if we can win at least 500ms + if (thisPacket.getTime() + 500 > mainTrk.keys.rbegin()->getTime()){ + return false; + } + + for (std::deque::reverse_iterator it = myMeta.tracks[mainTrack].keys.rbegin(); it != myMeta.tracks[mainTrack].keys.rend(); ++it){ + seekPos = it->getTime(); + if(seekPos <= thisPacket.getTime()){return false;} + bool good = true; + //check if all tracks have data for this point in time + for (std::set::iterator ti = selectedTracks.begin(); ti != selectedTracks.end(); ++ti){ + if (!myMeta.tracks.count(*ti)){ + HIGH_MSG("Skipping track %lu, not in tracks", *ti); + continue; + }//ignore missing tracks + DTSC::Track & thisTrack = myMeta.tracks[*ti]; + if (thisTrack.lastms < seekPos+needsLookAhead+thisTrack.minKeepAway){good = false; break;} + if (mainTrack == *ti){continue;}//skip self + if (thisTrack.lastms == thisTrack.firstms){ + HIGH_MSG("Skipping track %lu, last equals first", *ti); + continue; + }//ignore point-tracks + HIGH_MSG("Track %lu is good", *ti); + } + //if yes, seek here + if (good){ + INFO_MSG("Skipping forward %llums (%u ms LA, %lu ms mKA)", seekPos - thisPacket.getTime(), needsLookAhead, mainTrk.minKeepAway); + seek(seekPos); + return true; + } + } + return false; + } + void Output::requestHandler(){ static bool firstData = true;//only the first time, we call onRequest if there's data buffered already. if ((firstData && myConn.Received().size()) || myConn.spool()){ diff --git a/src/output/output.h b/src/output/output.h index daf1310f..d2bcde61 100644 --- a/src/output/output.h +++ b/src/output/output.h @@ -69,6 +69,7 @@ namespace Mist { virtual void onRequest(); static void listener(Util::Config & conf, int (*callback)(Socket::Connection & S)); virtual void initialSeek(); + virtual bool liveSeek(); virtual bool onFinish() { return false; } diff --git a/src/output/output_progressive_mp4.cpp b/src/output/output_progressive_mp4.cpp index 3c7ea83c..693449a1 100644 --- a/src/output/output_progressive_mp4.cpp +++ b/src/output/output_progressive_mp4.cpp @@ -925,16 +925,8 @@ namespace Mist { if (myMeta.live) { //if header needed if (!partListLength || partListSent >= partListLength) { - DTSC::Track & mainTrk = myMeta.tracks[vidTrack]; - // The extra 2000ms here is for the metadata sync delay. - // It can be removed once we get rid of that. - // (sync delay = ~1s, minimum lookAhead is 420ms -> ~600ms extra needed, we use 2000ms to be safe) - if (myMeta.sourceURI.find("http://") == std::string::npos || myMeta.sourceURI.find(".m3u") == std::string::npos){ - if (fragSeqNum > 10 && thisPacket.getTime() + needsLookAhead + 2000 < mainTrk.keys.rbegin()->getTime() && mainTrk.lastms - mainTrk.keys.rbegin()->getTime() > needsLookAhead){ - INFO_MSG("Skipping forward %llums (%u ms LA)", mainTrk.keys.rbegin()->getTime() - thisPacket.getTime(), needsLookAhead); - seek(mainTrk.keys.rbegin()->getTime()); - return; - } + if (fragSeqNum > 10){ + if (liveSeek()){return;} } //building set first buildFragment();//map with metadata for keyframe diff --git a/src/output/output_rtsp.cpp b/src/output/output_rtsp.cpp index 667dade4..a011cd6d 100644 --- a/src/output/output_rtsp.cpp +++ b/src/output/output_rtsp.cpp @@ -108,16 +108,7 @@ namespace Mist{ if (myMeta.live && lastTimeSync + 666 < timestamp){ lastTimeSync = timestamp; updateMeta(); - DTSC::Track &mainTrk = myMeta.tracks[getMainSelectedTrack()]; - // The extra 2000ms here is for the metadata sync delay. - // It can be removed once we get rid of that. - if (timestamp + 2000 + needsLookAhead < mainTrk.keys.rbegin()->getTime() && - mainTrk.lastms - mainTrk.keys.rbegin()->getTime() > needsLookAhead){ - INFO_MSG("Skipping forward %llums (%llu ms LA)", - mainTrk.keys.rbegin()->getTime() - thisPacket.getTime(), needsLookAhead); - seek(mainTrk.keys.rbegin()->getTime()); - return; - } + if (liveSeek()){return;} } void *socket = 0;