Bug 1061525 - Part 6: Add readback code for converting NV12 MacIOSurfaces into RGB. r=nical
☠☠ backed out by 5ddf7484b5ea ☠ ☠
authorMatt Woodrow <mwoodrow@mozilla.com>
Mon, 03 Aug 2015 17:57:54 -0400
changeset 287652 5e90b9dab7facad69349e580c2d114a1288b6a5c
parent 287651 ef5ce3d6412aff37453bca8f02a42e46118d8aa8
child 287653 2f29812c4d49f58b6e73431f6c2c3832c3662822
push id5067
push userraliiev@mozilla.com
push dateMon, 21 Sep 2015 14:04:52 +0000
treeherdermozilla-beta@14221ffe5b2f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersnical
bugs1061525
milestone42.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 1061525 - Part 6: Add readback code for converting NV12 MacIOSurfaces into RGB. r=nical
gfx/layers/MacIOSurfaceImage.cpp
--- a/gfx/layers/MacIOSurfaceImage.cpp
+++ b/gfx/layers/MacIOSurfaceImage.cpp
@@ -2,54 +2,102 @@
  * 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 "MacIOSurfaceImage.h"
 #include "mozilla/layers/CompositableClient.h"
 #include "mozilla/layers/CompositableForwarder.h"
 #include "mozilla/layers/MacIOSurfaceTextureClientOGL.h"
+#include "YCbCrUtils.h"
 
 using namespace mozilla;
 using namespace mozilla::layers;
+using namespace mozilla::gfx;
 
 TextureClient*
 MacIOSurfaceImage::GetTextureClient(CompositableClient* aClient)
 {
   if (!mTextureClient) {
     mTextureClient = MacIOSurfaceTextureClientOGL::Create(aClient->GetForwarder(),
                                                           TextureFlags::DEFAULT,
                                                           mSurface);
   }
   return mTextureClient;
 }
 
-already_AddRefed<gfx::SourceSurface>
+already_AddRefed<SourceSurface>
 MacIOSurfaceImage::GetAsSourceSurface()
 {
+  RefPtr<DataSourceSurface> dataSurface;
   mSurface->Lock();
   size_t bytesPerRow = mSurface->GetBytesPerRow();
   size_t ioWidth = mSurface->GetDevicePixelWidth();
   size_t ioHeight = mSurface->GetDevicePixelHeight();
 
-  unsigned char* ioData = (unsigned char*)mSurface->GetBaseAddress();
+  SurfaceFormat format = mSurface->GetFormat() == SurfaceFormat::NV12 ? SurfaceFormat::B8G8R8X8 : SurfaceFormat::B8G8R8A8;
 
-  RefPtr<gfx::DataSourceSurface> dataSurface
-    = gfx::Factory::CreateDataSourceSurface(gfx::IntSize(ioWidth, ioHeight), gfx::SurfaceFormat::B8G8R8A8);
+  dataSurface = Factory::CreateDataSourceSurface(IntSize(ioWidth, ioHeight), format);
   if (NS_WARN_IF(!dataSurface)) {
     return nullptr;
   }
 
-  gfx::DataSourceSurface::MappedSurface mappedSurface;
-  if (!dataSurface->Map(gfx::DataSourceSurface::WRITE, &mappedSurface))
+  DataSourceSurface::MappedSurface mappedSurface;
+  if (!dataSurface->Map(DataSourceSurface::WRITE, &mappedSurface))
     return nullptr;
 
-  for (size_t i = 0; i < ioHeight; ++i) {
-    memcpy(mappedSurface.mData + i * mappedSurface.mStride,
-           ioData + i * bytesPerRow,
-           ioWidth * 4);
+  if (mSurface->GetFormat() == SurfaceFormat::NV12) {
+    if (mSurface->GetDevicePixelWidth() > PlanarYCbCrImage::MAX_DIMENSION ||
+        mSurface->GetDevicePixelHeight() > PlanarYCbCrImage::MAX_DIMENSION) {
+      return nullptr;
+    }
+
+    /* Extract and separate the CbCr planes */
+    size_t cbCrStride = mSurface->GetBytesPerRow(1);
+    size_t cbCrWidth = mSurface->GetDevicePixelWidth(1);
+    size_t cbCrHeight = mSurface->GetDevicePixelHeight(1);
+
+    nsAutoArrayPtr<uint8_t> cbPlane(new uint8_t[cbCrWidth * cbCrHeight]);
+    nsAutoArrayPtr<uint8_t> crPlane(new uint8_t[cbCrWidth * cbCrHeight]);
+
+    uint8_t* src = (uint8_t*)mSurface->GetBaseAddressOfPlane(1);
+    uint8_t* cbDest = cbPlane;
+    uint8_t* crDest = crPlane;
+
+    for (size_t i = 0; i < cbCrHeight; i++) {
+      uint8_t* rowSrc = src + cbCrStride * i;
+      for (size_t j = 0; j < cbCrWidth; j++) {
+        *cbDest = *rowSrc;
+        cbDest++;
+        rowSrc++;
+        *crDest = *rowSrc;
+        crDest++;
+        rowSrc++;
+      }
+    }
+
+    /* Convert to RGB */
+    PlanarYCbCrData data;
+    data.mYChannel = (uint8_t*)mSurface->GetBaseAddressOfPlane(0);
+    data.mYStride = mSurface->GetBytesPerRow(0);
+    data.mYSize = IntSize(mSurface->GetDevicePixelWidth(0), mSurface->GetDevicePixelHeight(0));
+    data.mCbChannel = cbPlane;
+    data.mCrChannel = crPlane;
+    data.mCbCrStride = cbCrWidth;
+    data.mCbCrSize = IntSize(cbCrWidth, cbCrHeight);
+    data.mPicSize = data.mYSize;
+
+    ConvertYCbCrToRGB(data, SurfaceFormat::B8G8R8X8, IntSize(ioWidth, ioHeight), mappedSurface.mData, mappedSurface.mStride);
+  } else {
+    unsigned char* ioData = (unsigned char*)mSurface->GetBaseAddress();
+
+    for (size_t i = 0; i < ioHeight; ++i) {
+      memcpy(mappedSurface.mData + i * mappedSurface.mStride,
+             ioData + i * bytesPerRow,
+             ioWidth * 4);
+    }
   }
 
   dataSurface->Unmap();
   mSurface->Unlock();
 
   return dataSurface.forget();
 }