Bug 1274626 part 2 - [WIP] - switch the video decoder to blank decoder dynamically; r?kaku
MozReview-Commit-ID: By8h71EsXrg
--- a/dom/media/MediaDecoderReader.h
+++ b/dom/media/MediaDecoderReader.h
@@ -302,16 +302,21 @@ public:
MOZ_ASSERT(OnTaskQueue());
mIsSuspended = aState;
}
AbstractCanonical<bool>* CanonicalIsSuspended() {
return &mIsSuspended;
}
+ // Switch the video decoder to BlankDecoderModule. It might takes effective
+ // since a few samples later depends on how much demuxed samples are already
+ // queued in the original video decoder.
+ virtual void SetVideoBlankDecode(bool aIsBlankDecode) {}
+
protected:
virtual ~MediaDecoderReader();
// Populates aBuffered with the time ranges which are buffered. This may only
// be called on the decode task queue, and should only be used internally by
// UpdateBuffered - mBuffered (or mirrors of it) should be used for everything
// else.
//
--- a/dom/media/MediaDecoderReaderWrapper.cpp
+++ b/dom/media/MediaDecoderReaderWrapper.cpp
@@ -405,9 +405,15 @@ MediaDecoderReaderWrapper::OnMetadataRea
self->mReader->DispatchSetStartTime(self->StartTime().ToMicroseconds());
},
[] () {
NS_WARNING("Setting start time on reader failed");
});
}
}
+void
+MediaDecoderReaderWrapper::SetVideoBlankDecode(bool aIsBlankDecode)
+{
+ return mReader->SetVideoBlankDecode(aIsBlankDecode);
+}
+
} // namespace mozilla
--- a/dom/media/MediaDecoderReaderWrapper.h
+++ b/dom/media/MediaDecoderReaderWrapper.h
@@ -115,16 +115,18 @@ public:
AbstractCanonical<bool>* CanonicalIsSuspended() {
return mReader->CanonicalIsSuspended();
}
#ifdef MOZ_EME
void SetCDMProxy(CDMProxy* aProxy) { mReader->SetCDMProxy(aProxy); }
#endif
+ void SetVideoBlankDecode(bool aIsBlankDecode);
+
private:
~MediaDecoderReaderWrapper();
void OnMetadataRead(MetadataHolder* aMetadata);
void OnMetadataNotRead() {}
MediaCallbackExc<WaitCallbackData>& WaitCallbackRef(MediaData::Type aType);
MozPromiseRequestHolder<WaitForDataPromise>& WaitRequestRef(MediaData::Type aType);
--- a/dom/media/MediaDecoderStateMachine.cpp
+++ b/dom/media/MediaDecoderStateMachine.cpp
@@ -1384,16 +1384,17 @@ void MediaDecoderStateMachine::Visibilit
// Resuming from suspended decoding
// If suspend timer exists, destroy it.
mVideoDecodeSuspendTimer.Reset();
if (mVideoDecodeSuspended) {
mVideoDecodeSuspended = false;
+ mReader->SetVideoBlankDecode(false);
if (mIsReaderSuspended) {
return;
}
// If an existing seek is in flight don't bother creating a new
// one to catch up.
if (mSeekTask || mQueuedSeek.Exists()) {
@@ -2666,18 +2667,21 @@ bool MediaDecoderStateMachine::IsStateMa
{
MOZ_ASSERT(OnTaskQueue());
return mDispatchedStateMachine || mDelayedScheduler.IsScheduled();
}
bool MediaDecoderStateMachine::IsVideoDecodeSuspended() const
{
MOZ_ASSERT(OnTaskQueue());
+#if 0
return (MediaPrefs::MDSMSuspendBackgroundVideoEnabled() && mVideoDecodeSuspended) ||
mIsReaderSuspended;
+#endif
+ return mIsReaderSuspended;
}
void
MediaDecoderStateMachine::LogicalPlaybackRateChanged()
{
MOZ_ASSERT(OnTaskQueue());
if (mLogicalPlaybackRate == 0) {
@@ -2959,16 +2963,17 @@ MediaDecoderStateMachine::VideoRequestSt
}
void
MediaDecoderStateMachine::OnSuspendTimerResolved()
{
DECODER_LOG("OnSuspendTimerResolved");
mVideoDecodeSuspendTimer.CompleteRequest();
mVideoDecodeSuspended = true;
+ mReader->SetVideoBlankDecode(true);
}
void
MediaDecoderStateMachine::OnSuspendTimerRejected()
{
DECODER_LOG("OnSuspendTimerRejected");
MOZ_ASSERT(OnTaskQueue());
MOZ_ASSERT(!mVideoDecodeSuspended);
--- a/dom/media/MediaFormatReader.cpp
+++ b/dom/media/MediaFormatReader.cpp
@@ -401,35 +401,41 @@ MediaFormatReader::EnsureDecoderCreated(
mPlatform->SetCDMProxy(mCDMProxy);
#else
// EME not supported.
return false;
#endif
}
}
+ RefPtr<PDMFactory> platform = mPlatform;
+ if (decoder.mIsBlankDecode) {
+ platform = new PDMFactory(true);
+ }
+ MOZ_ASSERT(platform, "No PDM is created.");
+
decoder.mDecoderInitialized = false;
MonitorAutoLock mon(decoder.mMonitor);
switch (aTrack) {
case TrackType::kAudioTrack: {
- decoder.mDecoder = mPlatform->CreateDecoder({
+ decoder.mDecoder = platform->CreateDecoder({
decoder.mInfo ? *decoder.mInfo->GetAsAudioInfo() : mInfo.mAudio,
decoder.mTaskQueue,
decoder.mCallback.get(),
mCrashHelper
});
break;
}
case TrackType::kVideoTrack: {
// Decoders use the layers backend to decide if they can use hardware decoding,
// so specify LAYERS_NONE if we want to forcibly disable it.
- decoder.mDecoder = mPlatform->CreateDecoder({
+ decoder.mDecoder = platform->CreateDecoder({
mVideo.mInfo ? *mVideo.mInfo->GetAsVideoInfo() : mInfo.mVideo,
decoder.mTaskQueue,
decoder.mCallback.get(),
mLayersBackendType,
GetImageContainer(),
mCrashHelper
});
break;
@@ -712,16 +718,21 @@ MediaFormatReader::NotifyDrainComplete(T
MOZ_ASSERT(OnTaskQueue());
auto& decoder = GetDecoderData(aTrack);
LOG("%s", TrackTypeToStr(aTrack));
if (!decoder.mOutputRequested) {
LOG("MediaFormatReader called DrainComplete() before flushing, ignoring.");
return;
}
decoder.mDrainComplete = true;
+
+ if (decoder.mIsBlankDecode) {
+ decoder.ShutdownDecoder();
+ }
+
ScheduleUpdate(aTrack);
}
void
MediaFormatReader::NotifyError(TrackType aTrack, MediaDataDecoderError aError)
{
MOZ_ASSERT(OnTaskQueue());
LOGV("%s Decoding error", TrackTypeToStr(aTrack));
@@ -2020,9 +2031,43 @@ MediaFormatReader::GetMozDebugReaderData
mVideo.mNumSamplesInput, mVideo.mNumSamplesOutput,
unsigned(size_t(mVideo.mSizeOfQueue)),
unsigned(mVideo.mOutput.Length()),
mVideo.mWaitingForData, mVideo.mLastStreamSourceID);
}
aString += NS_ConvertUTF8toUTF16(result);
}
+void
+MediaFormatReader::SetVideoBlankDecode(bool aIsBlankDecode)
+{
+ OwnerThread()->Dispatch(
+ NewRunnableMethod<TrackType, bool>(this, &MediaFormatReader::SetBlankDecode,
+ TrackType::kVideoTrack, aIsBlankDecode));
+
+}
+
+void
+MediaFormatReader::SetBlankDecode(TrackType aTrack, bool aIsBlankDecode)
+{
+ MOZ_ASSERT(self->OnTaskQueue());
+ auto& decoder = GetDecoderData(aTrack);
+
+ LOG("%s, decoder.mIsBlankDecode = %d => aIsBlankDecode = %d",
+ TrackTypeToStr(aTrack), decoder.mIsBlankDecode, aIsBlankDecode);
+
+ if (decoder.mIsBlankDecode == aIsBlankDecode) {
+ return;
+ }
+
+ decoder.mIsBlankDecode = aIsBlankDecode;
+
+ if (decoder.mIsBlankDecode) {
+ decoder.mNeedDraining = true;
+ } else {
+ decoder.ShutdownDecoder();
+ }
+
+ ScheduleUpdate(aTrack);
+
+}
+
} // namespace mozilla
--- a/dom/media/MediaFormatReader.h
+++ b/dom/media/MediaFormatReader.h
@@ -96,16 +96,18 @@ public:
#ifdef MOZ_EME
void SetCDMProxy(CDMProxy* aProxy) override;
#endif
// Returns a string describing the state of the decoder data.
// Used for debugging purposes.
void GetMozDebugReaderData(nsAString& aString);
+ void SetVideoBlankDecode(bool aIsBlankDecode) override;
+
private:
bool HasVideo() { return mVideo.mTrackDemuxer; }
bool HasAudio() { return mAudio.mTrackDemuxer; }
bool IsWaitingOnCDMResource();
bool InitDemuxer();
@@ -248,16 +250,17 @@ private:
, mMaxConsecutiveError(aNumOfMaxError)
, mNumSamplesInput(0)
, mNumSamplesOutput(0)
, mNumSamplesOutputTotal(0)
, mNumSamplesSkippedTotal(0)
, mSizeOfQueue(0)
, mIsHardwareAccelerated(false)
, mLastStreamSourceID(UINT32_MAX)
+ , mIsBlankDecode(false)
{}
MediaFormatReader* mOwner;
// Disambiguate Audio vs Video.
MediaData::Type mType;
RefPtr<MediaTrackDemuxer> mTrackDemuxer;
// TaskQueue on which decoder can choose to decode.
// Only non-null up until the decoder is created.
@@ -422,16 +425,19 @@ private:
Atomic<bool> mIsHardwareAccelerated;
// Sample format monitoring.
uint32_t mLastStreamSourceID;
Maybe<uint32_t> mNextStreamSourceID;
media::TimeIntervals mTimeRanges;
Maybe<media::TimeUnit> mLastTimeRangesEnd;
RefPtr<SharedTrackInfo> mInfo;
Maybe<media::TimeUnit> mFirstDemuxedSampleTime;
+
+ // Use BlankDecoderModule or not.
+ bool mIsBlankDecode;
};
class DecoderDataWithPromise : public DecoderData {
public:
DecoderDataWithPromise(MediaFormatReader* aOwner,
MediaData::Type aType,
uint32_t aDecodeAhead,
uint32_t aNumOfMaxError)
@@ -567,13 +573,15 @@ private:
RefPtr<VideoFrameContainer> mVideoFrameContainer;
layers::ImageContainer* GetImageContainer();
#ifdef MOZ_EME
RefPtr<CDMProxy> mCDMProxy;
#endif
RefPtr<GMPCrashHelper> mCrashHelper;
+
+ void SetBlankDecode(TrackType aTrack, bool aIsBlankDecode);
};
} // namespace mozilla
#endif
--- a/dom/media/platforms/PDMFactory.cpp
+++ b/dom/media/platforms/PDMFactory.cpp
@@ -75,16 +75,22 @@ StaticAutoPtr<PDMFactoryImpl> PDMFactory
StaticMutex PDMFactory::sMonitor;
PDMFactory::PDMFactory()
{
EnsureInit();
CreatePDMs();
}
+PDMFactory::PDMFactory(bool aUseBlankDecodeModule)
+{
+ EnsureInit();
+ CreatePDMs(aUseBlankDecodeModule);
+}
+
PDMFactory::~PDMFactory()
{
}
void
PDMFactory::EnsureInit() const
{
StaticMutexAutoLock mon(sMonitor);
@@ -195,21 +201,21 @@ PDMFactory::SupportsMimeType(const nsACS
if (mEMEPDM) {
return mEMEPDM->SupportsMimeType(aMimeType, aDiagnostics);
}
RefPtr<PlatformDecoderModule> current = GetDecoder(aMimeType, aDiagnostics);
return !!current;
}
void
-PDMFactory::CreatePDMs()
+PDMFactory::CreatePDMs(bool aUseBlankDecoderModule /* = false */)
{
RefPtr<PlatformDecoderModule> m;
- if (MediaPrefs::PDMUseBlankDecoder()) {
+ if (MediaPrefs::PDMUseBlankDecoder() || aUseBlankDecoderModule) {
m = CreateBlankDecoderModule();
StartupPDM(m);
// The Blank PDM SupportsMimeType reports true for all codecs; the creation
// of its decoder is infallible. As such it will be used for all media, we
// can stop creating more PDM from this point.
return;
}
--- a/dom/media/platforms/PDMFactory.h
+++ b/dom/media/platforms/PDMFactory.h
@@ -19,16 +19,18 @@ class PDMFactoryImpl;
template<class T> class StaticAutoPtr;
class PDMFactory final {
public:
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(PDMFactory)
PDMFactory();
+ explicit PDMFactory(bool aUseBlankDecodeModule);
+
// Factory method that creates the appropriate PlatformDecoderModule for
// the platform we're running on. Caller is responsible for deleting this
// instance. It's expected that there will be multiple
// PlatformDecoderModules alive at the same time.
// This is called on the decode task queue.
already_AddRefed<MediaDataDecoder>
CreateDecoder(const CreateDecoderParams& aParams);
@@ -41,17 +43,17 @@ public:
// does not decode, we create a PDM and use that to create MediaDataDecoders
// that we use on on aTaskQueue to decode the decrypted stream.
// This is called on the decode task queue.
void SetCDMProxy(CDMProxy* aProxy);
#endif
private:
virtual ~PDMFactory();
- void CreatePDMs();
+ void CreatePDMs(bool aForceBlankDecoderModule = false);
// Startup the provided PDM and add it to our list if successful.
bool StartupPDM(PlatformDecoderModule* aPDM);
// Returns the first PDM in our list supporting the mimetype.
already_AddRefed<PlatformDecoderModule>
GetDecoder(const nsACString& aMimeType,
DecoderDoctorDiagnostics* aDiagnostics) const;
already_AddRefed<MediaDataDecoder>