Bug 1204622 - release codec listener at reader task queue. r=jya
authorAlfredo Yang <ayang@mozilla.com>
Thu, 01 Oct 2015 00:43:00 +0200
changeset 265959 9a0c443ed6f3488bfdd67669e5b3cdb767a45e8e
parent 265958 c10f8817d787f4c7b7a2309b9ad070b2644de45a
child 265960 f8547896d5823f66f61430cdaf5d7104cb241604
push id66078
push usercbook@mozilla.com
push dateMon, 05 Oct 2015 07:30:10 +0000
treeherdermozilla-inbound@b958e25b1ecf [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjya
bugs1204622
milestone44.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 1204622 - release codec listener at reader task queue. r=jya
dom/media/platforms/gonk/GonkMediaDataDecoder.cpp
dom/media/platforms/gonk/GonkVideoDecoderManager.cpp
dom/media/platforms/gonk/GonkVideoDecoderManager.h
--- a/dom/media/platforms/gonk/GonkMediaDataDecoder.cpp
+++ b/dom/media/platforms/gonk/GonkMediaDataDecoder.cpp
@@ -56,17 +56,22 @@ GonkMediaDataDecoder::Init()
   mDrainComplete = false;
 
   return mManager->Init(mCallback);
 }
 
 nsresult
 GonkMediaDataDecoder::Shutdown()
 {
-  return mManager->Shutdown();
+  nsresult rv = mManager->Shutdown();
+
+  // Because codec allocated runnable and init promise is at reader TaskQueue,
+  // so manager needs to be destroyed at reader TaskQueue to prevent racing.
+  mManager = nullptr;
+  return rv;
 }
 
 // Inserts data into the decoder's pipeline.
 nsresult
 GonkMediaDataDecoder::Input(MediaRawData* aSample)
 {
   nsCOMPtr<nsIRunnable> runnable(
     NS_NewRunnableMethodWithArg<nsRefPtr<MediaRawData>>(
--- a/dom/media/platforms/gonk/GonkVideoDecoderManager.cpp
+++ b/dom/media/platforms/gonk/GonkVideoDecoderManager.cpp
@@ -66,16 +66,17 @@ GonkVideoDecoderManager::GonkVideoDecode
   mInitialFrame = frameSize;
   mHandler = new MessageHandler(this);
   mVideoListener = new VideoResourceListener(this);
 
 }
 
 GonkVideoDecoderManager::~GonkVideoDecoderManager()
 {
+  mVideoListener->NotifyManagerRelease();
   MOZ_COUNT_DTOR(GonkVideoDecoderManager);
 }
 
 nsRefPtr<MediaDataDecoder::InitPromise>
 GonkVideoDecoderManager::Init(MediaDataDecoderCallback* aCallback)
 {
   nsIntSize displaySize(mDisplayWidth, mDisplayHeight);
   nsIntRect pictureRect(0, 0, mVideoWidth, mVideoHeight);
@@ -558,33 +559,65 @@ GonkVideoDecoderManager::VideoResourceLi
 GonkVideoDecoderManager::VideoResourceListener::~VideoResourceListener()
 {
   mManager = nullptr;
 }
 
 void
 GonkVideoDecoderManager::VideoResourceListener::codecReserved()
 {
+  // This class holds VideoResourceListener reference to prevent it's destroyed.
+  class CodecListenerHolder : public nsRunnable {
+  public:
+    CodecListenerHolder(VideoResourceListener* aListener)
+      : mVideoListener(aListener) {}
+
+    NS_IMETHOD Run()
+    {
+      mVideoListener->NotifyCodecReserved();
+      mVideoListener = nullptr;
+      return NS_OK;
+    }
+
+    android::sp<VideoResourceListener> mVideoListener;
+  };
+
   if (mManager) {
-    nsCOMPtr<nsIRunnable> r =
-      NS_NewNonOwningRunnableMethod(mManager, &GonkVideoDecoderManager::codecReserved);
-    mManager->mReaderTaskQueue->Dispatch(r.forget());
+    nsRefPtr<CodecListenerHolder> runner = new CodecListenerHolder(this);
+    mManager->mReaderTaskQueue->Dispatch(runner.forget());
   }
 }
 
 void
 GonkVideoDecoderManager::VideoResourceListener::codecCanceled()
 {
   if (mManager) {
+    MOZ_ASSERT(mManager->mReaderTaskQueue->IsCurrentThreadIn());
     nsCOMPtr<nsIRunnable> r =
       NS_NewNonOwningRunnableMethod(mManager, &GonkVideoDecoderManager::codecCanceled);
     mManager->mReaderTaskQueue->Dispatch(r.forget());
   }
 }
 
+void
+GonkVideoDecoderManager::VideoResourceListener::NotifyManagerRelease()
+{
+  MOZ_ASSERT_IF(mManager, mManager->mReaderTaskQueue->IsCurrentThreadIn());
+  mManager = nullptr;
+}
+
+void
+GonkVideoDecoderManager::VideoResourceListener::NotifyCodecReserved()
+{
+  if (mManager) {
+    MOZ_ASSERT(mManager->mReaderTaskQueue->IsCurrentThreadIn());
+    mManager->codecReserved();
+  }
+}
+
 uint8_t *
 GonkVideoDecoderManager::GetColorConverterBuffer(int32_t aWidth, int32_t aHeight)
 {
   // Allocate a temporary YUV420Planer buffer.
   size_t yuv420p_y_size = aWidth * aHeight;
   size_t yuv420p_u_size = ((aWidth + 1) / 2) * ((aHeight + 1) / 2);
   size_t yuv420p_v_size = yuv420p_u_size;
   size_t yuv420p_size = yuv420p_y_size + yuv420p_u_size + yuv420p_v_size;
--- a/dom/media/platforms/gonk/GonkVideoDecoderManager.h
+++ b/dom/media/platforms/gonk/GonkVideoDecoderManager.h
@@ -92,16 +92,19 @@ private:
   {
   public:
     VideoResourceListener(GonkVideoDecoderManager *aManager);
     ~VideoResourceListener();
 
     void codecReserved() override;
     void codecCanceled() override;
 
+    void NotifyManagerRelease();
+    void NotifyCodecReserved();
+
   private:
     // Forbidden
     VideoResourceListener() = delete;
     VideoResourceListener(const VideoResourceListener &rhs) = delete;
     const VideoResourceListener &operator=(const VideoResourceListener &rhs) = delete;
 
     GonkVideoDecoderManager *mManager;
   };