2013-07-30 13:59:51 +04:00
|
|
|
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
|
|
|
* 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/. */
|
|
|
|
|
2013-08-12 03:17:23 +04:00
|
|
|
#include "ImageDataSerializer.h"
|
|
|
|
#include "gfx2DGlue.h" // for SurfaceFormatToImageFormat
|
2015-05-29 18:01:46 +03:00
|
|
|
#include "mozilla/gfx/Point.h" // for IntSize
|
2013-08-12 03:17:23 +04:00
|
|
|
#include "mozilla/Assertions.h" // for MOZ_ASSERT, etc
|
|
|
|
#include "mozilla/gfx/2D.h" // for DataSourceSurface, Factory
|
2014-12-09 21:19:29 +03:00
|
|
|
#include "mozilla/gfx/Logging.h" // for gfxDebug
|
2013-08-12 03:17:23 +04:00
|
|
|
#include "mozilla/gfx/Tools.h" // for GetAlignedStride, etc
|
2015-12-16 21:50:58 +03:00
|
|
|
#include "mozilla/gfx/Types.h"
|
2013-08-12 03:17:23 +04:00
|
|
|
#include "mozilla/mozalloc.h" // for operator delete, etc
|
2016-05-17 12:14:54 +03:00
|
|
|
#include "YCbCrUtils.h" // for YCbCr conversions
|
2013-07-30 13:59:51 +04:00
|
|
|
|
|
|
|
namespace mozilla {
|
|
|
|
namespace layers {
|
2015-12-16 21:50:58 +03:00
|
|
|
namespace ImageDataSerializer {
|
2013-07-30 13:59:51 +04:00
|
|
|
|
2013-10-16 05:00:30 +04:00
|
|
|
using namespace gfx;
|
|
|
|
|
2015-12-16 21:50:58 +03:00
|
|
|
int32_t
|
|
|
|
ComputeRGBStride(SurfaceFormat aFormat, int32_t aWidth)
|
2013-08-26 08:13:22 +04:00
|
|
|
{
|
2016-08-25 20:57:39 +03:00
|
|
|
return GetAlignedStride<4>(aWidth, BytesPerPixel(aFormat));
|
2013-08-26 08:13:22 +04:00
|
|
|
}
|
|
|
|
|
2015-12-16 21:50:58 +03:00
|
|
|
int32_t
|
|
|
|
GetRGBStride(const RGBDescriptor& aDescriptor)
|
|
|
|
{
|
|
|
|
return ComputeRGBStride(aDescriptor.format(), aDescriptor.size().width);
|
|
|
|
}
|
|
|
|
|
2013-07-30 13:59:51 +04:00
|
|
|
uint32_t
|
2015-12-16 21:50:58 +03:00
|
|
|
ComputeRGBBufferSize(IntSize aSize, SurfaceFormat aFormat)
|
2013-07-30 13:59:51 +04:00
|
|
|
{
|
2014-12-09 21:19:29 +03:00
|
|
|
MOZ_ASSERT(aSize.height >= 0 && aSize.width >= 0);
|
2015-11-18 18:59:11 +03:00
|
|
|
|
|
|
|
// This takes care of checking whether there could be overflow
|
|
|
|
// with enough margin for the metadata.
|
|
|
|
if (!gfx::Factory::AllowedSurfaceSize(aSize)) {
|
2014-12-09 21:19:29 +03:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2016-08-25 20:57:39 +03:00
|
|
|
// Note we're passing height instad of the bpp parameter, but the end
|
|
|
|
// result is the same - and the bpp was already taken care of in the
|
|
|
|
// ComputeRGBStride function.
|
|
|
|
int32_t bufsize = GetAlignedStride<16>(ComputeRGBStride(aFormat, aSize.width),
|
|
|
|
aSize.height);
|
2014-12-09 21:19:29 +03:00
|
|
|
|
2015-11-18 18:59:11 +03:00
|
|
|
if (bufsize < 0) {
|
|
|
|
// This should not be possible thanks to Factory::AllowedSurfaceSize
|
2014-12-09 21:19:29 +03:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-11-18 18:59:11 +03:00
|
|
|
return bufsize;
|
2013-07-30 13:59:51 +04:00
|
|
|
}
|
|
|
|
|
2015-12-16 21:50:58 +03:00
|
|
|
|
|
|
|
|
|
|
|
// Minimum required shmem size in bytes
|
|
|
|
uint32_t
|
|
|
|
ComputeYCbCrBufferSize(const gfx::IntSize& aYSize, int32_t aYStride,
|
|
|
|
const gfx::IntSize& aCbCrSize, int32_t aCbCrStride)
|
2013-07-30 13:59:51 +04:00
|
|
|
{
|
2015-12-16 21:50:58 +03:00
|
|
|
MOZ_ASSERT(aYSize.height >= 0 && aYSize.width >= 0);
|
2015-11-18 18:59:11 +03:00
|
|
|
|
2015-12-16 21:50:58 +03:00
|
|
|
if (aYSize.height < 0 || aYSize.width < 0 || aCbCrSize.height < 0 || aCbCrSize.width < 0 ||
|
2016-01-08 17:10:27 +03:00
|
|
|
!gfx::Factory::AllowedSurfaceSize(IntSize(aYStride, aYSize.height)) ||
|
|
|
|
!gfx::Factory::AllowedSurfaceSize(IntSize(aCbCrStride, aCbCrSize.height))) {
|
2015-12-16 21:50:58 +03:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
// Overflow checks are performed in AllowedSurfaceSize
|
2016-08-25 20:57:39 +03:00
|
|
|
return GetAlignedStride<4>(aYSize.height, aYStride) +
|
|
|
|
2 * GetAlignedStride<4>(aCbCrSize.height, aCbCrStride);
|
2013-07-30 13:59:51 +04:00
|
|
|
}
|
|
|
|
|
2015-12-16 21:50:58 +03:00
|
|
|
// Minimum required shmem size in bytes
|
|
|
|
uint32_t
|
|
|
|
ComputeYCbCrBufferSize(const gfx::IntSize& aYSize, const gfx::IntSize& aCbCrSize)
|
2013-07-30 13:59:51 +04:00
|
|
|
{
|
2015-12-16 21:50:58 +03:00
|
|
|
return ComputeYCbCrBufferSize(aYSize, aYSize.width, aCbCrSize, aCbCrSize.width);
|
2013-07-30 13:59:51 +04:00
|
|
|
}
|
|
|
|
|
2013-10-16 05:00:30 +04:00
|
|
|
uint32_t
|
2015-12-16 21:50:58 +03:00
|
|
|
ComputeYCbCrBufferSize(uint32_t aBufferSize)
|
2013-10-16 05:00:30 +04:00
|
|
|
{
|
2016-08-25 20:57:39 +03:00
|
|
|
return GetAlignedStride<4>(aBufferSize, 1);
|
2013-10-16 05:00:30 +04:00
|
|
|
}
|
|
|
|
|
2015-12-16 21:50:58 +03:00
|
|
|
void ComputeYCbCrOffsets(int32_t yStride, int32_t yHeight,
|
|
|
|
int32_t cbCrStride, int32_t cbCrHeight,
|
2016-08-25 20:57:39 +03:00
|
|
|
uint32_t& outYOffset, uint32_t& outCbOffset,
|
|
|
|
uint32_t& outCrOffset)
|
2013-07-30 13:59:51 +04:00
|
|
|
{
|
2015-12-16 21:50:58 +03:00
|
|
|
outYOffset = 0;
|
2016-08-25 20:57:39 +03:00
|
|
|
outCbOffset = outYOffset + GetAlignedStride<4>(yStride, yHeight);
|
|
|
|
outCrOffset = outCbOffset + GetAlignedStride<4>(cbCrStride, cbCrHeight);
|
2013-07-30 13:59:51 +04:00
|
|
|
}
|
|
|
|
|
2015-12-16 21:50:58 +03:00
|
|
|
gfx::SurfaceFormat FormatFromBufferDescriptor(const BufferDescriptor& aDescriptor)
|
2013-07-30 13:59:51 +04:00
|
|
|
{
|
2015-12-16 21:50:58 +03:00
|
|
|
switch (aDescriptor.type()) {
|
|
|
|
case BufferDescriptor::TRGBDescriptor:
|
|
|
|
return aDescriptor.get_RGBDescriptor().format();
|
|
|
|
case BufferDescriptor::TYCbCrDescriptor:
|
|
|
|
return gfx::SurfaceFormat::YUV;
|
|
|
|
default:
|
2016-05-06 17:19:31 +03:00
|
|
|
MOZ_CRASH("GFX: FormatFromBufferDescriptor");
|
2015-12-16 21:50:58 +03:00
|
|
|
}
|
2013-07-30 13:59:51 +04:00
|
|
|
}
|
|
|
|
|
2015-12-16 21:50:58 +03:00
|
|
|
gfx::IntSize SizeFromBufferDescriptor(const BufferDescriptor& aDescriptor)
|
2013-10-16 05:00:30 +04:00
|
|
|
{
|
2015-12-16 21:50:58 +03:00
|
|
|
switch (aDescriptor.type()) {
|
|
|
|
case BufferDescriptor::TRGBDescriptor:
|
|
|
|
return aDescriptor.get_RGBDescriptor().size();
|
|
|
|
case BufferDescriptor::TYCbCrDescriptor:
|
|
|
|
return aDescriptor.get_YCbCrDescriptor().ySize();
|
|
|
|
default:
|
2016-05-06 17:19:31 +03:00
|
|
|
MOZ_CRASH("GFX: SizeFromBufferDescriptor");
|
2015-09-19 12:19:07 +03:00
|
|
|
}
|
2013-07-30 13:59:51 +04:00
|
|
|
}
|
|
|
|
|
2016-06-30 05:12:31 +03:00
|
|
|
Maybe<gfx::IntSize> CbCrSizeFromBufferDescriptor(const BufferDescriptor& aDescriptor)
|
|
|
|
{
|
|
|
|
switch (aDescriptor.type()) {
|
|
|
|
case BufferDescriptor::TRGBDescriptor:
|
|
|
|
return Nothing();
|
|
|
|
case BufferDescriptor::TYCbCrDescriptor:
|
|
|
|
return Some(aDescriptor.get_YCbCrDescriptor().cbCrSize());
|
|
|
|
default:
|
|
|
|
MOZ_CRASH("GFX: CbCrSizeFromBufferDescriptor");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-10-12 05:46:28 +03:00
|
|
|
Maybe<YUVColorSpace> YUVColorSpaceFromBufferDescriptor(const BufferDescriptor& aDescriptor)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
switch (aDescriptor.type()) {
|
|
|
|
case BufferDescriptor::TRGBDescriptor:
|
|
|
|
return Nothing();
|
|
|
|
case BufferDescriptor::TYCbCrDescriptor:
|
|
|
|
return Some(aDescriptor.get_YCbCrDescriptor().yUVColorSpace());
|
|
|
|
default:
|
|
|
|
MOZ_CRASH("GFX: CbCrSizeFromBufferDescriptor");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-06-30 05:12:31 +03:00
|
|
|
Maybe<StereoMode> StereoModeFromBufferDescriptor(const BufferDescriptor& aDescriptor)
|
|
|
|
{
|
|
|
|
switch (aDescriptor.type()) {
|
|
|
|
case BufferDescriptor::TRGBDescriptor:
|
|
|
|
return Nothing();
|
|
|
|
case BufferDescriptor::TYCbCrDescriptor:
|
|
|
|
return Some(aDescriptor.get_YCbCrDescriptor().stereoMode());
|
|
|
|
default:
|
|
|
|
MOZ_CRASH("GFX: CbCrSizeFromBufferDescriptor");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-12-16 21:50:58 +03:00
|
|
|
uint8_t* GetYChannel(uint8_t* aBuffer, const YCbCrDescriptor& aDescriptor)
|
|
|
|
{
|
|
|
|
return aBuffer + aDescriptor.yOffset();
|
|
|
|
}
|
|
|
|
|
|
|
|
uint8_t* GetCbChannel(uint8_t* aBuffer, const YCbCrDescriptor& aDescriptor)
|
|
|
|
{
|
|
|
|
return aBuffer + aDescriptor.cbOffset();
|
|
|
|
}
|
|
|
|
|
|
|
|
uint8_t* GetCrChannel(uint8_t* aBuffer, const YCbCrDescriptor& aDescriptor)
|
2013-07-30 13:59:51 +04:00
|
|
|
{
|
2015-12-16 21:50:58 +03:00
|
|
|
return aBuffer + aDescriptor.crOffset();
|
2013-07-30 13:59:51 +04:00
|
|
|
}
|
|
|
|
|
2015-12-16 21:50:58 +03:00
|
|
|
already_AddRefed<DataSourceSurface>
|
2016-07-09 04:59:59 +03:00
|
|
|
DataSourceSurfaceFromYCbCrDescriptor(uint8_t* aBuffer, const YCbCrDescriptor& aDescriptor, gfx::DataSourceSurface* aSurface)
|
2015-12-16 21:50:58 +03:00
|
|
|
{
|
|
|
|
gfx::IntSize ySize = aDescriptor.ySize();
|
|
|
|
gfx::IntSize cbCrSize = aDescriptor.cbCrSize();
|
|
|
|
int32_t yStride = ySize.width;
|
|
|
|
int32_t cbCrStride = cbCrSize.width;
|
|
|
|
|
2016-07-09 04:59:59 +03:00
|
|
|
RefPtr<DataSourceSurface> result;
|
|
|
|
if (aSurface) {
|
|
|
|
MOZ_ASSERT(aSurface->GetSize() == ySize);
|
|
|
|
MOZ_ASSERT(aSurface->GetFormat() == gfx::SurfaceFormat::B8G8R8X8);
|
|
|
|
if (aSurface->GetSize() == ySize &&
|
|
|
|
aSurface->GetFormat() == gfx::SurfaceFormat::B8G8R8X8) {
|
|
|
|
result = aSurface;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!result) {
|
|
|
|
result =
|
|
|
|
Factory::CreateDataSourceSurface(ySize, gfx::SurfaceFormat::B8G8R8X8);
|
|
|
|
}
|
2015-12-16 21:50:58 +03:00
|
|
|
if (NS_WARN_IF(!result)) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
DataSourceSurface::MappedSurface map;
|
|
|
|
if (NS_WARN_IF(!result->Map(DataSourceSurface::MapType::WRITE, &map))) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2016-05-17 12:14:54 +03:00
|
|
|
layers::PlanarYCbCrData ycbcrData;
|
|
|
|
ycbcrData.mYChannel = GetYChannel(aBuffer, aDescriptor);
|
|
|
|
ycbcrData.mYStride = yStride;
|
|
|
|
ycbcrData.mYSize = ySize;
|
|
|
|
ycbcrData.mCbChannel = GetCbChannel(aBuffer, aDescriptor);
|
|
|
|
ycbcrData.mCrChannel = GetCrChannel(aBuffer, aDescriptor);
|
|
|
|
ycbcrData.mCbCrStride = cbCrStride;
|
|
|
|
ycbcrData.mCbCrSize = cbCrSize;
|
|
|
|
ycbcrData.mPicSize = ySize;
|
2016-10-12 05:46:28 +03:00
|
|
|
ycbcrData.mYUVColorSpace = aDescriptor.yUVColorSpace();
|
2016-05-17 12:14:54 +03:00
|
|
|
|
|
|
|
gfx::ConvertYCbCrToRGB(ycbcrData,
|
|
|
|
gfx::SurfaceFormat::B8G8R8X8,
|
|
|
|
ySize,
|
|
|
|
map.mData,
|
|
|
|
map.mStride);
|
|
|
|
|
2015-12-16 21:50:58 +03:00
|
|
|
result->Unmap();
|
|
|
|
return result.forget();
|
|
|
|
}
|
|
|
|
|
2016-08-16 04:54:17 +03:00
|
|
|
void
|
|
|
|
ConvertAndScaleFromYCbCrDescriptor(uint8_t* aBuffer,
|
|
|
|
const YCbCrDescriptor& aDescriptor,
|
|
|
|
const gfx::SurfaceFormat& aDestFormat,
|
|
|
|
const gfx::IntSize& aDestSize,
|
|
|
|
unsigned char* aDestBuffer,
|
|
|
|
int32_t aStride)
|
|
|
|
{
|
|
|
|
MOZ_ASSERT(aBuffer);
|
|
|
|
gfx::IntSize ySize = aDescriptor.ySize();
|
|
|
|
gfx::IntSize cbCrSize = aDescriptor.cbCrSize();
|
|
|
|
int32_t yStride = ySize.width;
|
|
|
|
int32_t cbCrStride = cbCrSize.width;
|
|
|
|
|
|
|
|
layers::PlanarYCbCrData ycbcrData;
|
|
|
|
ycbcrData.mYChannel = GetYChannel(aBuffer, aDescriptor);
|
|
|
|
ycbcrData.mYStride = yStride;
|
|
|
|
ycbcrData.mYSize = ySize;
|
|
|
|
ycbcrData.mCbChannel = GetCbChannel(aBuffer, aDescriptor);
|
|
|
|
ycbcrData.mCrChannel = GetCrChannel(aBuffer, aDescriptor);
|
|
|
|
ycbcrData.mCbCrStride = cbCrStride;
|
|
|
|
ycbcrData.mCbCrSize = cbCrSize;
|
|
|
|
ycbcrData.mPicSize = ySize;
|
2016-10-12 05:46:28 +03:00
|
|
|
ycbcrData.mYUVColorSpace = aDescriptor.yUVColorSpace();
|
2016-08-16 04:54:17 +03:00
|
|
|
|
|
|
|
gfx::ConvertYCbCrToRGB(ycbcrData, aDestFormat, aDestSize, aDestBuffer, aStride);
|
|
|
|
}
|
2015-12-16 21:50:58 +03:00
|
|
|
|
|
|
|
} // namespace ImageDataSerializer
|
2013-07-30 13:59:51 +04:00
|
|
|
} // namespace layers
|
|
|
|
} // namespace mozilla
|