diff --git a/content/media/mediasource/SourceBuffer.cpp b/content/media/mediasource/SourceBuffer.cpp index 0cb1e48768d..8896b3420bf 100644 --- a/content/media/mediasource/SourceBuffer.cpp +++ b/content/media/mediasource/SourceBuffer.cpp @@ -280,10 +280,7 @@ SourceBuffer::Abort(ErrorResult& aRv) mAppendWindowEnd = PositiveInfinity(); MSE_DEBUG("%p Abort: Discarding decoder.", this); - if (mDecoder) { - mDecoder->GetResource()->Ended(); - mDecoder = nullptr; - } + DiscardDecoder(); } void @@ -309,7 +306,7 @@ void SourceBuffer::Detach() { Ended(); - mDecoder = nullptr; + DiscardDecoder(); mMediaSource = nullptr; } @@ -330,7 +327,7 @@ SourceBuffer::SourceBuffer(MediaSource* aMediaSource, const nsACString& aType) , mTimestampOffset(0) , mAppendMode(SourceBufferAppendMode::Segments) , mUpdating(false) - , mDecoderInit(false) + , mDecoderInitialized(false) { MOZ_ASSERT(aMediaSource); mParser = ContainerParser::CreateForMIMEType(aType); @@ -347,9 +344,7 @@ SourceBuffer::Create(MediaSource* aMediaSource, const nsACString& aType) SourceBuffer::~SourceBuffer() { - if (mDecoder) { - mDecoder->GetResource()->Ended(); - } + DiscardDecoder(); } MediaSource* @@ -382,15 +377,27 @@ SourceBuffer::QueueAsyncSimpleEvent(const char* aName) bool SourceBuffer::InitNewDecoder() { + MOZ_ASSERT(!mDecoder); MediaSourceDecoder* parentDecoder = mMediaSource->GetDecoder(); nsRefPtr decoder = parentDecoder->CreateSubDecoder(mType); if (!decoder) { return false; } mDecoder = decoder; + mDecoderInitialized = false; return true; } +void +SourceBuffer::DiscardDecoder() +{ + if (mDecoder) { + mDecoder->GetResource()->Ended(); + } + mDecoder = nullptr; + mDecoderInitialized = false; +} + void SourceBuffer::StartUpdating() { @@ -432,18 +439,28 @@ SourceBuffer::AppendData(const uint8_t* aData, uint32_t aLength, ErrorResult& aR // TODO: Test buffer full flag. StartUpdating(); // TODO: Run buffer append algorithm asynchronously (would call StopUpdating()). - if (!mDecoder || mParser->IsInitSegmentPresent(aData, aLength)) { - if (!mDecoder || mDecoderInit) { - MSE_DEBUG("%p AppendBuffer: New initialization segment, creating decoder.", this); - mDecoder->GetResource()->Ended(); + if (mParser->IsInitSegmentPresent(aData, aLength)) { + MSE_DEBUG("%p AppendBuffer: New initialization segment.", this); + if (mDecoderInitialized) { + // Existing decoder has been used, time for a new one. + DiscardDecoder(); + } - if (!InitNewDecoder()) { - aRv.Throw(NS_ERROR_FAILURE); // XXX: Review error handling. - return; - } + // If we've got a decoder here, it's not initialized, so we can use it + // rather than creating a new one. + if (!mDecoder && !InitNewDecoder()) { + aRv.Throw(NS_ERROR_FAILURE); // XXX: Review error handling. + return; } MSE_DEBUG("%p AppendBuffer: Decoder marked as initialized.", this); - mDecoderInit = true; + mDecoderInitialized = true; + } else if (!mDecoderInitialized) { + MSE_DEBUG("%p AppendBuffer: Non-initialization segment appended during initialization."); + Optional decodeError(MediaSourceEndOfStreamError::Decode); + ErrorResult dummy; + mMediaSource->EndOfStream(decodeError, dummy); + aRv.Throw(NS_ERROR_FAILURE); + return; } // XXX: For future reference: NDA call must run on the main thread. mDecoder->NotifyDataArrived(reinterpret_cast(aData), diff --git a/content/media/mediasource/SourceBuffer.h b/content/media/mediasource/SourceBuffer.h index 98c5c7f4eeb..9438310a23c 100644 --- a/content/media/mediasource/SourceBuffer.h +++ b/content/media/mediasource/SourceBuffer.h @@ -119,9 +119,13 @@ private: void DispatchSimpleEvent(const char* aName); void QueueAsyncSimpleEvent(const char* aName); - // Create a new decoder for mType, add it to mDecoders and update mCurrentDecoder. + // Create a new decoder for mType, and store the result in mDecoder. + // Returns true if mDecoder was set. bool InitNewDecoder(); + // Set mDecoder to null and reset mDecoderInitialized. + void DiscardDecoder(); + // Update mUpdating and fire the appropriate events. void StartUpdating(); void StopUpdating(); @@ -150,7 +154,7 @@ private: SourceBufferAppendMode mAppendMode; bool mUpdating; - bool mDecoderInit; + bool mDecoderInitialized; }; } // namespace dom diff --git a/content/media/mediasource/test/crashtests/1005366.html b/content/media/mediasource/test/crashtests/1005366.html new file mode 100644 index 00000000000..aa8b7f652e0 --- /dev/null +++ b/content/media/mediasource/test/crashtests/1005366.html @@ -0,0 +1,27 @@ + + + + + + + + diff --git a/content/media/test/crashtests/926665.html b/content/media/mediasource/test/crashtests/926665.html similarity index 100% rename from content/media/test/crashtests/926665.html rename to content/media/mediasource/test/crashtests/926665.html diff --git a/content/media/mediasource/test/crashtests/crashtests.list b/content/media/mediasource/test/crashtests/crashtests.list new file mode 100644 index 00000000000..994d0f2fde5 --- /dev/null +++ b/content/media/mediasource/test/crashtests/crashtests.list @@ -0,0 +1,2 @@ +test-pref(media.mediasource.enabled,true) load 926665.html +test-pref(media.mediasource.enabled,true) load 1005366.html diff --git a/content/media/test/crashtests/crashtests.list b/content/media/test/crashtests/crashtests.list index 53c19b99cf3..019d132c1e1 100644 --- a/content/media/test/crashtests/crashtests.list +++ b/content/media/test/crashtests/crashtests.list @@ -69,4 +69,4 @@ load offline-buffer-source-ended-1.html skip-if(B2G) HTTP load media-element-source-seek-1.html # intermittent B2G timeouts, bug 994351 skip-if(B2G) load oscillator-ended-1.html # intermittent B2G timeouts, bug 920338 skip-if(B2G) load oscillator-ended-2.html # intermittent B2G timeouts, bug 920338 -test-pref(media.mediasource.enabled,true) load 926665.html +include ../../mediasource/test/crashtests/crashtests.list