Line data Source code
1 : /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 : * This Source Code Form is subject to the terms of the Mozilla Public
3 : * License, v. 2.0. If a copy of the MPL was not distributed with this
4 : * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 :
6 : #include "ImageDataSerializer.h"
7 : #include "gfx2DGlue.h" // for SurfaceFormatToImageFormat
8 : #include "mozilla/gfx/Point.h" // for IntSize
9 : #include "mozilla/Assertions.h" // for MOZ_ASSERT, etc
10 : #include "mozilla/gfx/2D.h" // for DataSourceSurface, Factory
11 : #include "mozilla/gfx/Logging.h" // for gfxDebug
12 : #include "mozilla/gfx/Tools.h" // for GetAlignedStride, etc
13 : #include "mozilla/gfx/Types.h"
14 : #include "mozilla/mozalloc.h" // for operator delete, etc
15 : #include "YCbCrUtils.h" // for YCbCr conversions
16 :
17 : namespace mozilla {
18 : namespace layers {
19 : namespace ImageDataSerializer {
20 :
21 : using namespace gfx;
22 :
23 : int32_t
24 27 : ComputeRGBStride(SurfaceFormat aFormat, int32_t aWidth)
25 : {
26 27 : return GetAlignedStride<4>(aWidth, BytesPerPixel(aFormat));
27 : }
28 :
29 : int32_t
30 9 : GetRGBStride(const RGBDescriptor& aDescriptor)
31 : {
32 9 : return ComputeRGBStride(aDescriptor.format(), aDescriptor.size().width);
33 : }
34 :
35 : uint32_t
36 9 : ComputeRGBBufferSize(IntSize aSize, SurfaceFormat aFormat)
37 : {
38 9 : 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 9 : if (!gfx::Factory::AllowedSurfaceSize(aSize)) {
43 0 : 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 9 : int32_t bufsize = GetAlignedStride<16>(ComputeRGBStride(aFormat, aSize.width),
50 9 : aSize.height);
51 :
52 9 : if (bufsize < 0) {
53 : // This should not be possible thanks to Factory::AllowedSurfaceSize
54 0 : return 0;
55 : }
56 :
57 9 : return bufsize;
58 : }
59 :
60 :
61 :
62 : // Minimum required shmem size in bytes
63 : uint32_t
64 0 : ComputeYCbCrBufferSize(const gfx::IntSize& aYSize, int32_t aYStride,
65 : const gfx::IntSize& aCbCrSize, int32_t aCbCrStride)
66 : {
67 0 : MOZ_ASSERT(aYSize.height >= 0 && aYSize.width >= 0);
68 :
69 0 : if (aYSize.height < 0 || aYSize.width < 0 || aCbCrSize.height < 0 || aCbCrSize.width < 0 ||
70 0 : !gfx::Factory::AllowedSurfaceSize(IntSize(aYStride, aYSize.height)) ||
71 0 : !gfx::Factory::AllowedSurfaceSize(IntSize(aCbCrStride, aCbCrSize.height))) {
72 0 : return 0;
73 : }
74 : // Overflow checks are performed in AllowedSurfaceSize
75 0 : return GetAlignedStride<4>(aYSize.height, aYStride) +
76 0 : 2 * GetAlignedStride<4>(aCbCrSize.height, aCbCrStride);
77 : }
78 :
79 : // Minimum required shmem size in bytes
80 : uint32_t
81 0 : ComputeYCbCrBufferSize(const gfx::IntSize& aYSize, const gfx::IntSize& aCbCrSize)
82 : {
83 0 : return ComputeYCbCrBufferSize(aYSize, aYSize.width, aCbCrSize, aCbCrSize.width);
84 : }
85 :
86 : uint32_t
87 0 : ComputeYCbCrBufferSize(uint32_t aBufferSize)
88 : {
89 0 : return GetAlignedStride<4>(aBufferSize, 1);
90 : }
91 :
92 0 : void ComputeYCbCrOffsets(int32_t yStride, int32_t yHeight,
93 : int32_t cbCrStride, int32_t cbCrHeight,
94 : uint32_t& outYOffset, uint32_t& outCbOffset,
95 : uint32_t& outCrOffset)
96 : {
97 0 : outYOffset = 0;
98 0 : outCbOffset = outYOffset + GetAlignedStride<4>(yStride, yHeight);
99 0 : outCrOffset = outCbOffset + GetAlignedStride<4>(cbCrStride, cbCrHeight);
100 0 : }
101 :
102 27 : gfx::SurfaceFormat FormatFromBufferDescriptor(const BufferDescriptor& aDescriptor)
103 : {
104 27 : switch (aDescriptor.type()) {
105 : case BufferDescriptor::TRGBDescriptor:
106 27 : return aDescriptor.get_RGBDescriptor().format();
107 : case BufferDescriptor::TYCbCrDescriptor:
108 0 : return gfx::SurfaceFormat::YUV;
109 : default:
110 0 : MOZ_CRASH("GFX: FormatFromBufferDescriptor");
111 : }
112 : }
113 :
114 9 : gfx::IntSize SizeFromBufferDescriptor(const BufferDescriptor& aDescriptor)
115 : {
116 9 : switch (aDescriptor.type()) {
117 : case BufferDescriptor::TRGBDescriptor:
118 9 : return aDescriptor.get_RGBDescriptor().size();
119 : case BufferDescriptor::TYCbCrDescriptor:
120 0 : return aDescriptor.get_YCbCrDescriptor().ySize();
121 : default:
122 0 : MOZ_CRASH("GFX: SizeFromBufferDescriptor");
123 : }
124 : }
125 :
126 0 : Maybe<gfx::IntSize> CbCrSizeFromBufferDescriptor(const BufferDescriptor& aDescriptor)
127 : {
128 0 : switch (aDescriptor.type()) {
129 : case BufferDescriptor::TRGBDescriptor:
130 0 : return Nothing();
131 : case BufferDescriptor::TYCbCrDescriptor:
132 0 : return Some(aDescriptor.get_YCbCrDescriptor().cbCrSize());
133 : default:
134 0 : MOZ_CRASH("GFX: CbCrSizeFromBufferDescriptor");
135 : }
136 : }
137 :
138 0 : Maybe<YUVColorSpace> YUVColorSpaceFromBufferDescriptor(const BufferDescriptor& aDescriptor)
139 : {
140 : {
141 0 : switch (aDescriptor.type()) {
142 : case BufferDescriptor::TRGBDescriptor:
143 0 : return Nothing();
144 : case BufferDescriptor::TYCbCrDescriptor:
145 0 : return Some(aDescriptor.get_YCbCrDescriptor().yUVColorSpace());
146 : default:
147 0 : MOZ_CRASH("GFX: CbCrSizeFromBufferDescriptor");
148 : }
149 : }
150 : }
151 :
152 0 : Maybe<StereoMode> StereoModeFromBufferDescriptor(const BufferDescriptor& aDescriptor)
153 : {
154 0 : switch (aDescriptor.type()) {
155 : case BufferDescriptor::TRGBDescriptor:
156 0 : return Nothing();
157 : case BufferDescriptor::TYCbCrDescriptor:
158 0 : return Some(aDescriptor.get_YCbCrDescriptor().stereoMode());
159 : default:
160 0 : MOZ_CRASH("GFX: CbCrSizeFromBufferDescriptor");
161 : }
162 : }
163 :
164 0 : uint8_t* GetYChannel(uint8_t* aBuffer, const YCbCrDescriptor& aDescriptor)
165 : {
166 0 : return aBuffer + aDescriptor.yOffset();
167 : }
168 :
169 0 : uint8_t* GetCbChannel(uint8_t* aBuffer, const YCbCrDescriptor& aDescriptor)
170 : {
171 0 : return aBuffer + aDescriptor.cbOffset();
172 : }
173 :
174 0 : uint8_t* GetCrChannel(uint8_t* aBuffer, const YCbCrDescriptor& aDescriptor)
175 : {
176 0 : return aBuffer + aDescriptor.crOffset();
177 : }
178 :
179 : already_AddRefed<DataSourceSurface>
180 0 : DataSourceSurfaceFromYCbCrDescriptor(uint8_t* aBuffer, const YCbCrDescriptor& aDescriptor, gfx::DataSourceSurface* aSurface)
181 : {
182 0 : gfx::IntSize ySize = aDescriptor.ySize();
183 0 : gfx::IntSize cbCrSize = aDescriptor.cbCrSize();
184 0 : int32_t yStride = ySize.width;
185 0 : int32_t cbCrStride = cbCrSize.width;
186 :
187 0 : RefPtr<DataSourceSurface> result;
188 0 : if (aSurface) {
189 0 : MOZ_ASSERT(aSurface->GetSize() == ySize);
190 0 : MOZ_ASSERT(aSurface->GetFormat() == gfx::SurfaceFormat::B8G8R8X8);
191 0 : if (aSurface->GetSize() == ySize &&
192 0 : aSurface->GetFormat() == gfx::SurfaceFormat::B8G8R8X8) {
193 0 : result = aSurface;
194 : }
195 : }
196 :
197 0 : if (!result) {
198 : result =
199 0 : Factory::CreateDataSourceSurface(ySize, gfx::SurfaceFormat::B8G8R8X8);
200 : }
201 0 : if (NS_WARN_IF(!result)) {
202 0 : return nullptr;
203 : }
204 :
205 : DataSourceSurface::MappedSurface map;
206 0 : if (NS_WARN_IF(!result->Map(DataSourceSurface::MapType::WRITE, &map))) {
207 0 : return nullptr;
208 : }
209 :
210 0 : layers::PlanarYCbCrData ycbcrData;
211 0 : ycbcrData.mYChannel = GetYChannel(aBuffer, aDescriptor);
212 0 : ycbcrData.mYStride = yStride;
213 0 : ycbcrData.mYSize = ySize;
214 0 : ycbcrData.mCbChannel = GetCbChannel(aBuffer, aDescriptor);
215 0 : ycbcrData.mCrChannel = GetCrChannel(aBuffer, aDescriptor);
216 0 : ycbcrData.mCbCrStride = cbCrStride;
217 0 : ycbcrData.mCbCrSize = cbCrSize;
218 0 : ycbcrData.mPicSize = ySize;
219 0 : ycbcrData.mYUVColorSpace = aDescriptor.yUVColorSpace();
220 :
221 0 : gfx::ConvertYCbCrToRGB(ycbcrData,
222 : gfx::SurfaceFormat::B8G8R8X8,
223 : ySize,
224 : map.mData,
225 0 : map.mStride);
226 :
227 0 : result->Unmap();
228 0 : return result.forget();
229 : }
230 :
231 : void
232 0 : ConvertAndScaleFromYCbCrDescriptor(uint8_t* aBuffer,
233 : const YCbCrDescriptor& aDescriptor,
234 : const gfx::SurfaceFormat& aDestFormat,
235 : const gfx::IntSize& aDestSize,
236 : unsigned char* aDestBuffer,
237 : int32_t aStride)
238 : {
239 0 : MOZ_ASSERT(aBuffer);
240 0 : gfx::IntSize ySize = aDescriptor.ySize();
241 0 : gfx::IntSize cbCrSize = aDescriptor.cbCrSize();
242 0 : int32_t yStride = ySize.width;
243 0 : int32_t cbCrStride = cbCrSize.width;
244 :
245 0 : layers::PlanarYCbCrData ycbcrData;
246 0 : ycbcrData.mYChannel = GetYChannel(aBuffer, aDescriptor);
247 0 : ycbcrData.mYStride = yStride;
248 0 : ycbcrData.mYSize = ySize;
249 0 : ycbcrData.mCbChannel = GetCbChannel(aBuffer, aDescriptor);
250 0 : ycbcrData.mCrChannel = GetCrChannel(aBuffer, aDescriptor);
251 0 : ycbcrData.mCbCrStride = cbCrStride;
252 0 : ycbcrData.mCbCrSize = cbCrSize;
253 0 : ycbcrData.mPicSize = ySize;
254 0 : ycbcrData.mYUVColorSpace = aDescriptor.yUVColorSpace();
255 :
256 0 : gfx::ConvertYCbCrToRGB(ycbcrData, aDestFormat, aDestSize, aDestBuffer, aStride);
257 0 : }
258 :
259 : } // namespace ImageDataSerializer
260 : } // namespace layers
261 : } // namespace mozilla
|