Bug 925381 - Fix mpeg4 video seek failure. r=nical, r=doublec
authorSotaro Ikeda <sikeda@mozilla.com>
Thu, 17 Oct 2013 11:09:15 -0400
changeset 165971 7b73d5834399753220e5ee70d7eea7e36d5b4ac6
parent 165970 d020cdb227800a53001bd5d51aab7bae145bca13
child 165972 e2b2297d5c1e03619f19b92fc08b236411f7a1e0
push id428
push userbbajaj@mozilla.com
push dateTue, 28 Jan 2014 00:16:25 +0000
treeherdermozilla-release@cd72a7ff3a75 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersnical, doublec
bugs925381
milestone27.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 925381 - Fix mpeg4 video seek failure. r=nical, r=doublec
content/media/VideoFrameContainer.cpp
content/media/omx/MediaOmxReader.cpp
gfx/layers/ImageContainer.cpp
gfx/layers/ImageContainer.h
gfx/layers/client/ImageClient.cpp
gfx/layers/client/ImageClient.h
gfx/layers/composite/CompositableHost.cpp
gfx/layers/composite/CompositableHost.h
gfx/layers/ipc/ImageBridgeChild.cpp
gfx/layers/ipc/ImageBridgeChild.h
gfx/layers/opengl/TextureHostOGL.cpp
gfx/layers/opengl/TextureHostOGL.h
--- a/content/media/VideoFrameContainer.cpp
+++ b/content/media/VideoFrameContainer.cpp
@@ -80,17 +80,17 @@ void VideoFrameContainer::ClearCurrentFr
   MutexAutoLock lock(mMutex);
 
   // See comment in SetCurrentFrame for the reasoning behind
   // using a kungFuDeathGrip here.
   nsRefPtr<Image> kungFuDeathGrip;
   kungFuDeathGrip = mImageContainer->LockCurrentImage();
   mImageContainer->UnlockCurrentImage();
 
-  mImageContainer->SetCurrentImage(nullptr);
+  mImageContainer->ClearAllImages();
   mImageSizeChanged = aResetSize;
 }
 
 ImageContainer* VideoFrameContainer::GetImageContainer() {
   return mImageContainer;
 }
 
 
--- a/content/media/omx/MediaOmxReader.cpp
+++ b/content/media/omx/MediaOmxReader.cpp
@@ -340,16 +340,20 @@ bool MediaOmxReader::DecodeAudioData()
                                  frame.mAudioChannels));
   return true;
 }
 
 nsresult MediaOmxReader::Seek(int64_t aTarget, int64_t aStartTime, int64_t aEndTime, int64_t aCurrentTime)
 {
   NS_ASSERTION(mDecoder->OnDecodeThread(), "Should be on decode thread.");
 
+  VideoFrameContainer* container = mDecoder->GetVideoFrameContainer();
+  if (container && container->GetImageContainer()) {
+    container->GetImageContainer()->ClearAllImagesExceptFront();
+  }
   mVideoQueue.Reset();
   mAudioQueue.Reset();
 
   mAudioSeekTimeUs = mVideoSeekTimeUs = aTarget;
 
   return DecodeToTarget(aTarget);
 }
 
--- a/gfx/layers/ImageContainer.cpp
+++ b/gfx/layers/ImageContainer.cpp
@@ -181,29 +181,49 @@ ImageContainer::ClearCurrentImage()
 {
   ReentrantMonitorAutoEnter mon(mReentrantMonitor);
   SetCurrentImageInternal(nullptr);
 }
 
 void
 ImageContainer::SetCurrentImage(Image *aImage)
 {
-  if (IsAsync() && !aImage) {
-    // Let ImageClient to release all TextureClients.
-    ImageBridgeChild::FlushImage(mImageClient, this);
+  if (!aImage) {
+    ClearAllImages();
     return;
   }
 
   ReentrantMonitorAutoEnter mon(mReentrantMonitor);
   if (IsAsync()) {
     ImageBridgeChild::DispatchImageClientUpdate(mImageClient, this);
   }
   SetCurrentImageInternal(aImage);
 }
 
+ void
+ImageContainer::ClearAllImages()
+{
+  if (IsAsync()) {
+    // Let ImageClient release all TextureClients.
+    ImageBridgeChild::FlushAllImages(mImageClient, this, false);
+    return;
+  }
+  ReentrantMonitorAutoEnter mon(mReentrantMonitor);
+  SetCurrentImageInternal(nullptr);
+}
+
+void
+ImageContainer::ClearAllImagesExceptFront()
+{
+  if (IsAsync()) {
+    // Let ImageClient release all TextureClients except front one.
+    ImageBridgeChild::FlushAllImages(mImageClient, this, true);
+  }
+}
+
 void
 ImageContainer::SetCurrentImageInTransaction(Image *aImage)
 {
   NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
   NS_ASSERTION(!mImageClient, "Should use async image transfer with ImageBridge.");
 
   SetCurrentImageInternal(aImage);
 }
--- a/gfx/layers/ImageContainer.h
+++ b/gfx/layers/ImageContainer.h
@@ -380,16 +380,27 @@ public:
    *
    * If this ImageContainer has an ImageClient for async video:
    * Schelude a task to send the image to the compositor using the 
    * PImageBridge protcol without using the main thread.
    */
   void SetCurrentImage(Image* aImage);
 
   /**
+   * Clear all images. Let ImageClient release all TextureClients.
+   */
+  void ClearAllImages();
+
+  /**
+   * Clear all images except current one.
+   * Let ImageClient release all TextureClients except front one.
+   */
+  void ClearAllImagesExceptFront();
+
+  /**
    * Clear the current image.
    * This function is expect to be called only from a CompositableClient
    * that belongs to ImageBridgeChild. Created to prevent dead lock.
    * See Bug 901224.
    */
   void ClearCurrentImage();
 
   /**
--- a/gfx/layers/client/ImageClient.cpp
+++ b/gfx/layers/client/ImageClient.cpp
@@ -93,28 +93,28 @@ ImageClientBuffered::ImageClientBuffered
 }
 
 TextureInfo ImageClientSingle::GetTextureInfo() const
 {
   return TextureInfo(COMPOSITABLE_IMAGE);
 }
 
 void
-ImageClientSingle::FlushImage()
+ImageClientSingle::FlushAllImages(bool aExceptFront)
 {
-  if (mFrontBuffer) {
+  if (!aExceptFront && mFrontBuffer) {
     RemoveTextureClient(mFrontBuffer);
     mFrontBuffer = nullptr;
   }
 }
 
 void
-ImageClientBuffered::FlushImage()
+ImageClientBuffered::FlushAllImages(bool aExceptFront)
 {
-  if (mFrontBuffer) {
+  if (!aExceptFront && mFrontBuffer) {
     RemoveTextureClient(mFrontBuffer);
     mFrontBuffer = nullptr;
   }
   if (mBackBuffer) {
     RemoveTextureClient(mBackBuffer);
     mBackBuffer = nullptr;
   }
 }
--- a/gfx/layers/client/ImageClient.h
+++ b/gfx/layers/client/ImageClient.h
@@ -60,17 +60,17 @@ public:
   virtual void UpdatePictureRect(nsIntRect aPictureRect);
 
   virtual already_AddRefed<Image> CreateImage(const uint32_t *aFormats,
                                               uint32_t aNumFormats) = 0;
 
   /**
    * Synchronously remove all the textures used by the image client.
    */
-  virtual void FlushImage() {}
+  virtual void FlushAllImages(bool aExceptFront) {}
 
 protected:
   ImageClient(CompositableForwarder* aFwd, CompositableType aType);
 
   CompositableType mType;
   int32_t mLastPaintedImageSerial;
   nsIntRect mPictureRect;
 };
@@ -95,17 +95,17 @@ public:
   CreateBufferTextureClient(gfx::SurfaceFormat aFormat,
                             TextureFlags aFlags = TEXTURE_FLAGS_DEFAULT) MOZ_OVERRIDE;
 
   virtual TextureInfo GetTextureInfo() const MOZ_OVERRIDE;
 
   virtual already_AddRefed<Image> CreateImage(const uint32_t *aFormats,
                                               uint32_t aNumFormats) MOZ_OVERRIDE;
 
-  virtual void FlushImage() MOZ_OVERRIDE;
+  virtual void FlushAllImages(bool aExceptFront) MOZ_OVERRIDE;
 
 protected:
   RefPtr<TextureClient> mFrontBuffer;
   // Some layers may want to enforce some flags to all their textures
   // (like disallowing tiling)
   TextureFlags mTextureFlags;
 };
 
@@ -118,17 +118,17 @@ public:
   ImageClientBuffered(CompositableForwarder* aFwd,
                       TextureFlags aFlags,
                       CompositableType aType);
 
   virtual bool UpdateImage(ImageContainer* aContainer, uint32_t aContentFlags);
 
   virtual void OnDetach() MOZ_OVERRIDE;
 
-  virtual void FlushImage() MOZ_OVERRIDE;
+  virtual void FlushAllImages(bool aExceptFront) MOZ_OVERRIDE;
 
 protected:
   RefPtr<TextureClient> mBackBuffer;
 };
 
 /**
  * An image client which uses a single texture client, may be single or double
  * buffered. (As opposed to using two texture clients for buffering, as in
--- a/gfx/layers/composite/CompositableHost.cpp
+++ b/gfx/layers/composite/CompositableHost.cpp
@@ -71,16 +71,19 @@ CompositableHost::RemoveTextureHost(uint
     if (it->GetNextSibling() &&
         it->GetNextSibling()->GetID() == aTextureID) {
       RefPtr<TextureHost> toRemove = it->GetNextSibling();
       it->SetNextSibling(it->GetNextSibling()->GetNextSibling());
       toRemove->SetNextSibling(nullptr);
     }
     it = it->GetNextSibling();
   }
+  if (!mFirstTexture && mBackendData) {
+    mBackendData->ClearData();
+  }
 }
 
 TextureHost*
 CompositableHost::GetTextureHost(uint64_t aTextureID)
 {
   RefPtr<TextureHost> it = mFirstTexture;
   while (it) {
     if (it->GetID() == aTextureID) {
--- a/gfx/layers/composite/CompositableHost.h
+++ b/gfx/layers/composite/CompositableHost.h
@@ -67,16 +67,17 @@ public:
   {
     MOZ_COUNT_CTOR(CompositableBackendSpecificData);
   }
   virtual ~CompositableBackendSpecificData()
   {
     MOZ_COUNT_DTOR(CompositableBackendSpecificData);
   }
   virtual void SetCompositor(Compositor* aCompositor) {}
+  virtual void ClearData() {}
 };
 
 /**
  * The compositor-side counterpart to CompositableClient. Responsible for
  * updating textures and data about textures from IPC and how textures are
  * composited (tiling, double buffering, etc.).
  *
  * Update (for images/canvases) and UpdateThebes (for Thebes) are called during
--- a/gfx/layers/ipc/ImageBridgeChild.cpp
+++ b/gfx/layers/ipc/ImageBridgeChild.cpp
@@ -417,57 +417,57 @@ void ImageBridgeChild::DispatchImageClie
   sImageBridgeChildSingleton->GetMessageLoop()->PostTask(
     FROM_HERE,
     NewRunnableFunction<
       void (*)(ImageClient*, ImageContainer*),
       ImageClient*,
       nsRefPtr<ImageContainer> >(&UpdateImageClientNow, aClient, aContainer));
 }
 
-static void FlushImageSync(ImageClient* aClient, ImageContainer* aContainer, ReentrantMonitor* aBarrier, bool* aDone)
+static void FlushAllImagesSync(ImageClient* aClient, ImageContainer* aContainer, bool aExceptFront, ReentrantMonitor* aBarrier, bool* aDone)
 {
-  ImageBridgeChild::FlushImageNow(aClient, aContainer);
+  ImageBridgeChild::FlushAllImagesNow(aClient, aContainer, aExceptFront);
 
   ReentrantMonitorAutoEnter autoMon(*aBarrier);
   *aDone = true;
   aBarrier->NotifyAll();
 }
 
 //static
-void ImageBridgeChild::FlushImage(ImageClient* aClient, ImageContainer* aContainer)
+void ImageBridgeChild::FlushAllImages(ImageClient* aClient, ImageContainer* aContainer, bool aExceptFront)
 {
   if (InImageBridgeChildThread()) {
-    FlushImageNow(aClient, aContainer);
+    FlushAllImagesNow(aClient, aContainer, aExceptFront);
     return;
   }
 
   ReentrantMonitor barrier("CreateImageClient Lock");
   ReentrantMonitorAutoEnter autoMon(barrier);
   bool done = false;
 
   sImageBridgeChildSingleton->GetMessageLoop()->PostTask(
     FROM_HERE,
-    NewRunnableFunction(&FlushImageSync, aClient, aContainer, &barrier, &done));
+    NewRunnableFunction(&FlushAllImagesSync, aClient, aContainer, aExceptFront, &barrier, &done));
 
   // should stop the thread until the ImageClient has been created on
   // the other thread
   while (!done) {
     barrier.Wait();
   }
 }
 
 //static
-void ImageBridgeChild::FlushImageNow(ImageClient* aClient, ImageContainer* aContainer)
+void ImageBridgeChild::FlushAllImagesNow(ImageClient* aClient, ImageContainer* aContainer, bool aExceptFront)
 {
   MOZ_ASSERT(aClient);
   sImageBridgeChildSingleton->BeginTransaction();
-  if (aContainer) {
+  if (aContainer && !aExceptFront) {
     aContainer->ClearCurrentImage();
   }
-  aClient->FlushImage();
+  aClient->FlushAllImages(aExceptFront);
   aClient->OnTransaction();
   sImageBridgeChildSingleton->EndTransaction();
   aClient->FlushTexturesToRemoveCallbacks();
 }
 
 void
 ImageBridgeChild::BeginTransaction()
 {
--- a/gfx/layers/ipc/ImageBridgeChild.h
+++ b/gfx/layers/ipc/ImageBridgeChild.h
@@ -238,22 +238,22 @@ public:
 
   static void DispatchReleaseImageClient(ImageClient* aClient);
   static void DispatchReleaseTextureClient(TextureClient* aClient);
   static void DispatchImageClientUpdate(ImageClient* aClient, ImageContainer* aContainer);
 
   /**
    * Flush all Images sent to CompositableHost.
    */
-  static void FlushImage(ImageClient* aClient, ImageContainer* aContainer);
+  static void FlushAllImages(ImageClient* aClient, ImageContainer* aContainer, bool aExceptFront);
 
   /**
    * Must be called on the ImageBridgeChild's thread.
    */
-  static void FlushImageNow(ImageClient* aClient, ImageContainer* aContainer);
+  static void FlushAllImagesNow(ImageClient* aClient, ImageContainer* aContainer, bool aExceptFront);
 
   // CompositableForwarder
 
   virtual void Connect(CompositableClient* aCompositable) MOZ_OVERRIDE;
 
   /**
    * See CompositableForwarder::AddTexture
    */
--- a/gfx/layers/opengl/TextureHostOGL.cpp
+++ b/gfx/layers/opengl/TextureHostOGL.cpp
@@ -181,16 +181,21 @@ CompositableDataGonkOGL::gl() const
   return mCompositor ? mCompositor->gl() : nullptr;
 }
 
 void CompositableDataGonkOGL::SetCompositor(Compositor* aCompositor)
 {
   mCompositor = static_cast<CompositorOGL*>(aCompositor);
 }
 
+void CompositableDataGonkOGL::ClearData()
+{
+  DeleteTextureIfPresent();
+}
+
 GLuint CompositableDataGonkOGL::GetTexture()
 {
   if (!mTexture) {
     gl()->MakeCurrent();
     gl()->fGenTextures(1, &mTexture);
   }
   return mTexture;
 }
--- a/gfx/layers/opengl/TextureHostOGL.h
+++ b/gfx/layers/opengl/TextureHostOGL.h
@@ -65,16 +65,17 @@ class TextureImageDeprecatedTextureHostO
  */
 class CompositableDataGonkOGL : public CompositableBackendSpecificData
 {
 public:
   CompositableDataGonkOGL();
   virtual ~CompositableDataGonkOGL();
 
   virtual void SetCompositor(Compositor* aCompositor) MOZ_OVERRIDE;
+  virtual void ClearData() MOZ_OVERRIDE;
   GLuint GetTexture();
   void DeleteTextureIfPresent();
   gl::GLContext* gl() const;
 protected:
   RefPtr<CompositorOGL> mCompositor;
   GLuint mTexture;
 };