Bug 983039 - [Media encoder] Support YV12 GrallocImage in OMXVideoEncoder on B2G. r=roc
authorJohn Lin <jolin@mozilla.com>
Fri, 14 Mar 2014 09:43:13 -0400
changeset 191835 a3e7678d969d3e4a465aee15015b8bac14df5ccb
parent 191834 ca4277d6971f1faaf73afc69c64b3499523391e9
child 191836 369e8353f89c33a830d55191011f3135e51bfa53
push id474
push userasasaki@mozilla.com
push dateMon, 02 Jun 2014 21:01:02 +0000
treeherdermozilla-release@967f4cf1b31c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersroc
bugs983039
milestone30.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 983039 - [Media encoder] Support YV12 GrallocImage in OMXVideoEncoder on B2G. r=roc
content/media/omx/OMXCodecWrapper.cpp
--- a/content/media/omx/OMXCodecWrapper.cpp
+++ b/content/media/omx/OMXCodecWrapper.cpp
@@ -225,16 +225,82 @@ ConvertPlanarYCbCrToNV12(const PlanarYCb
       vSrc += vPixStride;
     }
     // Pick next source line.
     u += lineStride;
     v += lineStride;
   }
 }
 
+// Convert pixels in graphic buffer to NV12 format. aSource is the layer image
+// containing source graphic buffer, and aDestination is the destination of
+// conversion. Currently only 2 source format are supported:
+// - NV21/HAL_PIXEL_FORMAT_YCrCb_420_SP (from camera preview window).
+// - YV12/HAL_PIXEL_FORMAT_YV12 (from video decoder).
+static
+void
+ConvertGrallocImageToNV12(GrallocImage* aSource, uint8_t* aDestination)
+{
+  // Get graphic buffer.
+  SurfaceDescriptor handle = aSource->GetSurfaceDescriptor();
+  SurfaceDescriptorGralloc gralloc = handle.get_SurfaceDescriptorGralloc();
+  sp<GraphicBuffer> graphicBuffer = GrallocBufferActor::GetFrom(gralloc);
+
+  int pixelFormat = graphicBuffer->getPixelFormat();
+  // Only support NV21 (from camera) or YV12 (from HW decoder output) for now.
+  NS_ENSURE_TRUE_VOID(pixelFormat == HAL_PIXEL_FORMAT_YCrCb_420_SP ||
+                      pixelFormat == HAL_PIXEL_FORMAT_YV12);
+
+  void* imgPtr = nullptr;
+  graphicBuffer->lock(GraphicBuffer::USAGE_SW_READ_MASK, &imgPtr);
+  // Build PlanarYCbCrData for NV21 or YV12 buffer.
+  PlanarYCbCrData yuv;
+  switch (pixelFormat) {
+    case HAL_PIXEL_FORMAT_YCrCb_420_SP: // From camera.
+      yuv.mYChannel = static_cast<uint8_t*>(imgPtr);
+      yuv.mYSkip = 0;
+      yuv.mYSize.width = graphicBuffer->getWidth();
+      yuv.mYSize.height = graphicBuffer->getHeight();
+      yuv.mYStride = graphicBuffer->getStride();
+      // 4:2:0.
+      yuv.mCbCrSize.width = yuv.mYSize.width / 2;
+      yuv.mCbCrSize.height = yuv.mYSize.height / 2;
+      // Interleaved VU plane.
+      yuv.mCrChannel = yuv.mYChannel + (yuv.mYStride * yuv.mYSize.height);
+      yuv.mCrSkip = 1;
+      yuv.mCbChannel = yuv.mCrChannel + 1;
+      yuv.mCbSkip = 1;
+      yuv.mCbCrStride = yuv.mYStride;
+      ConvertPlanarYCbCrToNV12(&yuv, aDestination);
+      break;
+    case HAL_PIXEL_FORMAT_YV12: // From video decoder.
+      // Android YV12 format is defined in system/core/include/system/graphics.h
+      yuv.mYChannel = static_cast<uint8_t*>(imgPtr);
+      yuv.mYSkip = 0;
+      yuv.mYSize.width = graphicBuffer->getWidth();
+      yuv.mYSize.height = graphicBuffer->getHeight();
+      yuv.mYStride = graphicBuffer->getStride();
+      // 4:2:0.
+      yuv.mCbCrSize.width = yuv.mYSize.width / 2;
+      yuv.mCbCrSize.height = yuv.mYSize.height / 2;
+      yuv.mCrChannel = yuv.mYChannel + (yuv.mYStride * yuv.mYSize.height);
+      // Aligned to 16 bytes boundary.
+      yuv.mCbCrStride = (yuv.mYStride / 2 + 15) & ~0x0F;
+      yuv.mCrSkip = 0;
+      yuv.mCbChannel = yuv.mCrChannel + (yuv.mCbCrStride * yuv.mCbCrSize.height);
+      yuv.mCbSkip = 0;
+      ConvertPlanarYCbCrToNV12(&yuv, aDestination);
+      break;
+    default:
+      NS_ERROR("Unsupported input gralloc image type. Should never be here.");
+  }
+
+  graphicBuffer->unlock();
+}
+
 nsresult
 OMXVideoEncoder::Encode(const Image* aImage, int aWidth, int aHeight,
                         int64_t aTimestamp, int aInputFlags)
 {
   MOZ_ASSERT(mStarted, "Configure() should be called before Encode().");
 
   NS_ENSURE_TRUE(aWidth == mWidth && aHeight == mHeight && aTimestamp >= 0,
                  NS_ERROR_INVALID_ARG);
@@ -247,17 +313,16 @@ OMXVideoEncoder::Encode(const Image* aIm
   NS_ENSURE_TRUE(result == OK, NS_ERROR_FAILURE);
 
   const sp<ABuffer>& inBuf = mInputBufs.itemAt(index);
   uint8_t* dst = inBuf->data();
   size_t dstSize = inBuf->capacity();
 
   size_t yLen = aWidth * aHeight;
   size_t uvLen = yLen / 2;
-
   // Buffer should be large enough to hold input image data.
   MOZ_ASSERT(dstSize >= yLen + uvLen);
 
   inBuf->setRange(0, yLen + uvLen);
 
   if (!aImage) {
     // Generate muted/black image directly in buffer.
     dstSize = yLen + uvLen;
@@ -268,50 +333,17 @@ OMXVideoEncoder::Encode(const Image* aIm
   } else {
     Image* img = const_cast<Image*>(aImage);
     ImageFormat format = img->GetFormat();
 
     MOZ_ASSERT(aWidth == img->GetSize().width &&
                aHeight == img->GetSize().height);
 
     if (format == ImageFormat::GRALLOC_PLANAR_YCBCR) {
-      // Get graphic buffer pointer.
-      void* imgPtr = nullptr;
-      GrallocImage* nativeImage = static_cast<GrallocImage*>(img);
-      SurfaceDescriptor handle = nativeImage->GetSurfaceDescriptor();
-      SurfaceDescriptorGralloc gralloc = handle.get_SurfaceDescriptorGralloc();
-      sp<GraphicBuffer> graphicBuffer = GrallocBufferActor::GetFrom(gralloc);
-      graphicBuffer->lock(GraphicBuffer::USAGE_SW_READ_MASK, &imgPtr);
-      uint8_t* src = static_cast<uint8_t*>(imgPtr);
-
-      // Only support NV21 for now.
-      MOZ_ASSERT(graphicBuffer->getPixelFormat() ==
-                 HAL_PIXEL_FORMAT_YCrCb_420_SP);
-
-      // Build PlanarYCbCrData for NV21 buffer.
-      PlanarYCbCrData nv21;
-      // Y plane.
-      nv21.mYChannel = src;
-      nv21.mYSize.width = aWidth;
-      nv21.mYSize.height = aHeight;
-      nv21.mYStride = aWidth;
-      nv21.mYSkip = 0;
-      // Interleaved VU plane.
-      nv21.mCrChannel = src + yLen;
-      nv21.mCrSkip = 1;
-      nv21.mCbChannel = nv21.mCrChannel + 1;
-      nv21.mCbSkip = 1;
-      nv21.mCbCrStride = aWidth;
-      // 4:2:0.
-      nv21.mCbCrSize.width = aWidth / 2;
-      nv21.mCbCrSize.height = aHeight / 2;
-
-      ConvertPlanarYCbCrToNV12(&nv21, dst);
-
-      graphicBuffer->unlock();
+      ConvertGrallocImageToNV12(static_cast<GrallocImage*>(img), dst);
     } else if (format == ImageFormat::PLANAR_YCBCR) {
       ConvertPlanarYCbCrToNV12(static_cast<PlanarYCbCrImage*>(img)->GetData(),
                              dst);
     } else {
       // TODO: support RGB to YUV color conversion.
       NS_ERROR("Unsupported input image type.");
     }
   }