diff options
Diffstat (limited to 'dom/media/mediasource/TrackBuffersManager.cpp')
-rw-r--r-- | dom/media/mediasource/TrackBuffersManager.cpp | 130 |
1 files changed, 35 insertions, 95 deletions
diff --git a/dom/media/mediasource/TrackBuffersManager.cpp b/dom/media/mediasource/TrackBuffersManager.cpp index e939442d3..fb57a4506 100644 --- a/dom/media/mediasource/TrackBuffersManager.cpp +++ b/dom/media/mediasource/TrackBuffersManager.cpp @@ -55,15 +55,14 @@ TrackBuffersManager::TrackBuffersManager(dom::SourceBufferAttributes* aAttribute , mType(aType) , mParser(ContainerParser::CreateForMIMEType(aType)) , mProcessedInput(0) - , mAppendRunning(false) , mTaskQueue(aParentDecoder->GetDemuxer()->GetTaskQueue()) , mSourceBufferAttributes(aAttributes) , mParentDecoder(new nsMainThreadPtrHolder<MediaSourceDecoder>(aParentDecoder, false /* strict */)) - , mAbort(false) , mEvictionThreshold(Preferences::GetUint("media.mediasource.eviction_threshold", 100 * (1 << 20))) , mEvictionOccurred(false) , mMonitor("TrackBuffersManager") + , mAppendRunning(false) { MOZ_ASSERT(NS_IsMainThread(), "Must be instantiated on the main thread"); } @@ -94,7 +93,6 @@ TrackBuffersManager::AppendIncomingBuffer(IncomingBuffer aData) { MOZ_ASSERT(OnTaskQueue()); mIncomingBuffers.AppendElement(aData); - mAbort = false; } nsRefPtr<TrackBuffersManager::AppendPromise> @@ -103,49 +101,42 @@ TrackBuffersManager::BufferAppend() MOZ_ASSERT(NS_IsMainThread()); MSE_DEBUG(""); + mAppendRunning = true; return ProxyMediaCall(GetTaskQueue(), this, __func__, &TrackBuffersManager::InitSegmentParserLoop); } -// Abort any pending AppendData. -// We don't really care about really aborting our inner loop as by spec the -// process is happening asynchronously, as such where and when we would abort is -// non-deterministic. The SourceBuffer also makes sure BufferAppend -// isn't called should the appendBuffer be immediately aborted. -// We do however want to ensure that no new task will be dispatched on our task -// queue and only let the current one finish its job. For this we set mAbort -// to true. +// The MSE spec requires that we abort the current SegmentParserLoop +// which is then followed by a call to ResetParserState. +// However due to our asynchronous design this causes inherent difficulities. +// As the spec behaviour is non deterministic anyway, we instead wait until the +// current AppendData has completed its run. void TrackBuffersManager::AbortAppendData() { MOZ_ASSERT(NS_IsMainThread()); MSE_DEBUG(""); - mAbort = true; + MonitorAutoLock mon(mMonitor); + while (mAppendRunning) { + mon.Wait(); + } } void TrackBuffersManager::ResetParserState() { MOZ_ASSERT(NS_IsMainThread()); - MOZ_ASSERT(!mAppendRunning, "AbortAppendData must have been called"); + MOZ_RELEASE_ASSERT(!mAppendRunning, "Append is running, abort must have been called"); MSE_DEBUG(""); // 1. If the append state equals PARSING_MEDIA_SEGMENT and the input buffer contains some complete coded frames, then run the coded frame processing algorithm until all of these complete coded frames have been processed. - if (mAppendState == AppendState::PARSING_MEDIA_SEGMENT) { - nsCOMPtr<nsIRunnable> task = - NS_NewRunnableMethod(this, &TrackBuffersManager::FinishCodedFrameProcessing); - GetTaskQueue()->Dispatch(task.forget()); - } else { - nsCOMPtr<nsIRunnable> task = - NS_NewRunnableMethod(this, &TrackBuffersManager::CompleteResetParserState); - GetTaskQueue()->Dispatch(task.forget()); - } + // SourceBuffer.abort() has ensured that all complete coded frames have been + // processed. As such, we don't need to check for the value of mAppendState. + nsCOMPtr<nsIRunnable> task = + NS_NewRunnableMethod(this, &TrackBuffersManager::CompleteResetParserState); + GetTaskQueue()->Dispatch(task.forget()); - // Our ResetParserState is really asynchronous, the current task has been - // interrupted and will complete shortly (or has already completed). - // We must however present to the main thread a stable, reset state. - // So we run the following operation now in the main thread. // 7. Set append state to WAITING_FOR_SEGMENT. SetAppendState(AppendState::WAITING_FOR_SEGMENT); } @@ -154,6 +145,7 @@ nsRefPtr<TrackBuffersManager::RangeRemovalPromise> TrackBuffersManager::RangeRemoval(TimeUnit aStart, TimeUnit aEnd) { MOZ_ASSERT(NS_IsMainThread()); + MOZ_RELEASE_ASSERT(!mAppendRunning, "Append is running"); MSE_DEBUG("From %.2f to %.2f", aStart.ToSeconds(), aEnd.ToSeconds()); mEnded = false; @@ -264,20 +256,6 @@ TrackBuffersManager::Detach() { MOZ_ASSERT(NS_IsMainThread()); MSE_DEBUG(""); - - // Abort pending operations if any. - AbortAppendData(); - - nsRefPtr<TrackBuffersManager> self = this; - nsCOMPtr<nsIRunnable> task = - NS_NewRunnableFunction([self] () { - // Clear our sourcebuffer - self->CodedFrameRemoval(TimeInterval(TimeUnit::FromSeconds(0), - TimeUnit::FromInfinity())); - self->mProcessingPromise.RejectIfExists(NS_ERROR_ABORT, __func__); - self->mAppendPromise.RejectIfExists(NS_ERROR_ABORT, __func__); - }); - GetTaskQueue()->Dispatch(task.forget()); } #if defined(DEBUG) @@ -289,28 +267,9 @@ TrackBuffersManager::Dump(const char* aPath) #endif void -TrackBuffersManager::FinishCodedFrameProcessing() -{ - MOZ_ASSERT(OnTaskQueue()); - - if (mProcessingRequest.Exists()) { - NS_WARNING("Processing request pending"); - mProcessingRequest.Disconnect(); - } - // The spec requires us to complete parsing synchronously any outstanding - // frames in the current media segment. This can't be implemented in a way - // that makes sense. - // As such we simply completely ignore the result of any pending input buffer. - // TODO: Link to W3C bug. - - CompleteResetParserState(); -} - -void TrackBuffersManager::CompleteResetParserState() { MOZ_ASSERT(OnTaskQueue()); - MOZ_ASSERT(!mAppendRunning); MSE_DEBUG(""); for (auto& track : GetTracksList()) { @@ -446,7 +405,6 @@ bool TrackBuffersManager::CodedFrameRemoval(TimeInterval aInterval) { MOZ_ASSERT(OnTaskQueue()); - MOZ_ASSERT(!mAppendRunning, "Logic error: Append in progress"); MSE_DEBUG("From %.2fs to %.2f", aInterval.mStart.ToSeconds(), aInterval.mEnd.ToSeconds()); @@ -548,8 +506,9 @@ nsRefPtr<TrackBuffersManager::AppendPromise> TrackBuffersManager::InitSegmentParserLoop() { MOZ_ASSERT(OnTaskQueue()); + MOZ_RELEASE_ASSERT(mAppendPromise.IsEmpty()); + MSE_DEBUG(""); - MOZ_ASSERT(mAppendPromise.IsEmpty() && !mAppendRunning); nsRefPtr<AppendPromise> p = mAppendPromise.Ensure(__func__); AppendIncomingBuffers(); @@ -583,6 +542,7 @@ void TrackBuffersManager::SegmentParserLoop() { MOZ_ASSERT(OnTaskQueue()); + while (true) { // 1. If the input buffer is empty, then jump to the need more data step below. if (!mInputBuffer || mInputBuffer->IsEmpty()) { @@ -656,7 +616,7 @@ TrackBuffersManager::SegmentParserLoop() ->Then(GetTaskQueue(), __func__, [self] (bool aNeedMoreData) { self->mProcessingRequest.Complete(); - if (aNeedMoreData || self->mAbort) { + if (aNeedMoreData) { self->NeedMoreData(); } else { self->ScheduleSegmentParserLoop(); @@ -675,10 +635,13 @@ void TrackBuffersManager::NeedMoreData() { MSE_DEBUG(""); - if (!mAbort) { - RestoreCachedVariables(); - } + RestoreCachedVariables(); mAppendRunning = false; + { + // Wake-up any pending Abort() + MonitorAutoLock mon(mMonitor); + mon.NotifyAll(); + } mAppendPromise.ResolveIfExists(mActiveTrack, __func__); } @@ -687,6 +650,11 @@ TrackBuffersManager::RejectAppend(nsresult aRejectValue, const char* aName) { MSE_DEBUG("rv=%d", aRejectValue); mAppendRunning = false; + { + // Wake-up any pending Abort() + MonitorAutoLock mon(mMonitor); + mon.NotifyAll(); + } mAppendPromise.RejectIfExists(aRejectValue, aName); } @@ -788,14 +756,8 @@ void TrackBuffersManager::OnDemuxerInitDone(nsresult) { MOZ_ASSERT(OnTaskQueue()); - MSE_DEBUG("mAbort:%d", static_cast<bool>(mAbort)); mDemuxerInitRequest.Complete(); - if (mAbort) { - RejectAppend(NS_ERROR_ABORT, __func__); - return; - } - MediaInfo info; uint32_t numVideos = mInputDemuxer->GetNumberTracks(TrackInfo::kVideoTrack); @@ -1034,9 +996,8 @@ TrackBuffersManager::OnDemuxFailed(TrackType aTrack, DemuxerFailureReason aFailure) { MOZ_ASSERT(OnTaskQueue()); - MSE_DEBUG("Failed to demux %s, failure:%d mAbort:%d", - aTrack == TrackType::kVideoTrack ? "video" : "audio", - aFailure, static_cast<bool>(mAbort)); + MSE_DEBUG("Failed to demux %s, failure:%d", + aTrack == TrackType::kVideoTrack ? "video" : "audio", aFailure); switch (aFailure) { case DemuxerFailureReason::END_OF_STREAM: case DemuxerFailureReason::WAITING_FOR_DATA: @@ -1063,15 +1024,10 @@ void TrackBuffersManager::DoDemuxVideo() { MOZ_ASSERT(OnTaskQueue()); - MSE_DEBUG("mAbort:%d", static_cast<bool>(mAbort)); if (!HasVideo()) { DoDemuxAudio(); return; } - if (mAbort) { - RejectProcessing(NS_ERROR_ABORT, __func__); - return; - } mVideoTracks.mDemuxRequest.Begin(mVideoTracks.mDemuxer->GetSamples(-1) ->Then(GetTaskQueue(), __func__, this, &TrackBuffersManager::OnVideoDemuxCompleted, @@ -1092,11 +1048,6 @@ void TrackBuffersManager::DoDemuxAudio() { MOZ_ASSERT(OnTaskQueue()); - MSE_DEBUG("mAbort:%d", static_cast<bool>(mAbort)); - if (mAbort) { - RejectProcessing(NS_ERROR_ABORT, __func__); - return; - } if (!HasAudio()) { CompleteCodedFrameProcessing(); return; @@ -1121,7 +1072,6 @@ void TrackBuffersManager::CompleteCodedFrameProcessing() { MOZ_ASSERT(OnTaskQueue()); - MSE_DEBUG("mAbort:%d", static_cast<bool>(mAbort)); // 1. For each coded frame in the media segment run the following steps: // Coded Frame Processing steps 1.1 to 1.21. @@ -1189,22 +1139,12 @@ TrackBuffersManager::CompleteCodedFrameProcessing() void TrackBuffersManager::RejectProcessing(nsresult aRejectValue, const char* aName) { - if (mAbort) { - // mAppendPromise will be resolved immediately upon mProcessingPromise - // completing. - mAppendRunning = false; - } mProcessingPromise.RejectIfExists(aRejectValue, __func__); } void TrackBuffersManager::ResolveProcessing(bool aResolveValue, const char* aName) { - if (mAbort) { - // mAppendPromise will be resolved immediately upon mProcessingPromise - // completing. - mAppendRunning = false; - } mProcessingPromise.ResolveIfExists(aResolveValue, __func__); } |