Source code

Revision control

Other Tools

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/. */
6
7
#include "ImageDataSerializer.h"
8
#include "gfx2DGlue.h" // for SurfaceFormatToImageFormat
9
#include "mozilla/gfx/Point.h" // for IntSize
10
#include "mozilla/Assertions.h" // for MOZ_ASSERT, etc
11
#include "mozilla/gfx/2D.h" // for DataSourceSurface, Factory
12
#include "mozilla/gfx/Logging.h" // for gfxDebug
13
#include "mozilla/gfx/Tools.h" // for GetAlignedStride, etc
14
#include "mozilla/gfx/Types.h"
15
#include "mozilla/mozalloc.h" // for operator delete, etc
16
#include "YCbCrUtils.h" // for YCbCr conversions
17
18
namespace mozilla {
19
namespace layers {
20
namespace ImageDataSerializer {
21
22
using namespace gfx;
23
24
int32_t ComputeRGBStride(SurfaceFormat aFormat, int32_t aWidth) {
25
#ifdef XP_MACOSX
26
// Some drivers require an alignment of 32 bytes for efficient texture upload.
27
return GetAlignedStride<32>(aWidth, BytesPerPixel(aFormat));
28
#else
29
return GetAlignedStride<4>(aWidth, BytesPerPixel(aFormat));
30
#endif
31
}
32
33
int32_t GetRGBStride(const RGBDescriptor& aDescriptor) {
34
return ComputeRGBStride(aDescriptor.format(), aDescriptor.size().width);
35
}
36
37
uint32_t ComputeRGBBufferSize(IntSize aSize, SurfaceFormat aFormat) {
38
MOZ_ASSERT(aSize.height >= 0 && aSize.width >= 0);
39
40
// This takes care of checking whether there could be overflow
41
// with enough margin for the metadata.
42
if (!gfx::Factory::AllowedSurfaceSize(aSize)) {
43
return 0;
44
}
45
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),
50
aSize.height);
51
52
if (bufsize < 0) {
53
// This should not be possible thanks to Factory::AllowedSurfaceSize
54
return 0;
55
}
56
57
return bufsize;
58
}
59
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);
65
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))) {
71
return 0;
72
}
73
74
// Overflow checks are performed in AllowedSurfaceSize
75
return GetAlignedStride<4>(aYSize.height, aYStride) +
76
2 * GetAlignedStride<4>(aCbCrSize.height, aCbCrStride);
77
}
78
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);
84
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))) {
90
return 0;
91
}
92
93
uint32_t yLength = GetAlignedStride<4>(aYStride, aYSize.height);
94
uint32_t cbCrLength = GetAlignedStride<4>(aCbCrStride, aCbCrSize.height);
95
if (yLength == 0 || cbCrLength == 0) {
96
return 0;
97
}
98
99
CheckedInt<uint32_t> yEnd = aYOffset;
100
yEnd += yLength;
101
CheckedInt<uint32_t> cbEnd = aCbOffset;
102
cbEnd += cbCrLength;
103
CheckedInt<uint32_t> crEnd = aCrOffset;
104
crEnd += cbCrLength;
105
106
if (!yEnd.isValid() || !cbEnd.isValid() || !crEnd.isValid() ||
107
yEnd.value() > aCbOffset || cbEnd.value() > aCrOffset) {
108
return 0;
109
}
110
111
return crEnd.value();
112
}
113
114
uint32_t ComputeYCbCrBufferSize(uint32_t aBufferSize) {
115
return GetAlignedStride<4>(aBufferSize, 1);
116
}
117
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) {
121
outYOffset = 0;
122
outCbOffset = outYOffset + GetAlignedStride<4>(yStride, yHeight);
123
outCrOffset = outCbOffset + GetAlignedStride<4>(cbCrStride, cbCrHeight);
124
}
125
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;
133
default:
134
MOZ_CRASH("GFX: FormatFromBufferDescriptor");
135
}
136
}
137
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().ySize();
144
default:
145
MOZ_CRASH("GFX: SizeFromBufferDescriptor");
146
}
147
}
148
149
Maybe<gfx::IntSize> CbCrSizeFromBufferDescriptor(
150
const BufferDescriptor& aDescriptor) {
151
switch (aDescriptor.type()) {
152
case BufferDescriptor::TRGBDescriptor:
153
return Nothing();
154
case BufferDescriptor::TYCbCrDescriptor:
155
return Some(aDescriptor.get_YCbCrDescriptor().cbCrSize());
156
default:
157
MOZ_CRASH("GFX: CbCrSizeFromBufferDescriptor");
158
}
159
}
160
161
Maybe<gfx::YUVColorSpace> YUVColorSpaceFromBufferDescriptor(
162
const BufferDescriptor& aDescriptor) {
163
switch (aDescriptor.type()) {
164
case BufferDescriptor::TRGBDescriptor:
165
return Nothing();
166
case BufferDescriptor::TYCbCrDescriptor:
167
return Some(aDescriptor.get_YCbCrDescriptor().yUVColorSpace());
168
default:
169
MOZ_CRASH("GFX: YUVColorSpaceFromBufferDescriptor");
170
}
171
}
172
173
Maybe<gfx::ColorDepth> ColorDepthFromBufferDescriptor(
174
const BufferDescriptor& aDescriptor) {
175
switch (aDescriptor.type()) {
176
case BufferDescriptor::TRGBDescriptor:
177
return Nothing();
178
case BufferDescriptor::TYCbCrDescriptor:
179
return Some(aDescriptor.get_YCbCrDescriptor().colorDepth());
180
default:
181
MOZ_CRASH("GFX: ColorDepthFromBufferDescriptor");
182
}
183
}
184
185
Maybe<gfx::ColorRange> ColorRangeFromBufferDescriptor(
186
const BufferDescriptor& aDescriptor) {
187
switch (aDescriptor.type()) {
188
case BufferDescriptor::TRGBDescriptor:
189
return Nothing();
190
case BufferDescriptor::TYCbCrDescriptor:
191
return Some(aDescriptor.get_YCbCrDescriptor().colorRange());
192
default:
193
MOZ_CRASH("GFX: YUVFullRangeFromBufferDescriptor");
194
}
195
}
196
197
Maybe<StereoMode> StereoModeFromBufferDescriptor(
198
const BufferDescriptor& aDescriptor) {
199
switch (aDescriptor.type()) {
200
case BufferDescriptor::TRGBDescriptor:
201
return Nothing();
202
case BufferDescriptor::TYCbCrDescriptor:
203
return Some(aDescriptor.get_YCbCrDescriptor().stereoMode());
204
default:
205
MOZ_CRASH("GFX: StereoModeFromBufferDescriptor");
206
}
207
}
208
209
uint8_t* GetYChannel(uint8_t* aBuffer, const YCbCrDescriptor& aDescriptor) {
210
return aBuffer + aDescriptor.yOffset();
211
}
212
213
uint8_t* GetCbChannel(uint8_t* aBuffer, const YCbCrDescriptor& aDescriptor) {
214
return aBuffer + aDescriptor.cbOffset();
215
}
216
217
uint8_t* GetCrChannel(uint8_t* aBuffer, const YCbCrDescriptor& aDescriptor) {
218
return aBuffer + aDescriptor.crOffset();
219
}
220
221
already_AddRefed<DataSourceSurface> DataSourceSurfaceFromYCbCrDescriptor(
222
uint8_t* aBuffer, const YCbCrDescriptor& aDescriptor,
223
gfx::DataSourceSurface* aSurface) {
224
gfx::IntSize ySize = aDescriptor.ySize();
225
226
RefPtr<DataSourceSurface> result;
227
if (aSurface) {
228
MOZ_ASSERT(aSurface->GetSize() == ySize);
229
MOZ_ASSERT(aSurface->GetFormat() == gfx::SurfaceFormat::B8G8R8X8);
230
if (aSurface->GetSize() == ySize &&
231
aSurface->GetFormat() == gfx::SurfaceFormat::B8G8R8X8) {
232
result = aSurface;
233
}
234
}
235
236
if (!result) {
237
result =
238
Factory::CreateDataSourceSurface(ySize, gfx::SurfaceFormat::B8G8R8X8);
239
}
240
if (NS_WARN_IF(!result)) {
241
return nullptr;
242
}
243
244
DataSourceSurface::MappedSurface map;
245
if (NS_WARN_IF(!result->Map(DataSourceSurface::MapType::WRITE, &map))) {
246
return nullptr;
247
}
248
249
layers::PlanarYCbCrData ycbcrData;
250
ycbcrData.mYChannel = GetYChannel(aBuffer, aDescriptor);
251
ycbcrData.mYStride = aDescriptor.yStride();
252
ycbcrData.mYSize = ySize;
253
ycbcrData.mCbChannel = GetCbChannel(aBuffer, aDescriptor);
254
ycbcrData.mCrChannel = GetCrChannel(aBuffer, aDescriptor);
255
ycbcrData.mCbCrStride = aDescriptor.cbCrStride();
256
ycbcrData.mCbCrSize = aDescriptor.cbCrSize();
257
ycbcrData.mPicSize = ySize;
258
ycbcrData.mYUVColorSpace = aDescriptor.yUVColorSpace();
259
ycbcrData.mColorDepth = aDescriptor.colorDepth();
260
261
gfx::ConvertYCbCrToRGB(ycbcrData, gfx::SurfaceFormat::B8G8R8X8, ySize,
262
map.mData, map.mStride);
263
264
result->Unmap();
265
return result.forget();
266
}
267
268
void ConvertAndScaleFromYCbCrDescriptor(uint8_t* aBuffer,
269
const YCbCrDescriptor& aDescriptor,
270
const gfx::SurfaceFormat& aDestFormat,
271
const gfx::IntSize& aDestSize,
272
unsigned char* aDestBuffer,
273
int32_t aStride) {
274
MOZ_ASSERT(aBuffer);
275
276
layers::PlanarYCbCrData ycbcrData;
277
ycbcrData.mYChannel = GetYChannel(aBuffer, aDescriptor);
278
ycbcrData.mYStride = aDescriptor.yStride();
279
;
280
ycbcrData.mYSize = aDescriptor.ySize();
281
ycbcrData.mCbChannel = GetCbChannel(aBuffer, aDescriptor);
282
ycbcrData.mCrChannel = GetCrChannel(aBuffer, aDescriptor);
283
ycbcrData.mCbCrStride = aDescriptor.cbCrStride();
284
ycbcrData.mCbCrSize = aDescriptor.cbCrSize();
285
ycbcrData.mPicSize = aDescriptor.ySize();
286
ycbcrData.mYUVColorSpace = aDescriptor.yUVColorSpace();
287
ycbcrData.mColorDepth = aDescriptor.colorDepth();
288
289
gfx::ConvertYCbCrToRGB(ycbcrData, aDestFormat, aDestSize, aDestBuffer,
290
aStride);
291
}
292
293
} // namespace ImageDataSerializer
294
} // namespace layers
295
} // namespace mozilla