Bug 1037282 - Create MediaResourceHandler and MediaCodecProxy. r=sotaro,cpearce
authorBruce Sun <brsun@mozilla.com>
Fri, 11 Jul 2014 11:01:30 +0800
changeset 215684 e2d48c70d9466b81ba13d152f7aabcdddad5a877
parent 215683 c9b503e42352221f0a2f8d10c7577ecddc1cb0c8
child 215685 fc19e46ce305cd678ec628997330d7f2a64688ee
push id515
push userraliiev@mozilla.com
push dateMon, 06 Oct 2014 12:51:51 +0000
treeherdermozilla-release@267c7a481bef [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssotaro, cpearce
bugs1037282
milestone33.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 1037282 - Create MediaResourceHandler and MediaCodecProxy. r=sotaro,cpearce
content/media/omx/MediaCodecProxy.cpp
content/media/omx/MediaCodecProxy.h
content/media/omx/mediaresourcemanager/IMediaResourceManagerService.h
content/media/omx/mediaresourcemanager/MediaResourceHandler.cpp
content/media/omx/mediaresourcemanager/MediaResourceHandler.h
content/media/omx/mediaresourcemanager/moz.build
content/media/omx/moz.build
new file mode 100644
--- /dev/null
+++ b/content/media/omx/MediaCodecProxy.cpp
@@ -0,0 +1,392 @@
+/* -*- 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 "MediaCodecProxy.h"
+
+#include <string.h>
+
+#include <binder/IPCThreadState.h>
+
+namespace android {
+
+sp<MediaCodecProxy>
+MediaCodecProxy::CreateByType(sp<ALooper> aLooper,
+                              const char *aMime,
+                              bool aEncoder,
+                              bool aAsync,
+                              wp<CodecResourceListener> aListener)
+{
+  sp<MediaCodecProxy> codec = new MediaCodecProxy(aLooper, aMime, aEncoder, aAsync, aListener);
+  if ((!aAsync && codec->allocated()) || codec->requestResource()) {
+    return codec;
+  }
+  return nullptr;
+}
+
+MediaCodecProxy::MediaCodecProxy(sp<ALooper> aLooper,
+                                 const char *aMime,
+                                 bool aEncoder,
+                                 bool aAsync,
+                                 wp<CodecResourceListener> aListener)
+  : mCodecLooper(aLooper)
+  , mCodecMime(aMime)
+  , mCodecEncoder(aEncoder)
+  , mListener(aListener)
+{
+  MOZ_ASSERT(mCodecLooper != nullptr, "ALooper should not be nullptr.");
+  if (aAsync) {
+    mResourceHandler = new MediaResourceHandler(this);
+  } else {
+    allocateCodec();
+  }
+}
+
+MediaCodecProxy::~MediaCodecProxy()
+{
+  releaseCodec();
+
+  // Complete all pending Binder ipc transactions
+  IPCThreadState::self()->flushCommands();
+
+  cancelResource();
+}
+
+bool
+MediaCodecProxy::requestResource()
+{
+  if (mResourceHandler == nullptr) {
+    return false;
+  }
+
+  if (strncasecmp(mCodecMime.get(), "video/", 6) == 0) {
+    mResourceHandler->requestResource(mCodecEncoder
+        ? IMediaResourceManagerService::HW_VIDEO_ENCODER
+        : IMediaResourceManagerService::HW_VIDEO_DECODER);
+  } else if (strncasecmp(mCodecMime.get(), "audio/", 6) == 0) {
+    mResourceHandler->requestResource(mCodecEncoder
+        ? IMediaResourceManagerService::HW_AUDIO_ENCODER
+        : IMediaResourceManagerService::HW_AUDIO_DECODER);
+  } else {
+    return false;
+  }
+
+  return true;
+}
+
+void
+MediaCodecProxy::cancelResource()
+{
+  if (mResourceHandler == nullptr) {
+    return;
+  }
+
+  mResourceHandler->cancelResource();
+}
+
+bool
+MediaCodecProxy::allocateCodec()
+{
+  if (mCodecLooper == nullptr) {
+    return false;
+  }
+
+  // Write Lock for mCodec
+  RWLock::AutoWLock awl(mCodecLock);
+
+  // Create MediaCodec
+  mCodec = MediaCodec::CreateByType(mCodecLooper, mCodecMime.get(), mCodecEncoder);
+  if (mCodec == nullptr) {
+    return false;
+  }
+
+  return true;
+}
+
+void
+MediaCodecProxy::releaseCodec()
+{
+  wp<MediaCodec> codec;
+
+  {
+    // Write Lock for mCodec
+    RWLock::AutoWLock awl(mCodecLock);
+
+    codec = mCodec;
+
+    // Release MediaCodec
+    if (mCodec != nullptr) {
+      mCodec->release();
+      mCodec = nullptr;
+    }
+  }
+
+  while (codec.promote() != nullptr) {
+    // this value come from stagefright's AwesomePlayer.
+    usleep(1000);
+  }
+}
+
+bool
+MediaCodecProxy::allocated() const
+{
+  // Read Lock for mCodec
+  RWLock::AutoRLock arl(mCodecLock);
+
+  return mCodec != nullptr;
+}
+
+status_t
+MediaCodecProxy::configure(const sp<AMessage> &aFormat,
+                           const sp<Surface> &aNativeWindow,
+                           const sp<ICrypto> &aCrypto,
+                           uint32_t aFlags)
+{
+  // Read Lock for mCodec
+  RWLock::AutoRLock arl(mCodecLock);
+
+  if (mCodec == nullptr) {
+    return NO_INIT;
+  }
+  return mCodec->configure(aFormat, aNativeWindow, aCrypto, aFlags);
+}
+
+status_t
+MediaCodecProxy::start()
+{
+  // Read Lock for mCodec
+  RWLock::AutoRLock arl(mCodecLock);
+
+  if (mCodec == nullptr) {
+    return NO_INIT;
+  }
+  return mCodec->start();
+}
+
+status_t
+MediaCodecProxy::stop()
+{
+  // Read Lock for mCodec
+  RWLock::AutoRLock arl(mCodecLock);
+
+  if (mCodec == nullptr) {
+    return NO_INIT;
+  }
+  return mCodec->stop();
+}
+
+status_t
+MediaCodecProxy::release()
+{
+  // Read Lock for mCodec
+  RWLock::AutoRLock arl(mCodecLock);
+
+  if (mCodec == nullptr) {
+    return NO_INIT;
+  }
+  return mCodec->release();
+}
+
+status_t
+MediaCodecProxy::flush()
+{
+  // Read Lock for mCodec
+  RWLock::AutoRLock arl(mCodecLock);
+
+  if (mCodec == nullptr) {
+    return NO_INIT;
+  }
+  return mCodec->flush();
+}
+
+status_t
+MediaCodecProxy::queueInputBuffer(size_t aIndex,
+                                  size_t aOffset,
+                                  size_t aSize,
+                                  int64_t aPresentationTimeUs,
+                                  uint32_t aFlags,
+                                  AString *aErrorDetailMessage)
+{
+  // Read Lock for mCodec
+  RWLock::AutoRLock arl(mCodecLock);
+
+  if (mCodec == nullptr) {
+    return NO_INIT;
+  }
+  return mCodec->queueInputBuffer(aIndex, aOffset, aSize,
+      aPresentationTimeUs, aFlags, aErrorDetailMessage);
+}
+
+status_t
+MediaCodecProxy::queueSecureInputBuffer(size_t aIndex,
+                                        size_t aOffset,
+                                        const CryptoPlugin::SubSample *aSubSamples,
+                                        size_t aNumSubSamples,
+                                        const uint8_t aKey[16],
+                                        const uint8_t aIV[16],
+                                        CryptoPlugin::Mode aMode,
+                                        int64_t aPresentationTimeUs,
+                                        uint32_t aFlags,
+                                        AString *aErrorDetailMessage)
+{
+  // Read Lock for mCodec
+  RWLock::AutoRLock arl(mCodecLock);
+
+  if (mCodec == nullptr) {
+    return NO_INIT;
+  }
+  return mCodec->queueSecureInputBuffer(aIndex, aOffset,
+      aSubSamples, aNumSubSamples, aKey, aIV, aMode,
+      aPresentationTimeUs, aFlags, aErrorDetailMessage);
+}
+
+status_t
+MediaCodecProxy::dequeueInputBuffer(size_t *aIndex,
+                                    int64_t aTimeoutUs)
+{
+  // Read Lock for mCodec
+  RWLock::AutoRLock arl(mCodecLock);
+
+  if (mCodec == nullptr) {
+    return NO_INIT;
+  }
+  return mCodec->dequeueInputBuffer(aIndex, aTimeoutUs);
+}
+
+status_t
+MediaCodecProxy::dequeueOutputBuffer(size_t *aIndex,
+                                     size_t *aOffset,
+                                     size_t *aSize,
+                                     int64_t *aPresentationTimeUs,
+                                     uint32_t *aFlags,
+                                     int64_t aTimeoutUs)
+{
+  // Read Lock for mCodec
+  RWLock::AutoRLock arl(mCodecLock);
+
+  if (mCodec == nullptr) {
+    return NO_INIT;
+  }
+  return mCodec->dequeueOutputBuffer(aIndex, aOffset, aSize,
+      aPresentationTimeUs, aFlags, aTimeoutUs);
+}
+
+status_t
+MediaCodecProxy::renderOutputBufferAndRelease(size_t aIndex)
+{
+  // Read Lock for mCodec
+  RWLock::AutoRLock arl(mCodecLock);
+
+  if (mCodec == nullptr) {
+    return NO_INIT;
+  }
+  return mCodec->renderOutputBufferAndRelease(aIndex);
+}
+
+status_t
+MediaCodecProxy::releaseOutputBuffer(size_t aIndex)
+{
+  // Read Lock for mCodec
+  RWLock::AutoRLock arl(mCodecLock);
+
+  if (mCodec == nullptr) {
+    return NO_INIT;
+  }
+  return mCodec->releaseOutputBuffer(aIndex);
+}
+
+status_t
+MediaCodecProxy::signalEndOfInputStream()
+{
+  // Read Lock for mCodec
+  RWLock::AutoRLock arl(mCodecLock);
+
+  if (mCodec == nullptr) {
+    return NO_INIT;
+  }
+  return mCodec->signalEndOfInputStream();
+}
+
+status_t
+MediaCodecProxy::getOutputFormat(sp<AMessage> *aFormat) const
+{
+  // Read Lock for mCodec
+  RWLock::AutoRLock arl(mCodecLock);
+
+  if (mCodec == nullptr) {
+    return NO_INIT;
+  }
+  return mCodec->getOutputFormat(aFormat);
+}
+
+status_t
+MediaCodecProxy::getInputBuffers(Vector<sp<ABuffer>> *aBuffers) const
+{
+  // Read Lock for mCodec
+  RWLock::AutoRLock arl(mCodecLock);
+
+  if (mCodec == nullptr) {
+    return NO_INIT;
+  }
+  return mCodec->getInputBuffers(aBuffers);
+}
+
+status_t
+MediaCodecProxy::getOutputBuffers(Vector<sp<ABuffer>> *aBuffers) const
+{
+  // Read Lock for mCodec
+  RWLock::AutoRLock arl(mCodecLock);
+
+  if (mCodec == nullptr) {
+    return NO_INIT;
+  }
+  return mCodec->getOutputBuffers(aBuffers);
+}
+
+void
+MediaCodecProxy::requestActivityNotification(const sp<AMessage> &aNotify)
+{
+  // Read Lock for mCodec
+  RWLock::AutoRLock arl(mCodecLock);
+
+  if (mCodec == nullptr) {
+    return;
+  }
+  mCodec->requestActivityNotification(aNotify);
+}
+
+// Called on a Binder thread
+void
+MediaCodecProxy::resourceReserved()
+{
+  // Create MediaCodec
+  releaseCodec();
+  if (!allocateCodec()) {
+    cancelResource();
+    return;
+  }
+
+  // Notification
+  sp<CodecResourceListener> listener = mListener.promote();
+  if (listener != nullptr) {
+    listener->codecReserved();
+  }
+}
+
+// Called on a Binder thread
+void
+MediaCodecProxy::resourceCanceled()
+{
+  // Release MediaCodec
+  releaseCodec();
+
+  // Notification
+  sp<CodecResourceListener> listener = mListener.promote();
+  if (listener != nullptr) {
+    listener->codecCanceled();
+  }
+}
+
+} // namespace android
new file mode 100644
--- /dev/null
+++ b/content/media/omx/MediaCodecProxy.h
@@ -0,0 +1,156 @@
+/* -*- 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/. */
+
+#ifndef MEDIA_CODEC_PROXY_H
+#define MEDIA_CODEC_PROXY_H
+
+#include <nsString.h>
+
+#include <stagefright/MediaCodec.h>
+#include <utils/threads.h>
+
+#include "MediaResourceHandler.h"
+
+namespace android {
+
+class MediaCodecProxy : public MediaResourceHandler::ResourceListener
+{
+public:
+  /* Codec resource notification listener.
+   * All functions are called on the Binder thread.
+   */
+  struct CodecResourceListener : public virtual RefBase {
+    /* The codec resource is reserved and can be granted.
+     * The client can allocate the requested resource.
+     */
+    virtual void codecReserved() = 0;
+    /* The codec resource is not reserved any more.
+     * The client should release the resource as soon as possible if the
+     * resource is still being held.
+     */
+    virtual void codecCanceled() = 0;
+  };
+
+  // Check whether MediaCodec has been allocated.
+  bool allocated() const;
+
+  // Static MediaCodec methods
+  // Only support MediaCodec::CreateByType()
+  static sp<MediaCodecProxy> CreateByType(sp<ALooper> aLooper,
+                                          const char *aMime,
+                                          bool aEncoder,
+                                          bool aAsync=false,
+                                          wp<CodecResourceListener> aListener=nullptr);
+
+  // MediaCodec methods
+  status_t configure(const sp<AMessage> &aFormat,
+                     const sp<Surface> &aNativeWindow,
+                     const sp<ICrypto> &aCrypto,
+                     uint32_t aFlags);
+
+  status_t start();
+
+  status_t stop();
+
+  status_t release();
+
+  status_t flush();
+
+  status_t queueInputBuffer(size_t aIndex,
+                            size_t aOffset,
+                            size_t aSize,
+                            int64_t aPresentationTimeUs,
+                            uint32_t aFlags,
+                            AString *aErrorDetailMessage=nullptr);
+
+  status_t queueSecureInputBuffer(size_t aIndex,
+                                  size_t aOffset,
+                                  const CryptoPlugin::SubSample *aSubSamples,
+                                  size_t aNumSubSamples,
+                                  const uint8_t aKey[16],
+                                  const uint8_t aIV[16],
+                                  CryptoPlugin::Mode aMode,
+                                  int64_t aPresentationTimeUs,
+                                  uint32_t aFlags,
+                                  AString *aErrorDetailMessage=nullptr);
+
+  status_t dequeueInputBuffer(size_t *aIndex,
+                              int64_t aTimeoutUs=INT64_C(0));
+
+  status_t dequeueOutputBuffer(size_t *aIndex,
+                               size_t *aOffset,
+                               size_t *aSize,
+                               int64_t *aPresentationTimeUs,
+                               uint32_t *aFlags,
+                               int64_t aTimeoutUs=INT64_C(0));
+
+  status_t renderOutputBufferAndRelease(size_t aIndex);
+
+  status_t releaseOutputBuffer(size_t aIndex);
+
+  status_t signalEndOfInputStream();
+
+  status_t getOutputFormat(sp<AMessage> *aFormat) const;
+
+  status_t getInputBuffers(Vector<sp<ABuffer>> *aBuffers) const;
+
+  status_t getOutputBuffers(Vector<sp<ABuffer>> *aBuffers) const;
+
+  // Notification will be posted once there "is something to do", i.e.
+  // an input/output buffer has become available, a format change is
+  // pending, an error is pending.
+  void requestActivityNotification(const sp<AMessage> &aNotify);
+
+protected:
+  virtual ~MediaCodecProxy();
+
+  // MediaResourceHandler::EventListener::resourceReserved()
+  virtual void resourceReserved();
+  // MediaResourceHandler::EventListener::resourceCanceled()
+  virtual void resourceCanceled();
+
+private:
+  // Forbidden
+  MediaCodecProxy() MOZ_DELETE;
+  MediaCodecProxy(const MediaCodecProxy &) MOZ_DELETE;
+  const MediaCodecProxy &operator=(const MediaCodecProxy &) MOZ_DELETE;
+
+  // Constructor for MediaCodecProxy::CreateByType
+  MediaCodecProxy(sp<ALooper> aLooper,
+                  const char *aMime,
+                  bool aEncoder,
+                  bool aAsync,
+                  wp<CodecResourceListener> aListener);
+
+  // Request Resource
+  bool requestResource();
+  // Cancel Resource
+  void cancelResource();
+
+  // Allocate Codec Resource
+  bool allocateCodec();
+  // Release Codec Resource
+  void releaseCodec();
+
+  // MediaCodec Parameter
+  sp<ALooper> mCodecLooper;
+  nsCString mCodecMime;
+  bool mCodecEncoder;
+
+  // Codec Resource Notification Listener
+  wp<CodecResourceListener> mListener;
+
+  // Media Resource Management
+  sp<MediaResourceHandler> mResourceHandler;
+
+  // MediaCodec instance
+  mutable RWLock mCodecLock;
+  sp<MediaCodec> mCodec;
+};
+
+} // namespace android
+
+#endif // MEDIA_CODEC_PROXY_H
--- a/content/media/omx/mediaresourcemanager/IMediaResourceManagerService.h
+++ b/content/media/omx/mediaresourcemanager/IMediaResourceManagerService.h
@@ -22,16 +22,17 @@ class IMediaResourceManagerService : pub
 public:
     DECLARE_META_INTERFACE(MediaResourceManagerService);
 
     // Enumeration for the resource types
     enum ResourceType {
       HW_VIDEO_DECODER = 0,
       HW_AUDIO_DECODER,  // Not supported currently.
       HW_VIDEO_ENCODER,
+      HW_AUDIO_ENCODER,  // Not supported currently.
       HW_CAMERA,          // Not supported currently.
       NUM_OF_RESOURCE_TYPES,
       INVALID_RESOURCE_TYPE = -1
     };
 
     enum ErrorCode {
         RESOURCE_NOT_AVAILABLE = -EAGAIN
     };
new file mode 100644
--- /dev/null
+++ b/content/media/omx/mediaresourcemanager/MediaResourceHandler.cpp
@@ -0,0 +1,92 @@
+/* -*- 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)
+{
+}
+
+MediaResourceHandler::~MediaResourceHandler()
+{
+  cancelResource();
+}
+
+bool
+MediaResourceHandler::requestResource(IMediaResourceManagerService::ResourceType aType)
+{
+  Mutex::Autolock al(mLock);
+
+  if (mClient != nullptr && mService != nullptr) {
+    return false;
+  }
+
+  sp<MediaResourceManagerClient> client = new MediaResourceManagerClient(this);
+  sp<IMediaResourceManagerService> service = client->getMediaResourceManagerService();
+
+  if (service == nullptr) {
+    return false;
+  }
+
+  if (service->requestMediaResource(client, (int)aType, true) != OK) {
+    return false;
+  }
+
+  mClient = client;
+  mService = service;
+  mType = aType;
+
+  return true;
+}
+
+void
+MediaResourceHandler::cancelResource()
+{
+  Mutex::Autolock al(mLock);
+
+  if (mClient != nullptr && mService != nullptr) {
+    mService->cancelClient(mClient, (int)mType);
+  }
+
+  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) {
+    listener->resourceReserved();
+  } else {
+    listener->resourceCanceled();
+  }
+}
+
+} // namespace android
new file mode 100644
--- /dev/null
+++ b/content/media/omx/mediaresourcemanager/MediaResourceHandler.h
@@ -0,0 +1,68 @@
+/* -*- 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/. */
+
+#ifndef MEDIA_RESOURCE_HANDLER_H
+#define MEDIA_RESOURCE_HANDLER_H
+
+#include <utils/threads.h>
+
+#include <mozilla/Attributes.h>
+
+#include "MediaResourceManagerClient.h"
+
+namespace android {
+
+class MediaResourceHandler : public MediaResourceManagerClient::EventListener
+{
+public:
+  /* Resource notification listener.
+   * All functions are called on the Binder thread.
+   */
+  struct ResourceListener : public virtual RefBase {
+    /* The resource is reserved and can be granted.
+     * The client can allocate the requested resource.
+     */
+    virtual void resourceReserved() = 0;
+    /* The resource is not reserved any more.
+     * The client should release the resource as soon as possible if the
+     * resource is still being held.
+     */
+    virtual void resourceCanceled() = 0;
+  };
+
+  MediaResourceHandler(const wp<ResourceListener> &aListener);
+
+  virtual ~MediaResourceHandler();
+
+  // Request Resource
+  bool requestResource(IMediaResourceManagerService::ResourceType aType);
+  // Cancel Resource
+  void cancelResource();
+
+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;
+};
+
+} // namespace android
+
+#endif // MEDIA_RESOURCE_HANDLER_H
--- a/content/media/omx/mediaresourcemanager/moz.build
+++ b/content/media/omx/mediaresourcemanager/moz.build
@@ -11,16 +11,17 @@ EXPORTS += [
     'MediaResourceManagerClient.h',
     'MediaResourceManagerService.h',
 ]
 
 SOURCES += [
     'IMediaResourceManagerClient.cpp',
     'IMediaResourceManagerDeathNotifier.cpp',
     'IMediaResourceManagerService.cpp',
+    'MediaResourceHandler.cpp',
     'MediaResourceManagerClient.cpp',
     'MediaResourceManagerService.cpp',
 ]
 
 include('/ipc/chromium/chromium-config.mozbuild')
 
 CXXFLAGS += [
     '-I%s/%s' % (CONFIG['ANDROID_SOURCE'], d) for d in [
--- a/content/media/omx/moz.build
+++ b/content/media/omx/moz.build
@@ -42,16 +42,24 @@ if 'rtsp' in CONFIG['NECKO_PROTOCOLS']:
         'RtspOmxDecoder.h',
         'RtspOmxReader.h',
     ]
     SOURCES += [
         'RtspOmxDecoder.cpp',
         'RtspOmxReader.cpp',
     ]
 
+if int(CONFIG['ANDROID_VERSION']) >= 16:
+    EXPORTS += [
+        'MediaCodecProxy.h',
+    ]
+    SOURCES += [
+        'MediaCodecProxy.cpp',
+    ]
+
 include('/ipc/chromium/chromium-config.mozbuild')
 
 FINAL_LIBRARY = 'gklayout'
 LOCAL_INCLUDES += [
     '/content/base/src',
     '/content/html/content/src',
     '/ipc/chromium/src',
     'mediaresourcemanager',