michael@0: /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- michael@0: * This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include "gfx2DGlue.h" michael@0: michael@0: #include "YCbCrUtils.h" michael@0: #include "yuv_convert.h" michael@0: #include "ycbcr_to_rgb565.h" michael@0: michael@0: namespace mozilla { michael@0: namespace gfx { michael@0: michael@0: void michael@0: GetYCbCrToRGBDestFormatAndSize(const layers::PlanarYCbCrData& aData, michael@0: SurfaceFormat& aSuggestedFormat, michael@0: IntSize& aSuggestedSize) michael@0: { michael@0: YUVType yuvtype = michael@0: TypeFromSize(aData.mYSize.width, michael@0: aData.mYSize.height, michael@0: aData.mCbCrSize.width, michael@0: aData.mCbCrSize.height); michael@0: michael@0: // 'prescale' is true if the scaling is to be done as part of the michael@0: // YCbCr to RGB conversion rather than on the RGB data when rendered. michael@0: bool prescale = aSuggestedSize.width > 0 && aSuggestedSize.height > 0 && michael@0: aSuggestedSize != aData.mPicSize; michael@0: michael@0: if (aSuggestedFormat == SurfaceFormat::R5G6B5) { michael@0: #if defined(HAVE_YCBCR_TO_RGB565) michael@0: if (prescale && michael@0: !IsScaleYCbCrToRGB565Fast(aData.mPicX, michael@0: aData.mPicY, michael@0: aData.mPicSize.width, michael@0: aData.mPicSize.height, michael@0: aSuggestedSize.width, michael@0: aSuggestedSize.height, michael@0: yuvtype, michael@0: FILTER_BILINEAR) && michael@0: IsConvertYCbCrToRGB565Fast(aData.mPicX, michael@0: aData.mPicY, michael@0: aData.mPicSize.width, michael@0: aData.mPicSize.height, michael@0: yuvtype)) { michael@0: prescale = false; michael@0: } michael@0: #else michael@0: // yuv2rgb16 function not available michael@0: aSuggestedFormat = SurfaceFormat::B8G8R8X8; michael@0: #endif michael@0: } michael@0: else if (aSuggestedFormat != SurfaceFormat::B8G8R8X8) { michael@0: // No other formats are currently supported. michael@0: aSuggestedFormat = SurfaceFormat::B8G8R8X8; michael@0: } michael@0: if (aSuggestedFormat == SurfaceFormat::B8G8R8X8) { michael@0: /* ScaleYCbCrToRGB32 does not support a picture offset, nor 4:4:4 data. michael@0: See bugs 639415 and 640073. */ michael@0: if (aData.mPicX != 0 || aData.mPicY != 0 || yuvtype == YV24) michael@0: prescale = false; michael@0: } michael@0: if (!prescale) { michael@0: aSuggestedSize = aData.mPicSize; michael@0: } michael@0: } michael@0: michael@0: void michael@0: ConvertYCbCrToRGB(const layers::PlanarYCbCrData& aData, michael@0: const SurfaceFormat& aDestFormat, michael@0: const IntSize& aDestSize, michael@0: unsigned char* aDestBuffer, michael@0: int32_t aStride) michael@0: { michael@0: // ConvertYCbCrToRGB et al. assume the chroma planes are rounded up if the michael@0: // luma plane is odd sized. michael@0: MOZ_ASSERT((aData.mCbCrSize.width == aData.mYSize.width || michael@0: aData.mCbCrSize.width == (aData.mYSize.width + 1) >> 1) && michael@0: (aData.mCbCrSize.height == aData.mYSize.height || michael@0: aData.mCbCrSize.height == (aData.mYSize.height + 1) >> 1)); michael@0: YUVType yuvtype = michael@0: TypeFromSize(aData.mYSize.width, michael@0: aData.mYSize.height, michael@0: aData.mCbCrSize.width, michael@0: aData.mCbCrSize.height); michael@0: michael@0: // Convert from YCbCr to RGB now, scaling the image if needed. michael@0: if (aDestSize != aData.mPicSize) { michael@0: #if defined(HAVE_YCBCR_TO_RGB565) michael@0: if (aDestFormat == SurfaceFormat::R5G6B5) { michael@0: ScaleYCbCrToRGB565(aData.mYChannel, michael@0: aData.mCbChannel, michael@0: aData.mCrChannel, michael@0: aDestBuffer, michael@0: aData.mPicX, michael@0: aData.mPicY, michael@0: aData.mPicSize.width, michael@0: aData.mPicSize.height, michael@0: aDestSize.width, michael@0: aDestSize.height, michael@0: aData.mYStride, michael@0: aData.mCbCrStride, michael@0: aStride, michael@0: yuvtype, michael@0: FILTER_BILINEAR); michael@0: } else michael@0: #endif michael@0: ScaleYCbCrToRGB32(aData.mYChannel, // michael@0: aData.mCbChannel, michael@0: aData.mCrChannel, michael@0: aDestBuffer, michael@0: aData.mPicSize.width, michael@0: aData.mPicSize.height, michael@0: aDestSize.width, michael@0: aDestSize.height, michael@0: aData.mYStride, michael@0: aData.mCbCrStride, michael@0: aStride, michael@0: yuvtype, michael@0: ROTATE_0, michael@0: FILTER_BILINEAR); michael@0: } else { // no prescale michael@0: #if defined(HAVE_YCBCR_TO_RGB565) michael@0: if (aDestFormat == SurfaceFormat::R5G6B5) { michael@0: ConvertYCbCrToRGB565(aData.mYChannel, michael@0: aData.mCbChannel, michael@0: aData.mCrChannel, michael@0: aDestBuffer, michael@0: aData.mPicX, michael@0: aData.mPicY, michael@0: aData.mPicSize.width, michael@0: aData.mPicSize.height, michael@0: aData.mYStride, michael@0: aData.mCbCrStride, michael@0: aStride, michael@0: yuvtype); michael@0: } else // aDestFormat != gfxImageFormat::RGB16_565 michael@0: #endif michael@0: ConvertYCbCrToRGB32(aData.mYChannel, // michael@0: aData.mCbChannel, michael@0: aData.mCrChannel, michael@0: aDestBuffer, michael@0: aData.mPicX, michael@0: aData.mPicY, michael@0: aData.mPicSize.width, michael@0: aData.mPicSize.height, michael@0: aData.mYStride, michael@0: aData.mCbCrStride, michael@0: aStride, michael@0: yuvtype); michael@0: } michael@0: } michael@0: michael@0: } michael@0: }