summaryrefslogtreecommitdiff
path: root/dom/media/mediasource/TrackBuffersManager.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'dom/media/mediasource/TrackBuffersManager.cpp')
-rw-r--r--dom/media/mediasource/TrackBuffersManager.cpp130
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__);
}