Bug 1248323: P2. Add readback code for converting YUV422 MacIOSurfaces into RGB. r=nical
MozReview-Commit-ID: 4jhP5fgXZhq
--- 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);
}