From 7c89122a527cec8e23fe596dd6907b059c1a1470 Mon Sep 17 00:00:00 2001 From: Thulinma Date: Fri, 10 Jun 2016 14:17:42 +0200 Subject: [PATCH] Improved output default seek position and completeKeyReady logic --- src/output/output.cpp | 75 ++++++++++++++++++++++++++++++++----------- src/output/output.h | 1 + 2 files changed, 57 insertions(+), 19 deletions(-) diff --git a/src/output/output.cpp b/src/output/output.cpp index 6c3c7ac2..9f5f7ed9 100644 --- a/src/output/output.cpp +++ b/src/output/output.cpp @@ -128,7 +128,8 @@ namespace Mist { if (!selectedTracks.size()){ selectDefaultTracks(); } - if (myMeta.tracks[getMainSelectedTrack()].keys.size() >= 2){ + unsigned int mainTrack = getMainSelectedTrack(); + if (mainTrack && myMeta.tracks.count(mainTrack) && myMeta.tracks[mainTrack].keys.size() >= 2){ return true; }else{ HIGH_MSG("NOT READY YET (%lu tracks, %lu = %lu keys)", myMeta.tracks.size(), getMainSelectedTrack(), myMeta.tracks[getMainSelectedTrack()].keys.size()); @@ -473,6 +474,7 @@ namespace Mist { bool Output::seek(unsigned int tid, unsigned long long pos, bool getNextKey){ if (myMeta.tracks[tid].lastms < pos){ INFO_MSG("Aborting seek to %llums in track %u: past end of track (= %llums).", pos, tid, myMeta.tracks[tid].lastms); + selectedTracks.erase(tid); return false; } unsigned int keyNum = getKeyForTime(tid, pos); @@ -485,6 +487,7 @@ namespace Mist { loadPageForKey(tid, keyNum + (getNextKey?1:0)); if (!nProxy.curPage.count(tid) || !nProxy.curPage[tid].mapped){ INFO_MSG("Aborting seek to %llums in track %u: not available.", pos, tid); + selectedTracks.erase(tid); return false; } sortedPageInfo tmp; @@ -519,9 +522,48 @@ namespace Mist { return seek(tid, pos, getNextKey); } } + selectedTracks.erase(tid); return false; } } + + /// This function decides where in the stream initial playback starts. + /// The default implementation calls seek(0) for VoD. + /// For live, it seeks to the last sync'ed keyframe of the main track. + /// Unless lastms < 5000, then it seeks to the first keyframe of the main track. + /// Aborts if there is no main track or it has no keyframes. + void Output::initialSeek(){ + unsigned long long seekPos = 0; + if (myMeta.live){ + long unsigned int mainTrack = getMainSelectedTrack(); + //cancel if there are no keys in the main track + if (!myMeta.tracks.count(mainTrack) || !myMeta.tracks[mainTrack].keys.size()){return;} + //seek to the newest keyframe, unless that is <5s, then seek to the oldest keyframe + for (std::deque::reverse_iterator it = myMeta.tracks[mainTrack].keys.rbegin(); it != myMeta.tracks[mainTrack].keys.rend(); ++it){ + seekPos = it->getTime(); + if (seekPos < 5000){continue;}//if we're near the start, skip back + 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 (mainTrack == *ti){continue;}//skip self + if (!myMeta.tracks.count(*ti)){ + HIGH_MSG("Skipping track %lu, not in tracks", *ti); + continue; + }//ignore missing tracks + if (myMeta.tracks[*ti].lastms == myMeta.tracks[*ti].firstms){ + HIGH_MSG("Skipping track %lu, last equals first", *ti); + continue; + }//ignore point-tracks + if (myMeta.tracks[*ti].lastms < seekPos){good = false; break;} + HIGH_MSG("Track %lu is good", *ti); + } + //if yes, seek here + if (good){break;} + } + } + MEDIUM_MSG("Initial seek to %llums", seekPos); + seek(seekPos); + } void Output::requestHandler(){ static bool firstData = true;//only the first time, we call onRequest if there's data buffered already. @@ -551,19 +593,7 @@ namespace Mist { sendHeader(); } if (!sought){ - if (myMeta.live){ - long unsigned int mainTrack = getMainSelectedTrack(); - //cancel if there are no keys in the main track - if (!myMeta.tracks.count(mainTrack) || !myMeta.tracks[mainTrack].keys.size()){break;} - //seek to the newest keyframe, unless that is <5s, then seek to the oldest keyframe - unsigned long long seekPos = myMeta.tracks[mainTrack].keys.rbegin()->getTime(); - if (seekPos < 5000){ - seekPos = myMeta.tracks[mainTrack].keys.begin()->getTime(); - } - seek(seekPos); - }else{ - seek(0); - } + initialSeek(); } if (prepareNext()){ if (thisPacket){ @@ -587,12 +617,19 @@ namespace Mist { if (thisTimeoutTries > timeoutTries) timeoutTries = thisTimeoutTries; } } + unsigned int mTrack = getMainSelectedTrack(); while(!completeKeyReady && timeoutTries>0){ - completeKeyReady = true; - for (std::set::iterator it = selectedTracks.begin(); it != selectedTracks.end(); it++){ - if (!myMeta.tracks[*it].keys.size() || myMeta.tracks[*it].keys.rbegin()->getTime() + myMeta.tracks[*it].keys.rbegin()->getLength() <= thisPacket.getTime() ){ - completeKeyReady = false; - break; + if (!myMeta.tracks[mTrack].keys.size() || myMeta.tracks[mTrack].keys.rbegin()->getTime() <= thisPacket.getTime()){ + completeKeyReady = false; + }else{ + DTSC::Key & mustHaveKey = myMeta.tracks[mTrack].getKey(getKeyForTime(mTrack, thisPacket.getTime())); + unsigned long long mustHaveTime = mustHaveKey.getTime() + mustHaveKey.getLength(); + completeKeyReady = true; + for (std::set::iterator it = selectedTracks.begin(); it != selectedTracks.end(); it++){ + if (myMeta.tracks[*it].lastms < mustHaveTime){ + completeKeyReady = false; + break; + } } } if (!completeKeyReady){ diff --git a/src/output/output.h b/src/output/output.h index 17d95c60..bb7f734e 100644 --- a/src/output/output.h +++ b/src/output/output.h @@ -58,6 +58,7 @@ namespace Mist { bool prepareNext(); virtual void dropTrack(uint32_t trackId, std::string reason, bool probablyBad = true); virtual void onRequest(); + virtual void initialSeek(); virtual bool onFinish() { return false; }