Bug 1316145 - ensure compositor events are dispatched to readers before Shutdown().
To prevent
bug 1318226, we use 2-phase dispatch
(main thread -> MDSM task queue -> reader task queue) to ensure events arrive
in correct order.
MozReview-Commit-ID: GKmVAAb9ifG
--- a/dom/media/AbstractMediaDecoder.h
+++ b/dom/media/AbstractMediaDecoder.h
@@ -18,17 +18,16 @@
#include "nsThreadUtils.h"
namespace mozilla
{
namespace layers
{
class ImageContainer;
- class KnowsCompositor;
} // namespace layers
class MediaResource;
class ReentrantMonitor;
class VideoFrameContainer;
class MediaDecoderOwner;
class CDMProxy;
class GMPCrashHelper;
@@ -64,25 +63,16 @@ public:
// MediaDecoderReader will register with this event to receive notifications
// in order to update buffer ranges.
// Return null if this decoder doesn't support the event.
virtual MediaEventSource<void>* DataArrivedEvent()
{
return nullptr;
}
- // Returns an event that will be notified when the owning document changes state
- // and we might have a new compositor. If this new compositor requires us to
- // recreate our decoders, then we expect the existing decoderis to return an
- // error independently of this.
- virtual MediaEventSource<RefPtr<layers::KnowsCompositor>>* CompositorUpdatedEvent()
- {
- return nullptr;
- }
-
// Notify the media decoder that a decryption key is required before emitting
// further output. This only needs to be overridden for decoders that expect
// encryption, such as the MediaSource decoder.
virtual void NotifyWaitingForKey() {}
// Return an event that will be notified when a decoder is waiting for a
// decryption key before it can return more output.
virtual MediaEventSource<void>* WaitingForKeyEvent()
--- a/dom/media/MediaDecoder.cpp
+++ b/dom/media/MediaDecoder.cpp
@@ -295,18 +295,17 @@ MediaDecoder::NotifyOwnerActivityChanged
dom::HTMLMediaElement* element = owner->GetMediaElement();
NS_ENSURE_TRUE_VOID(element);
RefPtr<LayerManager> layerManager =
nsContentUtils::LayerManagerForDocument(element->OwnerDoc());
NS_ENSURE_TRUE_VOID(layerManager);
- RefPtr<KnowsCompositor> knowsCompositor = layerManager->AsShadowForwarder();
- mCompositorUpdatedEvent.Notify(knowsCompositor);
+ mDecoderStateMachine->NotifyCompositorChanged(layerManager->AsShadowForwarder());
}
void
MediaDecoder::Pause()
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(!IsShutdown());
if (mPlayState == PLAY_STATE_LOADING || IsEnded()) {
--- a/dom/media/MediaDecoder.h
+++ b/dom/media/MediaDecoder.h
@@ -545,36 +545,32 @@ private:
// state machine. Call on the main thread only.
void MetadataLoaded(nsAutoPtr<MediaInfo> aInfo,
nsAutoPtr<MetadataTags> aTags,
MediaDecoderEventVisibility aEventVisibility);
MediaEventSource<void>*
DataArrivedEvent() override { return &mDataArrivedEvent; }
- MediaEventSource<RefPtr<layers::KnowsCompositor>>*
- CompositorUpdatedEvent() override { return &mCompositorUpdatedEvent; }
-
void OnPlaybackEvent(MediaEventType aEvent);
void OnPlaybackErrorEvent(const MediaResult& aError);
void OnDecoderDoctorEvent(DecoderDoctorEvent aEvent);
void OnMediaNotSeekable()
{
mMediaSeekable = false;
}
void FinishShutdown();
void ConnectMirrors(MediaDecoderStateMachine* aObject);
void DisconnectMirrors();
MediaEventProducer<void> mDataArrivedEvent;
- MediaEventProducer<RefPtr<layers::KnowsCompositor>> mCompositorUpdatedEvent;
// The state machine object for handling the decoding. It is safe to
// call methods of this object from other threads. Its internal data
// is synchronised on a monitor. The lifetime of this object is
// after mPlayState is LOADING and before mPlayState is SHUTDOWN. It
// is safe to access it during this period.
//
// Explicitly prievate to force access via accessors.
--- a/dom/media/MediaDecoderReader.h
+++ b/dom/media/MediaDecoderReader.h
@@ -19,16 +19,20 @@
#include "MediaTimer.h"
#include "AudioCompactor.h"
#include "Intervals.h"
#include "TimeUnits.h"
#include "SeekTarget.h"
namespace mozilla {
+namespace layers {
+class KnowsCompositor;
+}
+
class CDMProxy;
class MediaDecoderReader;
struct WaitForDataRejectValue
{
enum Reason {
SHUTDOWN,
CANCELED
@@ -289,16 +293,18 @@ public:
return mOnMediaNotSeekable;
}
// 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) {}
+ virtual void NotifyCompositorChanged(layers::KnowsCompositor* aCompositor) {}
+
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
@@ -414,9 +414,17 @@ MediaDecoderReaderWrapper::SetVideoBlank
{
MOZ_ASSERT(mOwnerThread->IsCurrentThreadIn());
nsCOMPtr<nsIRunnable> r =
NewRunnableMethod<bool>(mReader, &MediaDecoderReader::SetVideoBlankDecode,
aIsBlankDecode);
mReader->OwnerThread()->Dispatch(r.forget());
}
+void
+MediaDecoderReaderWrapper::NotifyCompositorChanged(KnowsCompositor* aCompositor)
+{
+ nsCOMPtr<nsIRunnable> r = NewRunnableMethod<RefPtr<KnowsCompositor>>(
+ mReader, &MediaDecoderReader::NotifyCompositorChanged, aCompositor);
+ mReader->OwnerThread()->Dispatch(r.forget());
+}
+
} // namespace mozilla
--- a/dom/media/MediaDecoderReaderWrapper.h
+++ b/dom/media/MediaDecoderReaderWrapper.h
@@ -12,16 +12,20 @@
#include "mozilla/Variant.h"
#include "nsISupportsImpl.h"
#include "MediaDecoderReader.h"
#include "MediaEventSource.h"
namespace mozilla {
+namespace layers {
+class KnowsCompositor;
+}
+
class StartTimeRendezvous;
typedef MozPromise<bool, bool, /* isExclusive = */ false> HaveStartTimePromise;
typedef Variant<MediaData*, MediaResult> AudioCallbackData;
typedef Variant<Tuple<MediaData*, TimeStamp>, MediaResult> VideoCallbackData;
typedef Variant<MediaData::Type, WaitForDataRejectValue> WaitCallbackData;
@@ -33,16 +37,17 @@ typedef Variant<MediaData::Type, WaitFor
*/
class MediaDecoderReaderWrapper {
typedef MediaDecoderReader::MetadataPromise MetadataPromise;
typedef MediaDecoderReader::MediaDataPromise MediaDataPromise;
typedef MediaDecoderReader::SeekPromise SeekPromise;
typedef MediaDecoderReader::WaitForDataPromise WaitForDataPromise;
typedef MediaDecoderReader::BufferedUpdatePromise BufferedUpdatePromise;
typedef MediaDecoderReader::TrackSet TrackSet;
+ typedef layers::KnowsCompositor KnowsCompositor;
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(MediaDecoderReaderWrapper);
private:
MediaCallbackExc<AudioCallbackData> mAudioCallback;
MediaCallbackExc<VideoCallbackData> mVideoCallback;
MediaCallbackExc<WaitCallbackData> mAudioWaitCallback;
MediaCallbackExc<WaitCallbackData> mVideoWaitCallback;
@@ -112,16 +117,18 @@ public:
AbstractCanonical<media::TimeIntervals>* CanonicalBuffered() {
return mReader->CanonicalBuffered();
}
void SetCDMProxy(CDMProxy* aProxy) { mReader->SetCDMProxy(aProxy); }
void SetVideoBlankDecode(bool aIsBlankDecode);
+ void NotifyCompositorChanged(KnowsCompositor* aCompositor);
+
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
@@ -3301,11 +3301,19 @@ void
MediaDecoderStateMachine::OnSuspendTimerRejected()
{
DECODER_LOG("OnSuspendTimerRejected");
MOZ_ASSERT(OnTaskQueue());
MOZ_ASSERT(!mVideoDecodeSuspended);
mVideoDecodeSuspendTimer.CompleteRequest();
}
+void
+MediaDecoderStateMachine::NotifyCompositorChanged(KnowsCompositor* aCompositor)
+{
+ nsCOMPtr<nsIRunnable> r = NewRunnableMethod<RefPtr<KnowsCompositor>>(
+ mReader, &MediaDecoderReaderWrapper::NotifyCompositorChanged, aCompositor);
+ OwnerThread()->Dispatch(r.forget());
+}
+
} // namespace mozilla
#undef NS_DispatchToMainThread
--- a/dom/media/MediaDecoderStateMachine.h
+++ b/dom/media/MediaDecoderStateMachine.h
@@ -100,16 +100,20 @@ hardware (via AudioStream).
#include "SeekTask.h"
namespace mozilla {
namespace media {
class MediaSink;
}
+namespace layers {
+class KnowsCompositor;
+}
+
class AudioSegment;
class DecodedStream;
class MediaDecoderReaderWrapper;
class OutputStreamManager;
class TaskQueue;
extern LazyLogModule gMediaDecoderLog;
extern LazyLogModule gMediaSampleLog;
@@ -219,16 +223,18 @@ public:
if (self->mAudioOffloading != aAudioOffloading) {
self->mAudioOffloading = aAudioOffloading;
self->ScheduleStateMachine();
}
});
OwnerThread()->Dispatch(r.forget());
}
+ void NotifyCompositorChanged(layers::KnowsCompositor* aCompositor);
+
// Drop reference to mResource. Only called during shutdown dance.
void BreakCycles() {
MOZ_ASSERT(NS_IsMainThread());
mResource = nullptr;
}
TimedMetadataEventSource& TimedMetadataEvent() {
return mMetadataManager.TimedMetadataEvent();
--- a/dom/media/MediaFormatReader.cpp
+++ b/dom/media/MediaFormatReader.cpp
@@ -439,22 +439,16 @@ MediaFormatReader::MediaFormatReader(Abs
, mTrackDemuxersMayBlock(false)
, mDemuxOnly(false)
, mSeekScheduled(false)
, mVideoFrameContainer(aVideoFrameContainer)
, mDecoderFactory(new DecoderFactory(this))
{
MOZ_ASSERT(aDemuxer);
MOZ_COUNT_CTOR(MediaFormatReader);
-
- if (aDecoder && aDecoder->CompositorUpdatedEvent()) {
- mCompositorUpdatedListener =
- aDecoder->CompositorUpdatedEvent()->Connect(
- mTaskQueue, this, &MediaFormatReader::NotifyCompositorUpdated);
- }
}
MediaFormatReader::~MediaFormatReader()
{
MOZ_COUNT_DTOR(MediaFormatReader);
}
RefPtr<ShutdownPromise>
@@ -505,18 +499,16 @@ MediaFormatReader::Shutdown()
mVideo.mTaskQueue = nullptr;
}
MOZ_ASSERT(!mVideo.HasPromise());
mDemuxer = nullptr;
mPlatform = nullptr;
mVideoFrameContainer = nullptr;
- mCompositorUpdatedListener.DisconnectIfExists();
-
return MediaDecoderReader::Shutdown();
}
void
MediaFormatReader::InitLayersBackendType()
{
// Extract the layer manager backend type so that platform decoders
// can determine whether it's worthwhile using hardware accelerated
--- a/dom/media/MediaFormatReader.h
+++ b/dom/media/MediaFormatReader.h
@@ -7,17 +7,16 @@
#if !defined(MediaFormatReader_h_)
#define MediaFormatReader_h_
#include "mozilla/Atomics.h"
#include "mozilla/Maybe.h"
#include "mozilla/TaskQueue.h"
#include "mozilla/Monitor.h"
-#include "MediaEventSource.h"
#include "MediaDataDemuxer.h"
#include "MediaDecoderReader.h"
#include "nsAutoPtr.h"
#include "PDMFactory.h"
namespace mozilla {
class CDMProxy;
@@ -561,19 +560,19 @@ private:
void ScheduleSeek();
void AttemptSeek();
void OnSeekFailed(TrackType aTrack, const MediaResult& aError);
void DoVideoSeek();
void OnVideoSeekCompleted(media::TimeUnit aTime);
void OnVideoSeekFailed(const MediaResult& aError);
bool mSeekScheduled;
- void NotifyCompositorUpdated(RefPtr<layers::KnowsCompositor> aKnowsCompositor)
+ void NotifyCompositorChanged(layers::KnowsCompositor* aCompositor) override
{
- mKnowsCompositor = aKnowsCompositor.forget();
+ mKnowsCompositor = aCompositor;
}
void DoAudioSeek();
void OnAudioSeekCompleted(media::TimeUnit aTime);
void OnAudioSeekFailed(const MediaResult& aError);
// The SeekTarget that was last given to Seek()
SeekTarget mOriginalSeekTarget;
// Temporary seek information while we wait for the data
@@ -587,15 +586,13 @@ private:
RefPtr<CDMProxy> mCDMProxy;
RefPtr<GMPCrashHelper> mCrashHelper;
void SetBlankDecode(TrackType aTrack, bool aIsBlankDecode);
class DecoderFactory;
UniquePtr<DecoderFactory> mDecoderFactory;
-
- MediaEventListener mCompositorUpdatedListener;
};
} // namespace mozilla
#endif