diff --git a/HLSPlugin/src/com/kaltura/hls/HLSIndexHandler.as b/HLSPlugin/src/com/kaltura/hls/HLSIndexHandler.as index 838777c..1831ab5 100644 --- a/HLSPlugin/src/com/kaltura/hls/HLSIndexHandler.as +++ b/HLSPlugin/src/com/kaltura/hls/HLSIndexHandler.as @@ -185,7 +185,7 @@ package com.kaltura.hls * streams that overflow the MPEG TS timestamps. Very long windows (>27 hours) may not work * properly. */ - public function updateSegmentTimes(segments:Vector., referenceTime:Number = NaN):Vector. + public function updateSegmentTimes(segments:Vector., referenceTime:Number = 0):Vector. { // Keep track of whatever segments we've assigned to. var setSegments:Object = {}; @@ -199,14 +199,11 @@ package com.kaltura.hls if(!startTimeWitnesses.hasOwnProperty(curUri)) continue; - if(false) trace("Segment #" + i + " from start witness " + startTimeWitnesses[curUri]); + //trace("Segment #" + i + " from start witness " + startTimeWitnesses[curUri]); segments[i].startTime = startTimeWitnesses[curUri]; if(endTimeWitnesses.hasOwnProperty(curUri)) - { - if(false) trace("Segment #" + i + " from end witness " + endTimeWitnesses[curUri]); segments[i].duration = endTimeWitnesses[curUri] - segments[i].startTime; - } setSegments[i] = 1; } @@ -216,12 +213,8 @@ package com.kaltura.hls // Then fill in any unknowns scanning forward.... for(i=1; i=0; i--) { - // We have an explicit value for this one, don't change it. - if(setSegments.hasOwnProperty(i)) - continue; - - // If the next one isn't known, don't propagate it back. - if(!setSegments.hasOwnProperty(i+1)) + // Skip unknowns and explicitly set values. + if(!setSegments.hasOwnProperty(i+1) || setSegments.hasOwnProperty(i)) continue; segments[i].startTime = segments[i+1].startTime - segments[i].duration; @@ -251,16 +240,12 @@ package com.kaltura.hls } // Dump results: - if(false) + /*trace("Last 10 manifest time reconstruction"); + for(i=Math.max(0, segments.length - 100); i= manifest.streams.length ) return updateSegmentTimes(manifest.streams[0].manifest.segments); + else return updateSegmentTimes(manifest.streams[quality].manifest.segments); } private function getManifestForQuality( quality:int):HLSManifestParser @@ -1847,18 +1813,16 @@ package com.kaltura.hls */ private function onBestEffortDownloadComplete(event:HTTPStreamingEvent):void { - var downloader:HLSHTTPStreamDownloader = event.downloader as HLSHTTPStreamDownloader; - if(_bestEffortDownloaderMonitor == null || _bestEffortDownloaderMonitor != event.target as IEventDispatcher) { // we're receiving an event for a download we abandoned - trace("Got event for abandoned best effort download! Attempting to close downloader."); - if(downloader) downloader.close(); + trace("Got event for abandoned best effort download!"); return; } // If we have 512kb of the segment and it's a progress event, we can probably get a timestamp. + var downloader:HLSHTTPStreamDownloader = event.downloader as HLSHTTPStreamDownloader; if(downloader.totalAvailableBytes < 512*1024 && downloader.isComplete == false && event.type == HTTPStreamingEvent.DOWNLOAD_PROGRESS) return; diff --git a/HLSPlugin/src/com/kaltura/hls/m2ts/PESProcessor.as b/HLSPlugin/src/com/kaltura/hls/m2ts/PESProcessor.as index b57137e..30d6834 100644 --- a/HLSPlugin/src/com/kaltura/hls/m2ts/PESProcessor.as +++ b/HLSPlugin/src/com/kaltura/hls/m2ts/PESProcessor.as @@ -41,7 +41,7 @@ package com.kaltura.hls.m2ts protected var pendingBuffers:Vector. = new Vector.(); protected var pendingLastConvertedIndex:int = 0; - public var lastPTS:Number = NaN, lastDTS:Number = NaN; + public var lastPTS:Number = 0, lastDTS:Number = 0; /** * Given a MPEG timestamp we've seen previously, determine if the new timestamp @@ -74,7 +74,7 @@ package com.kaltura.hls.m2ts transcoder.clear(clearAACConfig); // Reset PTS/DTS reference. - lastPTS = lastDTS = NaN; + lastPTS = lastDTS = 0; } private function parseProgramAssociationTable(bytes:ByteArray, cursor:uint):Boolean diff --git a/HLSPlugin/src/org/osmf/net/httpstreaming/HLSHTTPNetStream.as b/HLSPlugin/src/org/osmf/net/httpstreaming/HLSHTTPNetStream.as index 2ea09cd..17165dc 100644 --- a/HLSPlugin/src/org/osmf/net/httpstreaming/HLSHTTPNetStream.as +++ b/HLSPlugin/src/org/osmf/net/httpstreaming/HLSHTTPNetStream.as @@ -470,6 +470,9 @@ package org.osmf.net.httpstreaming // This code is optimized because it is frequently called and causes // (on FF FP 17 debug) one second frame drop events when too slow. + if(isNaN(_initialTime)) + return _lastValidTimeTime; + var startTime:int = getTimer(); // Do we need to expire the cache? @@ -498,6 +501,7 @@ package org.osmf.net.httpstreaming } _timeCache_streamStartAbsoluteTime = indexHandler.streamStartAbsoluteTime; + _timeCache_LastUpdatedTimestamp = startTime; } @@ -507,12 +511,9 @@ package org.osmf.net.httpstreaming //trace(" super.time (" + super.time + ") + " + _initialTime + " = " + potentialNewTime); // If we are VOD, then offset time so 0 seconds is the start of the stream. - if(indexHandler) - { - var lastMan:HLSManifestParser = indexHandler.getLastSequenceManifest(); - if(lastMan && lastMan.streamEnds == true && _timeCache_streamStartAbsoluteTime) - potentialNewTime -= _timeCache_streamStartAbsoluteTime; - } + var lastMan:HLSManifestParser = indexHandler.getLastSequenceManifest(); + if(lastMan && lastMan.streamEnds == true && _timeCache_streamStartAbsoluteTime) + potentialNewTime -= _timeCache_streamStartAbsoluteTime; // Take into account any cached live edge offset. if(_timeCache_liveEdge != Number.MAX_VALUE) @@ -1116,9 +1117,6 @@ package org.osmf.net.httpstreaming indexHandler.bumpedTime = false; } - // Clear time cache to ensure accurate time reporting. - _timeCache_LastUpdatedTimestamp = NaN; - // Netstream seek in data generation mode only clears the buffer. // It does not matter what value you pass to it. However, netstream // apparently doesn't do that if the value given is larger than @@ -1207,7 +1205,7 @@ package org.osmf.net.httpstreaming setState(HTTPStreamingState.SEEK); break; } - + // start the recovery process if we need to recover and our buffer is getting too low if (recoveryDelayTimer.running && recoveryDelayTimer.currentCount >= 1) { @@ -1248,7 +1246,7 @@ package org.osmf.net.httpstreaming if ( (_state != HTTPStreamingState.PLAY) // we are no longer in play mode || (bytes == null) // or we don't have any additional data - || (processed >= OSMFSettings.hdsBytesProcessingLimit && isNaN(_enhancedSeekTarget)) // or we have processed enough data + || (processed >= OSMFSettings.hdsBytesProcessingLimit) // or we have processed enough data ) { keepProcessing = false; @@ -1879,11 +1877,7 @@ package org.osmf.net.httpstreaming { // we need to parse the initial bytes _flvParserProcessed = 0; - inBytes.position = 0; - - // Apply sanity to any seek values. - capSeekToLiveEdge(); - + inBytes.position = 0; _flvParser.parse(inBytes, true, onTag); processed += _flvParserProcessed; if(!_flvParserDone) @@ -1960,21 +1954,12 @@ package org.osmf.net.httpstreaming return timestampCastHelper; } - private var _capSeekToLiveEdge_LastRunTime:Number = 0; - protected function capSeekToLiveEdge():void { - var curTime:int = getTimer(); - if(curTime - _capSeekToLiveEdge_LastRunTime < 1000) - return; - // Make sure we don't go past the live edge even if it changes while seeking. if(!indexHandler || !indexHandler.isLiveEdgeValid) return; - // Met prereqs so we don't have to check as much now. - _capSeekToLiveEdge_LastRunTime = curTime; - var liveEdgeValue:Number = indexHandler.liveEdge; //trace("Seeing live edge of " + liveEdgeValue); @@ -1998,6 +1983,7 @@ package org.osmf.net.httpstreaming */ private function onTag(tag:FLVTag):Boolean { + capSeekToLiveEdge(); if(_enhancedSeekTarget == Number.MAX_VALUE) { @@ -2018,19 +2004,23 @@ package org.osmf.net.httpstreaming logger.debug("Saw tag @ " + realTimestamp + " timestamp=" + tag.timestamp + " currentTime=" + currentTime + " _seekTime=" + _seekTime + " _enhancedSeekTarget="+ _enhancedSeekTarget + " dataSize=" + tag.dataSize); } - if (_playForDuration >= 0 && !isNaN(_initialTime)) + if (_playForDuration >= 0) { - if (currentTime > (_initialTime + _playForDuration)) + if (_initialTime >= 0) // until we know this, we don't know where to stop, and if we're enhanced-seeking then we need that logic to be what sets this up { - setState(HTTPStreamingState.STOP); - _flvParserDone = true; - if (!isNaN(_seekTime)) + if (currentTime > (_initialTime + _playForDuration)) { - _seekTime = _playForDuration + _initialTime; // FMS behavior... the time is always the final time, even if we seek to past it - // XXX actually, FMS actually lets exactly one frame though at that point and that's why the time gets to be what it is - // XXX that we don't exactly mimic that is also why setting a duration of zero doesn't do what FMS does (plays exactly that one still frame) + + setState(HTTPStreamingState.STOP); + _flvParserDone = true; + if (_seekTime < 0) + { + _seekTime = _playForDuration + _initialTime; // FMS behavior... the time is always the final time, even if we seek to past it + // XXX actually, FMS actually lets exactly one frame though at that point and that's why the time gets to be what it is + // XXX that we don't exactly mimic that is also why setting a duration of zero doesn't do what FMS does (plays exactly that one still frame) + } + return false; } - return false; } } @@ -2039,8 +2029,7 @@ package org.osmf.net.httpstreaming // Note if we have encountered an I-frame. var sawIFrame:Boolean = isTagIFrame(tag as FLVTagVideo); - if (currentTime < _enhancedSeekTarget - || (_enhancedSeekTags != null && _enhancedSeekSawIFrame == false)) + if (currentTime < _enhancedSeekTarget || (_enhancedSeekTags != null && _enhancedSeekSawIFrame == false)) { CONFIG::LOGGING { @@ -2105,8 +2094,7 @@ package org.osmf.net.httpstreaming super.pause(); _initialTime = NaN; - _timeCache_LastUpdatedTimestamp = NaN; - + var codecID:int; var haveSeenVideoTag:Boolean = false; @@ -2132,7 +2120,6 @@ package org.osmf.net.httpstreaming haveSeenVideoTag = true; } - // Copy timestamp unmodified. vTag.timestamp = tag.timestamp; var bytes:ByteArray = new ByteArray(); @@ -2166,6 +2153,7 @@ package org.osmf.net.httpstreaming // Update the last written time so we don't RESET_SEEK inappropriately. lastWrittenTime = wrapTagTimestampToFLVTimestamp(tag.timestamp) / 1000.0; + } // and append this one @@ -2663,7 +2651,7 @@ package org.osmf.net.httpstreaming // Skip totally implausible tags - we need to splice which means the splice must happen after // tags we have fed into the flash decoder. if(!scanningForIFrame && - pendingTags.length > 0 && realTimestamp < wrapTagTimestampToFLVTimestamp(pendingTags[0].timestamp) - 64) + pendingTags.length > 0 && realTimestamp < wrapTagTimestampToFLVTimestamp(pendingTags[0].timestamp)) { scanningForIFrame = true;