Bug 1198664 - Refactor: move common behaviors to base class. r=bwu,jya
authorJohn Lin <jolin@mozilla.com>
Tue, 06 Oct 2015 02:18:00 +0200
changeset 266836 48a3c0d344578db5be0253037011d9fc59d8d10b
parent 266835 b31170d704caf2bb09c184b5655a6165a4469273
child 266837 5b288da01560891f6f09dc8a038222ac21a3d51c
push id29499
push userkwierso@gmail.com
push dateThu, 08 Oct 2015 21:29:10 +0000
treeherdermozilla-central@46da59584acb [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbwu, jya
bugs1198664
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 1198664 - Refactor: move common behaviors to base class. r=bwu,jya
dom/media/platforms/gonk/GonkAudioDecoderManager.cpp
dom/media/platforms/gonk/GonkAudioDecoderManager.h
dom/media/platforms/gonk/GonkMediaDataDecoder.cpp
dom/media/platforms/gonk/GonkMediaDataDecoder.h
dom/media/platforms/gonk/GonkVideoDecoderManager.cpp
dom/media/platforms/gonk/GonkVideoDecoderManager.h
--- a/dom/media/platforms/gonk/GonkAudioDecoderManager.cpp
+++ b/dom/media/platforms/gonk/GonkAudioDecoderManager.cpp
@@ -29,58 +29,51 @@ extern PRLogModuleInfo* GetPDMLog();
 #define READ_OUTPUT_BUFFER_TIMEOUT_US  3000
 
 using namespace android;
 typedef android::MediaCodecProxy MediaCodecProxy;
 
 namespace mozilla {
 
 GonkAudioDecoderManager::GonkAudioDecoderManager(const AudioInfo& aConfig)
-  : mLastDecodedTime(0)
-  , mAudioChannels(aConfig.mChannels)
+  : mAudioChannels(aConfig.mChannels)
   , mAudioRate(aConfig.mRate)
   , mAudioProfile(aConfig.mProfile)
   , mAudioBuffer(nullptr)
-  , mMonitor("GonkAudioDecoderManager")
 {
   MOZ_COUNT_CTOR(GonkAudioDecoderManager);
   MOZ_ASSERT(mAudioChannels);
   mCodecSpecificData = aConfig.mCodecSpecificConfig;
   mMimeType = aConfig.mMimeType;
-
 }
 
 GonkAudioDecoderManager::~GonkAudioDecoderManager()
 {
   MOZ_COUNT_DTOR(GonkAudioDecoderManager);
 }
 
 nsRefPtr<MediaDataDecoder::InitPromise>
-GonkAudioDecoderManager::Init(MediaDataDecoderCallback* aCallback)
+GonkAudioDecoderManager::Init()
 {
-  if (InitMediaCodecProxy(aCallback)) {
+  if (InitMediaCodecProxy()) {
     return InitPromise::CreateAndResolve(TrackType::kAudioTrack, __func__);
   } else {
     return InitPromise::CreateAndReject(DecoderFailureReason::INIT_ERROR, __func__);
   }
 }
 
 bool
-GonkAudioDecoderManager::InitMediaCodecProxy(MediaDataDecoderCallback* aCallback)
+GonkAudioDecoderManager::InitMediaCodecProxy()
 {
   status_t rv = OK;
-  if (mLooper != nullptr) {
+  if (!InitLoopers(MediaData::AUDIO_DATA)) {
     return false;
   }
-  // Create ALooper
-  mLooper = new ALooper;
-  mLooper->setName("GonkAudioDecoderManager");
-  mLooper->start();
 
-  mDecoder = MediaCodecProxy::CreateByType(mLooper, mMimeType.get(), false, nullptr);
+  mDecoder = MediaCodecProxy::CreateByType(mDecodeLooper, mMimeType.get(), false, nullptr);
   if (!mDecoder.get()) {
     return false;
   }
   if (!mDecoder->AskMediaCodecAndWait())
   {
     mDecoder = nullptr;
     return false;
   }
@@ -105,62 +98,16 @@ GonkAudioDecoderManager::InitMediaCodecP
   if (rv == OK) {
     return true;
   } else {
     GADM_LOG("Failed to input codec specific data!");
     return false;
   }
 }
 
-bool
-GonkAudioDecoderManager::HasQueuedSample()
-{
-    MonitorAutoLock mon(mMonitor);
-    return mQueueSample.Length();
-}
-
-nsresult
-GonkAudioDecoderManager::Input(MediaRawData* aSample)
-{
-  MonitorAutoLock mon(mMonitor);
-  nsRefPtr<MediaRawData> sample;
-
-  if (aSample) {
-    sample = aSample;
-  } else {
-    // It means EOS with empty sample.
-    sample = new MediaRawData();
-  }
-
-  mQueueSample.AppendElement(sample);
-
-  status_t rv;
-  while (mQueueSample.Length()) {
-    nsRefPtr<MediaRawData> data = mQueueSample.ElementAt(0);
-    {
-      MonitorAutoUnlock mon_exit(mMonitor);
-      rv = mDecoder->Input(reinterpret_cast<const uint8_t*>(data->Data()),
-                           data->Size(),
-                           data->mTime,
-                           0);
-    }
-    if (rv == OK) {
-      mQueueSample.RemoveElementAt(0);
-    } else if (rv == -EAGAIN || rv == -ETIMEDOUT) {
-      // In most cases, EAGAIN or ETIMEOUT are safe because OMX can't fill
-      // buffer on time.
-      return NS_OK;
-    } else {
-      return NS_ERROR_UNEXPECTED;
-    }
-  }
-
-  return NS_OK;
-}
-
 nsresult
 GonkAudioDecoderManager::CreateAudioData(int64_t aStreamOffset, AudioData **v) {
   if (!(mAudioBuffer != nullptr && mAudioBuffer->data() != nullptr)) {
     GADM_LOG("Audio Buffer is not valid!");
     return NS_ERROR_UNEXPECTED;
   }
 
   int64_t timeUs;
@@ -170,23 +117,23 @@ GonkAudioDecoderManager::CreateAudioData
 
   if (mAudioBuffer->range_length() == 0) {
     // Some decoders may return spurious empty buffers that we just want to ignore
     // quoted from Android's AwesomePlayer.cpp
     ReleaseAudioBuffer();
     return NS_ERROR_NOT_AVAILABLE;
   }
 
-  if (mLastDecodedTime > timeUs) {
+  if (mLastTime > timeUs) {
     ReleaseAudioBuffer();
     GADM_LOG("Output decoded sample time is revert. time=%lld", timeUs);
     MOZ_ASSERT(false);
     return NS_ERROR_NOT_AVAILABLE;
   }
-  mLastDecodedTime = timeUs;
+  mLastTime = timeUs;
 
   const uint8_t *data = static_cast<const uint8_t*>(mAudioBuffer->data());
   size_t dataOffset = mAudioBuffer->range_offset();
   size_t size = mAudioBuffer->range_length();
 
   nsAutoArrayPtr<AudioDataValue> buffer(new AudioDataValue[size/2]);
   memcpy(buffer.get(), data+dataOffset, size);
   uint32_t frames = size / (2 * mAudioChannels);
@@ -203,33 +150,16 @@ GonkAudioDecoderManager::CreateAudioData
                                                 mAudioChannels,
                                                 mAudioRate);
   ReleaseAudioBuffer();
   audioData.forget(v);
   return NS_OK;
 }
 
 nsresult
-GonkAudioDecoderManager::Flush()
-{
-  {
-    MonitorAutoLock mon(mMonitor);
-    mQueueSample.Clear();
-  }
-
-  mLastDecodedTime = 0;
-
-  if (mDecoder->flush() != OK) {
-    return NS_ERROR_FAILURE;
-  }
-
-  return NS_OK;
-}
-
-nsresult
 GonkAudioDecoderManager::Output(int64_t aStreamOffset,
                                 nsRefPtr<MediaData>& aOutData)
 {
   aOutData = nullptr;
   status_t err;
   err = mDecoder->Output(&mAudioBuffer, READ_OUTPUT_BUFFER_TIMEOUT_US);
 
   switch (err) {
--- a/dom/media/platforms/gonk/GonkAudioDecoderManager.h
+++ b/dom/media/platforms/gonk/GonkAudioDecoderManager.h
@@ -8,62 +8,43 @@
 #define GonkAudioDecoderManager_h_
 
 #include "mozilla/RefPtr.h"
 #include "GonkMediaDataDecoder.h"
 
 using namespace android;
 
 namespace android {
-struct MOZ_EXPORT ALooper;
 class MOZ_EXPORT MediaBuffer;
 } // namespace android
 
 namespace mozilla {
 
 class GonkAudioDecoderManager : public GonkDecoderManager {
 typedef android::MediaCodecProxy MediaCodecProxy;
 public:
   GonkAudioDecoderManager(const AudioInfo& aConfig);
 
-  virtual ~GonkAudioDecoderManager() override;
+  virtual ~GonkAudioDecoderManager();
 
-  nsRefPtr<InitPromise> Init(MediaDataDecoderCallback* aCallback) override;
-
-  nsresult Input(MediaRawData* aSample) override;
+  nsRefPtr<InitPromise> Init() override;
 
   nsresult Output(int64_t aStreamOffset,
                           nsRefPtr<MediaData>& aOutput) override;
 
-  nsresult Flush() override;
-
-  bool HasQueuedSample() override;
-
 private:
-  bool InitMediaCodecProxy(MediaDataDecoderCallback* aCallback);
+  bool InitMediaCodecProxy();
 
   nsresult CreateAudioData(int64_t aStreamOffset,
                               AudioData** aOutData);
 
   void ReleaseAudioBuffer();
 
-  int64_t mLastDecodedTime;
-
   uint32_t mAudioChannels;
   uint32_t mAudioRate;
   const uint32_t mAudioProfile;
 
-  MediaDataDecoderCallback*  mReaderCallback;
   android::MediaBuffer* mAudioBuffer;
-  android::sp<ALooper> mLooper;
-
-  // This monitor protects mQueueSample.
-  Monitor mMonitor;
-
-  // An queue with the MP4 samples which are waiting to be sent into OMX.
-  // If an element is an empty MP4Sample, that menas EOS. There should not
-  // any sample be queued after EOS.
-  nsTArray<nsRefPtr<MediaRawData>> mQueueSample;
 };
 
 } // namespace mozilla
 
 #endif // GonkAudioDecoderManager_h_
--- a/dom/media/platforms/gonk/GonkMediaDataDecoder.cpp
+++ b/dom/media/platforms/gonk/GonkMediaDataDecoder.cpp
@@ -3,64 +3,167 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 #include "GonkMediaDataDecoder.h"
 #include "VideoUtils.h"
 #include "nsTArray.h"
 #include "MediaCodecProxy.h"
 
+#include <stagefright/foundation/ADebug.h>
+
 #include "mozilla/Logging.h"
 #include <android/log.h>
 #define GMDD_LOG(...) __android_log_print(ANDROID_LOG_DEBUG, "GonkMediaDataDecoder", __VA_ARGS__)
 
 extern PRLogModuleInfo* GetPDMLog();
 #define LOG(...) MOZ_LOG(GetPDMLog(), mozilla::LogLevel::Debug, (__VA_ARGS__))
 
 using namespace android;
 
 namespace mozilla {
 
+bool
+GonkDecoderManager::InitLoopers(MediaData::Type aType)
+{
+  MOZ_ASSERT(mDecodeLooper.get() == nullptr && mTaskLooper.get() == nullptr);
+  MOZ_ASSERT(aType == MediaData::VIDEO_DATA || aType == MediaData::AUDIO_DATA);
+
+  const char* suffix = (aType == MediaData::VIDEO_DATA ? "video" : "audio");
+  mDecodeLooper = new ALooper;
+  android::AString name("MediaCodecProxy/");
+  name.append(suffix);
+  mDecodeLooper->setName(name.c_str());
+
+  mTaskLooper = new ALooper;
+  name.setTo("GonkDecoderManager/");
+  name.append(suffix);
+  mTaskLooper->setName(name.c_str());
+  mTaskLooper->registerHandler(this);
+
+  return mDecodeLooper->start() == OK && mTaskLooper->start() == OK;
+}
+
+nsresult
+GonkDecoderManager::Input(MediaRawData* aSample)
+{
+  MutexAutoLock lock(mMutex);
+  nsRefPtr<MediaRawData> sample;
+
+  if (!aSample) {
+    // It means EOS with empty sample.
+    sample = new MediaRawData();
+  } else {
+    sample = aSample;
+  }
+
+  mQueuedSamples.AppendElement(sample);
+
+  status_t rv;
+  while (mQueuedSamples.Length()) {
+    nsRefPtr<MediaRawData> data = mQueuedSamples.ElementAt(0);
+    {
+      MutexAutoUnlock unlock(mMutex);
+      rv = mDecoder->Input(reinterpret_cast<const uint8_t*>(data->Data()),
+                           data->Size(),
+                           data->mTime,
+                           0);
+    }
+    if (rv == OK) {
+      mQueuedSamples.RemoveElementAt(0);
+    } else if (rv == -EAGAIN || rv == -ETIMEDOUT) {
+      // In most cases, EAGAIN or ETIMEOUT are safe because OMX can't fill
+      // buffer on time.
+      return NS_OK;
+    } else {
+      return NS_ERROR_UNEXPECTED;
+    }
+  }
+
+  return NS_OK;
+}
+
+nsresult
+GonkDecoderManager::Flush()
+{
+  if (mDecoder == nullptr) {
+    GMDD_LOG("Decoder is not initialized");
+    return NS_ERROR_UNEXPECTED;
+  }
+  {
+    MutexAutoLock lock(mMutex);
+    mQueuedSamples.Clear();
+  }
+
+  mLastTime = 0;
+
+  if (mDecoder->flush() != OK) {
+    return NS_ERROR_FAILURE;
+  }
+
+  return NS_OK;
+}
+
 nsresult
 GonkDecoderManager::Shutdown()
 {
   if (mDecoder.get()) {
     mDecoder->stop();
     mDecoder->ReleaseMediaResources();
     mDecoder = nullptr;
   }
 
   mInitPromise.RejectIfExists(DecoderFailureReason::CANCELED, __func__);
 
   return NS_OK;
 }
 
+bool
+GonkDecoderManager::HasQueuedSample()
+{
+  MutexAutoLock lock(mMutex);
+  return mQueuedSamples.Length();
+}
+
+void
+GonkDecoderManager::onMessageReceived(const sp<AMessage> &aMessage)
+{
+  switch (aMessage->what()) {
+    default:
+      {
+        TRESPASS();
+        break;
+      }
+  }
+}
+
 GonkMediaDataDecoder::GonkMediaDataDecoder(GonkDecoderManager* aManager,
                                            FlushableTaskQueue* aTaskQueue,
                                            MediaDataDecoderCallback* aCallback)
   : mTaskQueue(aTaskQueue)
   , mCallback(aCallback)
   , mManager(aManager)
   , mSignaledEOS(false)
   , mDrainComplete(false)
 {
   MOZ_COUNT_CTOR(GonkMediaDataDecoder);
+  mManager->SetDecodeCallback(aCallback);
 }
 
 GonkMediaDataDecoder::~GonkMediaDataDecoder()
 {
   MOZ_COUNT_DTOR(GonkMediaDataDecoder);
 }
 
 nsRefPtr<MediaDataDecoder::InitPromise>
 GonkMediaDataDecoder::Init()
 {
   mDrainComplete = false;
 
-  return mManager->Init(mCallback);
+  return mManager->Init();
 }
 
 nsresult
 GonkMediaDataDecoder::Shutdown()
 {
   nsresult rv = mManager->Shutdown();
 
   // Because codec allocated runnable and init promise is at reader TaskQueue,
--- a/dom/media/platforms/gonk/GonkMediaDataDecoder.h
+++ b/dom/media/platforms/gonk/GonkMediaDataDecoder.h
@@ -2,66 +2,97 @@
 /* vim:set ts=2 sw=2 sts=2 et cindent: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #if !defined(GonkMediaDataDecoder_h_)
 #define GonkMediaDataDecoder_h_
 #include "PlatformDecoderModule.h"
+#include <stagefright/foundation/AHandler.h>
 
 namespace android {
+struct ALooper;
 class MediaCodecProxy;
 } // namespace android
 
 namespace mozilla {
 class MediaRawData;
 
 // Manage the data flow from inputting encoded data and outputting decode data.
-class GonkDecoderManager {
+class GonkDecoderManager : public android::AHandler {
 public:
   typedef TrackInfo::TrackType TrackType;
   typedef MediaDataDecoder::InitPromise InitPromise;
   typedef MediaDataDecoder::DecoderFailureReason DecoderFailureReason;
 
   virtual ~GonkDecoderManager() {}
 
-  virtual nsRefPtr<InitPromise> Init(MediaDataDecoderCallback* aCallback) = 0;
-
   // Add samples into OMX decoder or queue them if decoder is out of input buffer.
-  virtual nsresult Input(MediaRawData* aSample) = 0;
+  nsresult Input(MediaRawData* aSample);
 
   // Produces decoded output, it blocks until output can be produced or a timeout
   // is expired or until EOS. Returns NS_OK on success, or NS_ERROR_NOT_AVAILABLE
   // if there's not enough data to produce more output. If this returns a failure
   // code other than NS_ERROR_NOT_AVAILABLE, an error will be reported to the
   // MP4Reader.
   // The overrided class should follow the same behaviour.
   virtual nsresult Output(int64_t aStreamOffset,
                           nsRefPtr<MediaData>& aOutput) = 0;
+  virtual nsRefPtr<InitPromise> Init() = 0;
 
   // Flush the queued sample.
-  virtual nsresult Flush() = 0;
+  nsresult Flush();
 
   // Shutdown decoder and rejects the init promise.
   nsresult Shutdown();
 
   // True if sample is queued.
-  virtual bool HasQueuedSample() = 0;
+  bool HasQueuedSample();
+
+  // Set callback for decoder events, such as requesting more input,
+  // returning output, or reporting error.
+  void SetDecodeCallback(MediaDataDecoderCallback* aCallback)
+  {
+    mDecodeCallback = aCallback;
+  }
 
 protected:
+  GonkDecoderManager()
+    : mMutex("GonkDecoderManager")
+    , mLastTime(0)
+    , mDecodeCallback(nullptr)
+  {}
+
+  bool InitLoopers(MediaData::Type aType);
+
+  void onMessageReceived(const android::sp<android::AMessage> &aMessage) override;
+
   nsRefPtr<MediaByteBuffer> mCodecSpecificData;
 
   nsAutoCString mMimeType;
 
   // MediaCodedc's wrapper that performs the decoding.
   android::sp<android::MediaCodecProxy> mDecoder;
+  // Looper for mDecoder to run on.
+  android::sp<android::ALooper> mDecodeLooper;
+  // Looper to run decode tasks such as recycling output buffers.
+  android::sp<android::ALooper> mTaskLooper;
 
   MozPromiseHolder<InitPromise> mInitPromise;
 
+  Mutex mMutex; // Protects mQueuedSamples.
+  // A queue that stores the samples waiting to be sent to mDecoder.
+  // Empty element means EOS and there shouldn't be any sample be queued after it.
+  // Samples are queued in caller's thread and dequeued in mTaskLooper.
+  nsTArray<nsRefPtr<MediaRawData>> mQueuedSamples;
+
+  int64_t mLastTime;  // The last decoded frame presentation time.
+
+  MediaDataDecoderCallback* mDecodeCallback; // Reports decoder output or error.
 };
 
 // Samples are decoded using the GonkDecoder (MediaCodec)
 // created by the GonkDecoderManager. This class implements
 // the higher-level logic that drives mapping the Gonk to the async
 // MediaDataDecoder interface. The specifics of decoding the exact stream
 // type are handled by GonkDecoderManager and the GonkDecoder it creates.
 class GonkMediaDataDecoder : public MediaDataDecoder {
@@ -96,17 +127,17 @@ private:
 
   // Called on the task queue. Orders the Gonk to drain, and then extracts
   // all available output.
   void ProcessDrain();
 
   RefPtr<FlushableTaskQueue> mTaskQueue;
   MediaDataDecoderCallback* mCallback;
 
-  nsAutoPtr<GonkDecoderManager> mManager;
+  android::sp<GonkDecoderManager> mManager;
 
   // The last offset into the media resource that was passed into Input().
   // This is used to approximate the decoder's position in the media resource.
   int64_t mLastStreamOffset;
   // Set it ture when there is no input data
   bool mSignaledEOS;
   // Set if there is no more output data from decoder
   bool mDrainComplete;
--- a/dom/media/platforms/gonk/GonkVideoDecoderManager.cpp
+++ b/dom/media/platforms/gonk/GonkVideoDecoderManager.cpp
@@ -12,20 +12,17 @@
 #include "ImageContainer.h"
 #include "VideoUtils.h"
 #include "nsThreadUtils.h"
 #include "Layers.h"
 #include "mozilla/Logging.h"
 #include "stagefright/MediaBuffer.h"
 #include "stagefright/MetaData.h"
 #include "stagefright/MediaErrors.h"
-#include <stagefright/foundation/ADebug.h>
-#include <stagefright/foundation/AMessage.h>
 #include <stagefright/foundation/AString.h>
-#include <stagefright/foundation/ALooper.h>
 #include "GonkNativeWindow.h"
 #include "GonkNativeWindowClient.h"
 #include "mozilla/layers/GrallocTextureClient.h"
 #include "mozilla/layers/TextureClient.h"
 #include <cutils/properties.h>
 
 #define READ_OUTPUT_BUFFER_TIMEOUT_US  3000
 
@@ -39,49 +36,45 @@ using namespace android;
 typedef android::MediaCodecProxy MediaCodecProxy;
 
 namespace mozilla {
 
 GonkVideoDecoderManager::GonkVideoDecoderManager(
   mozilla::layers::ImageContainer* aImageContainer,
   const VideoInfo& aConfig)
   : mImageContainer(aImageContainer)
-  , mReaderCallback(nullptr)
-  , mLastDecodedTime(0)
   , mColorConverterBufferSize(0)
   , mNativeWindow(nullptr)
   , mPendingReleaseItemsLock("GonkVideoDecoderManager::mPendingReleaseItemsLock")
-  , mMonitor("GonkVideoDecoderManager")
 {
   MOZ_COUNT_CTOR(GonkVideoDecoderManager);
   mMimeType = aConfig.mMimeType;
   mVideoWidth  = aConfig.mDisplay.width;
   mVideoHeight = aConfig.mDisplay.height;
   mDisplayWidth = aConfig.mDisplay.width;
   mDisplayHeight = aConfig.mDisplay.height;
   mInfo.mVideo = aConfig;
 
   mCodecSpecificData = aConfig.mCodecSpecificConfig;
   nsIntRect pictureRect(0, 0, mVideoWidth, mVideoHeight);
   nsIntSize frameSize(mVideoWidth, mVideoHeight);
   mPicture = pictureRect;
   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)
+GonkVideoDecoderManager::Init()
 {
   nsIntSize displaySize(mDisplayWidth, mDisplayHeight);
   nsIntRect pictureRect(0, 0, mVideoWidth, mVideoHeight);
 
   uint32_t maxWidth, maxHeight;
   char propValue[PROPERTY_VALUE_MAX];
   property_get("ro.moz.omx.hw.max_width", propValue, "-1");
   maxWidth = -1 == atoi(propValue) ? MAX_VIDEO_WIDTH : atoi(propValue);
@@ -96,94 +89,41 @@ GonkVideoDecoderManager::Init(MediaDataD
   // Validate the container-reported frame and pictureRect sizes. This ensures
   // that our video frame creation code doesn't overflow.
   nsIntSize frameSize(mVideoWidth, mVideoHeight);
   if (!IsValidVideoRegion(frameSize, pictureRect, displaySize)) {
     GVDM_LOG("It is not a valid region");
     return InitPromise::CreateAndReject(DecoderFailureReason::INIT_ERROR, __func__);
   }
 
-  mReaderCallback = aCallback;
-
   mReaderTaskQueue = AbstractThread::GetCurrent()->AsTaskQueue();
   MOZ_ASSERT(mReaderTaskQueue);
 
-  if (mLooper.get() != nullptr) {
+  if (mDecodeLooper.get() != nullptr) {
     return InitPromise::CreateAndReject(DecoderFailureReason::INIT_ERROR, __func__);
   }
-  // Create ALooper
-  mLooper = new ALooper;
-  mManagerLooper = new ALooper;
-  mManagerLooper->setName("GonkVideoDecoderManager");
-  // Register AMessage handler to ALooper.
-  mManagerLooper->registerHandler(mHandler);
-  // Start ALooper thread.
-  if (mLooper->start() != OK || mManagerLooper->start() != OK ) {
+
+  if (!InitLoopers(MediaData::VIDEO_DATA)) {
     return InitPromise::CreateAndReject(DecoderFailureReason::INIT_ERROR, __func__);
   }
+
   nsRefPtr<InitPromise> p = mInitPromise.Ensure(__func__);
-  mDecoder = MediaCodecProxy::CreateByType(mLooper, mMimeType.get(), false, mVideoListener);
+  mDecoder = MediaCodecProxy::CreateByType(mDecodeLooper, mMimeType.get(), false, mVideoListener);
   mDecoder->AsyncAskMediaCodec();
 
   uint32_t capability = MediaCodecProxy::kEmptyCapability;
   if (mDecoder->getCapability(&capability) == OK && (capability &
       MediaCodecProxy::kCanExposeGraphicBuffer)) {
     mNativeWindow = new GonkNativeWindow();
   }
 
   return p;
 }
 
 nsresult
-GonkVideoDecoderManager::Input(MediaRawData* aSample)
-{
-  MonitorAutoLock mon(mMonitor);
-  nsRefPtr<MediaRawData> sample;
-
-  if (!aSample) {
-    // It means EOS with empty sample.
-    sample = new MediaRawData();
-  } else {
-    sample = aSample;
-  }
-
-  mQueueSample.AppendElement(sample);
-
-  status_t rv;
-  while (mQueueSample.Length()) {
-    nsRefPtr<MediaRawData> data = mQueueSample.ElementAt(0);
-    {
-      MonitorAutoUnlock mon_unlock(mMonitor);
-      rv = mDecoder->Input(reinterpret_cast<const uint8_t*>(data->Data()),
-                           data->Size(),
-                           data->mTime,
-                           0);
-    }
-    if (rv == OK) {
-      mQueueSample.RemoveElementAt(0);
-    } else if (rv == -EAGAIN || rv == -ETIMEDOUT) {
-      // In most cases, EAGAIN or ETIMEOUT are safe because OMX can't fill
-      // buffer on time.
-      return NS_OK;
-    } else {
-      return NS_ERROR_UNEXPECTED;
-    }
-  }
-
-  return NS_OK;
-}
-
-bool
-GonkVideoDecoderManager::HasQueuedSample()
-{
-    MonitorAutoLock mon(mMonitor);
-    return mQueueSample.Length();
-}
-
-nsresult
 GonkVideoDecoderManager::CreateVideoData(int64_t aStreamOffset, VideoData **v)
 {
   *v = nullptr;
   nsRefPtr<VideoData> data;
   int64_t timeUs;
   int32_t keyFrame;
 
   if (mVideoBuffer == nullptr) {
@@ -192,22 +132,22 @@ GonkVideoDecoderManager::CreateVideoData
   }
 
   if (!mVideoBuffer->meta_data()->findInt64(kKeyTime, &timeUs)) {
     ReleaseVideoBuffer();
     GVDM_LOG("Decoder did not return frame time");
     return NS_ERROR_UNEXPECTED;
   }
 
-  if (mLastDecodedTime > timeUs) {
+  if (mLastTime > timeUs) {
     ReleaseVideoBuffer();
     GVDM_LOG("Output decoded sample time is revert. time=%lld", timeUs);
     return NS_ERROR_NOT_AVAILABLE;
   }
-  mLastDecodedTime = timeUs;
+  mLastTime = timeUs;
 
   if (mVideoBuffer->range_length() == 0) {
     // Some decoders may return spurious empty buffers that we just want to ignore
     // quoted from Android's AwesomePlayer.cpp
     ReleaseVideoBuffer();
     return NS_ERROR_NOT_AVAILABLE;
   }
 
@@ -362,37 +302,16 @@ GonkVideoDecoderManager::SetVideoFormat(
       return false;
     }
     return true;
   }
   GVDM_LOG("Fail to get output format");
   return false;
 }
 
-nsresult
-GonkVideoDecoderManager::Flush()
-{
-  if (mDecoder == nullptr) {
-    GVDM_LOG("Decoder is not inited");
-    return NS_ERROR_UNEXPECTED;
-  }
-  {
-    MonitorAutoLock mon(mMonitor);
-    mQueueSample.Clear();
-  }
-
- mLastDecodedTime = 0;
-
-  if (mDecoder->flush() != OK) {
-    return NS_ERROR_FAILURE;
-  }
-
-  return NS_OK;
-}
-
 // Blocks until decoded sample is produced by the deoder.
 nsresult
 GonkVideoDecoderManager::Output(int64_t aStreamOffset,
                                 nsRefPtr<MediaData>& aOutData)
 {
   aOutData = nullptr;
   status_t err;
   if (mDecoder == nullptr) {
@@ -511,48 +430,32 @@ GonkVideoDecoderManager::codecReserved()
 
 void
 GonkVideoDecoderManager::codecCanceled()
 {
   GVDM_LOG("codecCanceled");
   mInitPromise.RejectIfExists(DecoderFailureReason::CANCELED, __func__);
 }
 
-// Called on GonkVideoDecoderManager::mManagerLooper thread.
+// Called on GonkDecoderManager::mTaskLooper thread.
 void
 GonkVideoDecoderManager::onMessageReceived(const sp<AMessage> &aMessage)
 {
   switch (aMessage->what()) {
     case kNotifyPostReleaseBuffer:
     {
       ReleaseAllPendingVideoBuffers();
       break;
     }
 
     default:
-      TRESPASS();
+    {
+      GonkDecoderManager::onMessageReceived(aMessage);
       break;
-  }
-}
-
-GonkVideoDecoderManager::MessageHandler::MessageHandler(GonkVideoDecoderManager *aManager)
-  : mManager(aManager)
-{
-}
-
-GonkVideoDecoderManager::MessageHandler::~MessageHandler()
-{
-  mManager = nullptr;
-}
-
-void
-GonkVideoDecoderManager::MessageHandler::onMessageReceived(const android::sp<android::AMessage> &aMessage)
-{
-  if (mManager != nullptr) {
-    mManager->onMessageReceived(aMessage);
+    }
   }
 }
 
 GonkVideoDecoderManager::VideoResourceListener::VideoResourceListener(GonkVideoDecoderManager *aManager)
   : mManager(aManager)
 {
 }
 
@@ -647,17 +550,17 @@ void GonkVideoDecoderManager::PostReleas
 {
   {
     MutexAutoLock autoLock(mPendingReleaseItemsLock);
     if (aBuffer) {
       mPendingReleaseItems.AppendElement(ReleaseItem(aBuffer, aReleaseFence));
     }
   }
   sp<AMessage> notify =
-            new AMessage(kNotifyPostReleaseBuffer, mHandler->id());
+            new AMessage(kNotifyPostReleaseBuffer, id());
   notify->post();
 
 }
 
 void GonkVideoDecoderManager::ReleaseAllPendingVideoBuffers()
 {
   nsTArray<ReleaseItem> releasingItems;
   {
--- a/dom/media/platforms/gonk/GonkVideoDecoderManager.h
+++ b/dom/media/platforms/gonk/GonkVideoDecoderManager.h
@@ -2,32 +2,29 @@
 /* vim:set ts=2 sw=2 sts=2 et cindent: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #if !defined(GonkVideoDecoderManager_h_)
 #define GonkVideoDecoderManager_h_
 
-#include <set>
 #include "nsRect.h"
 #include "GonkMediaDataDecoder.h"
 #include "mozilla/RefPtr.h"
 #include "I420ColorConverterHelper.h"
 #include "MediaCodecProxy.h"
-#include <stagefright/foundation/AHandler.h>
 #include "GonkNativeWindow.h"
 #include "GonkNativeWindowClient.h"
 #include "mozilla/layers/FenceUtils.h"
 #include <ui/Fence.h>
 
 using namespace android;
 
 namespace android {
-struct ALooper;
 class MediaBuffer;
 struct MOZ_EXPORT AString;
 class GonkNativeWindow;
 } // namespace android
 
 namespace mozilla {
 
 namespace layers {
@@ -37,61 +34,40 @@ class TextureClient;
 class GonkVideoDecoderManager : public GonkDecoderManager {
 typedef android::MediaCodecProxy MediaCodecProxy;
 typedef mozilla::layers::TextureClient TextureClient;
 
 public:
   GonkVideoDecoderManager(mozilla::layers::ImageContainer* aImageContainer,
                           const VideoInfo& aConfig);
 
-  virtual ~GonkVideoDecoderManager() override;
+  virtual ~GonkVideoDecoderManager();
 
-  nsRefPtr<InitPromise> Init(MediaDataDecoderCallback* aCallback) override;
-
-  nsresult Input(MediaRawData* aSample) override;
+  nsRefPtr<InitPromise> Init() override;
 
   nsresult Output(int64_t aStreamOffset,
                           nsRefPtr<MediaData>& aOutput) override;
 
-  nsresult Flush() override;
-
-  bool HasQueuedSample() override;
-
   static void RecycleCallback(TextureClient* aClient, void* aClosure);
 
 private:
   struct FrameInfo
   {
     int32_t mWidth = 0;
     int32_t mHeight = 0;
     int32_t mStride = 0;
     int32_t mSliceHeight = 0;
     int32_t mColorFormat = 0;
     int32_t mCropLeft = 0;
     int32_t mCropTop = 0;
     int32_t mCropRight = 0;
     int32_t mCropBottom = 0;
   };
-  class MessageHandler : public android::AHandler
-  {
-  public:
-    MessageHandler(GonkVideoDecoderManager *aManager);
-    ~MessageHandler();
 
-    void onMessageReceived(const android::sp<android::AMessage> &aMessage) override;
-
-  private:
-    // Forbidden
-    MessageHandler() = delete;
-    MessageHandler(const MessageHandler &rhs) = delete;
-    const MessageHandler &operator=(const MessageHandler &rhs) = delete;
-
-    GonkVideoDecoderManager *mManager;
-  };
-  friend class MessageHandler;
+  void onMessageReceived(const android::sp<android::AMessage> &aMessage) override;
 
   class VideoResourceListener : public android::MediaCodecProxy::CodecResourceListener
   {
   public:
     VideoResourceListener(GonkVideoDecoderManager *aManager);
     ~VideoResourceListener();
 
     void codecReserved() override;
@@ -114,43 +90,36 @@ private:
 
   nsresult CreateVideoData(int64_t aStreamOffset, VideoData** aOutData);
   void ReleaseVideoBuffer();
   uint8_t* GetColorConverterBuffer(int32_t aWidth, int32_t aHeight);
 
   // For codec resource management
   void codecReserved();
   void codecCanceled();
-  void onMessageReceived(const sp<AMessage> &aMessage);
 
   void ReleaseAllPendingVideoBuffers();
   void PostReleaseVideoBuffer(android::MediaBuffer *aBuffer,
                               layers::FenceHandle mReleaseFence);
 
   uint32_t mVideoWidth;
   uint32_t mVideoHeight;
   uint32_t mDisplayWidth;
   uint32_t mDisplayHeight;
   nsIntRect mPicture;
   nsIntSize mInitialFrame;
 
   nsRefPtr<layers::ImageContainer> mImageContainer;
 
   android::MediaBuffer* mVideoBuffer;
 
-  MediaDataDecoderCallback*  mReaderCallback;
   MediaInfo mInfo;
   android::sp<VideoResourceListener> mVideoListener;
-  android::sp<MessageHandler> mHandler;
-  android::sp<ALooper> mLooper;
-  android::sp<ALooper> mManagerLooper;
   FrameInfo mFrameInfo;
 
-  int64_t mLastDecodedTime;  // The last decoded frame presentation time.
-
   // color converter
   android::I420ColorConverterHelper mColorConverter;
   nsAutoArrayPtr<uint8_t> mColorConverterBuffer;
   size_t mColorConverterBufferSize;
 
   android::sp<android::GonkNativeWindow> mNativeWindow;
   enum {
     kNotifyPostReleaseBuffer = 'nprb',
@@ -163,24 +132,16 @@ private:
     android::MediaBuffer* mBuffer;
     layers::FenceHandle mReleaseFence;
   };
   nsTArray<ReleaseItem> mPendingReleaseItems;
 
   // The lock protects mPendingReleaseItems.
   Mutex mPendingReleaseItemsLock;
 
-  // This monitor protects mQueueSample.
-  Monitor mMonitor;
-
-  // This TaskQueue should be the same one in mReaderCallback->OnReaderTaskQueue().
+  // This TaskQueue should be the same one in mDecodeCallback->OnReaderTaskQueue().
   // It is for codec resource mangement, decoding task should not dispatch to it.
   nsRefPtr<TaskQueue> mReaderTaskQueue;
-
-  // An queue with the MP4 samples which are waiting to be sent into OMX.
-  // If an element is an empty MP4Sample, that menas EOS. There should not
-  // any sample be queued after EOS.
-  nsTArray<nsRefPtr<MediaRawData>> mQueueSample;
 };
 
 } // namespace mozilla
 
 #endif // GonkVideoDecoderManager_h_