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/. */
8 #include "MacIOSurfaceHelpers.h"
9 #include "mozilla/gfx/MacIOSurface.h"
10 #include "YCbCrUtils.h"
18 #define ALIGNED_32(x) ((x + 31) & ~31)
19 #define ALIGNEDPTR_32(x) \
20 reinterpret_cast<uint8_t*>((reinterpret_cast<uintptr_t>(x) + 31) & ~31)
22 static already_AddRefed
<SourceSurface
>
23 CreateSourceSurfaceFromLockedMacIOSurface(MacIOSurface
* aSurface
) {
24 size_t bytesPerRow
= aSurface
->GetBytesPerRow();
25 size_t ioWidth
= aSurface
->GetDevicePixelWidth();
26 size_t ioHeight
= aSurface
->GetDevicePixelHeight();
27 IntSize
size((int32_t)ioWidth
, (int32_t)ioHeight
);
28 SurfaceFormat ioFormat
= aSurface
->GetFormat();
30 if ((ioFormat
== SurfaceFormat::NV12
|| ioFormat
== SurfaceFormat::YUV422
) &&
31 (ioWidth
> PlanarYCbCrImage::MAX_DIMENSION
||
32 ioHeight
> PlanarYCbCrImage::MAX_DIMENSION
)) {
36 SurfaceFormat format
=
37 (ioFormat
== SurfaceFormat::NV12
|| ioFormat
== SurfaceFormat::YUV422
)
38 ? SurfaceFormat::B8G8R8X8
39 : SurfaceFormat::B8G8R8A8
;
41 RefPtr
<DataSourceSurface
> dataSurface
=
42 Factory::CreateDataSourceSurface(size
, format
);
43 if (NS_WARN_IF(!dataSurface
)) {
47 DataSourceSurface::MappedSurface mappedSurface
;
48 if (!dataSurface
->Map(DataSourceSurface::WRITE
, &mappedSurface
)) {
52 if (ioFormat
== SurfaceFormat::NV12
) {
53 /* Extract and separate the CbCr planes */
54 size_t cbCrStride
= aSurface
->GetBytesPerRow(1);
55 size_t cbCrWidth
= aSurface
->GetDevicePixelWidth(1);
56 size_t cbCrHeight
= aSurface
->GetDevicePixelHeight(1);
58 auto cbPlane
= MakeUnique
<uint8_t[]>(cbCrWidth
* cbCrHeight
);
59 auto crPlane
= MakeUnique
<uint8_t[]>(cbCrWidth
* cbCrHeight
);
61 uint8_t* src
= (uint8_t*)aSurface
->GetBaseAddressOfPlane(1);
62 uint8_t* cbDest
= cbPlane
.get();
63 uint8_t* crDest
= crPlane
.get();
65 for (size_t i
= 0; i
< cbCrHeight
; i
++) {
66 uint8_t* rowSrc
= src
+ cbCrStride
* i
;
67 for (size_t j
= 0; j
< cbCrWidth
; j
++) {
79 data
.mYChannel
= (uint8_t*)aSurface
->GetBaseAddressOfPlane(0);
80 data
.mYStride
= aSurface
->GetBytesPerRow(0);
81 data
.mCbChannel
= cbPlane
.get();
82 data
.mCrChannel
= crPlane
.get();
83 data
.mCbCrStride
= cbCrWidth
;
84 data
.mPictureRect
= IntRect(IntPoint(0, 0), size
);
85 data
.mYUVColorSpace
= aSurface
->GetYUVColorSpace();
86 data
.mColorPrimaries
= aSurface
->mColorPrimaries
;
87 data
.mColorRange
= aSurface
->IsFullRange() ? gfx::ColorRange::FULL
88 : gfx::ColorRange::LIMITED
;
89 data
.mChromaSubsampling
= ChromaSubsampling::HALF_WIDTH_AND_HEIGHT
;
91 ConvertYCbCrToRGB(data
, SurfaceFormat::B8G8R8X8
, size
, mappedSurface
.mData
,
92 mappedSurface
.mStride
);
93 } else if (ioFormat
== SurfaceFormat::YUV422
) {
94 if (ioWidth
== ALIGNED_32(ioWidth
)) {
95 // Optimization when width is aligned to 32.
96 libyuv::ConvertToARGB((uint8_t*)aSurface
->GetBaseAddress(),
97 0 /* not used */, mappedSurface
.mData
,
98 mappedSurface
.mStride
, 0, 0, size
.width
,
99 size
.height
, size
.width
, size
.height
,
100 libyuv::kRotate0
, libyuv::FOURCC_YUYV
);
102 /* Convert to YV16 */
103 size_t cbCrWidth
= (ioWidth
+ 1) >> 1;
104 size_t cbCrHeight
= ioHeight
;
105 // Ensure our stride is a multiple of 32 to allow for memory aligned rows.
106 size_t cbCrStride
= ALIGNED_32(cbCrWidth
);
107 size_t strideDelta
= cbCrStride
- cbCrWidth
;
108 MOZ_ASSERT(strideDelta
<= 31);
110 auto yPlane
= MakeUnique
<uint8_t[]>(cbCrStride
* 2 * ioHeight
+ 31);
111 auto cbPlane
= MakeUnique
<uint8_t[]>(cbCrStride
* cbCrHeight
+ 31);
112 auto crPlane
= MakeUnique
<uint8_t[]>(cbCrStride
* cbCrHeight
+ 31);
114 uint8_t* src
= (uint8_t*)aSurface
->GetBaseAddress();
115 uint8_t* yDest
= ALIGNEDPTR_32(yPlane
.get());
116 uint8_t* cbDest
= ALIGNEDPTR_32(cbPlane
.get());
117 uint8_t* crDest
= ALIGNEDPTR_32(crPlane
.get());
119 for (size_t i
= 0; i
< ioHeight
; i
++) {
120 uint8_t* rowSrc
= src
+ bytesPerRow
* i
;
121 for (size_t j
= 0; j
< cbCrWidth
; j
++) {
136 cbDest
+= strideDelta
;
137 crDest
+= strideDelta
;
138 yDest
+= strideDelta
<< 1;
143 PlanarYCbCrData data
;
144 data
.mYChannel
= ALIGNEDPTR_32(yPlane
.get());
145 data
.mYStride
= cbCrStride
* 2;
146 data
.mCbChannel
= ALIGNEDPTR_32(cbPlane
.get());
147 data
.mCrChannel
= ALIGNEDPTR_32(crPlane
.get());
148 data
.mCbCrStride
= cbCrStride
;
149 data
.mPictureRect
= IntRect(IntPoint(0, 0), size
);
150 data
.mYUVColorSpace
= aSurface
->GetYUVColorSpace();
151 data
.mColorPrimaries
= aSurface
->mColorPrimaries
;
152 data
.mColorRange
= aSurface
->IsFullRange() ? gfx::ColorRange::FULL
153 : gfx::ColorRange::LIMITED
;
154 data
.mChromaSubsampling
= ChromaSubsampling::HALF_WIDTH
;
156 ConvertYCbCrToRGB(data
, SurfaceFormat::B8G8R8X8
, size
,
157 mappedSurface
.mData
, mappedSurface
.mStride
);
160 unsigned char* ioData
= (unsigned char*)aSurface
->GetBaseAddress();
162 for (size_t i
= 0; i
< ioHeight
; ++i
) {
163 memcpy(mappedSurface
.mData
+ i
* mappedSurface
.mStride
,
164 ioData
+ i
* bytesPerRow
, ioWidth
* 4);
168 dataSurface
->Unmap();
170 return dataSurface
.forget();
173 already_AddRefed
<SourceSurface
> CreateSourceSurfaceFromMacIOSurface(
174 MacIOSurface
* aSurface
) {
176 RefPtr
<SourceSurface
> result
=
177 CreateSourceSurfaceFromLockedMacIOSurface(aSurface
);
179 return result
.forget();
182 } // namespace layers
183 } // namespace mozilla