Bug 1154512 - Remove MediaTaskQueue::SyncDispatch() from PDM. r=cpearce
authorAlfredo Yang <ayang>
Mon, 04 May 2015 03:04:00 -0400
changeset 273622 8bc8f9c19385d97167982b31f08cd7fa73d3df3d
parent 273621 1bc82fa210381fd026ddd9dbe40d214929fd01d8
child 273623 87329d2ed8ce7a805872efb9ea9c4c9f7efd0525
push id863
push userraliiev@mozilla.com
push dateMon, 03 Aug 2015 13:22:43 +0000
treeherdermozilla-release@f6321b14228d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerscpearce
bugs1154512
milestone40.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 1154512 - Remove MediaTaskQueue::SyncDispatch() from PDM. r=cpearce
dom/media/fmp4/gonk/GonkMediaDataDecoder.cpp
dom/media/fmp4/gonk/GonkMediaDataDecoder.h
dom/media/fmp4/gonk/GonkVideoDecoderManager.cpp
dom/media/fmp4/gonk/GonkVideoDecoderManager.h
--- a/dom/media/fmp4/gonk/GonkMediaDataDecoder.cpp
+++ b/dom/media/fmp4/gonk/GonkMediaDataDecoder.cpp
@@ -21,104 +21,65 @@ PRLogModuleInfo* GetDemuxerLog();
 #define LOG(...)
 #endif
 
 using namespace android;
 
 namespace mozilla {
 
 GonkDecoderManager::GonkDecoderManager(MediaTaskQueue* aTaskQueue)
-  : mTaskQueue(aTaskQueue)
+  : mMonitor("GonkDecoderManager")
+  , mTaskQueue(aTaskQueue)
 {
 }
 
 nsresult
 GonkDecoderManager::Input(MediaRawData* aSample)
 {
-  MOZ_ASSERT(mTaskQueue->IsCurrentThreadIn());
-
-  // To maintain the order of the MP4Sample, it needs to send the queued samples
-  // to OMX first. And then the current input aSample.
-  // If it fails to input sample to OMX, it needs to add current into queue
-  // for next round.
-  uint32_t len = mQueueSample.Length();
-  status_t rv = OK;
-
-  for (uint32_t i = 0; i < len; i++) {
-    rv = SendSampleToOMX(mQueueSample.ElementAt(0));
-    if (rv != OK) {
-      break;
-    }
-    mQueueSample.RemoveElementAt(0);
-  }
-
-  // When EOS, aSample will be null and sends this empty MediaRawData to nofity
-  // OMX it reachs EOS.
+  ReentrantMonitorAutoEnter mon(mMonitor);
   nsRefPtr<MediaRawData> sample;
+
   if (!aSample) {
+    // It means EOS with empty sample.
     sample = new MediaRawData();
-  }
-
-  // If rv is OK, that means mQueueSample is empty, now try to queue current input
-  // aSample.
-  if (rv == OK) {
-    MOZ_ASSERT(!mQueueSample.Length());
-    MediaRawData* tmp;
-    if (aSample) {
-      tmp = aSample;
-      if (!PerformFormatSpecificProcess(aSample)) {
-        return NS_ERROR_FAILURE;
-      }
-    } else {
-      tmp = sample;
-    }
-    rv = SendSampleToOMX(tmp);
-    if (rv == OK) {
-      return NS_OK;
+  } else {
+    sample = aSample;
+    if (!PerformFormatSpecificProcess(sample)) {
+      return NS_ERROR_FAILURE;
     }
   }
 
-  // Current valid sample can't be sent into OMX, adding the clone one into queue
-  // for next round.
-  if (!sample) {
-      sample = aSample->Clone();
-      if (!sample) {
-        return NS_ERROR_OUT_OF_MEMORY;
-      }
-  }
   mQueueSample.AppendElement(sample);
 
-  // In most cases, EAGAIN or ETIMEOUT safe due to OMX can't process the
-  // filled buffer on time. It should be gone When requeuing sample next time.
-  if (rv == -EAGAIN || rv == -ETIMEDOUT) {
-    return NS_OK;
+  status_t rv;
+  while (mQueueSample.Length()) {
+    nsRefPtr<MediaRawData> data = mQueueSample.ElementAt(0);
+    {
+      ReentrantMonitorAutoExit mon_exit(mMonitor);
+      rv = SendSampleToOMX(data);
+    }
+    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_ERROR_UNEXPECTED;
+  return NS_OK;
 }
 
 nsresult
 GonkDecoderManager::Flush()
 {
-  class ClearQueueRunnable : public nsRunnable
-  {
-  public:
-    explicit ClearQueueRunnable(GonkDecoderManager* aManager)
-      : mManager(aManager) {}
-
-    NS_IMETHOD Run()
-    {
-      mManager->ClearQueuedSample();
-      return NS_OK;
-    }
-
-    GonkDecoderManager* mManager;
-  };
-
-  mTaskQueue->SyncDispatch(new ClearQueueRunnable(this));
+  ReentrantMonitorAutoEnter mon(mMonitor);
+  mQueueSample.Clear();
   return NS_OK;
 }
 
 GonkMediaDataDecoder::GonkMediaDataDecoder(GonkDecoderManager* aManager,
                                            FlushableMediaTaskQueue* aTaskQueue,
                                            MediaDataDecoderCallback* aCallback)
   : mTaskQueue(aTaskQueue)
   , mCallback(aCallback)
--- a/dom/media/fmp4/gonk/GonkMediaDataDecoder.h
+++ b/dom/media/fmp4/gonk/GonkMediaDataDecoder.h
@@ -39,35 +39,33 @@ public:
   virtual nsresult Output(int64_t aStreamOffset,
                           nsRefPtr<MediaData>& aOutput) = 0;
 
   // Flush the queued sample.
   // It this function is overrided by subclass, this functino should be called
   // in the overrided function.
   virtual nsresult Flush();
 
-  // It should be called in MediaTash thread.
+  // It should be called in MediaTask thread.
   bool HasQueuedSample() {
-    MOZ_ASSERT(mTaskQueue->IsCurrentThreadIn());
+    ReentrantMonitorAutoEnter mon(mMonitor);
     return mQueueSample.Length();
   }
 
-  void ClearQueuedSample() {
-    MOZ_ASSERT(mTaskQueue->IsCurrentThreadIn());
-    mQueueSample.Clear();
-  }
-
 protected:
   // It performs special operation to MP4 sample, the real action is depended on
   // the codec type.
   virtual bool PerformFormatSpecificProcess(MediaRawData* aSample) { return true; }
 
   // It sends MP4Sample to OMX layer. It must be overrided by subclass.
   virtual android::status_t SendSampleToOMX(MediaRawData* aSample) = 0;
 
+  // This monitor protects mQueueSample.
+  ReentrantMonitor 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;
 
   RefPtr<MediaTaskQueue> mTaskQueue;
 
   nsRefPtr<MediaByteBuffer> mCodecSpecificData;
--- a/dom/media/fmp4/gonk/GonkVideoDecoderManager.cpp
+++ b/dom/media/fmp4/gonk/GonkVideoDecoderManager.cpp
@@ -45,16 +45,17 @@ namespace mozilla {
 
 GonkVideoDecoderManager::GonkVideoDecoderManager(
   MediaTaskQueue* aTaskQueue,
   mozilla::layers::ImageContainer* aImageContainer,
   const VideoInfo& aConfig)
   : GonkDecoderManager(aTaskQueue)
   , mImageContainer(aImageContainer)
   , mReaderCallback(nullptr)
+  , mLastDecodedTime(0)
   , mColorConverterBufferSize(0)
   , mNativeWindow(nullptr)
   , mPendingVideoBuffersLock("GonkVideoDecoderManager::mPendingVideoBuffersLock")
 {
   MOZ_COUNT_CTOR(GonkVideoDecoderManager);
   mMimeType = aConfig.mMimeType;
   mVideoWidth  = aConfig.mDisplay.width;
   mVideoHeight = aConfig.mDisplay.height;
@@ -113,61 +114,16 @@ GonkVideoDecoderManager::Init(MediaDataD
     mNativeWindow = new GonkNativeWindow();
   }
 
   mReaderCallback->NotifyResourcesStatusChanged();
 
   return mDecoder;
 }
 
-void
-GonkVideoDecoderManager::QueueFrameTimeIn(int64_t aPTS, int64_t aDuration)
-{
-  MOZ_ASSERT(mTaskQueue->IsCurrentThreadIn());
-
-  FrameTimeInfo timeInfo = {aPTS, aDuration};
-  mFrameTimeInfo.AppendElement(timeInfo);
-}
-
-nsresult
-GonkVideoDecoderManager::QueueFrameTimeOut(int64_t aPTS, int64_t& aDuration)
-{
-  MOZ_ASSERT(mTaskQueue->IsCurrentThreadIn());
-
-  // Set default to 1 here.
-  // During seeking, frames could still in MediaCodec and the mFrameTimeInfo could
-  // be cleared before these frames are out from MediaCodec. This is ok because
-  // these frames are old frame before seeking.
-  aDuration = 1;
-  for (uint32_t i = 0; i < mFrameTimeInfo.Length(); i++) {
-    const FrameTimeInfo& entry = mFrameTimeInfo.ElementAt(i);
-    if (i == 0) {
-      if (entry.pts > aPTS) {
-        // Codec sent a frame with rollbacked PTS time. It could
-        // be codec's problem.
-        ReleaseVideoBuffer();
-        return NS_ERROR_NOT_AVAILABLE;
-      }
-    }
-
-    // Ideally, the first entry in mFrameTimeInfo should be the one we are looking
-    // for. However, MediaCodec could dropped frame and the first entry doesn't
-    // match current decoded frame's PTS.
-    if (entry.pts == aPTS) {
-      aDuration = entry.duration;
-      if (i > 0) {
-        LOG("Frame could be dropped by MediaCodec, %d dropped frames.", i);
-      }
-      mFrameTimeInfo.RemoveElementsAt(0, i+1);
-      break;
-    }
-  }
-  return NS_OK;
-}
-
 nsresult
 GonkVideoDecoderManager::CreateVideoData(int64_t aStreamOffset, VideoData **v)
 {
   *v = nullptr;
   nsRefPtr<VideoData> data;
   int64_t timeUs;
   int32_t keyFrame;
 
@@ -176,19 +132,22 @@ GonkVideoDecoderManager::CreateVideoData
     return NS_ERROR_UNEXPECTED;
   }
 
   if (!mVideoBuffer->meta_data()->findInt64(kKeyTime, &timeUs)) {
     GVDM_LOG("Decoder did not return frame time");
     return NS_ERROR_UNEXPECTED;
   }
 
-  int64_t duration;
-  nsresult rv = QueueFrameTimeOut(timeUs, duration);
-  NS_ENSURE_SUCCESS(rv, rv);
+  if (mLastDecodedTime > timeUs) {
+    ReleaseVideoBuffer();
+    GVDM_LOG("Output decoded sample time is revert. time=%lld", timeUs);
+    return NS_ERROR_NOT_AVAILABLE;
+  }
+  mLastDecodedTime = 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;
   }
 
@@ -219,17 +178,18 @@ GonkVideoDecoderManager::CreateVideoData
     GrallocTextureClientOGL* grallocClient = static_cast<GrallocTextureClientOGL*>(textureClient.get());
     grallocClient->SetMediaBuffer(mVideoBuffer);
     textureClient->SetRecycleCallback(GonkVideoDecoderManager::RecycleCallback, this);
 
     data = VideoData::Create(mInfo.mVideo,
                              mImageContainer,
                              aStreamOffset,
                              timeUs,
-                             duration,
+                             1, // No way to pass sample duration from muxer to
+                                // OMX codec, so we hardcode the duration here.
                              textureClient,
                              keyFrame,
                              -1,
                              picture);
   } else {
     if (!mVideoBuffer->data()) {
       GVDM_LOG("No data in Video Buffer!");
       return NS_ERROR_UNEXPECTED;
@@ -433,57 +393,27 @@ void GonkVideoDecoderManager::ReleaseVid
     mDecoder->ReleaseMediaBuffer(mVideoBuffer);
     mVideoBuffer = nullptr;
   }
 }
 
 status_t
 GonkVideoDecoderManager::SendSampleToOMX(MediaRawData* aSample)
 {
-  // An empty MediaRawData is going to notify EOS to decoder. It doesn't need
-  // to keep PTS and duration.
-  if (aSample->mData && aSample->mDuration && aSample->mTime) {
-    QueueFrameTimeIn(aSample->mTime, aSample->mDuration);
-  }
-
   return mDecoder->Input(reinterpret_cast<const uint8_t*>(aSample->mData),
                          aSample->mSize,
                          aSample->mTime,
                          0);
 }
 
-void
-GonkVideoDecoderManager::ClearQueueFrameTime()
-{
-  MOZ_ASSERT(mTaskQueue->IsCurrentThreadIn());
-  mFrameTimeInfo.Clear();
-}
-
 nsresult
 GonkVideoDecoderManager::Flush()
 {
   GonkDecoderManager::Flush();
-
-  class ClearFrameTimeRunnable : public nsRunnable
-  {
-  public:
-    explicit ClearFrameTimeRunnable(GonkVideoDecoderManager* aManager)
-      : mManager(aManager) {}
-
-    NS_IMETHOD Run()
-    {
-      mManager->ClearQueueFrameTime();
-      return NS_OK;
-    }
-
-    GonkVideoDecoderManager* mManager;
-  };
-
-  mTaskQueue->SyncDispatch(new ClearFrameTimeRunnable(this));
-
+  mLastDecodedTime = 0;
   status_t err = mDecoder->flush();
   if (err != OK) {
     return NS_ERROR_FAILURE;
   }
   return NS_OK;
 }
 
 void
--- a/dom/media/fmp4/gonk/GonkVideoDecoderManager.h
+++ b/dom/media/fmp4/gonk/GonkVideoDecoderManager.h
@@ -103,43 +103,30 @@ private:
     VideoResourceListener() = delete;
     VideoResourceListener(const VideoResourceListener &rhs) = delete;
     const VideoResourceListener &operator=(const VideoResourceListener &rhs) = delete;
 
     GonkVideoDecoderManager *mManager;
   };
   friend class VideoResourceListener;
 
-  // FrameTimeInfo keeps the presentation time stamp (pts) and its duration.
-  // On MediaDecoderStateMachine, it needs pts and duration to display decoded
-  // frame correctly. But OMX can carry one field of time info (kKeyTime) so
-  // we use FrameTimeInfo to keep pts and duration.
-  struct FrameTimeInfo {
-    int64_t pts;       // presentation time stamp of this frame.
-    int64_t duration;  // the playback duration.
-  };
-
   bool SetVideoFormat();
 
   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);
 
-  void QueueFrameTimeIn(int64_t aPTS, int64_t aDuration);
-  nsresult QueueFrameTimeOut(int64_t aPTS, int64_t& aDuration);
-  void ClearQueueFrameTime();
-
   uint32_t mVideoWidth;
   uint32_t mVideoHeight;
   uint32_t mDisplayWidth;
   uint32_t mDisplayHeight;
   nsIntRect mPicture;
   nsIntSize mInitialFrame;
 
   android::sp<MediaCodecProxy> mDecoder;
@@ -150,21 +137,17 @@ private:
   MediaDataDecoderCallback*  mReaderCallback;
   MediaInfo mInfo;
   android::sp<VideoResourceListener> mVideoListener;
   android::sp<MessageHandler> mHandler;
   android::sp<ALooper> mLooper;
   android::sp<ALooper> mManagerLooper;
   FrameInfo mFrameInfo;
 
-  // Array of FrameTimeInfo whose corresponding frames are sent to OMX.
-  // Ideally, it is a FIFO. Input() adds the entry to the end element and
-  // CreateVideoData() takes the first entry. However, there are exceptions
-  // due to MediaCodec error or seeking.
-  nsTArray<FrameTimeInfo> mFrameTimeInfo;
+  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 {