1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
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 "ImageDataSerializer.h"
9 #include "YCbCrUtils.h" // for YCbCr conversions
10 #include "gfx2DGlue.h" // for SurfaceFormatToImageFormat
11 #include "mozilla/Assertions.h" // for MOZ_ASSERT, etc
12 #include "mozilla/gfx/2D.h" // for DataSourceSurface, Factory
13 #include "mozilla/gfx/Logging.h" // for gfxDebug
14 #include "mozilla/gfx/Tools.h" // for GetAlignedStride, etc
15 #include "mozilla/gfx/Types.h"
16 #include "mozilla/mozalloc.h" // for operator delete, etc
20 namespace ImageDataSerializer
{
24 int32_t ComputeRGBStride(SurfaceFormat aFormat
, int32_t aWidth
) {
26 // Some drivers require an alignment of 32 bytes for efficient texture upload.
27 return GetAlignedStride
<32>(aWidth
, BytesPerPixel(aFormat
));
29 return GetAlignedStride
<4>(aWidth
, BytesPerPixel(aFormat
));
33 int32_t GetRGBStride(const RGBDescriptor
& aDescriptor
) {
34 return ComputeRGBStride(aDescriptor
.format(), aDescriptor
.size().width
);
37 uint32_t ComputeRGBBufferSize(IntSize aSize
, SurfaceFormat aFormat
) {
38 MOZ_ASSERT(aSize
.height
>= 0 && aSize
.width
>= 0);
40 // This takes care of checking whether there could be overflow
41 // with enough margin for the metadata.
42 if (!gfx::Factory::AllowedSurfaceSize(aSize
)) {
46 // Note we're passing height instad of the bpp parameter, but the end
47 // result is the same - and the bpp was already taken care of in the
48 // ComputeRGBStride function.
49 int32_t bufsize
= GetAlignedStride
<16>(ComputeRGBStride(aFormat
, aSize
.width
),
53 // This should not be possible thanks to Factory::AllowedSurfaceSize
60 // Minimum required shmem size in bytes
61 uint32_t ComputeYCbCrBufferSize(const gfx::IntSize
& aYSize
, int32_t aYStride
,
62 const gfx::IntSize
& aCbCrSize
,
63 int32_t aCbCrStride
) {
64 MOZ_ASSERT(aYSize
.height
>= 0 && aYSize
.width
>= 0);
66 if (aYSize
.height
< 0 || aYSize
.width
< 0 || aCbCrSize
.height
< 0 ||
67 aCbCrSize
.width
< 0 ||
68 !gfx::Factory::AllowedSurfaceSize(IntSize(aYStride
, aYSize
.height
)) ||
69 !gfx::Factory::AllowedSurfaceSize(
70 IntSize(aCbCrStride
, aCbCrSize
.height
))) {
74 // Overflow checks are performed in AllowedSurfaceSize
75 return GetAlignedStride
<4>(aYSize
.height
, aYStride
) +
76 2 * GetAlignedStride
<4>(aCbCrSize
.height
, aCbCrStride
);
79 uint32_t ComputeYCbCrBufferSize(const gfx::IntSize
& aYSize
, int32_t aYStride
,
80 const gfx::IntSize
& aCbCrSize
,
81 int32_t aCbCrStride
, uint32_t aYOffset
,
82 uint32_t aCbOffset
, uint32_t aCrOffset
) {
83 MOZ_ASSERT(aYSize
.height
>= 0 && aYSize
.width
>= 0);
85 if (aYSize
.height
< 0 || aYSize
.width
< 0 || aCbCrSize
.height
< 0 ||
86 aCbCrSize
.width
< 0 ||
87 !gfx::Factory::AllowedSurfaceSize(IntSize(aYStride
, aYSize
.height
)) ||
88 !gfx::Factory::AllowedSurfaceSize(
89 IntSize(aCbCrStride
, aCbCrSize
.height
))) {
93 uint32_t yLength
= GetAlignedStride
<4>(aYStride
, aYSize
.height
);
94 uint32_t cbCrLength
= GetAlignedStride
<4>(aCbCrStride
, aCbCrSize
.height
);
95 if (yLength
== 0 || cbCrLength
== 0) {
99 CheckedInt
<uint32_t> yEnd
= aYOffset
;
101 CheckedInt
<uint32_t> cbEnd
= aCbOffset
;
103 CheckedInt
<uint32_t> crEnd
= aCrOffset
;
106 if (!yEnd
.isValid() || !cbEnd
.isValid() || !crEnd
.isValid() ||
107 yEnd
.value() > aCbOffset
|| cbEnd
.value() > aCrOffset
) {
111 return crEnd
.value();
114 uint32_t ComputeYCbCrBufferSize(uint32_t aBufferSize
) {
115 return GetAlignedStride
<4>(aBufferSize
, 1);
118 void ComputeYCbCrOffsets(int32_t yStride
, int32_t yHeight
, int32_t cbCrStride
,
119 int32_t cbCrHeight
, uint32_t& outYOffset
,
120 uint32_t& outCbOffset
, uint32_t& outCrOffset
) {
122 outCbOffset
= outYOffset
+ GetAlignedStride
<4>(yStride
, yHeight
);
123 outCrOffset
= outCbOffset
+ GetAlignedStride
<4>(cbCrStride
, cbCrHeight
);
126 gfx::SurfaceFormat
FormatFromBufferDescriptor(
127 const BufferDescriptor
& aDescriptor
) {
128 switch (aDescriptor
.type()) {
129 case BufferDescriptor::TRGBDescriptor
:
130 return aDescriptor
.get_RGBDescriptor().format();
131 case BufferDescriptor::TYCbCrDescriptor
:
132 return gfx::SurfaceFormat::YUV
;
134 MOZ_CRASH("GFX: FormatFromBufferDescriptor");
138 gfx::IntSize
SizeFromBufferDescriptor(const BufferDescriptor
& aDescriptor
) {
139 switch (aDescriptor
.type()) {
140 case BufferDescriptor::TRGBDescriptor
:
141 return aDescriptor
.get_RGBDescriptor().size();
142 case BufferDescriptor::TYCbCrDescriptor
: {
143 return aDescriptor
.get_YCbCrDescriptor().display().Size();
146 MOZ_CRASH("GFX: SizeFromBufferDescriptor");
150 gfx::IntRect
RectFromBufferDescriptor(const BufferDescriptor
& aDescriptor
) {
151 switch (aDescriptor
.type()) {
152 case BufferDescriptor::TRGBDescriptor
: {
153 auto size
= aDescriptor
.get_RGBDescriptor().size();
154 return gfx::IntRect(0, 0, size
.Width(), size
.Height());
156 case BufferDescriptor::TYCbCrDescriptor
:
157 return aDescriptor
.get_YCbCrDescriptor().display();
159 MOZ_CRASH("GFX: RectFromBufferDescriptor");
163 Maybe
<gfx::IntSize
> YSizeFromBufferDescriptor(
164 const BufferDescriptor
& aDescriptor
) {
165 switch (aDescriptor
.type()) {
166 case BufferDescriptor::TRGBDescriptor
:
168 case BufferDescriptor::TYCbCrDescriptor
:
169 return Some(aDescriptor
.get_YCbCrDescriptor().ySize());
171 MOZ_CRASH("GFX: YSizeFromBufferDescriptor");
175 Maybe
<gfx::IntSize
> CbCrSizeFromBufferDescriptor(
176 const BufferDescriptor
& aDescriptor
) {
177 switch (aDescriptor
.type()) {
178 case BufferDescriptor::TRGBDescriptor
:
180 case BufferDescriptor::TYCbCrDescriptor
:
181 return Some(aDescriptor
.get_YCbCrDescriptor().cbCrSize());
183 MOZ_CRASH("GFX: CbCrSizeFromBufferDescriptor");
187 Maybe
<int32_t> YStrideFromBufferDescriptor(
188 const BufferDescriptor
& aDescriptor
) {
189 switch (aDescriptor
.type()) {
190 case BufferDescriptor::TRGBDescriptor
:
192 case BufferDescriptor::TYCbCrDescriptor
:
193 return Some(aDescriptor
.get_YCbCrDescriptor().yStride());
195 MOZ_CRASH("GFX: YStrideFromBufferDescriptor");
199 Maybe
<int32_t> CbCrStrideFromBufferDescriptor(
200 const BufferDescriptor
& aDescriptor
) {
201 switch (aDescriptor
.type()) {
202 case BufferDescriptor::TRGBDescriptor
:
204 case BufferDescriptor::TYCbCrDescriptor
:
205 return Some(aDescriptor
.get_YCbCrDescriptor().cbCrStride());
207 MOZ_CRASH("GFX: CbCrStrideFromBufferDescriptor");
211 Maybe
<gfx::YUVColorSpace
> YUVColorSpaceFromBufferDescriptor(
212 const BufferDescriptor
& aDescriptor
) {
213 switch (aDescriptor
.type()) {
214 case BufferDescriptor::TRGBDescriptor
:
216 case BufferDescriptor::TYCbCrDescriptor
:
217 return Some(aDescriptor
.get_YCbCrDescriptor().yUVColorSpace());
219 MOZ_CRASH("GFX: YUVColorSpaceFromBufferDescriptor");
223 Maybe
<gfx::ColorDepth
> ColorDepthFromBufferDescriptor(
224 const BufferDescriptor
& aDescriptor
) {
225 switch (aDescriptor
.type()) {
226 case BufferDescriptor::TRGBDescriptor
:
228 case BufferDescriptor::TYCbCrDescriptor
:
229 return Some(aDescriptor
.get_YCbCrDescriptor().colorDepth());
231 MOZ_CRASH("GFX: ColorDepthFromBufferDescriptor");
235 Maybe
<gfx::ColorRange
> ColorRangeFromBufferDescriptor(
236 const BufferDescriptor
& aDescriptor
) {
237 switch (aDescriptor
.type()) {
238 case BufferDescriptor::TRGBDescriptor
:
240 case BufferDescriptor::TYCbCrDescriptor
:
241 return Some(aDescriptor
.get_YCbCrDescriptor().colorRange());
243 MOZ_CRASH("GFX: YUVFullRangeFromBufferDescriptor");
247 Maybe
<StereoMode
> StereoModeFromBufferDescriptor(
248 const BufferDescriptor
& aDescriptor
) {
249 switch (aDescriptor
.type()) {
250 case BufferDescriptor::TRGBDescriptor
:
252 case BufferDescriptor::TYCbCrDescriptor
:
253 return Some(aDescriptor
.get_YCbCrDescriptor().stereoMode());
255 MOZ_CRASH("GFX: StereoModeFromBufferDescriptor");
259 Maybe
<gfx::ChromaSubsampling
> ChromaSubsamplingFromBufferDescriptor(
260 const BufferDescriptor
& aDescriptor
) {
261 switch (aDescriptor
.type()) {
262 case BufferDescriptor::TRGBDescriptor
:
264 case BufferDescriptor::TYCbCrDescriptor
:
265 return Some(aDescriptor
.get_YCbCrDescriptor().chromaSubsampling());
267 MOZ_CRASH("GFX: ChromaSubsamplingFromBufferDescriptor");
271 uint8_t* GetYChannel(uint8_t* aBuffer
, const YCbCrDescriptor
& aDescriptor
) {
272 return aBuffer
+ aDescriptor
.yOffset();
275 uint8_t* GetCbChannel(uint8_t* aBuffer
, const YCbCrDescriptor
& aDescriptor
) {
276 return aBuffer
+ aDescriptor
.cbOffset();
279 uint8_t* GetCrChannel(uint8_t* aBuffer
, const YCbCrDescriptor
& aDescriptor
) {
280 return aBuffer
+ aDescriptor
.crOffset();
283 already_AddRefed
<DataSourceSurface
> DataSourceSurfaceFromYCbCrDescriptor(
284 uint8_t* aBuffer
, const YCbCrDescriptor
& aDescriptor
,
285 gfx::DataSourceSurface
* aSurface
) {
286 const gfx::IntRect display
= aDescriptor
.display();
287 const gfx::IntSize size
= display
.Size();
288 RefPtr
<DataSourceSurface
> result
;
290 MOZ_ASSERT(aSurface
->GetSize() == size
);
291 MOZ_ASSERT(aSurface
->GetFormat() == gfx::SurfaceFormat::B8G8R8X8
);
292 if (aSurface
->GetSize() == size
&&
293 aSurface
->GetFormat() == gfx::SurfaceFormat::B8G8R8X8
) {
300 Factory::CreateDataSourceSurface(size
, gfx::SurfaceFormat::B8G8R8X8
);
302 if (NS_WARN_IF(!result
)) {
306 DataSourceSurface::MappedSurface map
;
307 if (NS_WARN_IF(!result
->Map(DataSourceSurface::MapType::WRITE
, &map
))) {
311 layers::PlanarYCbCrData ycbcrData
;
312 ycbcrData
.mYChannel
= GetYChannel(aBuffer
, aDescriptor
);
313 ycbcrData
.mYStride
= aDescriptor
.yStride();
314 ycbcrData
.mCbChannel
= GetCbChannel(aBuffer
, aDescriptor
);
315 ycbcrData
.mCrChannel
= GetCrChannel(aBuffer
, aDescriptor
);
316 ycbcrData
.mCbCrStride
= aDescriptor
.cbCrStride();
317 ycbcrData
.mPictureRect
= aDescriptor
.display();
318 ycbcrData
.mYUVColorSpace
= aDescriptor
.yUVColorSpace();
319 ycbcrData
.mColorDepth
= aDescriptor
.colorDepth();
320 ycbcrData
.mChromaSubsampling
= aDescriptor
.chromaSubsampling();
322 gfx::ConvertYCbCrToRGB(ycbcrData
, gfx::SurfaceFormat::B8G8R8X8
, size
,
323 map
.mData
, map
.mStride
);
326 return result
.forget();
329 void ConvertAndScaleFromYCbCrDescriptor(uint8_t* aBuffer
,
330 const YCbCrDescriptor
& aDescriptor
,
331 const gfx::SurfaceFormat
& aDestFormat
,
332 const gfx::IntSize
& aDestSize
,
333 unsigned char* aDestBuffer
,
337 layers::PlanarYCbCrData ycbcrData
;
338 ycbcrData
.mYChannel
= GetYChannel(aBuffer
, aDescriptor
);
339 ycbcrData
.mYStride
= aDescriptor
.yStride();
340 ycbcrData
.mCbChannel
= GetCbChannel(aBuffer
, aDescriptor
);
341 ycbcrData
.mCrChannel
= GetCrChannel(aBuffer
, aDescriptor
);
342 ycbcrData
.mCbCrStride
= aDescriptor
.cbCrStride();
343 ycbcrData
.mPictureRect
= aDescriptor
.display();
344 ycbcrData
.mYUVColorSpace
= aDescriptor
.yUVColorSpace();
345 ycbcrData
.mColorDepth
= aDescriptor
.colorDepth();
346 ycbcrData
.mChromaSubsampling
= aDescriptor
.chromaSubsampling();
348 gfx::ConvertYCbCrToRGB(ycbcrData
, aDestFormat
, aDestSize
, aDestBuffer
,
352 gfx::IntSize
GetCroppedCbCrSize(const YCbCrDescriptor
& aDescriptor
) {
353 return ChromaSize(aDescriptor
.display().Size(),
354 aDescriptor
.chromaSubsampling());
357 } // namespace ImageDataSerializer
358 } // namespace layers
359 } // namespace mozilla