Bug 1105209 - Add media resource request API. r=kentuckyfriedtakahe
authorAlfredo Yang <ayang@mozilla.com>
Mon, 15 Dec 2014 22:25:00 -0500
changeset 219943 0435b9bb6482f49f17dcefccabafd34d4b10e88c
parent 219942 770e5a186d6fec230515abf1ef47288de33ea106
child 219944 11e571ee223400dea3dcb64a22b3aa9cecba3d7e
push id27973
push userryanvm@gmail.com
push dateTue, 16 Dec 2014 21:03:16 +0000
treeherdermozilla-central@8401afdb6e6c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerskentuckyfriedtakahe
bugs1105209
milestone37.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 1105209 - Add media resource request API. r=kentuckyfriedtakahe
dom/media/MediaDecoderStateMachine.cpp
dom/media/fmp4/MP4Reader.cpp
dom/media/fmp4/MP4Reader.h
dom/media/fmp4/PlatformDecoderModule.h
dom/media/fmp4/gonk/GonkMediaDataDecoder.cpp
dom/media/fmp4/gonk/GonkMediaDataDecoder.h
dom/media/fmp4/gonk/GonkVideoDecoderManager.cpp
dom/media/fmp4/gonk/GonkVideoDecoderManager.h
dom/media/omx/MediaCodecProxy.cpp
dom/media/omx/MediaCodecProxy.h
dom/media/omx/mediaresourcemanager/MediaResourceHandler.cpp
dom/media/omx/mediaresourcemanager/MediaResourceHandler.h
--- a/dom/media/MediaDecoderStateMachine.cpp
+++ b/dom/media/MediaDecoderStateMachine.cpp
@@ -2729,16 +2729,22 @@ MediaDecoderStateMachine::FlushDecoding(
     // reader Shutdown() task below, as the sample-delivery tasks will
     // keep video frames alive until after we've called Reader::Shutdown(),
     // and shutdown on B2G will fail as there are outstanding video frames
     // alive.
     ReentrantMonitorAutoExit exitMon(mDecoder->GetReentrantMonitor());
     DecodeTaskQueue()->FlushAndDispatch(task);
   }
 
+  // These flags will be reset when the decoded data returned in OnAudioDecoded()
+  // and OnVideoDecoded(). Because the decode tasks are flushed, these flags need
+  // to be reset here.
+  mAudioRequestPending = false;
+  mVideoRequestPending = false;
+
   // We must reset playback so that all references to frames queued
   // in the state machine are dropped, else subsequent calls to Shutdown()
   // or ReleaseMediaResources() can fail on B2G.
   ResetPlayback();
 }
 
 void MediaDecoderStateMachine::RenderVideoFrame(VideoData* aData,
                                                 TimeStamp aTarget)
--- a/dom/media/fmp4/MP4Reader.cpp
+++ b/dom/media/fmp4/MP4Reader.cpp
@@ -199,16 +199,24 @@ public:
   }
 private:
   nsRefPtr<AbstractMediaDecoder> mDecoder;
   nsTArray<uint8_t> mInitData;
   nsString mInitDataType;
 };
 #endif
 
+void MP4Reader::RequestCodecResource() {
+#ifdef MOZ_GONK_MEDIACODEC
+  if(mVideo.mDecoder) {
+    mVideo.mDecoder->AllocateMediaResources();
+  }
+#endif
+}
+
 bool MP4Reader::IsWaitingOnCodecResource() {
 #ifdef MOZ_GONK_MEDIACODEC
   return mVideo.mDecoder && mVideo.mDecoder->IsWaitingMediaResources();
 #endif
   return false;
 }
 
 bool MP4Reader::IsWaitingOnCDMResource() {
@@ -268,16 +276,24 @@ bool
 MP4Reader::IsSupportedVideoMimeType(const char* aMimeType)
 {
   return (!strcmp(aMimeType, "video/mp4") ||
           !strcmp(aMimeType, "video/avc") ||
           !strcmp(aMimeType, "video/x-vnd.on2.vp6")) &&
          mPlatform->SupportsVideoMimeType(aMimeType);
 }
 
+void
+MP4Reader::PreReadMetadata()
+{
+  if (mPlatform) {
+    RequestCodecResource();
+  }
+}
+
 nsresult
 MP4Reader::ReadMetadata(MediaInfo* aInfo,
                         MetadataTags** aTags)
 {
   if (!mDemuxerInitialized) {
     bool ok = mDemuxer->Init();
     NS_ENSURE_TRUE(ok, NS_ERROR_FAILURE);
 
@@ -724,16 +740,17 @@ MP4Reader::Flush(TrackType aTrack)
     data.mOutput.Clear();
     data.mNumSamplesInput = 0;
     data.mNumSamplesOutput = 0;
     data.mInputExhausted = false;
     if (data.HasPromise()) {
       data.RejectPromise(CANCELED, __func__);
     }
     data.mDiscontinuity = true;
+    data.mUpdateScheduled = false;
   }
   if (aTrack == kVideo) {
     mQueuedVideoSample = nullptr;
   }
   VLOG("Flush(%s) END", TrackTypeToStr(aTrack));
 }
 
 bool
--- a/dom/media/fmp4/MP4Reader.h
+++ b/dom/media/fmp4/MP4Reader.h
@@ -40,16 +40,21 @@ public:
   virtual nsRefPtr<VideoDataPromise>
   RequestVideoData(bool aSkipToNextKeyframe, int64_t aTimeThreshold) MOZ_OVERRIDE;
 
   virtual nsRefPtr<AudioDataPromise> RequestAudioData() MOZ_OVERRIDE;
 
   virtual bool HasAudio() MOZ_OVERRIDE;
   virtual bool HasVideo() MOZ_OVERRIDE;
 
+  // PreReadMetadata() is called by MediaDecoderStateMachine::DecodeMetadata()
+  // before checking hardware resource. In Gonk, it requests hardware codec so
+  // MediaDecoderStateMachine could go to DORMANT state if the hardware codec is
+  // not available.
+  virtual void PreReadMetadata() MOZ_OVERRIDE;
   virtual nsresult ReadMetadata(MediaInfo* aInfo,
                                 MetadataTags** aTags) MOZ_OVERRIDE;
 
   virtual void ReadUpdatedMetadata(MediaInfo* aInfo) MOZ_OVERRIDE;
 
   virtual void Seek(int64_t aTime,
                     int64_t aStartTime,
                     int64_t aEndTime,
@@ -102,16 +107,17 @@ private:
   void InputExhausted(mp4_demuxer::TrackType aTrack);
   void Error(mp4_demuxer::TrackType aTrack);
   void Flush(mp4_demuxer::TrackType aTrack);
   void DrainComplete(mp4_demuxer::TrackType aTrack);
   void UpdateIndex();
   bool IsSupportedAudioMimeType(const char* aMimeType);
   bool IsSupportedVideoMimeType(const char* aMimeType);
   void NotifyResourcesStatusChanged();
+  void RequestCodecResource();
   bool IsWaitingOnCodecResource();
   virtual bool IsWaitingOnCDMResource() MOZ_OVERRIDE;
 
   nsAutoPtr<mp4_demuxer::MP4Demuxer> mDemuxer;
   nsAutoPtr<PlatformDecoderModule> mPlatform;
 
   class DecoderCallback : public MediaDataDecoderCallback {
   public:
--- a/dom/media/fmp4/PlatformDecoderModule.h
+++ b/dom/media/fmp4/PlatformDecoderModule.h
@@ -226,15 +226,16 @@ public:
 
   // For Codec Resource Management
   virtual bool IsWaitingMediaResources() {
     return false;
   };
   virtual bool IsDormantNeeded() {
     return false;
   };
+  virtual void AllocateMediaResources() {}
   virtual void ReleaseMediaResources() {}
   virtual void ReleaseDecoder() {}
 };
 
 } // namespace mozilla
 
 #endif
--- a/dom/media/fmp4/gonk/GonkMediaDataDecoder.cpp
+++ b/dom/media/fmp4/gonk/GonkMediaDataDecoder.cpp
@@ -160,13 +160,19 @@ GonkMediaDataDecoder::IsWaitingMediaReso
 
 bool
 GonkMediaDataDecoder::IsDormantNeeded() {
 
   return mDecoder.get() ? true : false;
 }
 
 void
+GonkMediaDataDecoder::AllocateMediaResources()
+{
+  mManager->AllocateMediaResources();
+}
+
+void
 GonkMediaDataDecoder::ReleaseMediaResources() {
   mManager->ReleaseMediaResources();
 }
 
 } // namespace mozilla
--- a/dom/media/fmp4/gonk/GonkMediaDataDecoder.h
+++ b/dom/media/fmp4/gonk/GonkMediaDataDecoder.h
@@ -30,16 +30,18 @@ public:
   // 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.
   virtual nsresult Input(mp4_demuxer::MP4Sample* aSample) = 0;
   virtual nsresult Output(int64_t aStreamOffset,
                           nsRefPtr<MediaData>& aOutput) = 0;
   virtual nsresult Flush() = 0;
 
+  virtual void AllocateMediaResources() {};
+
   virtual void ReleaseMediaResources() {};
 };
 
 // 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.
@@ -60,16 +62,18 @@ public:
   virtual nsresult Drain() MOZ_OVERRIDE;
 
   virtual nsresult Shutdown() MOZ_OVERRIDE;
 
   virtual bool IsWaitingMediaResources() MOZ_OVERRIDE;
 
   virtual bool IsDormantNeeded() MOZ_OVERRIDE;
 
+  virtual void AllocateMediaResources() MOZ_OVERRIDE;
+
   virtual void ReleaseMediaResources() MOZ_OVERRIDE;
 
 private:
 
   // Called on the task queue. Inserts the sample into the decoder, and
   // extracts output if available, if aSample is null, it means there is
   // no data from source, it will notify the decoder EOS and flush all the
   // decoded frames.
--- a/dom/media/fmp4/gonk/GonkVideoDecoderManager.cpp
+++ b/dom/media/fmp4/gonk/GonkVideoDecoderManager.cpp
@@ -470,16 +470,22 @@ GonkVideoDecoderManager::Flush()
   }
 
   MonitorAutoLock mon(mMonitor);
   mFrameTimeInfo.Clear();
   return NS_OK;
 }
 
 void
+GonkVideoDecoderManager::AllocateMediaResources()
+{
+  mDecoder->RequestMediaResources();
+}
+
+void
 GonkVideoDecoderManager::codecReserved()
 {
   sp<AMessage> format = new AMessage;
   sp<Surface> surface;
 
   // Fixed values
   format->setString("mime", "video/avc");
   format->setInt32("width", mVideoWidth);
--- a/dom/media/fmp4/gonk/GonkVideoDecoderManager.h
+++ b/dom/media/fmp4/gonk/GonkVideoDecoderManager.h
@@ -47,16 +47,18 @@ public:
 
   virtual nsresult Input(mp4_demuxer::MP4Sample* aSample) MOZ_OVERRIDE;
 
   virtual nsresult Output(int64_t aStreamOffset,
                           nsRefPtr<MediaData>& aOutput) MOZ_OVERRIDE;
 
   virtual nsresult Flush() MOZ_OVERRIDE;
 
+  virtual void AllocateMediaResources();
+
   virtual void ReleaseMediaResources();
 
   static void RecycleCallback(TextureClient* aClient, void* aClosure);
 
 private:
   struct FrameInfo
   {
     int32_t mWidth = 0;
--- a/dom/media/omx/MediaCodecProxy.cpp
+++ b/dom/media/omx/MediaCodecProxy.cpp
@@ -131,16 +131,22 @@ MediaCodecProxy::requestResource()
   } else {
     return false;
   }
 
   return true;
 }
 
 void
+MediaCodecProxy::RequestMediaResources()
+{
+  requestResource();
+}
+
+void
 MediaCodecProxy::cancelResource()
 {
   if (mResourceHandler == nullptr) {
     return;
   }
 
   mResourceHandler->cancelResource();
 }
@@ -567,17 +573,16 @@ status_t MediaCodecProxy::Output(MediaBu
   int64_t timeUs = 0;
   uint32_t flags = 0;
 
   *aBuffer = nullptr;
 
   status_t err = dequeueOutputBuffer(&index, &offset, &size,
                                       &timeUs, &flags, aTimeoutUs);
   if (err != OK) {
-    ALOG("Output returned %d", err);
     return err;
   }
 
   MediaBuffer *buffer;
   sp<GraphicBuffer> graphicBuffer;
 
   if (getOutputGraphicBufferFromIndex(index, &graphicBuffer) == OK &&
       graphicBuffer != nullptr) {
@@ -593,19 +598,20 @@ status_t MediaCodecProxy::Output(MediaBu
   if (flags & MediaCodec::BUFFER_FLAG_EOS) {
     return ERROR_END_OF_STREAM;
   }
   return err;
 }
 
 bool MediaCodecProxy::IsWaitingResources()
 {
-  // Write Lock for mCodec
-  RWLock::AutoWLock awl(mCodecLock);
-  return mCodec == nullptr;
+  if (mResourceHandler.get()) {
+    return mResourceHandler->IsWaitingResource();
+  }
+  return false;
 }
 
 bool MediaCodecProxy::IsDormantNeeded()
 {
   return mCodecLooper.get() ? true : false;
 }
 
 void MediaCodecProxy::ReleaseMediaResources()
--- a/dom/media/omx/MediaCodecProxy.h
+++ b/dom/media/omx/MediaCodecProxy.h
@@ -126,16 +126,17 @@ public:
 
   // If aData is null, will notify decoder input EOS
   status_t Input(const uint8_t* aData, uint32_t aDataSize,
                  int64_t aTimestampUsecs, uint64_t flags);
   status_t Output(MediaBuffer** aBuffer, int64_t aTimeoutUs);
   bool Prepare();
   bool IsWaitingResources();
   bool IsDormantNeeded();
+  void RequestMediaResources();
   void ReleaseMediaResources();
   // This updates mOutputBuffer when receiving INFO_OUTPUT_BUFFERS_CHANGED event.
   bool UpdateOutputBuffers();
 
   void ReleaseMediaBuffer(MediaBuffer* abuffer);
 
 protected:
   virtual ~MediaCodecProxy();
--- a/dom/media/omx/mediaresourcemanager/MediaResourceHandler.cpp
+++ b/dom/media/omx/mediaresourcemanager/MediaResourceHandler.cpp
@@ -1,33 +1,39 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* 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/. */
 
 #include "MediaResourceHandler.h"
-
 #include "mozilla/NullPtr.h"
 
 namespace android {
 
 MediaResourceHandler::MediaResourceHandler(const wp<ResourceListener> &aListener)
   : mListener(aListener)
-  , mState(MediaResourceManagerClient::CLIENT_STATE_WAIT_FOR_RESOURCE)
   , mType(IMediaResourceManagerService::INVALID_RESOURCE_TYPE)
+  , mWaitingResource(false)
 {
 }
 
 MediaResourceHandler::~MediaResourceHandler()
 {
   cancelResource();
 }
 
 bool
+MediaResourceHandler::IsWaitingResource()
+{
+  Mutex::Autolock al(mLock);
+  return mWaitingResource;
+}
+
+bool
 MediaResourceHandler::requestResource(IMediaResourceManagerService::ResourceType aType)
 {
   Mutex::Autolock al(mLock);
 
   if (mClient != nullptr && mService != nullptr) {
     return false;
   }
 
@@ -40,53 +46,51 @@ MediaResourceHandler::requestResource(IM
 
   if (service->requestMediaResource(client, (int)aType, true) != OK) {
     return false;
   }
 
   mClient = client;
   mService = service;
   mType = aType;
+  mWaitingResource = true;
 
   return true;
 }
 
 void
 MediaResourceHandler::cancelResource()
 {
   Mutex::Autolock al(mLock);
 
   if (mClient != nullptr && mService != nullptr) {
     mService->cancelClient(mClient, (int)mType);
   }
 
+  mWaitingResource = false;
   mClient = nullptr;
   mService = nullptr;
 }
 
 // Called on a Binder thread
 void
 MediaResourceHandler::statusChanged(int aEvent)
 {
   sp<ResourceListener> listener;
 
   Mutex::Autolock autoLock(mLock);
 
-  MediaResourceManagerClient::State state = (MediaResourceManagerClient::State)aEvent;
-  if (state == mState) {
-    return;
-  }
-
-  mState = state;
-
   listener = mListener.promote();
   if (listener == nullptr) {
     return;
   }
 
-  if (mState == MediaResourceManagerClient::CLIENT_STATE_RESOURCE_ASSIGNED) {
+  mWaitingResource = false;
+
+  MediaResourceManagerClient::State state = (MediaResourceManagerClient::State)aEvent;
+  if (state == MediaResourceManagerClient::CLIENT_STATE_RESOURCE_ASSIGNED) {
     listener->resourceReserved();
   } else {
     listener->resourceCanceled();
   }
 }
 
 } // namespace android
--- a/dom/media/omx/mediaresourcemanager/MediaResourceHandler.h
+++ b/dom/media/omx/mediaresourcemanager/MediaResourceHandler.h
@@ -37,32 +37,35 @@ public:
 
   virtual ~MediaResourceHandler();
 
   // Request Resource
   bool requestResource(IMediaResourceManagerService::ResourceType aType);
   // Cancel Resource
   void cancelResource();
 
+  bool IsWaitingResource();
+
 protected:
   // MediaResourceManagerClient::EventListener::statusChanged()
   virtual void statusChanged(int event);
 
 private:
   // Forbidden
   MediaResourceHandler() MOZ_DELETE;
   MediaResourceHandler(const MediaResourceHandler &) MOZ_DELETE;
   const MediaResourceHandler &operator=(const MediaResourceHandler &) MOZ_DELETE;
 
   // Resource Notification Listener
   wp<ResourceListener> mListener;
 
   // Resource Management
   Mutex mLock;
-  MediaResourceManagerClient::State mState;
   sp<IMediaResourceManagerClient> mClient;
   sp<IMediaResourceManagerService> mService;
   IMediaResourceManagerService::ResourceType mType;
+
+  bool mWaitingResource;
 };
 
 } // namespace android
 
 #endif // MEDIA_RESOURCE_HANDLER_H