Bug 931733 - Ease vendor porting of HAL_PIXEL_FORMAT_XXX for color format conversion. r=mwu, a=1.4+
authorSolomon Chiu <schiu@mozilla.com>
Fri, 04 Jul 2014 02:38:00 +0200
changeset 207726 c6da1999f77a0bba5acb102821c2d59f426ac507
parent 207725 d5fb5bf53526e0b50facb2bf517b5cbee601731e
child 207727 4272b20e0667245ac3c692024ad621b669e4ab00
push id3741
push userasasaki@mozilla.com
push dateMon, 21 Jul 2014 20:25:18 +0000
treeherdermozilla-beta@4d6f46f5af68 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmwu, 1
bugs931733
milestone32.0a2
Bug 931733 - Ease vendor porting of HAL_PIXEL_FORMAT_XXX for color format conversion. r=mwu, a=1.4+
gfx/layers/GrallocImages.cpp
gfx/layers/GrallocImages.h
--- a/gfx/layers/GrallocImages.cpp
+++ b/gfx/layers/GrallocImages.cpp
@@ -145,29 +145,47 @@ void GrallocImage::SetData(const Gralloc
 /**
  * Converts YVU420 semi planar frames to RGB565, possibly taking different
  * stride values.
  * Needed because the Android ColorConverter class assumes that the Y and UV
  * channels have equal stride.
  */
 static void
 ConvertYVU420SPToRGB565(void *aYData, uint32_t aYStride,
-                        void *aUVData, uint32_t aUVStride,
+                        void *aUData, void *aVData, uint32_t aUVStride,
                         void *aOut,
                         uint32_t aWidth, uint32_t aHeight)
 {
   uint8_t *y = (uint8_t*)aYData;
-  int8_t *uv = (int8_t*)aUVData;
+  bool isCbCr;
+  int8_t *uv;
+
+  if (aUData < aVData) {
+    // The color format is YCbCr
+    isCbCr = true;
+    uv = (int8_t*)aUData;
+  } else {
+    // The color format is YCrCb
+    isCbCr = false;
+    uv = (int8_t*)aVData;
+  }
 
   uint16_t *rgb = (uint16_t*)aOut;
 
   for (size_t i = 0; i < aHeight; i++) {
     for (size_t j = 0; j < aWidth; j++) {
-      int8_t d = uv[j | 1] - 128;
-      int8_t e = uv[j & ~1] - 128;
+      int8_t d, e;
+
+      if (isCbCr) {
+        d = uv[j & ~1] - 128;
+        e = uv[j | 1] - 128;
+      } else {
+        d = uv[j | 1] - 128;
+        e = uv[j & ~1] - 128;
+      }
 
       // Constants taken from https://en.wikipedia.org/wiki/YUV
       int32_t r = (298 * y[j] + 409 * e + 128) >> 11;
       int32_t g = (298 * y[j] - 100 * d - 208 * e + 128) >> 10;
       int32_t b = (298 * y[j] + 516 * d + 128) >> 11;
 
       r = r > 0x1f ? 0x1f : r < 0 ? 0 : r;
       g = g > 0x3f ? 0x3f : g < 0 ? 0 : g;
@@ -178,119 +196,198 @@ ConvertYVU420SPToRGB565(void *aYData, ui
 
     y += aYStride;
     if (i % 2) {
       uv += aUVStride;
     }
   }
 }
 
+/**
+ * Converts the format of vendor-specific YVU420(planar and semi-planar)
+ * with the help of GraphicBuffer::lockYCbCr. In this way, we can convert
+ * the YUV color format without awaring actual definition/enumeration
+ * of vendor formats.
+ */
+static status_t
+ConvertVendorYUVFormatToRGB565(android::sp<GraphicBuffer>& aBuffer,
+                               gfx::DataSourceSurface *aSurface,
+                               gfx::DataSourceSurface::MappedSurface *aMappedSurface)
+{
+  status_t rv = BAD_VALUE;
+
+#if ANDROID_VERSION >= 18
+  android_ycbcr ycbcr;
+
+  // Check if the vendor provides explicit addresses of Y/Cb/Cr buffer from lockYCbCr
+  rv = aBuffer->lockYCbCr(android::GraphicBuffer::USAGE_SW_READ_OFTEN, &ycbcr);
+
+  if (rv != OK) {
+    NS_WARNING("Couldn't lock graphic buffer using lockYCbCr()");
+    return rv;
+  }
+
+  GraphicBufferAutoUnlock unlock(aBuffer);
+
+  uint32_t width = aSurface->GetSize().width;
+  uint32_t height = aSurface->GetSize().height;
+
+  if (ycbcr.chroma_step == 2) {
+    // From the system/core/include/system/graphics.h
+    // @chroma_step is the distance in bytes from one chroma pixel value to
+    // the next.  This is 2 bytes for semiplanar (because chroma values are
+    // interleaved and each chroma value is one byte) and 1 for planar.
+    ConvertYVU420SPToRGB565(ycbcr.y, ycbcr.ystride,
+                            ycbcr.cb, ycbcr.cr, ycbcr.cstride,
+                            aMappedSurface->mData,
+                            width, height);
+  } else {
+    layers::PlanarYCbCrData ycbcrData;
+    ycbcrData.mYChannel     = static_cast<uint8_t*>(ycbcr.y);
+    ycbcrData.mYStride      = ycbcr.ystride;
+    ycbcrData.mYSize        = aSurface->GetSize();
+    ycbcrData.mCbChannel    = static_cast<uint8_t*>(ycbcr.cb);
+    ycbcrData.mCrChannel    = static_cast<uint8_t*>(ycbcr.cr);
+    ycbcrData.mCbCrStride   = ycbcr.cstride;
+    ycbcrData.mCbCrSize     = aSurface->GetSize() / 2;
+    ycbcrData.mPicSize      = aSurface->GetSize();
+
+    gfx::ConvertYCbCrToRGB(ycbcrData,
+                           aSurface->GetFormat(),
+                           aSurface->GetSize(),
+                           aMappedSurface->mData,
+                           aMappedSurface->mStride);
+  }
+#endif
+
+  return rv;
+}
+
+static status_t
+ConvertOmxYUVFormatToRGB565(android::sp<GraphicBuffer>& aBuffer,
+                            gfx::DataSourceSurface *aSurface,
+                            gfx::DataSourceSurface::MappedSurface *aMappedSurface,
+                            const layers::PlanarYCbCrData& aYcbcrData,
+                            int aOmxFormat)
+{
+  if (!aOmxFormat) {
+    NS_WARNING("Unknown color format");
+    return BAD_VALUE;
+  }
+
+  status_t rv;
+  uint8_t *buffer;
+
+  rv = aBuffer->lock(android::GraphicBuffer::USAGE_SW_READ_OFTEN,
+                     reinterpret_cast<void **>(&buffer));
+  if (rv != OK) {
+    NS_WARNING("Couldn't lock graphic buffer");
+    return BAD_VALUE;
+  }
+
+  GraphicBufferAutoUnlock unlock(aBuffer);
+
+  uint32_t format = aBuffer->getPixelFormat();
+  uint32_t width = aSurface->GetSize().width;
+  uint32_t height = aSurface->GetSize().height;
+
+  if (format == GrallocImage::HAL_PIXEL_FORMAT_YCrCb_420_SP_ADRENO) {
+    // The Adreno hardware decoder aligns image dimensions to a multiple of 32,
+    // so we have to account for that here
+    uint32_t alignedWidth = ALIGN(width, 32);
+    uint32_t alignedHeight = ALIGN(height, 32);
+    uint32_t uvOffset = ALIGN(alignedHeight * alignedWidth, 4096);
+    uint32_t uvStride = 2 * ALIGN(width / 2, 32);
+    ConvertYVU420SPToRGB565(buffer, alignedWidth,
+                            buffer + uvOffset + 1,
+                            buffer + uvOffset,
+                            uvStride,
+                            aMappedSurface->mData,
+                            width, height);
+    return OK;
+  }
+
+  if (format == HAL_PIXEL_FORMAT_YCrCb_420_SP) {
+    uint32_t uvOffset = height * width;
+    ConvertYVU420SPToRGB565(buffer, width,
+                            buffer + uvOffset + 1,
+                            buffer + uvOffset,
+                            width,
+                            aMappedSurface->mData,
+                            width, height);
+    return OK;
+  }
+
+  if (format == HAL_PIXEL_FORMAT_YV12) {
+    gfx::ConvertYCbCrToRGB(aYcbcrData,
+                           aSurface->GetFormat(),
+                           aSurface->GetSize(),
+                           aSurface->GetData(),
+                           aSurface->Stride());
+    return OK;
+  }
+
+  android::ColorConverter colorConverter((OMX_COLOR_FORMATTYPE)aOmxFormat,
+                                         OMX_COLOR_Format16bitRGB565);
+  if (!colorConverter.isValid()) {
+    NS_WARNING("Invalid color conversion");
+    return BAD_VALUE;
+  }
+
+  rv = colorConverter.convert(buffer, width, height,
+                              0, 0, width - 1, height - 1 /* source crop */,
+                              aMappedSurface->mData, width, height,
+                              0, 0, width - 1, height - 1 /* dest crop */);
+  if (rv) {
+    NS_WARNING("OMX color conversion failed");
+    return BAD_VALUE;
+  }
+
+  return OK;
+}
+
 TemporaryRef<gfx::SourceSurface>
 GrallocImage::GetAsSourceSurface()
 {
   if (!mTextureClient) {
     return nullptr;
   }
+
   android::sp<GraphicBuffer> graphicBuffer =
     mTextureClient->GetGraphicBuffer();
 
-  void *buffer;
-  int32_t rv =
-    graphicBuffer->lock(android::GraphicBuffer::USAGE_SW_READ_OFTEN, &buffer);
-
-  if (rv) {
-    NS_WARNING("Couldn't lock graphic buffer");
-    return nullptr;
-  }
-
-  GraphicBufferAutoUnlock unlock(graphicBuffer);
-
-  uint32_t format = graphicBuffer->getPixelFormat();
-  uint32_t omxFormat = 0;
-
-  for (int i = 0; sColorIdMap[i]; i += 2) {
-    if (sColorIdMap[i] == format) {
-      omxFormat = sColorIdMap[i + 1];
-      break;
-    }
-  }
-
-  if (!omxFormat) {
-    NS_WARNING("Unknown color format");
-    return nullptr;
-  }
-
-  RefPtr<gfx::DataSourceSurface> surface
-    = gfx::Factory::CreateDataSourceSurface(GetSize(), gfx::SurfaceFormat::R5G6B5);
-
-  uint32_t width = GetSize().width;
-  uint32_t height = GetSize().height;
+  RefPtr<gfx::DataSourceSurface> surface =
+    gfx::Factory::CreateDataSourceSurface(GetSize(), gfx::SurfaceFormat::R5G6B5);
 
   gfx::DataSourceSurface::MappedSurface mappedSurface;
   if (!surface->Map(gfx::DataSourceSurface::WRITE, &mappedSurface)) {
     NS_WARNING("Could not map DataSourceSurface");
     return nullptr;
   }
 
-  if (format == HAL_PIXEL_FORMAT_YCrCb_420_SP_ADRENO) {
-    // The Adreno hardware decoder aligns image dimensions to a multiple of 32,
-    // so we have to account for that here
-    uint32_t alignedWidth = ALIGN(width, 32);
-    uint32_t alignedHeight = ALIGN(height, 32);
-    uint32_t uvOffset = ALIGN(alignedHeight * alignedWidth, 4096);
-    uint32_t uvStride = 2 * ALIGN(width / 2, 32);
-    uint8_t* buffer_as_bytes = static_cast<uint8_t*>(buffer);
-    ConvertYVU420SPToRGB565(buffer, alignedWidth,
-                            buffer_as_bytes + uvOffset, uvStride,
-                            mappedSurface.mData,
-                            width, height);
+  int32_t rv;
+  uint32_t omxFormat = 0;
 
+  omxFormat = GrallocImage::GetOmxFormat(graphicBuffer->getPixelFormat());
+  if (!omxFormat) {
+    rv = ConvertVendorYUVFormatToRGB565(graphicBuffer, surface, &mappedSurface);
     surface->Unmap();
-    return surface;
-  }
 
-  if (format == HAL_PIXEL_FORMAT_YCrCb_420_SP) {
-    uint32_t uvOffset = height * width;
-    ConvertYVU420SPToRGB565(buffer, width,
-                            buffer + uvOffset, width,
-                            mappedSurface.mData,
-                            width, height);
+    if (rv != OK) {
+      NS_WARNING("Unknown color format");
+      return nullptr;
+    }
 
-    surface->Unmap();
     return surface;
   }
 
-  if (format == HAL_PIXEL_FORMAT_YV12) {
-    gfx::ConvertYCbCrToRGB(mData,
-                           surface->GetFormat(),
-                           mSize,
-                           surface->GetData(),
-                           surface->Stride());
-    surface->Unmap();
-    return surface;
-  }
-
-  android::ColorConverter colorConverter((OMX_COLOR_FORMATTYPE)omxFormat,
-                                         OMX_COLOR_Format16bitRGB565);
-
-  if (!colorConverter.isValid()) {
-    NS_WARNING("Invalid color conversion");
-    surface->Unmap();
-    return nullptr;
-  }
-
-  rv = colorConverter.convert(buffer, width, height,
-                              0, 0, width - 1, height - 1 /* source crop */,
-                              mappedSurface.mData, width, height,
-                              0, 0, width - 1, height - 1 /* dest crop */);
-
+  rv = ConvertOmxYUVFormatToRGB565(graphicBuffer, surface, &mappedSurface, mData, omxFormat);
   surface->Unmap();
 
-  if (rv) {
-    NS_WARNING("OMX color conversion failed");
+  if (rv != OK) {
     return nullptr;
   }
 
   return surface;
 }
 
 android::sp<android::GraphicBuffer>
 GrallocImage::GetGraphicBuffer() const
--- a/gfx/layers/GrallocImages.h
+++ b/gfx/layers/GrallocImages.h
@@ -102,16 +102,30 @@ public:
     return static_cast<uint8_t*>(GetNativeBuffer());
   }
 
   int GetUsage()
   {
     return (static_cast<ANativeWindowBuffer*>(GetNativeBuffer()))->usage;
   }
 
+  static int GetOmxFormat(int aFormat)
+  {
+    uint32_t omxFormat = 0;
+
+    for (int i = 0; sColorIdMap[i]; i += 2) {
+      if (sColorIdMap[i] == aFormat) {
+        omxFormat = sColorIdMap[i + 1];
+        break;
+      }
+    }
+
+    return omxFormat;
+  }
+
 private:
   RefPtr<GrallocTextureClientOGL> mTextureClient;
 };
 
 } // namespace layers
 } // namespace mozilla
 #endif