Bug 1248323: P2. Add readback code for converting YUV422 MacIOSurfaces into RGB. r=nical draft
authorJean-Yves Avenard <jyavenard@mozilla.com>
Tue, 23 Feb 2016 23:47:29 +1100
changeset 334390 0f63c1399f08a1d02c6baa7fc105a4f3196b5808
parent 334389 66c569e6e44c9dd041e85a0ccec84cc6dbb1edb1
child 334391 4a3deb022f5a34e411cd1c73b479c58362d8bd32
push id11531
push userbmo:jyavenard@mozilla.com
push dateThu, 25 Feb 2016 03:18:04 +0000
reviewersnical
bugs1248323
milestone47.0a1
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);
     }