Bug 1174721 - Use AudioCompactor for GonkAudioDecoderManager. r=sotaro
authorBenjamin Chen <bechen@mozilla.com>
Wed, 21 Oct 2015 10:09:39 +0800
changeset 303910 bd7a7ac80d3decb3e53c8ec98d42e0eace6a87be
parent 303909 ca1313dd74111b6130163c348f06a0469c4d02eb
child 303911 f20fa392e98b618b934efa12c5d91a8964cca67d
push id1001
push userraliiev@mozilla.com
push dateMon, 18 Jan 2016 19:06:03 +0000
treeherdermozilla-release@8b89261f3ac4 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssotaro
bugs1174721
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 1174721 - Use AudioCompactor for GonkAudioDecoderManager. r=sotaro
dom/media/platforms/gonk/GonkAudioDecoderManager.cpp
dom/media/platforms/gonk/GonkAudioDecoderManager.h
dom/media/platforms/gonk/GonkMediaDataDecoder.h
--- a/dom/media/platforms/gonk/GonkAudioDecoderManager.cpp
+++ b/dom/media/platforms/gonk/GonkAudioDecoderManager.cpp
@@ -34,17 +34,17 @@ using namespace android;
 typedef android::MediaCodecProxy MediaCodecProxy;
 
 namespace mozilla {
 
 GonkAudioDecoderManager::GonkAudioDecoderManager(const AudioInfo& aConfig)
   : mAudioChannels(aConfig.mChannels)
   , mAudioRate(aConfig.mRate)
   , mAudioProfile(aConfig.mProfile)
-  , mAudioBuffer(nullptr)
+  , mAudioCompactor(mAudioQueue)
 {
   MOZ_COUNT_CTOR(GonkAudioDecoderManager);
   MOZ_ASSERT(mAudioChannels);
   mCodecSpecificData = aConfig.mCodecSpecificConfig;
   mMimeType = aConfig.mMimeType;
 }
 
 GonkAudioDecoderManager::~GonkAudioDecoderManager()
@@ -102,87 +102,104 @@ GonkAudioDecoderManager::InitMediaCodecP
     return true;
   } else {
     GADM_LOG("Failed to input codec specific data!");
     return false;
   }
 }
 
 nsresult
-GonkAudioDecoderManager::CreateAudioData(int64_t aStreamOffset, AudioData **v) {
-  if (!(mAudioBuffer != nullptr && mAudioBuffer->data() != nullptr)) {
+GonkAudioDecoderManager::CreateAudioData(MediaBuffer* aBuffer, int64_t aStreamOffset)
+{
+  if (!(aBuffer != nullptr && aBuffer->data() != nullptr)) {
     GADM_LOG("Audio Buffer is not valid!");
     return NS_ERROR_UNEXPECTED;
   }
 
   int64_t timeUs;
-  if (!mAudioBuffer->meta_data()->findInt64(kKeyTime, &timeUs)) {
+  if (!aBuffer->meta_data()->findInt64(kKeyTime, &timeUs)) {
     return NS_ERROR_UNEXPECTED;
   }
 
-  if (mAudioBuffer->range_length() == 0) {
+  if (aBuffer->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 (mLastTime > timeUs) {
-    ReleaseAudioBuffer();
     GADM_LOG("Output decoded sample time is revert. time=%lld", timeUs);
     MOZ_ASSERT(false);
     return NS_ERROR_NOT_AVAILABLE;
   }
   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();
+  const uint8_t *data = static_cast<const uint8_t*>(aBuffer->data());
+  size_t dataOffset = aBuffer->range_offset();
+  size_t size = aBuffer->range_length();
 
-  nsAutoArrayPtr<AudioDataValue> buffer(new AudioDataValue[size/2]);
-  memcpy(buffer.get(), data+dataOffset, size);
   uint32_t frames = size / (2 * mAudioChannels);
 
   CheckedInt64 duration = FramesToUsecs(frames, mAudioRate);
   if (!duration.isValid()) {
     return NS_ERROR_UNEXPECTED;
   }
-  RefPtr<AudioData> audioData = new AudioData(aStreamOffset,
-                                                timeUs,
-                                                duration.value(),
-                                                frames,
-                                                buffer.forget(),
-                                                mAudioChannels,
-                                                mAudioRate);
-  ReleaseAudioBuffer();
-  audioData.forget(v);
+
+  typedef AudioCompactor::NativeCopy OmxCopy;
+  mAudioCompactor.Push(aStreamOffset,
+                       timeUs,
+                       mAudioRate,
+                       frames,
+                       mAudioChannels,
+                       OmxCopy(data+dataOffset,
+                               size,
+                               mAudioChannels));
   return NS_OK;
 }
 
+class AutoReleaseAudioBuffer
+{
+public:
+  AutoReleaseAudioBuffer(MediaBuffer* aBuffer, MediaCodecProxy* aCodecProxy)
+    : mAudioBuffer(aBuffer)
+    , mCodecProxy(aCodecProxy)
+  {}
+
+  ~AutoReleaseAudioBuffer()
+  {
+    if (mAudioBuffer) {
+      mCodecProxy->ReleaseMediaBuffer(mAudioBuffer);
+    }
+  }
+private:
+  MediaBuffer* mAudioBuffer;
+  sp<MediaCodecProxy> mCodecProxy;
+};
+
 nsresult
 GonkAudioDecoderManager::Output(int64_t aStreamOffset,
                                 RefPtr<MediaData>& aOutData)
 {
   aOutData = nullptr;
+  if (mAudioQueue.GetSize() > 0) {
+    aOutData = mAudioQueue.PopFront();
+    return mAudioQueue.AtEndOfStream() ? NS_ERROR_ABORT : NS_OK;
+  }
+
   status_t err;
-  err = mDecoder->Output(&mAudioBuffer, READ_OUTPUT_BUFFER_TIMEOUT_US);
+  MediaBuffer* audioBuffer = nullptr;
+  err = mDecoder->Output(&audioBuffer, READ_OUTPUT_BUFFER_TIMEOUT_US);
+  AutoReleaseAudioBuffer a(audioBuffer, mDecoder.get());
 
   switch (err) {
     case OK:
     {
-      RefPtr<AudioData> data;
-      nsresult rv = CreateAudioData(aStreamOffset, getter_AddRefs(data));
-      if (rv == NS_ERROR_NOT_AVAILABLE) {
-        // Decoder outputs an empty video buffer, try again
-        return NS_ERROR_NOT_AVAILABLE;
-      } else if (rv != NS_OK || data == nullptr) {
-        return NS_ERROR_UNEXPECTED;
-      }
-      aOutData = data;
-      return NS_OK;
+      nsresult rv = CreateAudioData(audioBuffer, aStreamOffset);
+      NS_ENSURE_SUCCESS(rv, rv);
+      break;
     }
     case android::INFO_FORMAT_CHANGED:
     {
       // If the format changed, update our cached info.
       GADM_LOG("Decoder format changed");
       sp<AMessage> audioCodecFormat;
 
       if (mDecoder->getOutputFormat(&audioCodecFormat) != OK ||
@@ -214,43 +231,45 @@ GonkAudioDecoderManager::Output(int64_t 
     }
     case -EAGAIN:
     {
       return NS_ERROR_NOT_AVAILABLE;
     }
     case android::ERROR_END_OF_STREAM:
     {
       GADM_LOG("Got EOS frame!");
-      RefPtr<AudioData> data;
-      nsresult rv = CreateAudioData(aStreamOffset, getter_AddRefs(data));
-      if (rv == NS_ERROR_NOT_AVAILABLE) {
-        // For EOS, no need to do any thing.
-        return NS_ERROR_ABORT;
-      } else if (rv != NS_OK || data == nullptr) {
-        GADM_LOG("Failed to create audio data!");
-        return NS_ERROR_UNEXPECTED;
-      }
-      aOutData = data;
-      return NS_ERROR_ABORT;
+      nsresult rv = CreateAudioData(audioBuffer, aStreamOffset);
+      NS_ENSURE_SUCCESS(rv, NS_ERROR_ABORT);
+      MOZ_ASSERT(mAudioQueue.GetSize() > 0);
+      mAudioQueue.Finish();
+      break;
     }
     case -ETIMEDOUT:
     {
       GADM_LOG("Timeout. can try again next time");
       return NS_ERROR_UNEXPECTED;
     }
     default:
     {
       GADM_LOG("Decoder failed, err=%d", err);
       return NS_ERROR_UNEXPECTED;
     }
   }
 
-  return NS_OK;
+  if (mAudioQueue.GetSize() > 0) {
+    aOutData = mAudioQueue.PopFront();
+    // Return NS_ERROR_ABORT at the last sample.
+    return mAudioQueue.AtEndOfStream() ? NS_ERROR_ABORT : NS_OK;
+  }
+
+  return NS_ERROR_NOT_AVAILABLE;
 }
 
-void GonkAudioDecoderManager::ReleaseAudioBuffer() {
-  if (mAudioBuffer) {
-    mDecoder->ReleaseMediaBuffer(mAudioBuffer);
-    mAudioBuffer = nullptr;
-  }
+nsresult
+GonkAudioDecoderManager::Flush()
+{
+  GADM_LOG("FLUSH<<<");
+  mAudioQueue.Reset();
+  GADM_LOG(">>>FLUSH");
+  return GonkDecoderManager::Flush();
 }
 
 } // namespace mozilla
--- a/dom/media/platforms/gonk/GonkAudioDecoderManager.h
+++ b/dom/media/platforms/gonk/GonkAudioDecoderManager.h
@@ -2,16 +2,17 @@
 /* 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(GonkAudioDecoderManager_h_)
 #define GonkAudioDecoderManager_h_
 
+#include "AudioCompactor.h"
 #include "mozilla/RefPtr.h"
 #include "GonkMediaDataDecoder.h"
 
 using namespace android;
 
 namespace android {
 class MOZ_EXPORT MediaBuffer;
 } // namespace android
@@ -25,26 +26,28 @@ public:
 
   virtual ~GonkAudioDecoderManager();
 
   RefPtr<InitPromise> Init() override;
 
   nsresult Output(int64_t aStreamOffset,
                           RefPtr<MediaData>& aOutput) override;
 
+  virtual nsresult Flush() override;
+
 private:
   bool InitMediaCodecProxy();
 
-  nsresult CreateAudioData(int64_t aStreamOffset,
-                              AudioData** aOutData);
-
-  void ReleaseAudioBuffer();
+  nsresult CreateAudioData(MediaBuffer* aBuffer, int64_t aStreamOffset);
 
   uint32_t mAudioChannels;
   uint32_t mAudioRate;
   const uint32_t mAudioProfile;
 
-  android::MediaBuffer* mAudioBuffer;
+  MediaQueue<AudioData> mAudioQueue;
+
+  AudioCompactor mAudioCompactor;
+
 };
 
 } // namespace mozilla
 
 #endif // GonkAudioDecoderManager_h_
--- a/dom/media/platforms/gonk/GonkMediaDataDecoder.h
+++ b/dom/media/platforms/gonk/GonkMediaDataDecoder.h
@@ -28,17 +28,17 @@ public:
 
   virtual RefPtr<InitPromise> Init() = 0;
 
   // Asynchronously send sample into mDecoder. If out of input buffer, aSample
   // will be queued for later re-send.
   nsresult Input(MediaRawData* aSample);
 
   // Flush the queued sample.
-  nsresult Flush();
+  virtual nsresult Flush();
 
   // Shutdown decoder and rejects the init promise.
   virtual nsresult Shutdown();
 
   // True if sample is queued.
   bool HasQueuedSample();
 
   // Set callback for decoder events, such as requesting more input,