Bug 938034 - Add GonkCameraImage format. r=roc
authorAlfredo Yang <ayang@mozilla.com>
Wed, 17 Dec 2014 23:42:00 -0500
changeset 246219 fca7e00e20806222df3268628913308d8beafc87
parent 246218 f2bfb9716f5cb2880fdae579cfc10cf40e52a63a
child 246220 1d898e84926b329008e9e89a3cc1466fb3a2f523
push id4489
push userraliiev@mozilla.com
push dateMon, 23 Feb 2015 15:17:55 +0000
treeherdermozilla-beta@fd7c3dc24146 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersroc
bugs938034
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 938034 - Add GonkCameraImage format. r=roc
dom/media/webrtc/GonkCameraImage.cpp
dom/media/webrtc/GonkCameraImage.h
dom/media/webrtc/moz.build
gfx/layers/GrallocImages.h
gfx/layers/ImageContainer.cpp
gfx/layers/ImageContainer.h
gfx/layers/ImageTypes.h
new file mode 100644
--- /dev/null
+++ b/dom/media/webrtc/GonkCameraImage.cpp
@@ -0,0 +1,81 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* 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 "GonkCameraImage.h"
+#include "stagefright/MediaBuffer.h"
+
+namespace mozilla {
+
+GonkCameraImage::GonkCameraImage()
+  : GrallocImage()
+  , mMonitor("GonkCameraImage.Monitor")
+  , mMediaBuffer(nullptr)
+  , mThread(nullptr)
+{
+  mFormat = ImageFormat::GONK_CAMERA_IMAGE;
+}
+
+GonkCameraImage::~GonkCameraImage()
+{
+  ReentrantMonitorAutoEnter mon(mMonitor);
+  // mMediaBuffer must be cleared before destructor.
+  MOZ_ASSERT(mMediaBuffer == nullptr);
+}
+
+nsresult
+GonkCameraImage::GetBuffer(android::MediaBuffer** aBuffer)
+{
+  ReentrantMonitorAutoEnter mon(mMonitor);
+
+  if (!mMediaBuffer) {
+    return NS_ERROR_FAILURE;
+  }
+
+  MOZ_ASSERT(NS_GetCurrentThread() == mThread);
+
+  *aBuffer = mMediaBuffer;
+  mMediaBuffer->add_ref();
+
+  return NS_OK;
+}
+
+bool
+GonkCameraImage::HasMediaBuffer()
+{
+  ReentrantMonitorAutoEnter mon(mMonitor);
+  return mMediaBuffer != nullptr;
+}
+
+nsresult
+GonkCameraImage::SetBuffer(android::MediaBuffer* aBuffer)
+{
+  ReentrantMonitorAutoEnter mon(mMonitor);
+  MOZ_ASSERT(!mMediaBuffer);
+
+  mMediaBuffer = aBuffer;
+  mMediaBuffer->add_ref();
+  mThread = NS_GetCurrentThread();
+
+  return NS_OK;
+}
+
+nsresult
+GonkCameraImage::ClearBuffer()
+{
+  ReentrantMonitorAutoEnter mon(mMonitor);
+
+  if (mMediaBuffer) {
+    MOZ_ASSERT(NS_GetCurrentThread() == mThread);
+    mMediaBuffer->release();
+    mMediaBuffer = nullptr;
+    mThread = nullptr;
+  }
+  return NS_OK;
+}
+
+} // namespace mozilla
+
+
new file mode 100644
--- /dev/null
+++ b/dom/media/webrtc/GonkCameraImage.h
@@ -0,0 +1,75 @@
+/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * 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 GONKCAMERAIMAGE_H
+#define GONKCAMERAIMAGE_H
+
+#include "mozilla/ReentrantMonitor.h"
+#include "ImageLayers.h"
+#include "ImageContainer.h"
+#include "GrallocImages.h"
+
+namespace android {
+class MOZ_EXPORT MediaBuffer;
+}
+
+namespace mozilla {
+
+/**
+ * GonkCameraImage has two parts. One is preview image which will be saved in
+ * GrallocImage, another kind is the MediaBuffer keeps in mMediaBuffer
+ * which is from gonk camera recording callback. The data in MediaBuffer is Gonk
+ * shared memory based on android binder (IMemory), the actual format in IMemory
+ * is platform dependent.
+ * This instance is created in MediaEngine when the preview image arrives.
+ * The MediaBuffer is attached to the current created GonkCameraImage via SetBuffer().
+ * After sending this image to MediaStreamGraph by AppendToTrack(), ClearBuffer()
+ * must be called to clear MediaBuffer to avoid MediaBuffer be kept in MSG thread.
+ * The reason to keep MediaBuffer be accessed from MSG thread is MediaBuffer is
+ * limited resource and it could cause frame rate jitter if MediaBuffer stay too
+ * long in other threads.
+ * So there will be 3 threads to accessed this class. First is camera preview
+ * thread which creates an instance of this class and initialize the preview
+ * image in the base class GrallocImage. Second is the camera recording
+ * thread which attaches MediaBuffer and sends this image to MediaStreamDirectListener.
+ * Third is the MSG thread via NotifyPull, the image should have preview image
+ * only in NotifyPull.
+ *
+ * Note: SetBuffer() and GetBuffer() should be called from the same thread. It
+ *       is forbidden to call GetBuffer() from other threads.
+ */
+class GonkCameraImage : public layers::GrallocImage
+{
+public:
+  GonkCameraImage();
+
+  // The returned aBuffer has called aBuffer->add_ref() already, so it is caller's
+  // duty to release aBuffer. It should be called from the same thread which
+  // called SetBuffer().
+  nsresult GetBuffer(android::MediaBuffer** aBuffer);
+
+  // Set MediaBuffer to image. It is caller's responsibility to call ClearBuffer()
+  // after the MediaBuffer is sent via MediaStreamGraph.
+  nsresult SetBuffer(android::MediaBuffer* aBuffer);
+
+  // It should be called from the same thread which called SetBuffer().
+  nsresult ClearBuffer();
+
+  bool HasMediaBuffer();
+
+protected:
+  virtual ~GonkCameraImage();
+
+  // mMonitor protects mMediaBuffer and mThread.
+  ReentrantMonitor mMonitor;
+  android::MediaBuffer* mMediaBuffer;
+  // Check if current thread is the same one which called SetBuffer().
+  // It doesn't need to hold reference count.
+  DebugOnly<nsIThread*> mThread;
+};
+
+} // namespace mozilla
+
+#endif /* GONKCAMERAIMAGE_H */
--- a/dom/media/webrtc/moz.build
+++ b/dom/media/webrtc/moz.build
@@ -31,18 +31,22 @@ if CONFIG['MOZ_WEBRTC']:
         '/dom/camera',
         '/media/libyuv/include',
         '/media/webrtc/signaling/src/common',
         '/media/webrtc/signaling/src/common/browser_logging',
         '/media/webrtc/trunk',
     ]
     # Gonk camera source.
     if CONFIG['MOZ_B2G_CAMERA']:
-        EXPORTS += ['MediaEngineGonkVideoSource.h']
+        EXPORTS += [
+            'GonkCameraImage.h',
+            'MediaEngineGonkVideoSource.h',
+        ]
         UNIFIED_SOURCES += [
+            'GonkCameraImage.cpp',
             'MediaEngineGonkVideoSource.cpp',
         ]
 
 XPIDL_SOURCES += [
     'nsITabSource.idl'
 ]
 
 UNIFIED_SOURCES += [
--- a/gfx/layers/GrallocImages.h
+++ b/gfx/layers/GrallocImages.h
@@ -92,16 +92,21 @@ public:
   void* GetNativeBuffer();
 
   virtual bool IsValid() { return !!mTextureClient; }
 
   virtual ISharedImage* AsSharedImage() MOZ_OVERRIDE { return this; }
 
   virtual TextureClient* GetTextureClient(CompositableClient* aClient) MOZ_OVERRIDE;
 
+  virtual GrallocImage* AsGrallocImage() MOZ_OVERRIDE
+  {
+    return this;
+  }
+
   virtual uint8_t* GetBuffer()
   {
     return static_cast<uint8_t*>(GetNativeBuffer());
   }
 
   int GetUsage()
   {
     return (static_cast<ANativeWindowBuffer*>(GetNativeBuffer()))->usage;
--- a/gfx/layers/ImageContainer.cpp
+++ b/gfx/layers/ImageContainer.cpp
@@ -14,16 +14,17 @@
 #include "mozilla/ipc/CrossProcessMutex.h"  // for CrossProcessMutex, etc
 #include "mozilla/layers/CompositorTypes.h"
 #include "mozilla/layers/ImageBridgeChild.h"  // for ImageBridgeChild
 #include "mozilla/layers/ImageClient.h"  // for ImageClient
 #include "nsISupportsUtils.h"           // for NS_IF_ADDREF
 #include "YCbCrUtils.h"                 // for YCbCr conversions
 #ifdef MOZ_WIDGET_GONK
 #include "GrallocImages.h"
+#include "GonkCameraImage.h"
 #endif
 #include "gfx2DGlue.h"
 #include "mozilla/gfx/2D.h"
 
 #ifdef XP_MACOSX
 #include "mozilla/gfx/QuartzSupport.h"
 #include "MacIOSurfaceImage.h"
 #endif
@@ -55,16 +56,20 @@ ImageFactory::CreateImage(ImageFormat aF
   if (aFormat == ImageFormat::GRALLOC_PLANAR_YCBCR) {
     img = new GrallocImage();
     return img.forget();
   }
   if (aFormat == ImageFormat::OVERLAY_IMAGE) {
     img = new OverlayImage();
     return img.forget();
   }
+  if (aFormat == ImageFormat::GONK_CAMERA_IMAGE) {
+    img = new GonkCameraImage();
+    return img.forget();
+  }
 #endif
   if (aFormat == ImageFormat::PLANAR_YCBCR) {
     img = new PlanarYCbCrImage(aRecycleBin);
     return img.forget();
   }
   if (aFormat == ImageFormat::CAIRO_SURFACE) {
     img = new CairoImage();
     return img.forget();
--- a/gfx/layers/ImageContainer.h
+++ b/gfx/layers/ImageContainer.h
@@ -100,16 +100,17 @@ class CrossProcessMutex;
 namespace layers {
 
 class ImageClient;
 class SharedPlanarYCbCrImage;
 class TextureClient;
 class CompositableClient;
 class CompositableForwarder;
 class SurfaceDescriptor;
+class GrallocImage;
 
 struct ImageBackendData
 {
   virtual ~ImageBackendData() {}
 
 protected:
   ImageBackendData() {}
 };
@@ -162,16 +163,21 @@ public:
 
   int32_t GetSerial() { return mSerial; }
 
   void MarkSent() { mSent = true; }
   bool IsSentToCompositor() { return mSent; }
 
   virtual TemporaryRef<gfx::SourceSurface> GetAsSourceSurface() = 0;
 
+  virtual GrallocImage* AsGrallocImage()
+  {
+    return nullptr;
+  }
+
 protected:
   Image(void* aImplData, ImageFormat aFormat) :
     mImplData(aImplData),
     mSerial(++sSerialCounter),
     mFormat(aFormat),
     mSent(false)
   {}
 
--- a/gfx/layers/ImageTypes.h
+++ b/gfx/layers/ImageTypes.h
@@ -21,16 +21,26 @@ MOZ_BEGIN_ENUM_CLASS(ImageFormat)
   /**
    * The GRALLOC_PLANAR_YCBCR format creates a GrallocImage, a subtype of
    * PlanarYCbCrImage. It takes a PlanarYCbCrImage data or the raw gralloc
    * data and can be used as a texture by Gonk backend directly.
    */
   GRALLOC_PLANAR_YCBCR,
 
   /**
+   * The GONK_CAMERA_IMAGE format creates a GonkCameraImage, which contains two
+   * parts. One is GrallocImage image for preview image. Another one is
+   * MediaBuffer from Gonk recording image. The preview image can be rendered in
+   * a layer for display. And the MediaBuffer will be used in component like OMX
+   * encoder. It is for GUM to support preview and recording image on Gonk
+   * camera.
+   */
+  GONK_CAMERA_IMAGE,
+
+  /**
    * The SHARED_RGB format creates a SharedRGBImage, which stores RGB data in
    * shared memory. Some Android hardware video decoders require this format.
    * Currently only used on Android.
    */
   SHARED_RGB,
 
   /**
    * The CAIRO_SURFACE format creates a CairoImage. All backends should