Bug 1316145 - ensure compositor events are dispatched to readers before Shutdown(). draft
authorJW Wang <jwwang@mozilla.com>
Fri, 18 Nov 2016 15:04:22 +0800
changeset 441025 8a9b2834fdb6ead05aa08c192a83bfd0f122fe9a
parent 441024 83b79c537018725ae1c73d1d8627cc1dcfc756fa
child 537469 b52dc82e5a251933865c7bfdfcaa8e094545704d
push id36331
push userjwwang@mozilla.com
push dateFri, 18 Nov 2016 07:08:48 +0000
bugs1316145, 1318226
milestone53.0a1
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
dom/media/AbstractMediaDecoder.h
dom/media/MediaDecoder.cpp
dom/media/MediaDecoder.h
dom/media/MediaDecoderReader.h
dom/media/MediaDecoderReaderWrapper.cpp
dom/media/MediaDecoderReaderWrapper.h
dom/media/MediaDecoderStateMachine.cpp
dom/media/MediaDecoderStateMachine.h
dom/media/MediaFormatReader.cpp
dom/media/MediaFormatReader.h
--- 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