1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim:set ts=2 sw=2 sts=2 et cindent: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "ImageUtils.h"
9 #include "ImageContainer.h"
10 #include "Intervals.h"
11 #include "mozilla/dom/ImageBitmapBinding.h"
13 using namespace mozilla::layers
;
14 using namespace mozilla::gfx
;
16 namespace mozilla::dom
{
18 static Maybe
<ImageBitmapFormat
> GetImageBitmapFormatFromSurfaceFromat(
19 SurfaceFormat aSurfaceFormat
) {
20 switch (aSurfaceFormat
) {
21 case SurfaceFormat::B8G8R8A8
:
22 case SurfaceFormat::B8G8R8X8
:
23 return Some(ImageBitmapFormat::BGRA32
);
24 case SurfaceFormat::R8G8B8A8
:
25 case SurfaceFormat::R8G8B8X8
:
26 return Some(ImageBitmapFormat::RGBA32
);
27 case SurfaceFormat::R8G8B8
:
28 return Some(ImageBitmapFormat::RGB24
);
29 case SurfaceFormat::B8G8R8
:
30 return Some(ImageBitmapFormat::BGR24
);
31 case SurfaceFormat::HSV
:
32 return Some(ImageBitmapFormat::HSV
);
33 case SurfaceFormat::Lab
:
34 return Some(ImageBitmapFormat::Lab
);
35 case SurfaceFormat::Depth
:
36 return Some(ImageBitmapFormat::DEPTH
);
37 case SurfaceFormat::A8
:
38 return Some(ImageBitmapFormat::GRAY8
);
39 case SurfaceFormat::R5G6B5_UINT16
:
40 case SurfaceFormat::YUV
:
41 case SurfaceFormat::NV12
:
42 case SurfaceFormat::P010
:
43 case SurfaceFormat::P016
:
44 case SurfaceFormat::UNKNOWN
:
50 static Maybe
<ImageBitmapFormat
> GetImageBitmapFormatFromPlanarYCbCrData(
51 layers::PlanarYCbCrData
const* aData
) {
54 auto ySize
= aData
->YDataSize();
55 auto cbcrSize
= aData
->CbCrDataSize();
56 media::Interval
<uintptr_t> YInterval(
57 uintptr_t(aData
->mYChannel
),
58 uintptr_t(aData
->mYChannel
) + ySize
.height
* aData
->mYStride
),
60 uintptr_t(aData
->mCbChannel
),
61 uintptr_t(aData
->mCbChannel
) + cbcrSize
.height
* aData
->mCbCrStride
),
63 uintptr_t(aData
->mCrChannel
),
64 uintptr_t(aData
->mCrChannel
) + cbcrSize
.height
* aData
->mCbCrStride
);
65 if (aData
->mYSkip
== 0 && aData
->mCbSkip
== 0 &&
66 aData
->mCrSkip
== 0) { // Possibly three planes.
67 if (!YInterval
.Intersects(CbInterval
) &&
68 !CbInterval
.Intersects(CrInterval
)) { // Three planes.
69 switch (aData
->mChromaSubsampling
) {
70 case ChromaSubsampling::FULL
:
71 return Some(ImageBitmapFormat::YUV444P
);
72 case ChromaSubsampling::HALF_WIDTH
:
73 return Some(ImageBitmapFormat::YUV422P
);
74 case ChromaSubsampling::HALF_WIDTH_AND_HEIGHT
:
75 return Some(ImageBitmapFormat::YUV420P
);
80 } else if (aData
->mYSkip
== 0 && aData
->mCbSkip
== 1 && aData
->mCrSkip
== 1 &&
81 aData
->mChromaSubsampling
==
82 ChromaSubsampling::HALF_WIDTH_AND_HEIGHT
) { // Possibly two
84 if (!YInterval
.Intersects(CbInterval
) &&
85 aData
->mCbChannel
== aData
->mCrChannel
- 1) { // Two planes.
86 return Some(ImageBitmapFormat::YUV420SP_NV12
); // Y-Cb-Cr
87 } else if (!YInterval
.Intersects(CrInterval
) &&
88 aData
->mCrChannel
== aData
->mCbChannel
- 1) { // Two planes.
89 return Some(ImageBitmapFormat::YUV420SP_NV21
); // Y-Cr-Cb
96 // ImageUtils::Impl implements the _generic_ algorithm which always readback
97 // data in RGBA format into CPU memory.
98 // Since layers::CairoImage is just a warpper to a DataSourceSurface, the
99 // implementation of CairoSurfaceImpl is nothing different to the generic
101 class ImageUtils::Impl
{
103 explicit Impl(layers::Image
* aImage
) : mImage(aImage
), mSurface(nullptr) {}
105 virtual ~Impl() = default;
107 virtual Maybe
<ImageBitmapFormat
> GetFormat() const {
108 return GetImageBitmapFormatFromSurfaceFromat(Surface()->GetFormat());
111 virtual uint32_t GetBufferLength() const {
112 DataSourceSurface::ScopedMap
map(Surface(), DataSourceSurface::READ
);
113 const uint32_t stride
= map
.GetStride();
114 const IntSize size
= Surface()->GetSize();
115 return (uint32_t)(size
.height
* stride
);
121 DataSourceSurface
* Surface() const {
123 RefPtr
<SourceSurface
> surface
= mImage
->GetAsSourceSurface();
126 mSurface
= surface
->GetDataSurface();
127 MOZ_ASSERT(mSurface
);
130 return mSurface
.get();
133 RefPtr
<layers::Image
> mImage
;
134 mutable RefPtr
<DataSourceSurface
> mSurface
;
137 // YUVImpl is optimized for the layers::PlanarYCbCrImage and layers::NVImage.
138 // This implementation does not readback data in RGBA format but keep it in YUV
140 class YUVImpl final
: public ImageUtils::Impl
{
142 explicit YUVImpl(layers::Image
* aImage
) : Impl(aImage
) {
143 MOZ_ASSERT(aImage
->GetFormat() == ImageFormat::PLANAR_YCBCR
||
144 aImage
->GetFormat() == ImageFormat::NV_IMAGE
);
147 Maybe
<ImageBitmapFormat
> GetFormat() const override
{
148 return GetImageBitmapFormatFromPlanarYCbCrData(GetPlanarYCbCrData());
151 uint32_t GetBufferLength() const override
{
152 if (mImage
->GetFormat() == ImageFormat::PLANAR_YCBCR
) {
153 return mImage
->AsPlanarYCbCrImage()->GetDataSize();
155 return mImage
->AsNVImage()->GetBufferSize();
159 const PlanarYCbCrData
* GetPlanarYCbCrData() const {
160 if (mImage
->GetFormat() == ImageFormat::PLANAR_YCBCR
) {
161 return mImage
->AsPlanarYCbCrImage()->GetData();
163 return mImage
->AsNVImage()->GetData();
167 // TODO: optimize for other platforms.
168 // For Windows: implement D3D9RGB32TextureImpl and D3D11ShareHandleTextureImpl.
169 // Others: SharedBGRImpl, MACIOSrufaceImpl, GLImageImpl, SurfaceTextureImpl
170 // EGLImageImpl and OverlayImegImpl.
172 ImageUtils::ImageUtils(layers::Image
* aImage
) : mImpl(nullptr) {
173 MOZ_ASSERT(aImage
, "Create ImageUtils with nullptr.");
174 switch (aImage
->GetFormat()) {
175 case mozilla::ImageFormat::PLANAR_YCBCR
:
176 case mozilla::ImageFormat::NV_IMAGE
:
177 mImpl
= new YUVImpl(aImage
);
179 case mozilla::ImageFormat::MOZ2D_SURFACE
:
181 mImpl
= new Impl(aImage
);
185 ImageUtils::~ImageUtils() {
192 Maybe
<ImageBitmapFormat
> ImageUtils::GetFormat() const {
194 return mImpl
->GetFormat();
197 uint32_t ImageUtils::GetBufferLength() const {
199 return mImpl
->GetBufferLength();
202 } // namespace mozilla::dom