зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1141979 - part7 - implement ImageUtils; r=jrmuizel
MozReview-Commit-ID: INrfdqBr4m4 --HG-- extra : transplant_source : %A2%9B%B0%C3%DEX%5B%DCW%7D%94%C1Ao%04A2%E6i%FD
This commit is contained in:
Родитель
17bc76bcc6
Коммит
c4341b59cc
|
@ -0,0 +1,291 @@
|
||||||
|
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||||
|
/* vim:set ts=2 sw=2 sts=2 et cindent: */
|
||||||
|
/* 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/. */
|
||||||
|
|
||||||
|
#include "ImageUtils.h"
|
||||||
|
#include "ImageBitmapUtils.h"
|
||||||
|
#include "ImageContainer.h"
|
||||||
|
#include "mozilla/AlreadyAddRefed.h"
|
||||||
|
#include "mozilla/dom/ImageBitmapBinding.h"
|
||||||
|
#include "mozilla/ErrorResult.h"
|
||||||
|
|
||||||
|
using namespace mozilla::layers;
|
||||||
|
using namespace mozilla::gfx;
|
||||||
|
|
||||||
|
namespace mozilla {
|
||||||
|
namespace dom {
|
||||||
|
|
||||||
|
static ImageBitmapFormat
|
||||||
|
GetImageBitmapFormatFromSurfaceFromat(SurfaceFormat aSurfaceFormat)
|
||||||
|
{
|
||||||
|
switch (aSurfaceFormat) {
|
||||||
|
case SurfaceFormat::B8G8R8A8:
|
||||||
|
case SurfaceFormat::B8G8R8X8:
|
||||||
|
return ImageBitmapFormat::BGRA32;
|
||||||
|
case SurfaceFormat::R8G8B8A8:
|
||||||
|
case SurfaceFormat::R8G8B8X8:
|
||||||
|
return ImageBitmapFormat::RGBA32;
|
||||||
|
case SurfaceFormat::R8G8B8:
|
||||||
|
return ImageBitmapFormat::RGB24;
|
||||||
|
case SurfaceFormat::B8G8R8:
|
||||||
|
return ImageBitmapFormat::BGR24;
|
||||||
|
case SurfaceFormat::HSV:
|
||||||
|
return ImageBitmapFormat::HSV;
|
||||||
|
case SurfaceFormat::Lab:
|
||||||
|
return ImageBitmapFormat::Lab;
|
||||||
|
case SurfaceFormat::Depth:
|
||||||
|
return ImageBitmapFormat::DEPTH;
|
||||||
|
case SurfaceFormat::A8:
|
||||||
|
return ImageBitmapFormat::GRAY8;
|
||||||
|
case SurfaceFormat::R5G6B5_UINT16:
|
||||||
|
case SurfaceFormat::YUV:
|
||||||
|
case SurfaceFormat::NV12:
|
||||||
|
case SurfaceFormat::UNKNOWN:
|
||||||
|
default:
|
||||||
|
return ImageBitmapFormat::EndGuard_;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static ImageBitmapFormat
|
||||||
|
GetImageBitmapFormatFromPlanarYCbCrData(layers::PlanarYCbCrData const *aData)
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(aData);
|
||||||
|
|
||||||
|
if (aData->mYSkip == 0 && aData->mCbSkip == 0 && aData->mCrSkip == 0) { // Possibly three planes.
|
||||||
|
if (aData->mCbChannel >= aData->mYChannel + aData->mYSize.height * aData->mYStride &&
|
||||||
|
aData->mCrChannel >= aData->mCbChannel + aData->mCbCrSize.height * aData->mCbCrStride) { // Three planes.
|
||||||
|
if (aData->mYSize.height == aData->mCbCrSize.height) {
|
||||||
|
if (aData->mYSize.width == aData->mCbCrSize.width) {
|
||||||
|
return ImageBitmapFormat::YUV444P;
|
||||||
|
} else if (((aData->mYSize.width + 1) / 2) == aData->mCbCrSize.width) {
|
||||||
|
return ImageBitmapFormat::YUV422P;
|
||||||
|
}
|
||||||
|
} else if (((aData->mYSize.height + 1) / 2) == aData->mCbCrSize.height) {
|
||||||
|
if (((aData->mYSize.width + 1) / 2) == aData->mCbCrSize.width) {
|
||||||
|
return ImageBitmapFormat::YUV420P;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (aData->mYSkip == 0 && aData->mCbSkip == 1 && aData->mCrSkip == 1) { // Possibly two planes.
|
||||||
|
if (aData->mCbChannel >= aData->mYChannel + aData->mYSize.height * aData->mYStride &&
|
||||||
|
aData->mCbChannel == aData->mCrChannel - 1) { // Two planes.
|
||||||
|
if (((aData->mYSize.height + 1) / 2) == aData->mCbCrSize.height &&
|
||||||
|
((aData->mYSize.width + 1) / 2) == aData->mCbCrSize.width) {
|
||||||
|
return ImageBitmapFormat::YUV420SP_NV12; // Y-Cb-Cr
|
||||||
|
}
|
||||||
|
} else if (aData->mCrChannel >= aData->mYChannel + aData->mYSize.height * aData->mYStride &&
|
||||||
|
aData->mCrChannel == aData->mCbChannel - 1) { // Two planes.
|
||||||
|
if (((aData->mYSize.height + 1) / 2) == aData->mCbCrSize.height &&
|
||||||
|
((aData->mYSize.width + 1) / 2) == aData->mCbCrSize.width) {
|
||||||
|
return ImageBitmapFormat::YUV420SP_NV21; // Y-Cr-Cb
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ImageBitmapFormat::EndGuard_;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ImageUtils::Impl implements the _generic_ algorithm which always readback
|
||||||
|
// data in RGBA format into CPU memory.
|
||||||
|
// Since layers::CairoImage is just a warpper to a DataSourceSurface, the
|
||||||
|
// implementation of CairoSurfaceImpl is nothing different to the generic
|
||||||
|
// version.
|
||||||
|
class ImageUtils::Impl
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit Impl(layers::Image* aImage)
|
||||||
|
: mImage(aImage)
|
||||||
|
, mSurface(nullptr)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual ~Impl()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual ImageBitmapFormat
|
||||||
|
GetFormat() const
|
||||||
|
{
|
||||||
|
return GetImageBitmapFormatFromSurfaceFromat(Surface()->GetFormat());
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual uint32_t
|
||||||
|
GetBufferLength() const
|
||||||
|
{
|
||||||
|
const uint32_t stride = Surface()->Stride();
|
||||||
|
const IntSize size = Surface()->GetSize();
|
||||||
|
return (uint32_t)(size.height * stride);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual UniquePtr<ImagePixelLayout>
|
||||||
|
MapDataInto(uint8_t* aBuffer,
|
||||||
|
uint32_t aOffset,
|
||||||
|
uint32_t aBufferLength,
|
||||||
|
ImageBitmapFormat aFormat,
|
||||||
|
ErrorResult& aRv) const
|
||||||
|
{
|
||||||
|
DataSourceSurface::ScopedMap map(Surface(), DataSourceSurface::READ);
|
||||||
|
if (!map.IsMapped()) {
|
||||||
|
aRv.Throw(NS_ERROR_ILLEGAL_VALUE);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy or convert data.
|
||||||
|
UniquePtr<ImagePixelLayout> srcLayout =
|
||||||
|
CreateDefaultPixelLayout(GetFormat(), Surface()->GetSize().width,
|
||||||
|
Surface()->GetSize().height, map.GetStride());
|
||||||
|
|
||||||
|
// Prepare destination buffer.
|
||||||
|
uint8_t* dstBuffer = aBuffer + aOffset;
|
||||||
|
UniquePtr<ImagePixelLayout> dstLayout =
|
||||||
|
CopyAndConvertImageData(GetFormat(), map.GetData(), srcLayout.get(),
|
||||||
|
aFormat, dstBuffer);
|
||||||
|
|
||||||
|
if (!dstLayout) {
|
||||||
|
aRv.Throw(NS_ERROR_NOT_AVAILABLE);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return dstLayout;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
Impl() {}
|
||||||
|
|
||||||
|
DataSourceSurface* Surface() const
|
||||||
|
{
|
||||||
|
if (!mSurface) {
|
||||||
|
RefPtr<SourceSurface> surface = mImage->GetAsSourceSurface();
|
||||||
|
MOZ_ASSERT(surface);
|
||||||
|
|
||||||
|
mSurface = surface->GetDataSurface();
|
||||||
|
MOZ_ASSERT(mSurface);
|
||||||
|
}
|
||||||
|
|
||||||
|
return mSurface.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
RefPtr<layers::Image> mImage;
|
||||||
|
mutable RefPtr<DataSourceSurface> mSurface;
|
||||||
|
};
|
||||||
|
|
||||||
|
// YUVImpl is optimized for the layers::PlanarYCbCrImage and layers::NVImage.
|
||||||
|
// This implementation does not readback data in RGBA format but keep it in YUV
|
||||||
|
// format family.
|
||||||
|
class YUVImpl final : public ImageUtils::Impl
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit YUVImpl(layers::Image* aImage)
|
||||||
|
: Impl(aImage)
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(aImage->GetFormat() == ImageFormat::PLANAR_YCBCR ||
|
||||||
|
aImage->GetFormat() == ImageFormat::NV_IMAGE);
|
||||||
|
}
|
||||||
|
|
||||||
|
ImageBitmapFormat GetFormat() const override
|
||||||
|
{
|
||||||
|
return GetImageBitmapFormatFromPlanarYCbCrData(GetPlanarYCbCrData());
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t GetBufferLength() const override
|
||||||
|
{
|
||||||
|
if (mImage->GetFormat() == ImageFormat::PLANAR_YCBCR) {
|
||||||
|
return mImage->AsPlanarYCbCrImage()->GetDataSize();
|
||||||
|
} else {
|
||||||
|
return mImage->AsNVImage()->GetBufferSize();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
UniquePtr<ImagePixelLayout>
|
||||||
|
MapDataInto(uint8_t* aBuffer,
|
||||||
|
uint32_t aOffset,
|
||||||
|
uint32_t aBufferLength,
|
||||||
|
ImageBitmapFormat aFormat,
|
||||||
|
ErrorResult& aRv) const override
|
||||||
|
{
|
||||||
|
// Prepare source buffer and pixel layout.
|
||||||
|
const PlanarYCbCrData* data = GetPlanarYCbCrData();
|
||||||
|
|
||||||
|
UniquePtr<ImagePixelLayout> srcLayout =
|
||||||
|
CreatePixelLayoutFromPlanarYCbCrData(data);
|
||||||
|
|
||||||
|
// Do conversion.
|
||||||
|
UniquePtr<ImagePixelLayout> dstLayout =
|
||||||
|
CopyAndConvertImageData(GetFormat(), data->mYChannel, srcLayout.get(),
|
||||||
|
aFormat, aBuffer+aOffset);
|
||||||
|
|
||||||
|
if (!dstLayout) {
|
||||||
|
aRv.Throw(NS_ERROR_NOT_AVAILABLE);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return dstLayout;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
const PlanarYCbCrData* GetPlanarYCbCrData() const
|
||||||
|
{
|
||||||
|
if (mImage->GetFormat() == ImageFormat::PLANAR_YCBCR) {
|
||||||
|
return mImage->AsPlanarYCbCrImage()->GetData();
|
||||||
|
} else {
|
||||||
|
return mImage->AsNVImage()->GetData();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// TODO: optimize for other platforms.
|
||||||
|
// For GONK: implement GrallocImageImpl, GrallocPlanarYCbCrImpl and GonkCameraImpl.
|
||||||
|
// For Windows: implement D3D9RGB32TextureImpl and D3D11ShareHandleTextureImpl.
|
||||||
|
// Others: SharedBGRImpl, MACIOSrufaceImpl, GLImageImpl, SurfaceTextureImpl
|
||||||
|
// EGLImageImpl and OverlayImegImpl.
|
||||||
|
|
||||||
|
ImageUtils::ImageUtils(layers::Image* aImage)
|
||||||
|
: mImpl(nullptr)
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(aImage, "Create ImageUtils with nullptr.");
|
||||||
|
switch(aImage->GetFormat()) {
|
||||||
|
case mozilla::ImageFormat::PLANAR_YCBCR:
|
||||||
|
case mozilla::ImageFormat::NV_IMAGE:
|
||||||
|
mImpl = new YUVImpl(aImage);
|
||||||
|
break;
|
||||||
|
case mozilla::ImageFormat::CAIRO_SURFACE:
|
||||||
|
default:
|
||||||
|
mImpl = new Impl(aImage);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ImageUtils::~ImageUtils()
|
||||||
|
{
|
||||||
|
if (mImpl) { delete mImpl; mImpl = nullptr; }
|
||||||
|
}
|
||||||
|
|
||||||
|
ImageBitmapFormat
|
||||||
|
ImageUtils::GetFormat() const
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(mImpl);
|
||||||
|
return mImpl->GetFormat();
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t
|
||||||
|
ImageUtils::GetBufferLength() const
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(mImpl);
|
||||||
|
return mImpl->GetBufferLength();
|
||||||
|
}
|
||||||
|
|
||||||
|
UniquePtr<ImagePixelLayout>
|
||||||
|
ImageUtils::MapDataInto(uint8_t* aBuffer,
|
||||||
|
uint32_t aOffset,
|
||||||
|
uint32_t aBufferLength,
|
||||||
|
ImageBitmapFormat aFormat,
|
||||||
|
ErrorResult& aRv) const
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(mImpl);
|
||||||
|
MOZ_ASSERT(aBuffer, "Map data into a null buffer.");
|
||||||
|
return mImpl->MapDataInto(aBuffer, aOffset, aBufferLength, aFormat, aRv);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace dom
|
||||||
|
} // namespace mozilla
|
|
@ -0,0 +1,73 @@
|
||||||
|
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||||
|
/* vim:set ts=2 sw=2 sts=2 et cindent: */
|
||||||
|
/* 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/. */
|
||||||
|
|
||||||
|
#ifndef mozilla_dom_ImageBitmapFormatUtils_h
|
||||||
|
#define mozilla_dom_ImageBitmapFormatUtils_h
|
||||||
|
|
||||||
|
#include "mozilla/UniquePtr.h"
|
||||||
|
#include "nsTArrayForwardDeclare.h"
|
||||||
|
|
||||||
|
namespace mozilla {
|
||||||
|
|
||||||
|
namespace layers {
|
||||||
|
class Image;
|
||||||
|
}
|
||||||
|
|
||||||
|
class ErrorResult;
|
||||||
|
|
||||||
|
namespace dom {
|
||||||
|
|
||||||
|
struct ChannelPixelLayout;
|
||||||
|
enum class ImageBitmapFormat : uint32_t;
|
||||||
|
|
||||||
|
typedef nsTArray<ChannelPixelLayout> ImagePixelLayout;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ImageUtils is a wrapper around layers::Image. It provides three unified
|
||||||
|
* methods to all sub-classes of layers::Image, which are:
|
||||||
|
*
|
||||||
|
* (1) GetFormat() converts the image's format into ImageBitmapFormat enum.
|
||||||
|
* (2) GetBufferLength() returns the number of bytes that are used to store
|
||||||
|
* the image's underlying raw data.
|
||||||
|
* (3) MapDataInto() writes the image's underlying raw data into a given
|
||||||
|
* ArrayBuffer in the given format. (If the given format is different from
|
||||||
|
* the existing format, the ImageUtils uses the ImageBitmapFormatUtils to
|
||||||
|
* performa color conversion.)
|
||||||
|
*
|
||||||
|
* In theory, the functionalities of this class could be merged into the
|
||||||
|
* interface of layers::Image. However, this is designed as a isolated wrapper
|
||||||
|
* because we don't want to pollute the layers::Image's interface with methods
|
||||||
|
* that are only meaningful to the ImageBitmap.
|
||||||
|
*/
|
||||||
|
class ImageUtils
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
class Impl;
|
||||||
|
ImageUtils() = delete;
|
||||||
|
ImageUtils(const ImageUtils&) = delete;
|
||||||
|
ImageUtils(ImageUtils&&) = delete;
|
||||||
|
ImageUtils& operator=(const ImageUtils&) = delete;
|
||||||
|
ImageUtils& operator=(ImageUtils&&) = delete;
|
||||||
|
|
||||||
|
explicit ImageUtils(layers::Image* aImage);
|
||||||
|
~ImageUtils();
|
||||||
|
|
||||||
|
ImageBitmapFormat GetFormat() const;
|
||||||
|
|
||||||
|
uint32_t GetBufferLength() const;
|
||||||
|
|
||||||
|
UniquePtr<ImagePixelLayout>
|
||||||
|
MapDataInto(uint8_t* aBuffer, uint32_t aOffset, uint32_t aBufferLength,
|
||||||
|
ImageBitmapFormat aFormat, ErrorResult& aRv) const;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
Impl* mImpl;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace dom
|
||||||
|
} // namespace mozilla
|
||||||
|
|
||||||
|
#endif /* mozilla_dom_ImageBitmapFormatUtils_h */
|
|
@ -63,6 +63,10 @@ UNIFIED_SOURCES += [
|
||||||
'OffscreenCanvas.cpp',
|
'OffscreenCanvas.cpp',
|
||||||
]
|
]
|
||||||
|
|
||||||
|
SOURCES += [
|
||||||
|
'ImageUtils.cpp',
|
||||||
|
]
|
||||||
|
|
||||||
# WebGL Sources
|
# WebGL Sources
|
||||||
UNIFIED_SOURCES += [
|
UNIFIED_SOURCES += [
|
||||||
'TexUnpackBlob.cpp',
|
'TexUnpackBlob.cpp',
|
||||||
|
|
Загрузка…
Ссылка в новой задаче