Bug 1672072 - P13. Always shut down decoder after creation. r=mattwoodrow,bryce,padenot

We also ensure that the MediaFormatReader will only shutdown once the CreateDecoderPromise has been resolved (or rejected)

This makes a few of the earlier changes redundant; as we can now guarantee all the objects provided to the PDMFactory will stay valid for the entire lifetime of the decoder. So we could do away with P4 and P7.

It's better that we keep those however, as it greatly simplify other usage of the PDMFactory. Ensuring that the user of the PDMFactory survives any decoder isn't a trivial affair.

Differential Revision: https://phabricator.services.mozilla.com/D96369
This commit is contained in:
Jean-Yves Avenard 2020-11-12 22:54:22 +00:00
Родитель 5b9a3683e4
Коммит 86118b9f7a
1 изменённых файлов: 68 добавлений и 47 удалений

Просмотреть файл

@ -209,6 +209,7 @@ class MediaFormatReader::DecoderFactory {
using InitPromise = MediaDataDecoder::InitPromise;
using TokenPromise = AllocPolicy::Promise;
using Token = AllocPolicy::Token;
using CreateDecoderPromise = PlatformDecoderModule::CreateDecoderPromise;
public:
explicit DecoderFactory(MediaFormatReader* aOwner)
@ -236,12 +237,20 @@ class MediaFormatReader::DecoderFactory {
auto& data = aTrack == TrackInfo::kAudioTrack ? mAudio : mVideo;
data.mPolicy->Cancel();
data.mTokenRequest.DisconnectIfExists();
if (data.mDecoderRequest.Exists()) {
if (data.mLiveToken) {
// We haven't completed creation of the decoder, and it hasn't been
// initialised yet.
// We can simply disconnect the promise without worrying about having to
// shut it down .
data.mDecoderRequest.Disconnect();
data.mLiveToken = nullptr;
// The decoder will be shutdown as soon as it's available and tracked by
// the ShutdownPromisePool.
mOwner->mShutdownPromisePool->Track(data.mCreateDecoderPromise->Then(
mOwner->mTaskQueue, __func__,
[](CreateDecoderPromise::ResolveOrRejectValue&& aResult) {
if (aResult.IsReject()) {
return ShutdownPromise::CreateAndResolve(true, __func__);
}
return aResult.ResolveValue()->Shutdown();
}));
// Free the token to leave room for a new decoder.
data.mToken = nullptr;
}
@ -254,13 +263,7 @@ class MediaFormatReader::DecoderFactory {
}
private:
enum class Stage : int8_t {
None,
WaitForToken,
CreateDecoder,
CreatingDecoder,
WaitForInit
};
enum class Stage : int8_t { None, WaitForToken, CreateDecoder, WaitForInit };
struct Data {
Data(DecoderData& aOwnerData, TrackType aTrack, TaskQueue* aThread)
@ -274,8 +277,16 @@ class MediaFormatReader::DecoderFactory {
RefPtr<Token> mToken;
RefPtr<MediaDataDecoder> mDecoder;
MozPromiseRequestHolder<TokenPromise> mTokenRequest;
MozPromiseRequestHolder<PlatformDecoderModule::CreateDecoderPromise>
mDecoderRequest;
struct DecoderCancelled : public SupportsWeakPtr {
NS_INLINE_DECL_REFCOUNTING_ONEVENTTARGET(DecoderCancelled)
private:
~DecoderCancelled() = default;
};
// Set when decoder is about to be created. If cleared before the decoder
// creation promise is resolved; it indicates that Shutdown() was called and
// further processing such as initialization should stop.
RefPtr<DecoderCancelled> mLiveToken;
RefPtr<CreateDecoderPromise> mCreateDecoderPromise;
MozPromiseRequestHolder<InitPromise> mInitRequest;
} mAudio, mVideo;
@ -327,19 +338,13 @@ void MediaFormatReader::DecoderFactory::RunStage(Data& aData) {
MOZ_ASSERT(!aData.mInitRequest.Exists());
DoCreateDecoder(aData);
aData.mStage = Stage::CreatingDecoder;
break;
}
case Stage::CreatingDecoder: {
MOZ_ASSERT(!aData.mDecoder);
MOZ_ASSERT(aData.mDecoderRequest.Exists());
aData.mStage = Stage::WaitForInit;
break;
}
case Stage::WaitForInit: {
MOZ_ASSERT(aData.mDecoder);
MOZ_ASSERT(aData.mInitRequest.Exists());
MOZ_ASSERT((aData.mDecoder && aData.mInitRequest.Exists()) ||
aData.mLiveToken);
break;
}
}
@ -365,6 +370,7 @@ void MediaFormatReader::DecoderFactory::DoCreateDecoder(Data& aData) {
auto onWaitingForKeyEvent =
[owner = ThreadSafeWeakPtr<MediaFormatReader>(owner)]() {
RefPtr<MediaFormatReader> mfr(owner);
MOZ_DIAGNOSTIC_ASSERT(mfr, "The MediaFormatReader didn't wait for us");
return mfr ? &mfr->OnTrackWaitingForKeyProducer() : nullptr;
};
@ -400,32 +406,47 @@ void MediaFormatReader::DecoderFactory::DoCreateDecoder(Data& aData) {
p = PlatformDecoderModule::CreateDecoderPromise::CreateAndReject(
NS_ERROR_DOM_MEDIA_FATAL_ERR, __func__);
}
p->Then(
mOwner->OwnerThread(), __func__,
[this, &aData, &ownerData](RefPtr<MediaDataDecoder>&& aDecoder) {
aData.mDecoderRequest.Complete();
aData.mDecoder = new MediaDataDecoderProxy(
aDecoder.forget(), do_AddRef(ownerData.mTaskQueue.get()));
aData.mDecoder = new AllocationWrapper(aData.mDecoder.forget(),
aData.mToken.forget());
DecoderDoctorLogger::LinkParentAndChild(
aData.mDecoder.get(), "decoder",
"MediaFormatReader::DecoderFactory", this);
DoInitDecoder(aData);
aData.mStage = Stage::WaitForInit;
},
[this, &aData](const MediaResult& aError) {
aData.mDecoderRequest.Complete();
NS_WARNING("Error constructing decoders");
aData.mToken = nullptr;
aData.mStage = Stage::None;
aData.mOwnerData.mDescription = aError.Description();
DDLOGEX2("MediaFormatReader::DecoderFactory", this, DDLogCategory::Log,
"create_decoder_error", aError);
mOwner->NotifyError(aData.mTrack, aError);
})
->Track(aData.mDecoderRequest);
aData.mLiveToken = MakeRefPtr<Data::DecoderCancelled>();
aData.mCreateDecoderPromise = p->Then(
mOwner->OwnerThread(), __func__,
[this, &aData, &ownerData, live = WeakPtr{aData.mLiveToken},
owner = ThreadSafeWeakPtr<MediaFormatReader>(owner)](
RefPtr<MediaDataDecoder>&& aDecoder) {
if (!live) {
return CreateDecoderPromise::CreateAndResolve(std::move(aDecoder),
__func__);
}
aData.mLiveToken = nullptr;
aData.mDecoder = new MediaDataDecoderProxy(
aDecoder.forget(), do_AddRef(ownerData.mTaskQueue.get()));
aData.mDecoder = new AllocationWrapper(aData.mDecoder.forget(),
aData.mToken.forget());
DecoderDoctorLogger::LinkParentAndChild(
aData.mDecoder.get(), "decoder",
"MediaFormatReader::DecoderFactory", this);
DoInitDecoder(aData);
return CreateDecoderPromise::CreateAndResolve(aData.mDecoder, __func__);
},
[this, &aData,
live = WeakPtr{aData.mLiveToken}](const MediaResult& aError) {
NS_WARNING("Error constructing decoders");
if (!live) {
return CreateDecoderPromise::CreateAndReject(aError, __func__);
}
aData.mLiveToken = nullptr;
aData.mToken = nullptr;
aData.mStage = Stage::None;
aData.mOwnerData.mDescription = aError.Description();
DDLOGEX2("MediaFormatReader::DecoderFactory", this, DDLogCategory::Log,
"create_decoder_error", aError);
mOwner->NotifyError(aData.mTrack, aError);
return CreateDecoderPromise::CreateAndReject(aError, __func__);
});
}
void MediaFormatReader::DecoderFactory::DoInitDecoder(Data& aData) {