blob: b761c35326be3bdef1ab744a98951e3e18396403 [file] [log] [blame]
Pawin Vongmasa36653902018-11-15 00:10:25 -08001/*
2 * Copyright 2018, The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17//#define LOG_NDEBUG 0
18#define LOG_TAG "Codec2BufferUtils"
19#include <utils/Log.h>
20
Pawin Vongmasa1f213362019-01-24 06:59:16 -080021#include <libyuv.h>
22
Pawin Vongmasa36653902018-11-15 00:10:25 -080023#include <list>
24#include <mutex>
25
Wonsik Kima38fdf22021-04-05 14:50:29 -070026#include <android/hardware_buffer.h>
Pawin Vongmasa36653902018-11-15 00:10:25 -080027#include <media/hardware/HardwareAPI.h>
28#include <media/stagefright/foundation/AUtils.h>
29
30#include <C2Debug.h>
31
32#include "Codec2BufferUtils.h"
33
34namespace android {
35
36namespace {
37
38/**
39 * A flippable, optimizable memcpy. Constructs such as (from ? src : dst) do not work as the results are
40 * always const.
41 */
42template<bool ToA, size_t S>
43struct MemCopier {
44 template<typename A, typename B>
45 inline static void copy(A *a, const B *b, size_t size) {
46 __builtin_memcpy(a, b, size);
47 }
48};
49
50template<size_t S>
51struct MemCopier<false, S> {
52 template<typename A, typename B>
53 inline static void copy(const A *a, B *b, size_t size) {
54 MemCopier<true, S>::copy(b, a, size);
55 }
56};
57
58/**
59 * Copies between a MediaImage and a graphic view.
60 *
61 * \param ToMediaImage whether to copy to (or from) the MediaImage
62 * \param view graphic view (could be ConstGraphicView or GraphicView depending on direction)
63 * \param img MediaImage data
64 * \param imgBase base of MediaImage (could be const uint8_t* or uint8_t* depending on direction)
65 */
66template<bool ToMediaImage, typename View, typename ImagePixel>
67static status_t _ImageCopy(View &view, const MediaImage2 *img, ImagePixel *imgBase) {
Pawin Vongmasa1f213362019-01-24 06:59:16 -080068 // TODO: more efficient copying --- e.g. copy interleaved planes together, etc.
Pawin Vongmasa36653902018-11-15 00:10:25 -080069 const C2PlanarLayout &layout = view.layout();
70 const size_t bpp = divUp(img->mBitDepthAllocated, 8u);
Pawin Vongmasa1f213362019-01-24 06:59:16 -080071
Pawin Vongmasa36653902018-11-15 00:10:25 -080072 for (uint32_t i = 0; i < layout.numPlanes; ++i) {
73 typename std::conditional<ToMediaImage, uint8_t, const uint8_t>::type *imgRow =
74 imgBase + img->mPlane[i].mOffset;
75 typename std::conditional<ToMediaImage, const uint8_t, uint8_t>::type *viewRow =
76 viewRow = view.data()[i];
77 const C2PlaneInfo &plane = layout.planes[i];
78 if (plane.colSampling != img->mPlane[i].mHorizSubsampling
79 || plane.rowSampling != img->mPlane[i].mVertSubsampling
80 || plane.allocatedDepth != img->mBitDepthAllocated
81 || plane.allocatedDepth < plane.bitDepth
82 // MediaImage only supports MSB values
83 || plane.rightShift != plane.allocatedDepth - plane.bitDepth
84 || (bpp > 1 && plane.endianness != plane.NATIVE)) {
85 return BAD_VALUE;
86 }
87
88 uint32_t planeW = img->mWidth / plane.colSampling;
89 uint32_t planeH = img->mHeight / plane.rowSampling;
Pawin Vongmasa8be93112018-12-11 14:01:42 -080090
Praveen Chavanbc2b7132022-01-19 23:02:56 -080091 bool canCopyByRow = (plane.colInc == bpp) && (img->mPlane[i].mColInc == bpp);
Pawin Vongmasa8be93112018-12-11 14:01:42 -080092 bool canCopyByPlane = canCopyByRow && (plane.rowInc == img->mPlane[i].mRowInc);
93 if (canCopyByPlane) {
94 MemCopier<ToMediaImage, 0>::copy(imgRow, viewRow, plane.rowInc * planeH);
95 } else if (canCopyByRow) {
96 for (uint32_t row = 0; row < planeH; ++row) {
97 MemCopier<ToMediaImage, 0>::copy(
98 imgRow, viewRow, std::min(plane.rowInc, img->mPlane[i].mRowInc));
99 imgRow += img->mPlane[i].mRowInc;
100 viewRow += plane.rowInc;
Pawin Vongmasa36653902018-11-15 00:10:25 -0800101 }
Pawin Vongmasa8be93112018-12-11 14:01:42 -0800102 } else {
103 for (uint32_t row = 0; row < planeH; ++row) {
104 decltype(imgRow) imgPtr = imgRow;
105 decltype(viewRow) viewPtr = viewRow;
106 for (uint32_t col = 0; col < planeW; ++col) {
107 MemCopier<ToMediaImage, 0>::copy(imgPtr, viewPtr, bpp);
108 imgPtr += img->mPlane[i].mColInc;
109 viewPtr += plane.colInc;
110 }
111 imgRow += img->mPlane[i].mRowInc;
112 viewRow += plane.rowInc;
113 }
Pawin Vongmasa36653902018-11-15 00:10:25 -0800114 }
115 }
116 return OK;
117}
118
119} // namespace
120
Harish Mahendrakarf0fa7a22021-12-10 20:36:32 -0800121bool IsFormatR10G10B10A2SupportedForLegacyRendering() {
122 const AHardwareBuffer_Desc desc = {
123 .width = 320,
124 .height = 240,
125 .format = AHARDWAREBUFFER_FORMAT_R10G10B10A2_UNORM,
126 .layers = 1,
127 .usage = AHARDWAREBUFFER_USAGE_CPU_READ_RARELY | AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN |
128 AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE,
129 .stride = 0,
130 .rfu0 = 0,
131 .rfu1 = 0,
132 };
133
134 return AHardwareBuffer_isSupported(&desc);
135}
136
Pawin Vongmasa36653902018-11-15 00:10:25 -0800137status_t ImageCopy(uint8_t *imgBase, const MediaImage2 *img, const C2GraphicView &view) {
Harish Mahendrakarf7c49e22019-05-24 14:19:16 -0700138 if (view.crop().width != img->mWidth || view.crop().height != img->mHeight) {
Pawin Vongmasa1f213362019-01-24 06:59:16 -0800139 return BAD_VALUE;
140 }
Wonsik Kimf37f2422021-03-04 15:38:59 -0800141 const uint8_t* src_y = view.data()[0];
142 const uint8_t* src_u = view.data()[1];
143 const uint8_t* src_v = view.data()[2];
144 int32_t src_stride_y = view.layout().planes[0].rowInc;
145 int32_t src_stride_u = view.layout().planes[1].rowInc;
146 int32_t src_stride_v = view.layout().planes[2].rowInc;
147 uint8_t* dst_y = imgBase + img->mPlane[0].mOffset;
148 uint8_t* dst_u = imgBase + img->mPlane[1].mOffset;
149 uint8_t* dst_v = imgBase + img->mPlane[2].mOffset;
150 int32_t dst_stride_y = img->mPlane[0].mRowInc;
151 int32_t dst_stride_u = img->mPlane[1].mRowInc;
152 int32_t dst_stride_v = img->mPlane[2].mRowInc;
153 int width = view.crop().width;
154 int height = view.crop().height;
155
Wonsik Kima38fdf22021-04-05 14:50:29 -0700156 if (IsNV12(view)) {
157 if (IsNV12(img)) {
158 libyuv::CopyPlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
159 libyuv::CopyPlane(src_u, src_stride_u, dst_u, dst_stride_u, width, height / 2);
160 return OK;
161 } else if (IsNV21(img)) {
162 if (!libyuv::NV21ToNV12(src_y, src_stride_y, src_u, src_stride_u,
163 dst_y, dst_stride_y, dst_v, dst_stride_v, width, height)) {
164 return OK;
165 }
166 } else if (IsI420(img)) {
Pawin Vongmasa1f213362019-01-24 06:59:16 -0800167 if (!libyuv::NV12ToI420(src_y, src_stride_y, src_u, src_stride_u, dst_y, dst_stride_y,
Wonsik Kimf37f2422021-03-04 15:38:59 -0800168 dst_u, dst_stride_u, dst_v, dst_stride_v, width, height)) {
Pawin Vongmasa1f213362019-01-24 06:59:16 -0800169 return OK;
170 }
Wonsik Kima38fdf22021-04-05 14:50:29 -0700171 }
172 } else if (IsNV21(view)) {
173 if (IsNV12(img)) {
174 if (!libyuv::NV21ToNV12(src_y, src_stride_y, src_v, src_stride_v,
175 dst_y, dst_stride_y, dst_u, dst_stride_u, width, height)) {
176 return OK;
177 }
178 } else if (IsNV21(img)) {
179 libyuv::CopyPlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
180 libyuv::CopyPlane(src_v, src_stride_v, dst_v, dst_stride_v, width, height / 2);
181 return OK;
182 } else if (IsI420(img)) {
183 if (!libyuv::NV21ToI420(src_y, src_stride_y, src_v, src_stride_v, dst_y, dst_stride_y,
184 dst_u, dst_stride_u, dst_v, dst_stride_v, width, height)) {
185 return OK;
186 }
187 }
188 } else if (IsI420(view)) {
189 if (IsNV12(img)) {
Pawin Vongmasa1f213362019-01-24 06:59:16 -0800190 if (!libyuv::I420ToNV12(src_y, src_stride_y, src_u, src_stride_u, src_v, src_stride_v,
Wonsik Kimf37f2422021-03-04 15:38:59 -0800191 dst_y, dst_stride_y, dst_u, dst_stride_u, width, height)) {
Pawin Vongmasa1f213362019-01-24 06:59:16 -0800192 return OK;
193 }
Wonsik Kima38fdf22021-04-05 14:50:29 -0700194 } else if (IsNV21(img)) {
195 if (!libyuv::I420ToNV21(src_y, src_stride_y, src_u, src_stride_u, src_v, src_stride_v,
196 dst_y, dst_stride_y, dst_v, dst_stride_v, width, height)) {
197 return OK;
198 }
199 } else if (IsI420(img)) {
200 libyuv::CopyPlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
201 libyuv::CopyPlane(src_u, src_stride_u, dst_u, dst_stride_u, width / 2, height / 2);
202 libyuv::CopyPlane(src_v, src_stride_v, dst_v, dst_stride_v, width / 2, height / 2);
203 return OK;
Pawin Vongmasa1f213362019-01-24 06:59:16 -0800204 }
205 }
Pawin Vongmasa36653902018-11-15 00:10:25 -0800206 return _ImageCopy<true>(view, img, imgBase);
207}
208
209status_t ImageCopy(C2GraphicView &view, const uint8_t *imgBase, const MediaImage2 *img) {
Harish Mahendrakarf7c49e22019-05-24 14:19:16 -0700210 if (view.crop().width != img->mWidth || view.crop().height != img->mHeight) {
Pawin Vongmasa1f213362019-01-24 06:59:16 -0800211 return BAD_VALUE;
212 }
Wonsik Kimf37f2422021-03-04 15:38:59 -0800213 const uint8_t* src_y = imgBase + img->mPlane[0].mOffset;
214 const uint8_t* src_u = imgBase + img->mPlane[1].mOffset;
215 const uint8_t* src_v = imgBase + img->mPlane[2].mOffset;
216 int32_t src_stride_y = img->mPlane[0].mRowInc;
217 int32_t src_stride_u = img->mPlane[1].mRowInc;
218 int32_t src_stride_v = img->mPlane[2].mRowInc;
219 uint8_t* dst_y = view.data()[0];
220 uint8_t* dst_u = view.data()[1];
221 uint8_t* dst_v = view.data()[2];
222 int32_t dst_stride_y = view.layout().planes[0].rowInc;
223 int32_t dst_stride_u = view.layout().planes[1].rowInc;
224 int32_t dst_stride_v = view.layout().planes[2].rowInc;
225 int width = view.crop().width;
226 int height = view.crop().height;
Wonsik Kima38fdf22021-04-05 14:50:29 -0700227 if (IsNV12(img)) {
228 if (IsNV12(view)) {
229 libyuv::CopyPlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
230 libyuv::CopyPlane(src_u, src_stride_u, dst_u, dst_stride_u, width, height / 2);
231 return OK;
232 } else if (IsNV21(view)) {
233 if (!libyuv::NV21ToNV12(src_y, src_stride_y, src_u, src_stride_u,
234 dst_y, dst_stride_y, dst_v, dst_stride_v, width, height)) {
235 return OK;
236 }
237 } else if (IsI420(view)) {
Pawin Vongmasa1f213362019-01-24 06:59:16 -0800238 if (!libyuv::NV12ToI420(src_y, src_stride_y, src_u, src_stride_u, dst_y, dst_stride_y,
Wonsik Kimf37f2422021-03-04 15:38:59 -0800239 dst_u, dst_stride_u, dst_v, dst_stride_v, width, height)) {
Pawin Vongmasa1f213362019-01-24 06:59:16 -0800240 return OK;
241 }
Wonsik Kima38fdf22021-04-05 14:50:29 -0700242 }
243 } else if (IsNV21(img)) {
244 if (IsNV12(view)) {
245 if (!libyuv::NV21ToNV12(src_y, src_stride_y, src_v, src_stride_v,
246 dst_y, dst_stride_y, dst_u, dst_stride_u, width, height)) {
247 return OK;
248 }
249 } else if (IsNV21(view)) {
250 libyuv::CopyPlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
251 libyuv::CopyPlane(src_v, src_stride_v, dst_v, dst_stride_v, width, height / 2);
252 return OK;
253 } else if (IsI420(view)) {
254 if (!libyuv::NV21ToI420(src_y, src_stride_y, src_v, src_stride_v, dst_y, dst_stride_y,
255 dst_u, dst_stride_u, dst_v, dst_stride_v, width, height)) {
256 return OK;
257 }
258 }
259 } else if (IsI420(img)) {
260 if (IsNV12(view)) {
Pawin Vongmasa1f213362019-01-24 06:59:16 -0800261 if (!libyuv::I420ToNV12(src_y, src_stride_y, src_u, src_stride_u, src_v, src_stride_v,
Wonsik Kimf37f2422021-03-04 15:38:59 -0800262 dst_y, dst_stride_y, dst_u, dst_stride_u, width, height)) {
Pawin Vongmasa1f213362019-01-24 06:59:16 -0800263 return OK;
264 }
Wonsik Kima38fdf22021-04-05 14:50:29 -0700265 } else if (IsNV21(view)) {
266 if (!libyuv::I420ToNV21(src_y, src_stride_y, src_u, src_stride_u, src_v, src_stride_v,
267 dst_y, dst_stride_y, dst_v, dst_stride_v, width, height)) {
268 return OK;
269 }
270 } else if (IsI420(view)) {
271 libyuv::CopyPlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
272 libyuv::CopyPlane(src_u, src_stride_u, dst_u, dst_stride_u, width / 2, height / 2);
273 libyuv::CopyPlane(src_v, src_stride_v, dst_v, dst_stride_v, width / 2, height / 2);
274 return OK;
Pawin Vongmasa1f213362019-01-24 06:59:16 -0800275 }
276 }
Pawin Vongmasa36653902018-11-15 00:10:25 -0800277 return _ImageCopy<false>(view, img, imgBase);
278}
279
280bool IsYUV420(const C2GraphicView &view) {
281 const C2PlanarLayout &layout = view.layout();
282 return (layout.numPlanes == 3
283 && layout.type == C2PlanarLayout::TYPE_YUV
284 && layout.planes[layout.PLANE_Y].channel == C2PlaneInfo::CHANNEL_Y
285 && layout.planes[layout.PLANE_Y].allocatedDepth == 8
286 && layout.planes[layout.PLANE_Y].bitDepth == 8
287 && layout.planes[layout.PLANE_Y].rightShift == 0
288 && layout.planes[layout.PLANE_Y].colSampling == 1
289 && layout.planes[layout.PLANE_Y].rowSampling == 1
290 && layout.planes[layout.PLANE_U].channel == C2PlaneInfo::CHANNEL_CB
291 && layout.planes[layout.PLANE_U].allocatedDepth == 8
292 && layout.planes[layout.PLANE_U].bitDepth == 8
293 && layout.planes[layout.PLANE_U].rightShift == 0
294 && layout.planes[layout.PLANE_U].colSampling == 2
295 && layout.planes[layout.PLANE_U].rowSampling == 2
296 && layout.planes[layout.PLANE_V].channel == C2PlaneInfo::CHANNEL_CR
297 && layout.planes[layout.PLANE_V].allocatedDepth == 8
298 && layout.planes[layout.PLANE_V].bitDepth == 8
299 && layout.planes[layout.PLANE_V].rightShift == 0
300 && layout.planes[layout.PLANE_V].colSampling == 2
301 && layout.planes[layout.PLANE_V].rowSampling == 2);
302}
303
Pawin Vongmasa1f213362019-01-24 06:59:16 -0800304bool IsNV12(const C2GraphicView &view) {
305 if (!IsYUV420(view)) {
306 return false;
307 }
308 const C2PlanarLayout &layout = view.layout();
309 return (layout.rootPlanes == 2
310 && layout.planes[layout.PLANE_U].colInc == 2
311 && layout.planes[layout.PLANE_U].rootIx == layout.PLANE_U
312 && layout.planes[layout.PLANE_U].offset == 0
313 && layout.planes[layout.PLANE_V].colInc == 2
314 && layout.planes[layout.PLANE_V].rootIx == layout.PLANE_U
315 && layout.planes[layout.PLANE_V].offset == 1);
316}
317
Wonsik Kima38fdf22021-04-05 14:50:29 -0700318bool IsNV21(const C2GraphicView &view) {
319 if (!IsYUV420(view)) {
320 return false;
321 }
322 const C2PlanarLayout &layout = view.layout();
323 return (layout.rootPlanes == 2
324 && layout.planes[layout.PLANE_U].colInc == 2
325 && layout.planes[layout.PLANE_U].rootIx == layout.PLANE_V
326 && layout.planes[layout.PLANE_U].offset == 1
327 && layout.planes[layout.PLANE_V].colInc == 2
328 && layout.planes[layout.PLANE_V].rootIx == layout.PLANE_V
329 && layout.planes[layout.PLANE_V].offset == 0);
330}
331
Pawin Vongmasa1f213362019-01-24 06:59:16 -0800332bool IsI420(const C2GraphicView &view) {
333 if (!IsYUV420(view)) {
334 return false;
335 }
336 const C2PlanarLayout &layout = view.layout();
337 return (layout.rootPlanes == 3
338 && layout.planes[layout.PLANE_U].colInc == 1
339 && layout.planes[layout.PLANE_U].rootIx == layout.PLANE_U
340 && layout.planes[layout.PLANE_U].offset == 0
341 && layout.planes[layout.PLANE_V].colInc == 1
342 && layout.planes[layout.PLANE_V].rootIx == layout.PLANE_V
343 && layout.planes[layout.PLANE_V].offset == 0);
344}
345
346bool IsYUV420(const MediaImage2 *img) {
347 return (img->mType == MediaImage2::MEDIA_IMAGE_TYPE_YUV
348 && img->mNumPlanes == 3
349 && img->mBitDepth == 8
350 && img->mBitDepthAllocated == 8
351 && img->mPlane[0].mHorizSubsampling == 1
352 && img->mPlane[0].mVertSubsampling == 1
353 && img->mPlane[1].mHorizSubsampling == 2
354 && img->mPlane[1].mVertSubsampling == 2
355 && img->mPlane[2].mHorizSubsampling == 2
356 && img->mPlane[2].mVertSubsampling == 2);
357}
358
359bool IsNV12(const MediaImage2 *img) {
360 if (!IsYUV420(img)) {
361 return false;
362 }
363 return (img->mPlane[1].mColInc == 2
364 && img->mPlane[2].mColInc == 2
Harish Mahendrakarcd59f032021-04-16 18:55:41 -0700365 && (img->mPlane[2].mOffset == img->mPlane[1].mOffset + 1));
Pawin Vongmasa1f213362019-01-24 06:59:16 -0800366}
367
Wonsik Kima38fdf22021-04-05 14:50:29 -0700368bool IsNV21(const MediaImage2 *img) {
369 if (!IsYUV420(img)) {
370 return false;
371 }
372 return (img->mPlane[1].mColInc == 2
373 && img->mPlane[2].mColInc == 2
Harish Mahendrakarcd59f032021-04-16 18:55:41 -0700374 && (img->mPlane[1].mOffset == img->mPlane[2].mOffset + 1));
Wonsik Kima38fdf22021-04-05 14:50:29 -0700375}
376
Pawin Vongmasa1f213362019-01-24 06:59:16 -0800377bool IsI420(const MediaImage2 *img) {
378 if (!IsYUV420(img)) {
379 return false;
380 }
381 return (img->mPlane[1].mColInc == 1
382 && img->mPlane[2].mColInc == 1
383 && img->mPlane[2].mOffset > img->mPlane[1].mOffset);
384}
385
Wonsik Kima38fdf22021-04-05 14:50:29 -0700386FlexLayout GetYuv420FlexibleLayout() {
387 static FlexLayout sLayout = []{
388 AHardwareBuffer_Desc desc = {
389 16, // width
390 16, // height
391 1, // layers
392 AHARDWAREBUFFER_FORMAT_Y8Cb8Cr8_420,
393 AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN | AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN,
394 0, // stride
395 0, // rfu0
396 0, // rfu1
397 };
398 AHardwareBuffer *buffer = nullptr;
399 int ret = AHardwareBuffer_allocate(&desc, &buffer);
400 if (ret != 0) {
401 return FLEX_LAYOUT_UNKNOWN;
402 }
403 class AutoCloser {
404 public:
405 AutoCloser(AHardwareBuffer *buffer) : mBuffer(buffer), mLocked(false) {}
406 ~AutoCloser() {
407 if (mLocked) {
408 AHardwareBuffer_unlock(mBuffer, nullptr);
409 }
410 AHardwareBuffer_release(mBuffer);
411 }
412
413 void setLocked() { mLocked = true; }
414
415 private:
416 AHardwareBuffer *mBuffer;
417 bool mLocked;
418 } autoCloser(buffer);
419 AHardwareBuffer_Planes planes;
420 ret = AHardwareBuffer_lockPlanes(
421 buffer,
422 AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN | AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN,
423 -1, // fence
424 nullptr, // rect
425 &planes);
426 if (ret != 0) {
427 AHardwareBuffer_release(buffer);
428 return FLEX_LAYOUT_UNKNOWN;
429 }
430 autoCloser.setLocked();
431 if (planes.planeCount != 3) {
432 return FLEX_LAYOUT_UNKNOWN;
433 }
434 if (planes.planes[0].pixelStride != 1) {
435 return FLEX_LAYOUT_UNKNOWN;
436 }
437 if (planes.planes[1].pixelStride == 1 && planes.planes[2].pixelStride == 1) {
438 return FLEX_LAYOUT_PLANAR;
439 }
440 if (planes.planes[1].pixelStride == 2 && planes.planes[2].pixelStride == 2) {
441 ssize_t uvDist =
442 static_cast<uint8_t *>(planes.planes[2].data) -
443 static_cast<uint8_t *>(planes.planes[1].data);
444 if (uvDist == 1) {
445 return FLEX_LAYOUT_SEMIPLANAR_UV;
446 } else if (uvDist == -1) {
447 return FLEX_LAYOUT_SEMIPLANAR_VU;
448 }
449 return FLEX_LAYOUT_UNKNOWN;
450 }
451 return FLEX_LAYOUT_UNKNOWN;
452 }();
453 return sLayout;
454}
455
Pawin Vongmasa36653902018-11-15 00:10:25 -0800456MediaImage2 CreateYUV420PlanarMediaImage2(
457 uint32_t width, uint32_t height, uint32_t stride, uint32_t vstride) {
458 return MediaImage2 {
459 .mType = MediaImage2::MEDIA_IMAGE_TYPE_YUV,
460 .mNumPlanes = 3,
461 .mWidth = width,
462 .mHeight = height,
463 .mBitDepth = 8,
464 .mBitDepthAllocated = 8,
465 .mPlane = {
466 {
467 .mOffset = 0,
468 .mColInc = 1,
469 .mRowInc = (int32_t)stride,
470 .mHorizSubsampling = 1,
471 .mVertSubsampling = 1,
472 },
473 {
474 .mOffset = stride * vstride,
475 .mColInc = 1,
476 .mRowInc = (int32_t)stride / 2,
477 .mHorizSubsampling = 2,
478 .mVertSubsampling = 2,
479 },
480 {
481 .mOffset = stride * vstride * 5 / 4,
482 .mColInc = 1,
483 .mRowInc = (int32_t)stride / 2,
484 .mHorizSubsampling = 2,
485 .mVertSubsampling = 2,
486 }
487 },
488 };
489}
490
491MediaImage2 CreateYUV420SemiPlanarMediaImage2(
492 uint32_t width, uint32_t height, uint32_t stride, uint32_t vstride) {
493 return MediaImage2 {
494 .mType = MediaImage2::MEDIA_IMAGE_TYPE_YUV,
495 .mNumPlanes = 3,
496 .mWidth = width,
497 .mHeight = height,
498 .mBitDepth = 8,
499 .mBitDepthAllocated = 8,
500 .mPlane = {
501 {
502 .mOffset = 0,
503 .mColInc = 1,
504 .mRowInc = (int32_t)stride,
505 .mHorizSubsampling = 1,
506 .mVertSubsampling = 1,
507 },
508 {
509 .mOffset = stride * vstride,
510 .mColInc = 2,
511 .mRowInc = (int32_t)stride,
512 .mHorizSubsampling = 2,
513 .mVertSubsampling = 2,
514 },
515 {
516 .mOffset = stride * vstride + 1,
517 .mColInc = 2,
518 .mRowInc = (int32_t)stride,
519 .mHorizSubsampling = 2,
520 .mVertSubsampling = 2,
521 }
522 },
523 };
524}
525
Manisha Jajoo478423c2021-05-20 21:28:14 +0530526// Matrix coefficient to convert RGB to Planar YUV data.
527// Each sub-array represents the 3X3 coeff used with R, G and B
528static const int16_t bt601Matrix[2][3][3] = {
529 { { 76, 150, 29 }, { -43, -85, 128 }, { 128, -107, -21 } }, /* RANGE_FULL */
530 { { 66, 129, 25 }, { -38, -74, 112 }, { 112, -94, -18 } }, /* RANGE_LIMITED */
531};
532
533static const int16_t bt709Matrix[2][3][3] = {
534 { { 54, 183, 18 }, { -29, -99, 128 }, { 128, -116, -12 } }, /* RANGE_FULL */
535 { { 47, 157, 16 }, { -26, -86, 112 }, { 112, -102, -10 } }, /* RANGE_LIMITED */
536};
537
Pawin Vongmasa36653902018-11-15 00:10:25 -0800538status_t ConvertRGBToPlanarYUV(
539 uint8_t *dstY, size_t dstStride, size_t dstVStride, size_t bufferSize,
Manisha Jajoo478423c2021-05-20 21:28:14 +0530540 const C2GraphicView &src, C2Color::matrix_t colorMatrix, C2Color::range_t colorRange) {
Pawin Vongmasa36653902018-11-15 00:10:25 -0800541 CHECK(dstY != nullptr);
542 CHECK((src.width() & 1) == 0);
543 CHECK((src.height() & 1) == 0);
544
545 if (dstStride * dstVStride * 3 / 2 > bufferSize) {
546 ALOGD("conversion buffer is too small for converting from RGB to YUV");
547 return NO_MEMORY;
548 }
549
550 uint8_t *dstU = dstY + dstStride * dstVStride;
551 uint8_t *dstV = dstU + (dstStride >> 1) * (dstVStride >> 1);
552
553 const C2PlanarLayout &layout = src.layout();
554 const uint8_t *pRed = src.data()[C2PlanarLayout::PLANE_R];
555 const uint8_t *pGreen = src.data()[C2PlanarLayout::PLANE_G];
556 const uint8_t *pBlue = src.data()[C2PlanarLayout::PLANE_B];
557
Manisha Jajoo478423c2021-05-20 21:28:14 +0530558 // set default range as limited
559 if (colorRange != C2Color::RANGE_FULL && colorRange != C2Color::RANGE_LIMITED) {
560 colorRange = C2Color::RANGE_LIMITED;
561 }
562 const int16_t (*weights)[3] =
563 (colorMatrix == C2Color::MATRIX_BT709) ?
564 bt709Matrix[colorRange - 1] : bt601Matrix[colorRange - 1];
565 uint8_t zeroLvl = colorRange == C2Color::RANGE_FULL ? 0 : 16;
566 uint8_t maxLvlLuma = colorRange == C2Color::RANGE_FULL ? 255 : 235;
567 uint8_t maxLvlChroma = colorRange == C2Color::RANGE_FULL ? 255 : 240;
568
569#define CLIP3(min,v,max) (((v) < (min)) ? (min) : (((max) > (v)) ? (v) : (max)))
Pawin Vongmasa36653902018-11-15 00:10:25 -0800570 for (size_t y = 0; y < src.height(); ++y) {
571 for (size_t x = 0; x < src.width(); ++x) {
Manisha Jajoo478423c2021-05-20 21:28:14 +0530572 uint8_t r = *pRed;
573 uint8_t g = *pGreen;
574 uint8_t b = *pBlue;
Pawin Vongmasa36653902018-11-15 00:10:25 -0800575
Manisha Jajoo478423c2021-05-20 21:28:14 +0530576 unsigned luma = ((r * weights[0][0] + g * weights[0][1] + b * weights[0][2]) >> 8) +
577 zeroLvl;
Pawin Vongmasa36653902018-11-15 00:10:25 -0800578
Manisha Jajoo478423c2021-05-20 21:28:14 +0530579 dstY[x] = CLIP3(zeroLvl, luma, maxLvlLuma);
Pawin Vongmasa36653902018-11-15 00:10:25 -0800580
581 if ((x & 1) == 0 && (y & 1) == 0) {
Manisha Jajoo478423c2021-05-20 21:28:14 +0530582 unsigned U = ((r * weights[1][0] + g * weights[1][1] + b * weights[1][2]) >> 8) +
583 128;
Pawin Vongmasa36653902018-11-15 00:10:25 -0800584
Manisha Jajoo478423c2021-05-20 21:28:14 +0530585 unsigned V = ((r * weights[2][0] + g * weights[2][1] + b * weights[2][2]) >> 8) +
586 128;
Pawin Vongmasa36653902018-11-15 00:10:25 -0800587
Manisha Jajoo478423c2021-05-20 21:28:14 +0530588 dstU[x >> 1] = CLIP3(zeroLvl, U, maxLvlChroma);
589 dstV[x >> 1] = CLIP3(zeroLvl, V, maxLvlChroma);
Pawin Vongmasa36653902018-11-15 00:10:25 -0800590 }
591 pRed += layout.planes[C2PlanarLayout::PLANE_R].colInc;
592 pGreen += layout.planes[C2PlanarLayout::PLANE_G].colInc;
593 pBlue += layout.planes[C2PlanarLayout::PLANE_B].colInc;
594 }
595
596 if ((y & 1) == 0) {
597 dstU += dstStride >> 1;
598 dstV += dstStride >> 1;
599 }
600
601 pRed -= layout.planes[C2PlanarLayout::PLANE_R].colInc * src.width();
602 pGreen -= layout.planes[C2PlanarLayout::PLANE_G].colInc * src.width();
603 pBlue -= layout.planes[C2PlanarLayout::PLANE_B].colInc * src.width();
604 pRed += layout.planes[C2PlanarLayout::PLANE_R].rowInc;
605 pGreen += layout.planes[C2PlanarLayout::PLANE_G].rowInc;
606 pBlue += layout.planes[C2PlanarLayout::PLANE_B].rowInc;
607
608 dstY += dstStride;
609 }
610 return OK;
611}
612
613namespace {
614
615/**
616 * A block of raw allocated memory.
617 */
618struct MemoryBlockPoolBlock {
619 MemoryBlockPoolBlock(size_t size)
620 : mData(new uint8_t[size]), mSize(mData ? size : 0) { }
621
622 ~MemoryBlockPoolBlock() {
623 delete[] mData;
624 }
625
626 const uint8_t *data() const {
627 return mData;
628 }
629
630 size_t size() const {
631 return mSize;
632 }
633
634 C2_DO_NOT_COPY(MemoryBlockPoolBlock);
635
636private:
637 uint8_t *mData;
638 size_t mSize;
639};
640
641/**
642 * A simple raw memory block pool implementation.
643 */
644struct MemoryBlockPoolImpl {
645 void release(std::list<MemoryBlockPoolBlock>::const_iterator block) {
646 std::lock_guard<std::mutex> lock(mMutex);
647 // return block to free blocks if it is the current size; otherwise, discard
648 if (block->size() == mCurrentSize) {
649 mFreeBlocks.splice(mFreeBlocks.begin(), mBlocksInUse, block);
650 } else {
651 mBlocksInUse.erase(block);
652 }
653 }
654
655 std::list<MemoryBlockPoolBlock>::const_iterator fetch(size_t size) {
656 std::lock_guard<std::mutex> lock(mMutex);
657 mFreeBlocks.remove_if([size](const MemoryBlockPoolBlock &block) -> bool {
658 return block.size() != size;
659 });
660 mCurrentSize = size;
661 if (mFreeBlocks.empty()) {
662 mBlocksInUse.emplace_front(size);
663 } else {
664 mBlocksInUse.splice(mBlocksInUse.begin(), mFreeBlocks, mFreeBlocks.begin());
665 }
666 return mBlocksInUse.begin();
667 }
668
669 MemoryBlockPoolImpl() = default;
670
671 C2_DO_NOT_COPY(MemoryBlockPoolImpl);
672
673private:
674 std::mutex mMutex;
675 std::list<MemoryBlockPoolBlock> mFreeBlocks;
676 std::list<MemoryBlockPoolBlock> mBlocksInUse;
677 size_t mCurrentSize;
678};
679
680} // namespace
681
682struct MemoryBlockPool::Impl : MemoryBlockPoolImpl {
683};
684
685struct MemoryBlock::Impl {
686 Impl(std::list<MemoryBlockPoolBlock>::const_iterator block,
687 std::shared_ptr<MemoryBlockPoolImpl> pool)
688 : mBlock(block), mPool(pool) {
689 }
690
691 ~Impl() {
692 mPool->release(mBlock);
693 }
694
695 const uint8_t *data() const {
696 return mBlock->data();
697 }
698
699 size_t size() const {
700 return mBlock->size();
701 }
702
703private:
704 std::list<MemoryBlockPoolBlock>::const_iterator mBlock;
705 std::shared_ptr<MemoryBlockPoolImpl> mPool;
706};
707
708MemoryBlock MemoryBlockPool::fetch(size_t size) {
709 std::list<MemoryBlockPoolBlock>::const_iterator poolBlock = mImpl->fetch(size);
710 return MemoryBlock(std::make_shared<MemoryBlock::Impl>(
711 poolBlock, std::static_pointer_cast<MemoryBlockPoolImpl>(mImpl)));
712}
713
714MemoryBlockPool::MemoryBlockPool()
715 : mImpl(std::make_shared<MemoryBlockPool::Impl>()) {
716}
717
718MemoryBlock::MemoryBlock(std::shared_ptr<MemoryBlock::Impl> impl)
719 : mImpl(impl) {
720}
721
722MemoryBlock::MemoryBlock() = default;
723
724MemoryBlock::~MemoryBlock() = default;
725
726const uint8_t* MemoryBlock::data() const {
727 return mImpl ? mImpl->data() : nullptr;
728}
729
730size_t MemoryBlock::size() const {
731 return mImpl ? mImpl->size() : 0;
732}
733
734MemoryBlock MemoryBlock::Allocate(size_t size) {
735 return MemoryBlockPool().fetch(size);
736}
737
738} // namespace android