|
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 "mozilla/layers/YCbCrImageDataSerializer.h" |
|
7 #include <string.h> // for memcpy |
|
8 #include "gfx2DGlue.h" // for ToIntSize |
|
9 #include "mozilla/gfx/2D.h" // for DataSourceSurface, Factory |
|
10 #include "mozilla/gfx/BaseSize.h" // for BaseSize |
|
11 #include "mozilla/gfx/Types.h" |
|
12 #include "mozilla/mozalloc.h" // for operator delete |
|
13 #include "yuv_convert.h" // for ConvertYCbCrToRGB32, etc |
|
14 |
|
15 #define MOZ_ALIGN_WORD(x) (((x) + 3) & ~3) |
|
16 |
|
17 namespace mozilla { |
|
18 |
|
19 using namespace gfx; |
|
20 |
|
21 namespace layers { |
|
22 |
|
23 // The Data is layed out as follows: |
|
24 // |
|
25 // +-----------------+ -++ --+ --+ <-- Beginning of the buffer |
|
26 // | YCbCrBufferInfo | | | | |
|
27 // +-----------------+ --+ | | |
|
28 // | data | | | YCbCrBufferInfo->[mY/mCb/mCr]Offset |
|
29 // +-----------------+ ------+ | |
|
30 // | data | | |
|
31 // +-----------------+ ----------+ |
|
32 // | data | |
|
33 // +-----------------+ |
|
34 // |
|
35 // There can be padding between the blocks above to keep word alignment. |
|
36 |
|
37 // Structure written at the beginning og the data blob containing the image |
|
38 // (as shown in the figure above). It contains the necessary informations to |
|
39 // read the image in the blob. |
|
40 struct YCbCrBufferInfo |
|
41 { |
|
42 uint32_t mYOffset; |
|
43 uint32_t mCbOffset; |
|
44 uint32_t mCrOffset; |
|
45 uint32_t mYStride; |
|
46 uint32_t mYWidth; |
|
47 uint32_t mYHeight; |
|
48 uint32_t mCbCrStride; |
|
49 uint32_t mCbCrWidth; |
|
50 uint32_t mCbCrHeight; |
|
51 StereoMode mStereoMode; |
|
52 }; |
|
53 |
|
54 static YCbCrBufferInfo* GetYCbCrBufferInfo(uint8_t* aData, size_t aDataSize) |
|
55 { |
|
56 return aDataSize >= sizeof(YCbCrBufferInfo) |
|
57 ? reinterpret_cast<YCbCrBufferInfo*>(aData) |
|
58 : nullptr; |
|
59 } |
|
60 |
|
61 void YCbCrImageDataDeserializerBase::Validate() |
|
62 { |
|
63 mIsValid = false; |
|
64 if (!mData) { |
|
65 return; |
|
66 } |
|
67 YCbCrBufferInfo* info = GetYCbCrBufferInfo(mData, mDataSize); |
|
68 if (!info) { |
|
69 return; |
|
70 } |
|
71 size_t requiredSize = ComputeMinBufferSize( |
|
72 IntSize(info->mYWidth, info->mYHeight), |
|
73 info->mYStride, |
|
74 IntSize(info->mCbCrWidth, info->mCbCrHeight), |
|
75 info->mCbCrStride); |
|
76 mIsValid = requiredSize <= mDataSize; |
|
77 |
|
78 } |
|
79 |
|
80 uint8_t* YCbCrImageDataDeserializerBase::GetYData() |
|
81 { |
|
82 YCbCrBufferInfo* info = GetYCbCrBufferInfo(mData, mDataSize); |
|
83 return reinterpret_cast<uint8_t*>(info) + info->mYOffset; |
|
84 } |
|
85 |
|
86 uint8_t* YCbCrImageDataDeserializerBase::GetCbData() |
|
87 { |
|
88 YCbCrBufferInfo* info = GetYCbCrBufferInfo(mData, mDataSize); |
|
89 return reinterpret_cast<uint8_t*>(info) + info->mCbOffset; |
|
90 } |
|
91 |
|
92 uint8_t* YCbCrImageDataDeserializerBase::GetCrData() |
|
93 { |
|
94 YCbCrBufferInfo* info = GetYCbCrBufferInfo(mData, mDataSize); |
|
95 return reinterpret_cast<uint8_t*>(info) + info->mCrOffset; |
|
96 } |
|
97 |
|
98 uint8_t* YCbCrImageDataDeserializerBase::GetData() |
|
99 { |
|
100 YCbCrBufferInfo* info = GetYCbCrBufferInfo(mData, mDataSize); |
|
101 return (reinterpret_cast<uint8_t*>(info)) + MOZ_ALIGN_WORD(sizeof(YCbCrBufferInfo)); |
|
102 } |
|
103 |
|
104 uint32_t YCbCrImageDataDeserializerBase::GetYStride() |
|
105 { |
|
106 YCbCrBufferInfo* info = GetYCbCrBufferInfo(mData, mDataSize); |
|
107 return info->mYStride; |
|
108 } |
|
109 |
|
110 uint32_t YCbCrImageDataDeserializerBase::GetCbCrStride() |
|
111 { |
|
112 YCbCrBufferInfo* info = GetYCbCrBufferInfo(mData, mDataSize); |
|
113 return info->mCbCrStride; |
|
114 } |
|
115 |
|
116 gfx::IntSize YCbCrImageDataDeserializerBase::GetYSize() |
|
117 { |
|
118 YCbCrBufferInfo* info = GetYCbCrBufferInfo(mData, mDataSize); |
|
119 return gfx::IntSize(info->mYWidth, info->mYHeight); |
|
120 } |
|
121 |
|
122 gfx::IntSize YCbCrImageDataDeserializerBase::GetCbCrSize() |
|
123 { |
|
124 YCbCrBufferInfo* info = GetYCbCrBufferInfo(mData, mDataSize); |
|
125 return gfx::IntSize(info->mCbCrWidth, info->mCbCrHeight); |
|
126 } |
|
127 |
|
128 StereoMode YCbCrImageDataDeserializerBase::GetStereoMode() |
|
129 { |
|
130 YCbCrBufferInfo* info = GetYCbCrBufferInfo(mData, mDataSize); |
|
131 return info->mStereoMode; |
|
132 } |
|
133 |
|
134 // Offset in bytes |
|
135 static size_t ComputeOffset(uint32_t aHeight, uint32_t aStride) |
|
136 { |
|
137 return MOZ_ALIGN_WORD(aHeight * aStride); |
|
138 } |
|
139 |
|
140 // Minimum required shmem size in bytes |
|
141 size_t |
|
142 YCbCrImageDataDeserializerBase::ComputeMinBufferSize(const gfx::IntSize& aYSize, |
|
143 uint32_t aYStride, |
|
144 const gfx::IntSize& aCbCrSize, |
|
145 uint32_t aCbCrStride) |
|
146 { |
|
147 return ComputeOffset(aYSize.height, aYStride) |
|
148 + 2 * ComputeOffset(aCbCrSize.height, aCbCrStride) |
|
149 + MOZ_ALIGN_WORD(sizeof(YCbCrBufferInfo)); |
|
150 } |
|
151 |
|
152 // Minimum required shmem size in bytes |
|
153 size_t |
|
154 YCbCrImageDataDeserializerBase::ComputeMinBufferSize(const gfx::IntSize& aYSize, |
|
155 const gfx::IntSize& aCbCrSize) |
|
156 { |
|
157 return ComputeMinBufferSize(aYSize, aYSize.width, aCbCrSize, aCbCrSize.width); |
|
158 } |
|
159 |
|
160 // Offset in bytes |
|
161 static size_t ComputeOffset(uint32_t aSize) |
|
162 { |
|
163 return MOZ_ALIGN_WORD(aSize); |
|
164 } |
|
165 |
|
166 // Minimum required shmem size in bytes |
|
167 size_t |
|
168 YCbCrImageDataDeserializerBase::ComputeMinBufferSize(uint32_t aSize) |
|
169 { |
|
170 return ComputeOffset(aSize) + MOZ_ALIGN_WORD(sizeof(YCbCrBufferInfo)); |
|
171 } |
|
172 |
|
173 void |
|
174 YCbCrImageDataSerializer::InitializeBufferInfo(uint32_t aYOffset, |
|
175 uint32_t aCbOffset, |
|
176 uint32_t aCrOffset, |
|
177 uint32_t aYStride, |
|
178 uint32_t aCbCrStride, |
|
179 const gfx::IntSize& aYSize, |
|
180 const gfx::IntSize& aCbCrSize, |
|
181 StereoMode aStereoMode) |
|
182 { |
|
183 YCbCrBufferInfo* info = GetYCbCrBufferInfo(mData, mDataSize); |
|
184 MOZ_ASSERT(info); // OK to assert here, this method is client-side-only |
|
185 uint32_t info_size = MOZ_ALIGN_WORD(sizeof(YCbCrBufferInfo)); |
|
186 info->mYOffset = info_size + aYOffset; |
|
187 info->mCbOffset = info_size + aCbOffset; |
|
188 info->mCrOffset = info_size + aCrOffset; |
|
189 info->mYStride = aYStride; |
|
190 info->mYWidth = aYSize.width; |
|
191 info->mYHeight = aYSize.height; |
|
192 info->mCbCrStride = aCbCrStride; |
|
193 info->mCbCrWidth = aCbCrSize.width; |
|
194 info->mCbCrHeight = aCbCrSize.height; |
|
195 info->mStereoMode = aStereoMode; |
|
196 Validate(); |
|
197 } |
|
198 |
|
199 void |
|
200 YCbCrImageDataSerializer::InitializeBufferInfo(uint32_t aYStride, |
|
201 uint32_t aCbCrStride, |
|
202 const gfx::IntSize& aYSize, |
|
203 const gfx::IntSize& aCbCrSize, |
|
204 StereoMode aStereoMode) |
|
205 { |
|
206 uint32_t yOffset = 0; |
|
207 uint32_t cbOffset = yOffset + MOZ_ALIGN_WORD(aYStride * aYSize.height); |
|
208 uint32_t crOffset = cbOffset + MOZ_ALIGN_WORD(aCbCrStride * aCbCrSize.height); |
|
209 return InitializeBufferInfo(yOffset, cbOffset, crOffset, |
|
210 aYStride, aCbCrStride, aYSize, aCbCrSize, aStereoMode); |
|
211 } |
|
212 |
|
213 void |
|
214 YCbCrImageDataSerializer::InitializeBufferInfo(const gfx::IntSize& aYSize, |
|
215 const gfx::IntSize& aCbCrSize, |
|
216 StereoMode aStereoMode) |
|
217 { |
|
218 return InitializeBufferInfo(aYSize.width, aCbCrSize.width, aYSize, aCbCrSize, aStereoMode); |
|
219 } |
|
220 |
|
221 static void CopyLineWithSkip(const uint8_t* src, uint8_t* dst, uint32_t len, uint32_t skip) { |
|
222 for (uint32_t i = 0; i < len; ++i) { |
|
223 *dst = *src; |
|
224 src += 1 + skip; |
|
225 ++dst; |
|
226 } |
|
227 } |
|
228 |
|
229 bool |
|
230 YCbCrImageDataSerializer::CopyData(const uint8_t* aYData, |
|
231 const uint8_t* aCbData, const uint8_t* aCrData, |
|
232 gfx::IntSize aYSize, uint32_t aYStride, |
|
233 gfx::IntSize aCbCrSize, uint32_t aCbCrStride, |
|
234 uint32_t aYSkip, uint32_t aCbCrSkip) |
|
235 { |
|
236 if (!IsValid() || GetYSize() != aYSize || GetCbCrSize() != aCbCrSize) { |
|
237 return false; |
|
238 } |
|
239 for (int i = 0; i < aYSize.height; ++i) { |
|
240 if (aYSkip == 0) { |
|
241 // fast path |
|
242 memcpy(GetYData() + i * GetYStride(), |
|
243 aYData + i * aYStride, |
|
244 aYSize.width); |
|
245 } else { |
|
246 // slower path |
|
247 CopyLineWithSkip(aYData + i * aYStride, |
|
248 GetYData() + i * GetYStride(), |
|
249 aYSize.width, aYSkip); |
|
250 } |
|
251 } |
|
252 for (int i = 0; i < aCbCrSize.height; ++i) { |
|
253 if (aCbCrSkip == 0) { |
|
254 // fast path |
|
255 memcpy(GetCbData() + i * GetCbCrStride(), |
|
256 aCbData + i * aCbCrStride, |
|
257 aCbCrSize.width); |
|
258 memcpy(GetCrData() + i * GetCbCrStride(), |
|
259 aCrData + i * aCbCrStride, |
|
260 aCbCrSize.width); |
|
261 } else { |
|
262 // slower path |
|
263 CopyLineWithSkip(aCbData + i * aCbCrStride, |
|
264 GetCbData() + i * GetCbCrStride(), |
|
265 aCbCrSize.width, aCbCrSkip); |
|
266 CopyLineWithSkip(aCrData + i * aCbCrStride, |
|
267 GetCrData() + i * GetCbCrStride(), |
|
268 aCbCrSize.width, aCbCrSkip); |
|
269 } |
|
270 } |
|
271 return true; |
|
272 } |
|
273 |
|
274 TemporaryRef<DataSourceSurface> |
|
275 YCbCrImageDataDeserializer::ToDataSourceSurface() |
|
276 { |
|
277 RefPtr<DataSourceSurface> result = |
|
278 Factory::CreateDataSourceSurface(GetYSize(), gfx::SurfaceFormat::B8G8R8X8); |
|
279 |
|
280 DataSourceSurface::MappedSurface map; |
|
281 result->Map(DataSourceSurface::MapType::WRITE, &map); |
|
282 |
|
283 gfx::ConvertYCbCrToRGB32(GetYData(), GetCbData(), GetCrData(), |
|
284 map.mData, |
|
285 0, 0, //pic x and y |
|
286 GetYSize().width, GetYSize().height, |
|
287 GetYStride(), GetCbCrStride(), |
|
288 map.mStride, |
|
289 gfx::YV12); |
|
290 result->Unmap(); |
|
291 return result.forget(); |
|
292 } |
|
293 |
|
294 |
|
295 } // namespace |
|
296 } // namespace |