Bug 1341200. Part 10 - streamline DecoderData::ShutdownDecoder() so it feels like a sync function and MFR doesn't need to explicitly wait for flush/shutdown to complete before creating new decoders.
MozReview-Commit-ID: F4tf1f7O89U
--- a/dom/media/MediaFormatReader.cpp
+++ b/dom/media/MediaFormatReader.cpp
@@ -381,26 +381,24 @@ MediaFormatReader::DecoderData::Shutdown
if (!mDecoder) {
// No decoder to shut down.
return;
}
if (mFlushing) {
// Flush is is in action. Shutdown will be initiated after flush completes.
- if (mShutdownPromise.IsEmpty()) {
- mOwner->mShutdownPromisePool->Track(mShutdownPromise.Ensure(__func__));
- }
- return;
- }
-
- if (!mShutdownPromise.IsEmpty()) {
- // This is called from the resolve/reject function of Flush.
- // Let's continue shutdown.
- mDecoder->Shutdown()->ChainTo(mShutdownPromise.Steal(), __func__);
+ MOZ_DIAGNOSTIC_ASSERT(mShutdownPromise);
+ mOwner->mShutdownPromisePool->Track(mShutdownPromise->Ensure(__func__));
+ // The order of decoder creation and shutdown is handled by LocalAllocPolicy
+ // and ShutdownPromisePool. MFR can now reset these members to a fresh state
+ // and be ready to create new decoders again without explicitly waiting for
+ // flush/shutdown to complete.
+ mShutdownPromise = nullptr;
+ mFlushing = false;
} else {
// No flush is in action. We can shut down the decoder now.
mOwner->mShutdownPromisePool->Track(mDecoder->Shutdown());
}
// mShutdownPromisePool will handle the order of decoder shutdown so
// we can forget mDecoder and be ready to create a new one.
mDecoder = nullptr;
@@ -421,38 +419,46 @@ MediaFormatReader::DecoderData::Flush()
mDrainRequest.DisconnectIfExists();
mDrainState = DrainState::None;
CancelWaitingForKey();
mOutput.Clear();
mNumSamplesInput = 0;
mNumSamplesOutput = 0;
mSizeOfQueue = 0;
if (mDecoder) {
- RefPtr<MediaFormatReader> owner = mOwner;
TrackType type = mType == MediaData::AUDIO_DATA
? TrackType::kAudioTrack
: TrackType::kVideoTrack;
mFlushing = true;
+ MOZ_DIAGNOSTIC_ASSERT(!mShutdownPromise);
+ mShutdownPromise = new SharedShutdownPromiseHolder();
+ RefPtr<SharedShutdownPromiseHolder> p = mShutdownPromise;
+ RefPtr<MediaDataDecoder> d = mDecoder;
mDecoder->Flush()
->Then(mOwner->OwnerThread(), __func__,
- [owner, type, this]() {
- mFlushing = false;
- if (!mShutdownPromise.IsEmpty()) {
- ShutdownDecoder();
+ [type, this, p, d]() {
+ if (!p->IsEmpty()) {
+ // Shutdown happened before flush completes. Let's continue to
+ // shut down the decoder. Note we don't access |this| because
+ // this decoder is no longer managed by MFR::DecoderData.
+ d->Shutdown()->ChainTo(p->Steal(), __func__);
return;
}
- owner->ScheduleUpdate(type);
+ mFlushing = false;
+ mShutdownPromise = nullptr;
+ mOwner->ScheduleUpdate(type);
},
- [owner, type, this](const MediaResult& aError) {
- mFlushing = false;
- if (!mShutdownPromise.IsEmpty()) {
- ShutdownDecoder();
+ [type, this, p, d](const MediaResult& aError) {
+ if (!p->IsEmpty()) {
+ d->Shutdown()->ChainTo(p->Steal(), __func__);
return;
}
- owner->NotifyError(type, aError);
+ mFlushing = false;
+ mShutdownPromise = nullptr;
+ mOwner->NotifyError(type, aError);
});
}
mFlushed = true;
}
class MediaFormatReader::DecoderFactory
{
using InitPromise = MediaDataDecoder::InitPromise;
--- a/dom/media/MediaFormatReader.h
+++ b/dom/media/MediaFormatReader.h
@@ -166,16 +166,23 @@ private:
None,
DrainRequested,
Draining,
PartialDrainPending,
DrainCompleted,
DrainAborted,
};
+ class SharedShutdownPromiseHolder : public MozPromiseHolder<ShutdownPromise>
+ {
+ NS_INLINE_DECL_THREADSAFE_REFCOUNTING(SharedShutdownPromiseHolder)
+ private:
+ ~SharedShutdownPromiseHolder() { }
+ };
+
struct DecoderData
{
DecoderData(MediaFormatReader* aOwner,
MediaData::Type aType,
uint32_t aNumOfMaxError)
: mOwner(aOwner)
, mType(aType)
, mMutex("DecoderData")
@@ -243,17 +250,17 @@ private:
return mWaitingForData || mWaitingForKey;
}
// MediaDataDecoder handler's variables.
MozPromiseRequestHolder<MediaDataDecoder::DecodePromise> mDecodeRequest;
bool mFlushing; // True if flush is in action.
// Set to true if the last operation run on the decoder was a flush.
bool mFlushed;
- MozPromiseHolder<ShutdownPromise> mShutdownPromise;
+ RefPtr<SharedShutdownPromiseHolder> mShutdownPromise;
MozPromiseRequestHolder<MediaDataDecoder::DecodePromise> mDrainRequest;
DrainState mDrainState;
bool HasPendingDrain() const
{
return mDrainState != DrainState::None;
}
void RequestDrain()