Bug 1315581 - Notify MediaFormatReader when the compositor gets recreated. r=jya,smaug,jw_wang
authorMatt Woodrow <mwoodrow@mozilla.com>
Tue, 08 Nov 2016 15:23:12 +1300
changeset 321632 e38e63ec11cc305aca30c97bba67feb2982c24cf
parent 321631 9ee070ee6dad5d0717f1da88bb94bfa25798c8f8
child 321633 3677545baae259dfde553b9df19879beaf396901
push id21
push usermaklebus@msu.edu
push dateThu, 01 Dec 2016 06:22:08 +0000
reviewersjya, smaug, jw_wang
bugs1315581
milestone52.0a1
Bug 1315581 - Notify MediaFormatReader when the compositor gets recreated. r=jya,smaug,jw_wang
dom/base/nsDocument.cpp
dom/base/nsDocument.h
dom/base/nsIDocument.h
dom/ipc/TabChild.cpp
dom/media/AbstractMediaDecoder.h
dom/media/MediaDecoder.cpp
dom/media/MediaDecoder.h
dom/media/MediaFormatReader.cpp
dom/media/MediaFormatReader.h
--- a/dom/base/nsDocument.cpp
+++ b/dom/base/nsDocument.cpp
@@ -12427,16 +12427,30 @@ nsDocument::ScheduleIntersectionObserver
 void
 nsDocument::NotifyIntersectionObservers()
 {
   for (const auto& observer : mIntersectionObservers) {
     observer->Notify();
   }
 }
 
+static bool
+NotifyLayerManagerRecreatedCallback(nsIDocument* aDocument, void* aData)
+{
+  aDocument->NotifyLayerManagerRecreated();
+  return true;
+}
+
+void
+nsDocument::NotifyLayerManagerRecreated()
+{
+  EnumerateActivityObservers(NotifyActivityChanged, nullptr);
+  EnumerateSubDocuments(NotifyLayerManagerRecreatedCallback, nullptr);
+}
+
 XPathEvaluator*
 nsIDocument::XPathEvaluator()
 {
   if (!mXPathEvaluator) {
     mXPathEvaluator = new dom::XPathEvaluator(this);
   }
   return mXPathEvaluator;
 }
--- a/dom/base/nsDocument.h
+++ b/dom/base/nsDocument.h
@@ -779,16 +779,18 @@ public:
   virtual void AddIntersectionObserver(
     mozilla::dom::DOMIntersectionObserver* aObserver) override;
   virtual void RemoveIntersectionObserver(
     mozilla::dom::DOMIntersectionObserver* aObserver) override;
   virtual void UpdateIntersectionObservations() override;
   virtual void ScheduleIntersectionObserverNotification() override;
   virtual void NotifyIntersectionObservers() override;
 
+  virtual void NotifyLayerManagerRecreated() override;
+
 
 private:
   void AddOnDemandBuiltInUASheet(mozilla::StyleSheet* aSheet);
   nsRadioGroupStruct* GetRadioGroupInternal(const nsAString& aName) const;
   void SendToConsole(nsCOMArray<nsISecurityConsoleMessage>& aMessages);
 
 public:
   // nsIDOMNode
--- a/dom/base/nsIDocument.h
+++ b/dom/base/nsIDocument.h
@@ -979,16 +979,18 @@ public:
     if (!mPageUnloadingEventTimeStamp ||
         parentTimeStamp < mPageUnloadingEventTimeStamp) {
       return parentTimeStamp;
     }
 
     return mPageUnloadingEventTimeStamp;
   }
 
+  virtual void NotifyLayerManagerRecreated() = 0;
+
 protected:
   virtual Element *GetRootElementInternal() const = 0;
 
   void SetPageUnloadingEventTimeStamp()
   {
     MOZ_ASSERT(!mPageUnloadingEventTimeStamp);
     mPageUnloadingEventTimeStamp = mozilla::TimeStamp::NowLoRes();
   }
--- a/dom/ipc/TabChild.cpp
+++ b/dom/ipc/TabChild.cpp
@@ -2983,16 +2983,19 @@ TabChild::ReinitRendering()
   ShadowLayerForwarder* lf = lm->AsShadowForwarder();
   lf->IdentifyTextureHost(mTextureFactoryIdentifier);
 
   mApzcTreeManager = CompositorBridgeChild::Get()->GetAPZCTreeManager(mLayersId);
   if (mApzcTreeManager) {
     APZChild* apz = ContentProcessController::Create(mUniqueId);
     CompositorBridgeChild::Get()->SendPAPZConstructor(apz, mLayersId);
   }
+
+  nsCOMPtr<nsIDocument> doc(GetDocument());
+  doc->NotifyLayerManagerRecreated();
 }
 
 void
 TabChild::CompositorUpdated(const TextureFactoryIdentifier& aNewIdentifier)
 {
   gfxPlatform::GetPlatform()->CompositorUpdated();
 
   RefPtr<LayerManager> lm = mPuppetWidget->GetLayerManager();
--- a/dom/media/AbstractMediaDecoder.h
+++ b/dom/media/AbstractMediaDecoder.h
@@ -20,16 +20,17 @@
 class GMPCrashHelper;
 
 namespace mozilla
 {
 
 namespace layers
 {
   class ImageContainer;
+  class KnowsCompositor;
 } // namespace layers
 class MediaResource;
 class ReentrantMonitor;
 class VideoFrameContainer;
 class MediaDecoderOwner;
 class CDMProxy;
 
 typedef nsDataHashtable<nsCStringHashKey, nsCString> MetadataTags;
@@ -64,16 +65,25 @@ 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
@@ -27,16 +27,18 @@
 #include "mozilla/dom/AudioTrackList.h"
 #include "mozilla/dom/HTMLMediaElement.h"
 #include "mozilla/dom/Promise.h"
 #include "mozilla/dom/VideoTrack.h"
 #include "mozilla/dom/VideoTrackList.h"
 #include "nsPrintfCString.h"
 #include "mozilla/Telemetry.h"
 #include "GMPService.h"
+#include "Layers.h"
+#include "mozilla/layers/ShadowLayers.h"
 
 #ifdef MOZ_ANDROID_OMX
 #include "AndroidBridge.h"
 #endif
 
 using namespace mozilla::dom;
 using namespace mozilla::layers;
 using namespace mozilla::media;
@@ -291,16 +293,29 @@ MediaDecoder::ResourceCallback::NotifyBy
 }
 
 void
 MediaDecoder::NotifyOwnerActivityChanged(bool aIsVisible)
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(!IsShutdown());
   SetElementVisibility(aIsVisible);
+
+  MediaDecoderOwner* owner = GetOwner();
+  NS_ENSURE_TRUE_VOID(owner);
+
+  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);
 }
 
 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
@@ -561,32 +561,36 @@ 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()
   {
     SetMediaSeekable(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/MediaFormatReader.cpp
+++ b/dom/media/MediaFormatReader.cpp
@@ -438,16 +438,22 @@ 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>
@@ -498,16 +504,18 @@ 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,16 +7,17 @@
 #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,16 +562,21 @@ 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)
+  {
+    mKnowsCompositor = aKnowsCompositor;
+  }
+
   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
   Maybe<media::TimeUnit> mFallbackSeekTime;
   Maybe<media::TimeUnit> mPendingSeekTime;
@@ -582,13 +588,15 @@ private:
   RefPtr<CDMProxy> mCDMProxy;
 
   RefPtr<GMPCrashHelper> mCrashHelper;
 
   void SetBlankDecode(TrackType aTrack, bool aIsBlankDecode);
 
   class DecoderFactory;
   UniquePtr<DecoderFactory> mDecoderFactory;
+
+  MediaEventListener mCompositorUpdatedListener;
 };
 
 } // namespace mozilla
 
 #endif