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 "mozilla/ScopeExit.h"
11 #include "YCbCrUtils.h"
19 #define ALIGNED_32(x) ((x + 31) & ~31)
20 #define ALIGNEDPTR_32(x) \
21 reinterpret_cast<uint8_t*>((reinterpret_cast<uintptr_t>(x) + 31) & ~31)
23 static nsresult
CopyFromLockedMacIOSurface(MacIOSurface
* aSurface
,
24 uint8_t* aData
, int32_t aStride
,
26 SurfaceFormat aFormat
) {
27 size_t bytesPerRow
= aSurface
->GetBytesPerRow();
28 SurfaceFormat ioFormat
= aSurface
->GetFormat();
30 if ((ioFormat
== SurfaceFormat::NV12
|| ioFormat
== SurfaceFormat::YUV422
) &&
31 (aSize
.width
> PlanarYCbCrImage::MAX_DIMENSION
||
32 aSize
.height
> PlanarYCbCrImage::MAX_DIMENSION
)) {
33 return NS_ERROR_FAILURE
;
36 if (ioFormat
== SurfaceFormat::NV12
) {
37 /* Extract and separate the CbCr planes */
38 size_t cbCrStride
= aSurface
->GetBytesPerRow(1);
39 size_t cbCrWidth
= aSurface
->GetDevicePixelWidth(1);
40 size_t cbCrHeight
= aSurface
->GetDevicePixelHeight(1);
42 auto cbPlane
= MakeUnique
<uint8_t[]>(cbCrWidth
* cbCrHeight
);
43 auto crPlane
= MakeUnique
<uint8_t[]>(cbCrWidth
* cbCrHeight
);
45 uint8_t* src
= (uint8_t*)aSurface
->GetBaseAddressOfPlane(1);
46 uint8_t* cbDest
= cbPlane
.get();
47 uint8_t* crDest
= crPlane
.get();
49 for (size_t i
= 0; i
< cbCrHeight
; i
++) {
50 uint8_t* rowSrc
= src
+ cbCrStride
* i
;
51 for (size_t j
= 0; j
< cbCrWidth
; j
++) {
63 data
.mYChannel
= (uint8_t*)aSurface
->GetBaseAddressOfPlane(0);
64 data
.mYStride
= aSurface
->GetBytesPerRow(0);
65 data
.mCbChannel
= cbPlane
.get();
66 data
.mCrChannel
= crPlane
.get();
67 data
.mCbCrStride
= cbCrWidth
;
68 data
.mPictureRect
= IntRect(IntPoint(0, 0), aSize
);
69 data
.mYUVColorSpace
= aSurface
->GetYUVColorSpace();
70 data
.mColorPrimaries
= aSurface
->mColorPrimaries
;
71 data
.mColorRange
= aSurface
->IsFullRange() ? gfx::ColorRange::FULL
72 : gfx::ColorRange::LIMITED
;
73 data
.mChromaSubsampling
= ChromaSubsampling::HALF_WIDTH_AND_HEIGHT
;
75 ConvertYCbCrToRGB(data
, SurfaceFormat::B8G8R8X8
, aSize
, aData
, aStride
);
76 } else if (ioFormat
== SurfaceFormat::YUV422
) {
77 if (aSize
.width
== ALIGNED_32(aSize
.width
)) {
78 // Optimization when width is aligned to 32.
79 libyuv::ConvertToARGB((uint8_t*)aSurface
->GetBaseAddress(),
80 0 /* not used */, aData
, aStride
, 0, 0, aSize
.width
,
81 aSize
.height
, aSize
.width
, aSize
.height
,
82 libyuv::kRotate0
, libyuv::FOURCC_YUYV
);
85 size_t cbCrWidth
= (aSize
.width
+ 1) >> 1;
86 size_t cbCrHeight
= aSize
.height
;
87 // Ensure our stride is a multiple of 32 to allow for memory aligned rows.
88 size_t cbCrStride
= ALIGNED_32(cbCrWidth
);
89 size_t strideDelta
= cbCrStride
- cbCrWidth
;
90 MOZ_ASSERT(strideDelta
<= 31);
92 auto yPlane
= MakeUnique
<uint8_t[]>(cbCrStride
* 2 * aSize
.height
+ 31);
93 auto cbPlane
= MakeUnique
<uint8_t[]>(cbCrStride
* cbCrHeight
+ 31);
94 auto crPlane
= MakeUnique
<uint8_t[]>(cbCrStride
* cbCrHeight
+ 31);
96 uint8_t* src
= (uint8_t*)aSurface
->GetBaseAddress();
97 uint8_t* yDest
= ALIGNEDPTR_32(yPlane
.get());
98 uint8_t* cbDest
= ALIGNEDPTR_32(cbPlane
.get());
99 uint8_t* crDest
= ALIGNEDPTR_32(crPlane
.get());
101 for (int32_t i
= 0; i
< aSize
.height
; i
++) {
102 uint8_t* rowSrc
= src
+ bytesPerRow
* i
;
103 for (size_t j
= 0; j
< cbCrWidth
; j
++) {
118 cbDest
+= strideDelta
;
119 crDest
+= strideDelta
;
120 yDest
+= strideDelta
<< 1;
125 PlanarYCbCrData data
;
126 data
.mYChannel
= ALIGNEDPTR_32(yPlane
.get());
127 data
.mYStride
= cbCrStride
* 2;
128 data
.mCbChannel
= ALIGNEDPTR_32(cbPlane
.get());
129 data
.mCrChannel
= ALIGNEDPTR_32(crPlane
.get());
130 data
.mCbCrStride
= cbCrStride
;
131 data
.mPictureRect
= IntRect(IntPoint(0, 0), aSize
);
132 data
.mYUVColorSpace
= aSurface
->GetYUVColorSpace();
133 data
.mColorPrimaries
= aSurface
->mColorPrimaries
;
134 data
.mColorRange
= aSurface
->IsFullRange() ? gfx::ColorRange::FULL
135 : gfx::ColorRange::LIMITED
;
136 data
.mChromaSubsampling
= ChromaSubsampling::HALF_WIDTH
;
138 ConvertYCbCrToRGB(data
, SurfaceFormat::B8G8R8X8
, aSize
, aData
, aStride
);
141 unsigned char* ioData
= (unsigned char*)aSurface
->GetBaseAddress();
143 for (int32_t i
= 0; i
< aSize
.height
; ++i
) {
144 memcpy(aData
+ i
* aStride
, ioData
+ i
* bytesPerRow
, aSize
.width
* 4);
151 already_AddRefed
<SourceSurface
> CreateSourceSurfaceFromMacIOSurface(
152 MacIOSurface
* aSurface
) {
154 auto scopeExit
= MakeScopeExit([&]() { aSurface
->Unlock(); });
156 size_t ioWidth
= aSurface
->GetDevicePixelWidth();
157 size_t ioHeight
= aSurface
->GetDevicePixelHeight();
158 IntSize
size((int32_t)ioWidth
, (int32_t)ioHeight
);
159 SurfaceFormat ioFormat
= aSurface
->GetFormat();
161 SurfaceFormat format
=
162 (ioFormat
== SurfaceFormat::NV12
|| ioFormat
== SurfaceFormat::YUV422
)
163 ? SurfaceFormat::B8G8R8X8
164 : SurfaceFormat::B8G8R8A8
;
166 RefPtr
<DataSourceSurface
> dataSurface
=
167 Factory::CreateDataSourceSurface(size
, format
);
168 if (NS_WARN_IF(!dataSurface
)) {
172 DataSourceSurface::ScopedMap
map(dataSurface
, DataSourceSurface::WRITE
);
173 if (NS_WARN_IF(!map
.IsMapped())) {
177 nsresult rv
= CopyFromLockedMacIOSurface(aSurface
, map
.GetData(),
178 map
.GetStride(), size
, format
);
179 if (NS_WARN_IF(NS_FAILED(rv
))) {
183 return dataSurface
.forget();
186 nsresult
CreateSurfaceDescriptorBufferFromMacIOSurface(
187 MacIOSurface
* aSurface
, SurfaceDescriptorBuffer
& aSdBuffer
,
188 Image::BuildSdbFlags aFlags
,
189 const std::function
<MemoryOrShmem(uint32_t)>& aAllocate
) {
191 auto scopeExit
= MakeScopeExit([&]() { aSurface
->Unlock(); });
193 size_t ioWidth
= aSurface
->GetDevicePixelWidth();
194 size_t ioHeight
= aSurface
->GetDevicePixelHeight();
195 IntSize
size((int32_t)ioWidth
, (int32_t)ioHeight
);
196 SurfaceFormat ioFormat
= aSurface
->GetFormat();
198 SurfaceFormat format
=
199 (ioFormat
== SurfaceFormat::NV12
|| ioFormat
== SurfaceFormat::YUV422
)
200 ? SurfaceFormat::B8G8R8X8
201 : SurfaceFormat::B8G8R8A8
;
203 uint8_t* buffer
= nullptr;
205 nsresult rv
= Image::AllocateSurfaceDescriptorBufferRgb(
206 size
, format
, buffer
, aSdBuffer
, stride
, aAllocate
);
207 if (NS_WARN_IF(NS_FAILED(rv
))) {
211 return CopyFromLockedMacIOSurface(aSurface
, buffer
, stride
, size
, format
);
214 } // namespace layers
215 } // namespace mozilla