Bug 1248323: P2. Add readback code for converting YUV422 MacIOSurfaces into RGB. r=nical
authorJean-Yves Avenard <jyavenard@mozilla.com>
Tue, 23 Feb 2016 23:47:29 +1100
changeset 321871 a8677612e6581ee1c6fb97d3b23156d98ade51e7
parent 321870 bb4b4249dda8b5372bac11bb36a8b3bf4c44f6c5
child 321872 95471e032d564b0db816f2894a68ff915612e476
push id5913
push userjlund@mozilla.com
push dateMon, 25 Apr 2016 16:57:49 +0000
treeherdermozilla-beta@dcaf0a6fa115 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersnical
bugs1248323
milestone47.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 1248323: P2. Add readback code for converting YUV422 MacIOSurfaces into RGB. r=nical MozReview-Commit-ID: 4jhP5fgXZhq
gfx/layers/MacIOSurfaceHelpers.cpp
--- a/gfx/layers/MacIOSurfaceHelpers.cpp
+++ b/gfx/layers/MacIOSurfaceHelpers.cpp
@@ -8,31 +8,37 @@
 #include "YCbCrUtils.h"
 
 namespace mozilla {
 
 using namespace gfx;
 
 namespace layers {
 
+#define ALIGNED_32(x) ((x+31)&~31)
+#define ALIGNEDPTR_32(x) reinterpret_cast<uint8_t*>((reinterpret_cast<uintptr_t>(x)+31)&~31)
+
 static already_AddRefed<SourceSurface>
 CreateSourceSurfaceFromLockedMacIOSurface(MacIOSurface* aSurface)
 {
   size_t bytesPerRow = aSurface->GetBytesPerRow();
   size_t ioWidth = aSurface->GetDevicePixelWidth();
   size_t ioHeight = aSurface->GetDevicePixelHeight();
   SurfaceFormat ioFormat = aSurface->GetFormat();
 
-  if (ioFormat == SurfaceFormat::NV12 &&
+  if ((ioFormat == SurfaceFormat::NV12 || ioFormat == SurfaceFormat::YUV422) &&
       (ioWidth > PlanarYCbCrImage::MAX_DIMENSION ||
        ioHeight > PlanarYCbCrImage::MAX_DIMENSION)) {
     return nullptr;
   }
 
-  SurfaceFormat format = ioFormat == SurfaceFormat::NV12 ? SurfaceFormat::B8G8R8X8 : SurfaceFormat::B8G8R8A8;
+  SurfaceFormat format =
+    (ioFormat == SurfaceFormat::NV12 || ioFormat == SurfaceFormat::YUV422)
+      ? SurfaceFormat::B8G8R8X8
+      : SurfaceFormat::B8G8R8A8;
 
   RefPtr<DataSourceSurface> dataSurface =
     Factory::CreateDataSourceSurface(IntSize(ioWidth, ioHeight), format);
   if (NS_WARN_IF(!dataSurface)) {
     return nullptr;
   }
 
   DataSourceSurface::MappedSurface mappedSurface;
@@ -64,24 +70,77 @@ CreateSourceSurfaceFromLockedMacIOSurfac
         rowSrc++;
       }
     }
 
     /* Convert to RGB */
     PlanarYCbCrData data;
     data.mYChannel = (uint8_t*)aSurface->GetBaseAddressOfPlane(0);
     data.mYStride = aSurface->GetBytesPerRow(0);
-    data.mYSize = IntSize(aSurface->GetDevicePixelWidth(0), aSurface->GetDevicePixelHeight(0));
+    data.mYSize = IntSize(ioWidth, ioHeight);
     data.mCbChannel = cbPlane.get();
     data.mCrChannel = crPlane.get();
     data.mCbCrStride = cbCrWidth;
     data.mCbCrSize = IntSize(cbCrWidth, cbCrHeight);
     data.mPicSize = data.mYSize;
 
     ConvertYCbCrToRGB(data, SurfaceFormat::B8G8R8X8, IntSize(ioWidth, ioHeight), mappedSurface.mData, mappedSurface.mStride);
+  } else if (ioFormat == SurfaceFormat::YUV422) {
+    /* Convert to YV16 */
+    size_t cbCrWidth = (ioWidth+1)>>1;
+    size_t cbCrHeight = ioHeight;
+    // Ensure our stride is a multiple of 32 to allow for memory aligned rows.
+    size_t cbCrStride = ALIGNED_32(cbCrWidth);
+    size_t strideDelta = cbCrStride - cbCrWidth;
+    MOZ_ASSERT(strideDelta <= 31);
+
+    auto yPlane = MakeUnique<uint8_t[]>(cbCrStride * 2 * ioHeight + 31);
+    auto cbPlane = MakeUnique<uint8_t[]>(cbCrStride * cbCrHeight + 31);
+    auto crPlane = MakeUnique<uint8_t[]>(cbCrStride * cbCrHeight + 31);
+
+    uint8_t* src = (uint8_t*)aSurface->GetBaseAddress();
+    uint8_t* yDest = ALIGNEDPTR_32(yPlane.get());
+    uint8_t* cbDest = ALIGNEDPTR_32(cbPlane.get());
+    uint8_t* crDest = ALIGNEDPTR_32(crPlane.get());
+
+    for (size_t i = 0; i < ioHeight; i++) {
+      uint8_t* rowSrc = src + bytesPerRow * i;
+      for (size_t j = 0; j < cbCrWidth; j++) {
+        *cbDest = *rowSrc;
+        cbDest++;
+        rowSrc++;
+        *yDest = *rowSrc;
+        yDest++;
+        rowSrc++;
+        *crDest = *rowSrc;
+        crDest++;
+        rowSrc++;
+        *yDest = *rowSrc;
+        yDest++;
+        rowSrc++;
+      }
+      if (strideDelta) {
+        cbDest += strideDelta;
+        crDest += strideDelta;
+        yDest  += strideDelta << 1;
+      }
+    }
+
+    /* Convert to RGB */
+    PlanarYCbCrData data;
+    data.mYChannel = ALIGNEDPTR_32(yPlane.get());
+    data.mYStride = cbCrStride * 2;
+    data.mYSize = IntSize(ioWidth, ioHeight);
+    data.mCbChannel = ALIGNEDPTR_32(cbPlane.get());
+    data.mCrChannel = ALIGNEDPTR_32(crPlane.get());
+    data.mCbCrStride = cbCrStride;
+    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*)aSurface->GetBaseAddress();
 
     for (size_t i = 0; i < ioHeight; ++i) {
       memcpy(mappedSurface.mData + i * mappedSurface.mStride,
              ioData + i * bytesPerRow,
              ioWidth * 4);
     }