From fecfc200523b97996fca817a8e61a17daf6df7dc Mon Sep 17 00:00:00 2001 From: Thulinma Date: Tue, 7 Jun 2016 15:24:11 +0200 Subject: [PATCH] Improved output default seek position and completeKeyReady logic --- src/output/output.cpp | 76 +++++++++++++++++++++++++++++++------------ src/output/output.h | 1 + 2 files changed, 57 insertions(+), 20 deletions(-) diff --git a/src/output/output.cpp b/src/output/output.cpp index 315396fb..cb62bfde 100644 --- a/src/output/output.cpp +++ b/src/output/output.cpp @@ -215,7 +215,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()); @@ -560,6 +561,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); @@ -572,6 +574,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; @@ -606,6 +609,7 @@ namespace Mist { return seek(tid, pos, getNextKey); } } + selectedTracks.erase(tid); return false; } } @@ -875,6 +879,44 @@ namespace Mist { return code; } /*LTS-END*/ + + /// 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. @@ -927,19 +969,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){ @@ -963,13 +993,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].type == "audio"){continue;} - 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 2cef5090..a05c7157 100644 --- a/src/output/output.h +++ b/src/output/output.h @@ -70,6 +70,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; }