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/. */
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
15 #define MOZ_ALIGN_WORD(x) (((x) + 3) & ~3)
23 // The Data is layed out as follows:
25 // +-----------------+ -++ --+ --+ <-- Beginning of the buffer
26 // | YCbCrBufferInfo | | | |
27 // +-----------------+ --+ | |
28 // | data | | | YCbCrBufferInfo->[mY/mCb/mCr]Offset
29 // +-----------------+ ------+ |
31 // +-----------------+ ----------+
33 // +-----------------+
35 // There can be padding between the blocks above to keep word alignment.
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
51 StereoMode mStereoMode
;
54 static YCbCrBufferInfo
* GetYCbCrBufferInfo(uint8_t* aData
, size_t aDataSize
)
56 return aDataSize
>= sizeof(YCbCrBufferInfo
)
57 ? reinterpret_cast<YCbCrBufferInfo
*>(aData
)
61 void YCbCrImageDataDeserializerBase::Validate()
67 YCbCrBufferInfo
* info
= GetYCbCrBufferInfo(mData
, mDataSize
);
71 size_t requiredSize
= ComputeMinBufferSize(
72 IntSize(info
->mYWidth
, info
->mYHeight
),
74 IntSize(info
->mCbCrWidth
, info
->mCbCrHeight
),
76 mIsValid
= requiredSize
<= mDataSize
;
80 uint8_t* YCbCrImageDataDeserializerBase::GetYData()
82 YCbCrBufferInfo
* info
= GetYCbCrBufferInfo(mData
, mDataSize
);
83 return reinterpret_cast<uint8_t*>(info
) + info
->mYOffset
;
86 uint8_t* YCbCrImageDataDeserializerBase::GetCbData()
88 YCbCrBufferInfo
* info
= GetYCbCrBufferInfo(mData
, mDataSize
);
89 return reinterpret_cast<uint8_t*>(info
) + info
->mCbOffset
;
92 uint8_t* YCbCrImageDataDeserializerBase::GetCrData()
94 YCbCrBufferInfo
* info
= GetYCbCrBufferInfo(mData
, mDataSize
);
95 return reinterpret_cast<uint8_t*>(info
) + info
->mCrOffset
;
98 uint8_t* YCbCrImageDataDeserializerBase::GetData()
100 YCbCrBufferInfo
* info
= GetYCbCrBufferInfo(mData
, mDataSize
);
101 return (reinterpret_cast<uint8_t*>(info
)) + MOZ_ALIGN_WORD(sizeof(YCbCrBufferInfo
));
104 uint32_t YCbCrImageDataDeserializerBase::GetYStride()
106 YCbCrBufferInfo
* info
= GetYCbCrBufferInfo(mData
, mDataSize
);
107 return info
->mYStride
;
110 uint32_t YCbCrImageDataDeserializerBase::GetCbCrStride()
112 YCbCrBufferInfo
* info
= GetYCbCrBufferInfo(mData
, mDataSize
);
113 return info
->mCbCrStride
;
116 gfx::IntSize
YCbCrImageDataDeserializerBase::GetYSize()
118 YCbCrBufferInfo
* info
= GetYCbCrBufferInfo(mData
, mDataSize
);
119 return gfx::IntSize(info
->mYWidth
, info
->mYHeight
);
122 gfx::IntSize
YCbCrImageDataDeserializerBase::GetCbCrSize()
124 YCbCrBufferInfo
* info
= GetYCbCrBufferInfo(mData
, mDataSize
);
125 return gfx::IntSize(info
->mCbCrWidth
, info
->mCbCrHeight
);
128 StereoMode
YCbCrImageDataDeserializerBase::GetStereoMode()
130 YCbCrBufferInfo
* info
= GetYCbCrBufferInfo(mData
, mDataSize
);
131 return info
->mStereoMode
;
135 static size_t ComputeOffset(uint32_t aHeight
, uint32_t aStride
)
137 return MOZ_ALIGN_WORD(aHeight
* aStride
);
140 // Minimum required shmem size in bytes
142 YCbCrImageDataDeserializerBase::ComputeMinBufferSize(const gfx::IntSize
& aYSize
,
144 const gfx::IntSize
& aCbCrSize
,
145 uint32_t aCbCrStride
)
147 return ComputeOffset(aYSize
.height
, aYStride
)
148 + 2 * ComputeOffset(aCbCrSize
.height
, aCbCrStride
)
149 + MOZ_ALIGN_WORD(sizeof(YCbCrBufferInfo
));
152 // Minimum required shmem size in bytes
154 YCbCrImageDataDeserializerBase::ComputeMinBufferSize(const gfx::IntSize
& aYSize
,
155 const gfx::IntSize
& aCbCrSize
)
157 return ComputeMinBufferSize(aYSize
, aYSize
.width
, aCbCrSize
, aCbCrSize
.width
);
161 static size_t ComputeOffset(uint32_t aSize
)
163 return MOZ_ALIGN_WORD(aSize
);
166 // Minimum required shmem size in bytes
168 YCbCrImageDataDeserializerBase::ComputeMinBufferSize(uint32_t aSize
)
170 return ComputeOffset(aSize
) + MOZ_ALIGN_WORD(sizeof(YCbCrBufferInfo
));
174 YCbCrImageDataSerializer::InitializeBufferInfo(uint32_t aYOffset
,
178 uint32_t aCbCrStride
,
179 const gfx::IntSize
& aYSize
,
180 const gfx::IntSize
& aCbCrSize
,
181 StereoMode aStereoMode
)
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
;
200 YCbCrImageDataSerializer::InitializeBufferInfo(uint32_t aYStride
,
201 uint32_t aCbCrStride
,
202 const gfx::IntSize
& aYSize
,
203 const gfx::IntSize
& aCbCrSize
,
204 StereoMode aStereoMode
)
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
);
214 YCbCrImageDataSerializer::InitializeBufferInfo(const gfx::IntSize
& aYSize
,
215 const gfx::IntSize
& aCbCrSize
,
216 StereoMode aStereoMode
)
218 return InitializeBufferInfo(aYSize
.width
, aCbCrSize
.width
, aYSize
, aCbCrSize
, aStereoMode
);
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
) {
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
)
236 if (!IsValid() || GetYSize() != aYSize
|| GetCbCrSize() != aCbCrSize
) {
239 for (int i
= 0; i
< aYSize
.height
; ++i
) {
242 memcpy(GetYData() + i
* GetYStride(),
243 aYData
+ i
* aYStride
,
247 CopyLineWithSkip(aYData
+ i
* aYStride
,
248 GetYData() + i
* GetYStride(),
249 aYSize
.width
, aYSkip
);
252 for (int i
= 0; i
< aCbCrSize
.height
; ++i
) {
253 if (aCbCrSkip
== 0) {
255 memcpy(GetCbData() + i
* GetCbCrStride(),
256 aCbData
+ i
* aCbCrStride
,
258 memcpy(GetCrData() + i
* GetCbCrStride(),
259 aCrData
+ i
* aCbCrStride
,
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
);
274 TemporaryRef
<DataSourceSurface
>
275 YCbCrImageDataDeserializer::ToDataSourceSurface()
277 RefPtr
<DataSourceSurface
> result
=
278 Factory::CreateDataSourceSurface(GetYSize(), gfx::SurfaceFormat::B8G8R8X8
);
279 if (NS_WARN_IF(!result
)) {
283 DataSourceSurface::MappedSurface map
;
284 result
->Map(DataSourceSurface::MapType::WRITE
, &map
);
286 gfx::ConvertYCbCrToRGB32(GetYData(), GetCbData(), GetCrData(),
289 GetYSize().width
, GetYSize().height
,
290 GetYStride(), GetCbCrStride(),
294 return result
.forget();