blob: 3bb659353a1080ca15bbdfa9487c849e8c3fd583 [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 "Codec2Buffer"
My Name6bd9a7d2022-03-25 12:37:58 -070019#define ATRACE_TAG ATRACE_TAG_VIDEO
Pawin Vongmasa36653902018-11-15 00:10:25 -080020#include <utils/Log.h>
My Name6bd9a7d2022-03-25 12:37:58 -070021#include <utils/Trace.h>
Pawin Vongmasa36653902018-11-15 00:10:25 -080022
Wonsik Kima79c5522022-01-18 16:29:24 -080023#include <aidl/android/hardware/graphics/common/Cta861_3.h>
24#include <aidl/android/hardware/graphics/common/Smpte2086.h>
Wonsik Kim89814312023-02-01 10:46:16 -080025#include <android-base/no_destructor.h>
bohua222c0b2021-01-12 18:54:53 -080026#include <android-base/properties.h>
Wonsik Kim41d83432020-04-27 16:40:49 -070027#include <android/hardware/cas/native/1.0/types.h>
28#include <android/hardware/drm/1.0/types.h>
Pawin Vongmasa36653902018-11-15 00:10:25 -080029#include <hidlmemory/FrameworkUtils.h>
30#include <media/hardware/HardwareAPI.h>
Robert Shih895fba92019-07-16 16:29:44 -070031#include <media/stagefright/CodecBase.h>
Pawin Vongmasa36653902018-11-15 00:10:25 -080032#include <media/stagefright/MediaCodecConstants.h>
33#include <media/stagefright/foundation/ABuffer.h>
34#include <media/stagefright/foundation/AMessage.h>
35#include <media/stagefright/foundation/AUtils.h>
Wonsik Kim41d83432020-04-27 16:40:49 -070036#include <mediadrm/ICrypto.h>
Pawin Vongmasa36653902018-11-15 00:10:25 -080037#include <nativebase/nativebase.h>
Devin Moore8e506ac2023-08-25 00:13:51 +000038#include <ui/GraphicBufferMapper.h>
Wonsik Kimebe0f9e2019-07-03 11:06:51 -070039#include <ui/Fence.h>
Pawin Vongmasa36653902018-11-15 00:10:25 -080040
41#include <C2AllocatorGralloc.h>
42#include <C2BlockInternal.h>
43#include <C2Debug.h>
44
45#include "Codec2Buffer.h"
46
47namespace android {
48
49// Codec2Buffer
50
51bool Codec2Buffer::canCopyLinear(const std::shared_ptr<C2Buffer> &buffer) const {
52 if (const_cast<Codec2Buffer *>(this)->base() == nullptr) {
53 return false;
54 }
55 if (!buffer) {
56 // Nothing to copy, so we can copy by doing nothing.
57 return true;
58 }
59 if (buffer->data().type() != C2BufferData::LINEAR) {
60 return false;
61 }
62 if (buffer->data().linearBlocks().size() == 0u) {
63 // Nothing to copy, so we can copy by doing nothing.
64 return true;
65 } else if (buffer->data().linearBlocks().size() > 1u) {
66 // We don't know how to copy more than one blocks.
67 return false;
68 }
69 if (buffer->data().linearBlocks()[0].size() > capacity()) {
70 // It won't fit.
71 return false;
72 }
73 return true;
74}
75
76bool Codec2Buffer::copyLinear(const std::shared_ptr<C2Buffer> &buffer) {
77 // We assume that all canCopyLinear() checks passed.
78 if (!buffer || buffer->data().linearBlocks().size() == 0u
79 || buffer->data().linearBlocks()[0].size() == 0u) {
80 setRange(0, 0);
81 return true;
82 }
83 C2ReadView view = buffer->data().linearBlocks()[0].map().get();
84 if (view.error() != C2_OK) {
85 ALOGD("Error while mapping: %d", view.error());
86 return false;
87 }
88 if (view.capacity() > capacity()) {
89 ALOGD("C2ConstLinearBlock lied --- it actually doesn't fit: view(%u) > this(%zu)",
90 view.capacity(), capacity());
91 return false;
92 }
93 memcpy(base(), view.data(), view.capacity());
94 setRange(0, view.capacity());
95 return true;
96}
97
98void Codec2Buffer::setImageData(const sp<ABuffer> &imageData) {
Wonsik Kimc48ddcf2019-02-11 16:16:57 -080099 mImageData = imageData;
Pawin Vongmasa36653902018-11-15 00:10:25 -0800100}
101
102// LocalLinearBuffer
103
104bool LocalLinearBuffer::canCopy(const std::shared_ptr<C2Buffer> &buffer) const {
105 return canCopyLinear(buffer);
106}
107
108bool LocalLinearBuffer::copy(const std::shared_ptr<C2Buffer> &buffer) {
109 return copyLinear(buffer);
110}
111
112// DummyContainerBuffer
113
Pawin Vongmasa8be93112018-12-11 14:01:42 -0800114static uint8_t sDummyByte[1] = { 0 };
115
Pawin Vongmasa36653902018-11-15 00:10:25 -0800116DummyContainerBuffer::DummyContainerBuffer(
117 const sp<AMessage> &format, const std::shared_ptr<C2Buffer> &buffer)
Pawin Vongmasa8be93112018-12-11 14:01:42 -0800118 : Codec2Buffer(format, new ABuffer(sDummyByte, 1)),
Pawin Vongmasa36653902018-11-15 00:10:25 -0800119 mBufferRef(buffer) {
120 setRange(0, buffer ? 1 : 0);
121}
122
123std::shared_ptr<C2Buffer> DummyContainerBuffer::asC2Buffer() {
Wonsik Kimf9b32122020-04-02 11:30:17 -0700124 return mBufferRef;
125}
126
127void DummyContainerBuffer::clearC2BufferRefs() {
128 mBufferRef.reset();
Pawin Vongmasa36653902018-11-15 00:10:25 -0800129}
130
131bool DummyContainerBuffer::canCopy(const std::shared_ptr<C2Buffer> &) const {
132 return !mBufferRef;
133}
134
135bool DummyContainerBuffer::copy(const std::shared_ptr<C2Buffer> &buffer) {
136 mBufferRef = buffer;
137 setRange(0, mBufferRef ? 1 : 0);
138 return true;
139}
140
141// LinearBlockBuffer
142
143// static
144sp<LinearBlockBuffer> LinearBlockBuffer::Allocate(
145 const sp<AMessage> &format, const std::shared_ptr<C2LinearBlock> &block) {
146 C2WriteView writeView(block->map().get());
147 if (writeView.error() != C2_OK) {
148 return nullptr;
149 }
150 return new LinearBlockBuffer(format, std::move(writeView), block);
151}
152
153std::shared_ptr<C2Buffer> LinearBlockBuffer::asC2Buffer() {
154 return C2Buffer::CreateLinearBuffer(mBlock->share(offset(), size(), C2Fence()));
155}
156
157bool LinearBlockBuffer::canCopy(const std::shared_ptr<C2Buffer> &buffer) const {
158 return canCopyLinear(buffer);
159}
160
161bool LinearBlockBuffer::copy(const std::shared_ptr<C2Buffer> &buffer) {
162 return copyLinear(buffer);
163}
164
165LinearBlockBuffer::LinearBlockBuffer(
166 const sp<AMessage> &format,
167 C2WriteView&& writeView,
168 const std::shared_ptr<C2LinearBlock> &block)
169 : Codec2Buffer(format, new ABuffer(writeView.data(), writeView.size())),
170 mWriteView(writeView),
171 mBlock(block) {
172}
173
174// ConstLinearBlockBuffer
175
176// static
177sp<ConstLinearBlockBuffer> ConstLinearBlockBuffer::Allocate(
178 const sp<AMessage> &format, const std::shared_ptr<C2Buffer> &buffer) {
179 if (!buffer
180 || buffer->data().type() != C2BufferData::LINEAR
181 || buffer->data().linearBlocks().size() != 1u) {
182 return nullptr;
183 }
184 C2ReadView readView(buffer->data().linearBlocks()[0].map().get());
185 if (readView.error() != C2_OK) {
186 return nullptr;
187 }
188 return new ConstLinearBlockBuffer(format, std::move(readView), buffer);
189}
190
191ConstLinearBlockBuffer::ConstLinearBlockBuffer(
192 const sp<AMessage> &format,
193 C2ReadView&& readView,
194 const std::shared_ptr<C2Buffer> &buffer)
195 : Codec2Buffer(format, new ABuffer(
196 // NOTE: ABuffer only takes non-const pointer but this data is
197 // supposed to be read-only.
198 const_cast<uint8_t *>(readView.data()), readView.capacity())),
199 mReadView(readView),
200 mBufferRef(buffer) {
201}
202
203std::shared_ptr<C2Buffer> ConstLinearBlockBuffer::asC2Buffer() {
Wonsik Kimf9b32122020-04-02 11:30:17 -0700204 return mBufferRef;
205}
206
207void ConstLinearBlockBuffer::clearC2BufferRefs() {
208 mBufferRef.reset();
Pawin Vongmasa36653902018-11-15 00:10:25 -0800209}
210
211// GraphicView2MediaImageConverter
212
213namespace {
214
215class GraphicView2MediaImageConverter {
216public:
217 /**
218 * Creates a C2GraphicView <=> MediaImage converter
219 *
220 * \param view C2GraphicView object
Wonsik Kimd79ee1f2020-08-27 17:41:56 -0700221 * \param format buffer format
Wonsik Kim7d966312019-06-04 14:00:49 -0700222 * \param copy whether the converter is used for copy or not
Pawin Vongmasa36653902018-11-15 00:10:25 -0800223 */
224 GraphicView2MediaImageConverter(
Wonsik Kimd79ee1f2020-08-27 17:41:56 -0700225 const C2GraphicView &view, const sp<AMessage> &format, bool copy)
Pawin Vongmasa36653902018-11-15 00:10:25 -0800226 : mInitCheck(NO_INIT),
227 mView(view),
228 mWidth(view.width()),
229 mHeight(view.height()),
Pawin Vongmasa36653902018-11-15 00:10:25 -0800230 mAllocatedDepth(0),
231 mBackBufferSize(0),
232 mMediaImage(new ABuffer(sizeof(MediaImage2))) {
My Name6bd9a7d2022-03-25 12:37:58 -0700233 ATRACE_CALL();
Wonsik Kimd79ee1f2020-08-27 17:41:56 -0700234 if (!format->findInt32(KEY_COLOR_FORMAT, &mClientColorFormat)) {
235 mClientColorFormat = COLOR_FormatYUV420Flexible;
236 }
237 if (!format->findInt32("android._color-format", &mComponentColorFormat)) {
238 mComponentColorFormat = COLOR_FormatYUV420Flexible;
239 }
Pawin Vongmasa36653902018-11-15 00:10:25 -0800240 if (view.error() != C2_OK) {
241 ALOGD("Converter: view.error() = %d", view.error());
242 mInitCheck = BAD_VALUE;
243 return;
244 }
245 MediaImage2 *mediaImage = (MediaImage2 *)mMediaImage->base();
246 const C2PlanarLayout &layout = view.layout();
247 if (layout.numPlanes == 0) {
248 ALOGD("Converter: 0 planes");
249 mInitCheck = BAD_VALUE;
250 return;
251 }
Harish Mahendrakarcac53852019-02-20 10:59:10 -0800252 memset(mediaImage, 0, sizeof(*mediaImage));
Pawin Vongmasa36653902018-11-15 00:10:25 -0800253 mAllocatedDepth = layout.planes[0].allocatedDepth;
254 uint32_t bitDepth = layout.planes[0].bitDepth;
255
256 // align width and height to support subsampling cleanly
Wonsik Kim8bfa17a2019-05-30 22:12:30 -0700257 uint32_t stride = align(view.crop().width, 2) * divUp(layout.planes[0].allocatedDepth, 8u);
258 uint32_t vStride = align(view.crop().height, 2);
Pawin Vongmasa36653902018-11-15 00:10:25 -0800259
Wonsik Kimd79ee1f2020-08-27 17:41:56 -0700260 bool tryWrapping = !copy;
261
Pawin Vongmasa36653902018-11-15 00:10:25 -0800262 switch (layout.type) {
Wonsik Kimd79ee1f2020-08-27 17:41:56 -0700263 case C2PlanarLayout::TYPE_YUV: {
Pawin Vongmasa36653902018-11-15 00:10:25 -0800264 mediaImage->mType = MediaImage2::MEDIA_IMAGE_TYPE_YUV;
265 if (layout.numPlanes != 3) {
266 ALOGD("Converter: %d planes for YUV layout", layout.numPlanes);
267 mInitCheck = BAD_VALUE;
268 return;
269 }
Arun Johnson3ab32cd2022-06-10 18:58:01 +0000270 std::optional<int> clientBitDepth = {};
271 switch (mClientColorFormat) {
272 case COLOR_FormatYUVP010:
273 clientBitDepth = 10;
274 break;
275 case COLOR_FormatYUV411PackedPlanar:
276 case COLOR_FormatYUV411Planar:
277 case COLOR_FormatYUV420Flexible:
278 case COLOR_FormatYUV420PackedPlanar:
279 case COLOR_FormatYUV420PackedSemiPlanar:
280 case COLOR_FormatYUV420Planar:
281 case COLOR_FormatYUV420SemiPlanar:
282 case COLOR_FormatYUV422Flexible:
283 case COLOR_FormatYUV422PackedPlanar:
284 case COLOR_FormatYUV422PackedSemiPlanar:
285 case COLOR_FormatYUV422Planar:
286 case COLOR_FormatYUV422SemiPlanar:
287 case COLOR_FormatYUV444Flexible:
288 case COLOR_FormatYUV444Interleaved:
289 clientBitDepth = 8;
290 break;
291 default:
292 // no-op; used with optional
293 break;
294
295 }
296 // conversion fails if client bit-depth and the component bit-depth differs
297 if ((clientBitDepth) && (bitDepth != clientBitDepth.value())) {
298 ALOGD("Bit depth of client: %d and component: %d differs",
299 *clientBitDepth, bitDepth);
300 mInitCheck = BAD_VALUE;
301 return;
302 }
Wonsik Kimd79ee1f2020-08-27 17:41:56 -0700303 C2PlaneInfo yPlane = layout.planes[C2PlanarLayout::PLANE_Y];
304 C2PlaneInfo uPlane = layout.planes[C2PlanarLayout::PLANE_U];
305 C2PlaneInfo vPlane = layout.planes[C2PlanarLayout::PLANE_V];
306 if (yPlane.channel != C2PlaneInfo::CHANNEL_Y
307 || uPlane.channel != C2PlaneInfo::CHANNEL_CB
308 || vPlane.channel != C2PlaneInfo::CHANNEL_CR) {
309 ALOGD("Converter: not YUV layout");
Pawin Vongmasa36653902018-11-15 00:10:25 -0800310 mInitCheck = BAD_VALUE;
311 return;
312 }
Wonsik Kimd79ee1f2020-08-27 17:41:56 -0700313 bool yuv420888 = yPlane.rowSampling == 1 && yPlane.colSampling == 1
314 && uPlane.rowSampling == 2 && uPlane.colSampling == 2
315 && vPlane.rowSampling == 2 && vPlane.colSampling == 2;
316 if (yuv420888) {
317 for (uint32_t i = 0; i < 3; ++i) {
318 const C2PlaneInfo &plane = layout.planes[i];
319 if (plane.allocatedDepth != 8 || plane.bitDepth != 8) {
320 yuv420888 = false;
321 break;
Pawin Vongmasa36653902018-11-15 00:10:25 -0800322 }
Wonsik Kimd79ee1f2020-08-27 17:41:56 -0700323 }
324 yuv420888 = yuv420888 && yPlane.colInc == 1 && uPlane.rowInc == vPlane.rowInc;
325 }
326 int32_t copyFormat = mClientColorFormat;
327 if (yuv420888 && mClientColorFormat == COLOR_FormatYUV420Flexible) {
328 if (uPlane.colInc == 2 && vPlane.colInc == 2
329 && yPlane.rowInc == uPlane.rowInc) {
330 copyFormat = COLOR_FormatYUV420PackedSemiPlanar;
331 } else if (uPlane.colInc == 1 && vPlane.colInc == 1
332 && yPlane.rowInc == uPlane.rowInc * 2) {
333 copyFormat = COLOR_FormatYUV420PackedPlanar;
334 }
335 }
336 ALOGV("client_fmt=0x%x y:{colInc=%d rowInc=%d} u:{colInc=%d rowInc=%d} "
337 "v:{colInc=%d rowInc=%d}",
338 mClientColorFormat,
339 yPlane.colInc, yPlane.rowInc,
340 uPlane.colInc, uPlane.rowInc,
341 vPlane.colInc, vPlane.rowInc);
342 switch (copyFormat) {
343 case COLOR_FormatYUV420Flexible:
Pawin Vongmasa36653902018-11-15 00:10:25 -0800344 case COLOR_FormatYUV420Planar:
345 case COLOR_FormatYUV420PackedPlanar:
346 mediaImage->mPlane[mediaImage->Y].mOffset = 0;
347 mediaImage->mPlane[mediaImage->Y].mColInc = 1;
Wonsik Kim8bfa17a2019-05-30 22:12:30 -0700348 mediaImage->mPlane[mediaImage->Y].mRowInc = stride;
Pawin Vongmasa36653902018-11-15 00:10:25 -0800349 mediaImage->mPlane[mediaImage->Y].mHorizSubsampling = 1;
350 mediaImage->mPlane[mediaImage->Y].mVertSubsampling = 1;
351
Wonsik Kim8bfa17a2019-05-30 22:12:30 -0700352 mediaImage->mPlane[mediaImage->U].mOffset = stride * vStride;
Pawin Vongmasa36653902018-11-15 00:10:25 -0800353 mediaImage->mPlane[mediaImage->U].mColInc = 1;
Wonsik Kim8bfa17a2019-05-30 22:12:30 -0700354 mediaImage->mPlane[mediaImage->U].mRowInc = stride / 2;
Pawin Vongmasa36653902018-11-15 00:10:25 -0800355 mediaImage->mPlane[mediaImage->U].mHorizSubsampling = 2;
356 mediaImage->mPlane[mediaImage->U].mVertSubsampling = 2;
357
Wonsik Kim8bfa17a2019-05-30 22:12:30 -0700358 mediaImage->mPlane[mediaImage->V].mOffset = stride * vStride * 5 / 4;
Pawin Vongmasa36653902018-11-15 00:10:25 -0800359 mediaImage->mPlane[mediaImage->V].mColInc = 1;
Wonsik Kim8bfa17a2019-05-30 22:12:30 -0700360 mediaImage->mPlane[mediaImage->V].mRowInc = stride / 2;
Pawin Vongmasa36653902018-11-15 00:10:25 -0800361 mediaImage->mPlane[mediaImage->V].mHorizSubsampling = 2;
362 mediaImage->mPlane[mediaImage->V].mVertSubsampling = 2;
Wonsik Kimd79ee1f2020-08-27 17:41:56 -0700363
364 if (tryWrapping && mClientColorFormat != COLOR_FormatYUV420Flexible) {
365 tryWrapping = yuv420888 && uPlane.colInc == 1 && vPlane.colInc == 1
366 && yPlane.rowInc == uPlane.rowInc * 2
367 && view.data()[0] < view.data()[1]
368 && view.data()[1] < view.data()[2];
369 }
Pawin Vongmasa36653902018-11-15 00:10:25 -0800370 break;
371
372 case COLOR_FormatYUV420SemiPlanar:
373 case COLOR_FormatYUV420PackedSemiPlanar:
374 mediaImage->mPlane[mediaImage->Y].mOffset = 0;
375 mediaImage->mPlane[mediaImage->Y].mColInc = 1;
Wonsik Kim8bfa17a2019-05-30 22:12:30 -0700376 mediaImage->mPlane[mediaImage->Y].mRowInc = stride;
Pawin Vongmasa36653902018-11-15 00:10:25 -0800377 mediaImage->mPlane[mediaImage->Y].mHorizSubsampling = 1;
378 mediaImage->mPlane[mediaImage->Y].mVertSubsampling = 1;
379
Wonsik Kim8bfa17a2019-05-30 22:12:30 -0700380 mediaImage->mPlane[mediaImage->U].mOffset = stride * vStride;
Pawin Vongmasa36653902018-11-15 00:10:25 -0800381 mediaImage->mPlane[mediaImage->U].mColInc = 2;
Wonsik Kim8bfa17a2019-05-30 22:12:30 -0700382 mediaImage->mPlane[mediaImage->U].mRowInc = stride;
Pawin Vongmasa36653902018-11-15 00:10:25 -0800383 mediaImage->mPlane[mediaImage->U].mHorizSubsampling = 2;
384 mediaImage->mPlane[mediaImage->U].mVertSubsampling = 2;
385
Wonsik Kim8bfa17a2019-05-30 22:12:30 -0700386 mediaImage->mPlane[mediaImage->V].mOffset = stride * vStride + 1;
Pawin Vongmasa36653902018-11-15 00:10:25 -0800387 mediaImage->mPlane[mediaImage->V].mColInc = 2;
Wonsik Kim8bfa17a2019-05-30 22:12:30 -0700388 mediaImage->mPlane[mediaImage->V].mRowInc = stride;
Pawin Vongmasa36653902018-11-15 00:10:25 -0800389 mediaImage->mPlane[mediaImage->V].mHorizSubsampling = 2;
390 mediaImage->mPlane[mediaImage->V].mVertSubsampling = 2;
Wonsik Kimd79ee1f2020-08-27 17:41:56 -0700391
392 if (tryWrapping && mClientColorFormat != COLOR_FormatYUV420Flexible) {
393 tryWrapping = yuv420888 && uPlane.colInc == 2 && vPlane.colInc == 2
394 && yPlane.rowInc == uPlane.rowInc
395 && view.data()[0] < view.data()[1]
396 && view.data()[1] < view.data()[2];
397 }
Pawin Vongmasa36653902018-11-15 00:10:25 -0800398 break;
399
Wonsik Kim29e3c4d2020-09-02 12:19:44 -0700400 case COLOR_FormatYUVP010:
Wonsik Kim08a8a2b2021-05-10 19:03:47 -0700401 // stride is in bytes
Wonsik Kim29e3c4d2020-09-02 12:19:44 -0700402 mediaImage->mPlane[mediaImage->Y].mOffset = 0;
403 mediaImage->mPlane[mediaImage->Y].mColInc = 2;
Wonsik Kim08a8a2b2021-05-10 19:03:47 -0700404 mediaImage->mPlane[mediaImage->Y].mRowInc = stride;
Wonsik Kim29e3c4d2020-09-02 12:19:44 -0700405 mediaImage->mPlane[mediaImage->Y].mHorizSubsampling = 1;
406 mediaImage->mPlane[mediaImage->Y].mVertSubsampling = 1;
407
Wonsik Kim08a8a2b2021-05-10 19:03:47 -0700408 mediaImage->mPlane[mediaImage->U].mOffset = stride * vStride;
Wonsik Kim29e3c4d2020-09-02 12:19:44 -0700409 mediaImage->mPlane[mediaImage->U].mColInc = 4;
Wonsik Kim08a8a2b2021-05-10 19:03:47 -0700410 mediaImage->mPlane[mediaImage->U].mRowInc = stride;
Wonsik Kim29e3c4d2020-09-02 12:19:44 -0700411 mediaImage->mPlane[mediaImage->U].mHorizSubsampling = 2;
412 mediaImage->mPlane[mediaImage->U].mVertSubsampling = 2;
413
Wonsik Kim08a8a2b2021-05-10 19:03:47 -0700414 mediaImage->mPlane[mediaImage->V].mOffset = stride * vStride + 2;
Wonsik Kim29e3c4d2020-09-02 12:19:44 -0700415 mediaImage->mPlane[mediaImage->V].mColInc = 4;
Wonsik Kim08a8a2b2021-05-10 19:03:47 -0700416 mediaImage->mPlane[mediaImage->V].mRowInc = stride;
Wonsik Kim29e3c4d2020-09-02 12:19:44 -0700417 mediaImage->mPlane[mediaImage->V].mHorizSubsampling = 2;
418 mediaImage->mPlane[mediaImage->V].mVertSubsampling = 2;
Wonsik Kimd79ee1f2020-08-27 17:41:56 -0700419 if (tryWrapping) {
420 tryWrapping = yPlane.allocatedDepth == 16
421 && uPlane.allocatedDepth == 16
422 && vPlane.allocatedDepth == 16
423 && yPlane.bitDepth == 10
424 && uPlane.bitDepth == 10
425 && vPlane.bitDepth == 10
426 && yPlane.rightShift == 6
427 && uPlane.rightShift == 6
428 && vPlane.rightShift == 6
429 && yPlane.rowSampling == 1 && yPlane.colSampling == 1
430 && uPlane.rowSampling == 2 && uPlane.colSampling == 2
431 && vPlane.rowSampling == 2 && vPlane.colSampling == 2
432 && yPlane.colInc == 2
433 && uPlane.colInc == 4
434 && vPlane.colInc == 4
435 && yPlane.rowInc == uPlane.rowInc
436 && yPlane.rowInc == vPlane.rowInc;
437 }
Wonsik Kim29e3c4d2020-09-02 12:19:44 -0700438 break;
439
Wonsik Kimd79ee1f2020-08-27 17:41:56 -0700440 default: {
441 // default to fully planar format --- this will be overridden if wrapping
442 // TODO: keep interleaved format
443 int32_t colInc = divUp(mAllocatedDepth, 8u);
444 int32_t rowInc = stride * colInc / yPlane.colSampling;
445 mediaImage->mPlane[mediaImage->Y].mOffset = 0;
446 mediaImage->mPlane[mediaImage->Y].mColInc = colInc;
447 mediaImage->mPlane[mediaImage->Y].mRowInc = rowInc;
448 mediaImage->mPlane[mediaImage->Y].mHorizSubsampling = yPlane.colSampling;
449 mediaImage->mPlane[mediaImage->Y].mVertSubsampling = yPlane.rowSampling;
450 int32_t offset = rowInc * vStride / yPlane.rowSampling;
451
452 rowInc = stride * colInc / uPlane.colSampling;
453 mediaImage->mPlane[mediaImage->U].mOffset = offset;
454 mediaImage->mPlane[mediaImage->U].mColInc = colInc;
455 mediaImage->mPlane[mediaImage->U].mRowInc = rowInc;
456 mediaImage->mPlane[mediaImage->U].mHorizSubsampling = uPlane.colSampling;
457 mediaImage->mPlane[mediaImage->U].mVertSubsampling = uPlane.rowSampling;
458 offset += rowInc * vStride / uPlane.rowSampling;
459
460 rowInc = stride * colInc / vPlane.colSampling;
461 mediaImage->mPlane[mediaImage->V].mOffset = offset;
462 mediaImage->mPlane[mediaImage->V].mColInc = colInc;
463 mediaImage->mPlane[mediaImage->V].mRowInc = rowInc;
464 mediaImage->mPlane[mediaImage->V].mHorizSubsampling = vPlane.colSampling;
465 mediaImage->mPlane[mediaImage->V].mVertSubsampling = vPlane.rowSampling;
466 break;
467 }
Pawin Vongmasa36653902018-11-15 00:10:25 -0800468 }
469 break;
Wonsik Kimd79ee1f2020-08-27 17:41:56 -0700470 }
471
Pawin Vongmasa36653902018-11-15 00:10:25 -0800472 case C2PlanarLayout::TYPE_YUVA:
Wonsik Kimd79ee1f2020-08-27 17:41:56 -0700473 ALOGD("Converter: unrecognized color format "
474 "(client %d component %d) for YUVA layout",
475 mClientColorFormat, mComponentColorFormat);
476 mInitCheck = NO_INIT;
Pawin Vongmasa36653902018-11-15 00:10:25 -0800477 return;
478 case C2PlanarLayout::TYPE_RGB:
Slawomir Rosek580a6442023-05-10 16:23:38 +0000479 mediaImage->mType = MediaImage2::MEDIA_IMAGE_TYPE_RGB;
Wonsik Kimd79ee1f2020-08-27 17:41:56 -0700480 // TODO: support MediaImage layout
Slawomir Rosek580a6442023-05-10 16:23:38 +0000481 switch (mClientColorFormat) {
482 case COLOR_FormatSurface:
483 case COLOR_FormatRGBFlexible:
484 case COLOR_Format24bitBGR888:
485 case COLOR_Format24bitRGB888:
486 ALOGD("Converter: accept color format "
487 "(client %d component %d) for RGB layout",
488 mClientColorFormat, mComponentColorFormat);
489 break;
490 default:
491 ALOGD("Converter: unrecognized color format "
492 "(client %d component %d) for RGB layout",
493 mClientColorFormat, mComponentColorFormat);
494 mInitCheck = BAD_VALUE;
495 return;
496 }
497 if (layout.numPlanes != 3) {
498 ALOGD("Converter: %d planes for RGB layout", layout.numPlanes);
499 mInitCheck = BAD_VALUE;
500 return;
501 }
502 break;
Pawin Vongmasa36653902018-11-15 00:10:25 -0800503 case C2PlanarLayout::TYPE_RGBA:
Slawomir Rosek580a6442023-05-10 16:23:38 +0000504 mediaImage->mType = MediaImage2::MEDIA_IMAGE_TYPE_RGBA;
Wonsik Kimd79ee1f2020-08-27 17:41:56 -0700505 // TODO: support MediaImage layout
Slawomir Rosek580a6442023-05-10 16:23:38 +0000506 switch (mClientColorFormat) {
507 case COLOR_FormatSurface:
508 case COLOR_FormatRGBAFlexible:
509 case COLOR_Format32bitABGR8888:
510 case COLOR_Format32bitARGB8888:
511 case COLOR_Format32bitBGRA8888:
512 ALOGD("Converter: accept color format "
513 "(client %d component %d) for RGBA layout",
514 mClientColorFormat, mComponentColorFormat);
515 break;
516 default:
517 ALOGD("Converter: unrecognized color format "
518 "(client %d component %d) for RGBA layout",
519 mClientColorFormat, mComponentColorFormat);
520 mInitCheck = BAD_VALUE;
521 return;
522 }
523 if (layout.numPlanes != 4) {
524 ALOGD("Converter: %d planes for RGBA layout", layout.numPlanes);
525 mInitCheck = BAD_VALUE;
526 return;
527 }
528 break;
Pawin Vongmasa36653902018-11-15 00:10:25 -0800529 default:
530 mediaImage->mType = MediaImage2::MEDIA_IMAGE_TYPE_UNKNOWN;
Wonsik Kimd79ee1f2020-08-27 17:41:56 -0700531 if (layout.numPlanes == 1) {
532 const C2PlaneInfo &plane = layout.planes[0];
533 if (plane.colInc < 0 || plane.rowInc < 0) {
534 // Copy-only if we have negative colInc/rowInc
535 tryWrapping = false;
536 }
537 mediaImage->mPlane[0].mOffset = 0;
538 mediaImage->mPlane[0].mColInc = std::abs(plane.colInc);
539 mediaImage->mPlane[0].mRowInc = std::abs(plane.rowInc);
540 mediaImage->mPlane[0].mHorizSubsampling = plane.colSampling;
541 mediaImage->mPlane[0].mVertSubsampling = plane.rowSampling;
542 } else {
543 ALOGD("Converter: unrecognized layout: color format (client %d component %d)",
544 mClientColorFormat, mComponentColorFormat);
545 mInitCheck = NO_INIT;
546 return;
547 }
548 break;
549 }
550 if (tryWrapping) {
551 // try to map directly. check if the planes are near one another
552 const uint8_t *minPtr = mView.data()[0];
553 const uint8_t *maxPtr = mView.data()[0];
554 int32_t planeSize = 0;
555 for (uint32_t i = 0; i < layout.numPlanes; ++i) {
556 const C2PlaneInfo &plane = layout.planes[i];
557 int64_t planeStride = std::abs(plane.rowInc / plane.colInc);
558 ssize_t minOffset = plane.minOffset(
559 mWidth / plane.colSampling, mHeight / plane.rowSampling);
560 ssize_t maxOffset = plane.maxOffset(
561 mWidth / plane.colSampling, mHeight / plane.rowSampling);
562 if (minPtr > mView.data()[i] + minOffset) {
563 minPtr = mView.data()[i] + minOffset;
564 }
565 if (maxPtr < mView.data()[i] + maxOffset) {
566 maxPtr = mView.data()[i] + maxOffset;
567 }
568 planeSize += planeStride * divUp(mAllocatedDepth, 8u)
569 * align(mHeight, 64) / plane.rowSampling;
570 }
571
Wonsik Kim1bf84162022-09-20 11:00:42 -0700572 if (minPtr == mView.data()[0] && (maxPtr - minPtr) <= planeSize) {
Wonsik Kimd79ee1f2020-08-27 17:41:56 -0700573 // FIXME: this is risky as reading/writing data out of bound results
574 // in an undefined behavior, but gralloc does assume a
575 // contiguous mapping
576 for (uint32_t i = 0; i < layout.numPlanes; ++i) {
577 const C2PlaneInfo &plane = layout.planes[i];
578 mediaImage->mPlane[i].mOffset = mView.data()[i] - minPtr;
579 mediaImage->mPlane[i].mColInc = plane.colInc;
580 mediaImage->mPlane[i].mRowInc = plane.rowInc;
581 mediaImage->mPlane[i].mHorizSubsampling = plane.colSampling;
582 mediaImage->mPlane[i].mVertSubsampling = plane.rowSampling;
583 }
Wonsik Kim1bf84162022-09-20 11:00:42 -0700584 mWrapped = new ABuffer(const_cast<uint8_t *>(minPtr), maxPtr - minPtr);
Wonsik Kimd79ee1f2020-08-27 17:41:56 -0700585 ALOGV("Converter: wrapped (capacity=%zu)", mWrapped->capacity());
586 }
Pawin Vongmasa36653902018-11-15 00:10:25 -0800587 }
588 mediaImage->mNumPlanes = layout.numPlanes;
Harish Mahendrakarf7c49e22019-05-24 14:19:16 -0700589 mediaImage->mWidth = view.crop().width;
590 mediaImage->mHeight = view.crop().height;
Pawin Vongmasa36653902018-11-15 00:10:25 -0800591 mediaImage->mBitDepth = bitDepth;
592 mediaImage->mBitDepthAllocated = mAllocatedDepth;
593
594 uint32_t bufferSize = 0;
595 for (uint32_t i = 0; i < layout.numPlanes; ++i) {
596 const C2PlaneInfo &plane = layout.planes[i];
597 if (plane.allocatedDepth < plane.bitDepth
598 || plane.rightShift != plane.allocatedDepth - plane.bitDepth) {
599 ALOGD("rightShift value of %u unsupported", plane.rightShift);
600 mInitCheck = BAD_VALUE;
601 return;
602 }
603 if (plane.allocatedDepth > 8 && plane.endianness != C2PlaneInfo::NATIVE) {
604 ALOGD("endianness value of %u unsupported", plane.endianness);
605 mInitCheck = BAD_VALUE;
606 return;
607 }
608 if (plane.allocatedDepth != mAllocatedDepth || plane.bitDepth != bitDepth) {
Wonsik Kimd79ee1f2020-08-27 17:41:56 -0700609 ALOGD("different allocatedDepth/bitDepth per plane unsupported");
Pawin Vongmasa36653902018-11-15 00:10:25 -0800610 mInitCheck = BAD_VALUE;
611 return;
612 }
Wonsik Kim08a8a2b2021-05-10 19:03:47 -0700613 // stride is in bytes
614 bufferSize += stride * vStride / plane.rowSampling / plane.colSampling;
Pawin Vongmasa36653902018-11-15 00:10:25 -0800615 }
616
617 mBackBufferSize = bufferSize;
618 mInitCheck = OK;
619 }
620
621 status_t initCheck() const { return mInitCheck; }
622
623 uint32_t backBufferSize() const { return mBackBufferSize; }
624
625 /**
626 * Wrap C2GraphicView using a MediaImage2. Note that if not wrapped, the content is not mapped
627 * in this function --- the caller should use CopyGraphicView2MediaImage() function to copy the
628 * data into a backing buffer explicitly.
629 *
630 * \return media buffer. This is null if wrapping failed.
631 */
632 sp<ABuffer> wrap() const {
633 if (mBackBuffer == nullptr) {
634 return mWrapped;
635 }
636 return nullptr;
637 }
638
639 bool setBackBuffer(const sp<ABuffer> &backBuffer) {
Wonsik Kim186fdbf2019-01-29 13:30:01 -0800640 if (backBuffer == nullptr) {
641 return false;
642 }
Pawin Vongmasa36653902018-11-15 00:10:25 -0800643 if (backBuffer->capacity() < mBackBufferSize) {
644 return false;
645 }
646 backBuffer->setRange(0, mBackBufferSize);
647 mBackBuffer = backBuffer;
648 return true;
649 }
650
651 /**
652 * Copy C2GraphicView to MediaImage2.
653 */
654 status_t copyToMediaImage() {
My Name6bd9a7d2022-03-25 12:37:58 -0700655 ATRACE_CALL();
Pawin Vongmasa36653902018-11-15 00:10:25 -0800656 if (mInitCheck != OK) {
657 return mInitCheck;
658 }
659 return ImageCopy(mBackBuffer->base(), getMediaImage(), mView);
660 }
661
662 const sp<ABuffer> &imageData() const { return mMediaImage; }
663
664private:
665 status_t mInitCheck;
666
667 const C2GraphicView mView;
668 uint32_t mWidth;
669 uint32_t mHeight;
Wonsik Kimd79ee1f2020-08-27 17:41:56 -0700670 int32_t mClientColorFormat; ///< SDK color format for MediaImage
671 int32_t mComponentColorFormat; ///< SDK color format from component
Pawin Vongmasa36653902018-11-15 00:10:25 -0800672 sp<ABuffer> mWrapped; ///< wrapped buffer (if we can map C2Buffer to an ABuffer)
673 uint32_t mAllocatedDepth;
674 uint32_t mBackBufferSize;
675 sp<ABuffer> mMediaImage;
676 std::function<sp<ABuffer>(size_t)> mAlloc;
677
678 sp<ABuffer> mBackBuffer; ///< backing buffer if we have to copy C2Buffer <=> ABuffer
679
680 MediaImage2 *getMediaImage() {
681 return (MediaImage2 *)mMediaImage->base();
682 }
683};
684
685} // namespace
686
687// GraphicBlockBuffer
688
689// static
690sp<GraphicBlockBuffer> GraphicBlockBuffer::Allocate(
691 const sp<AMessage> &format,
692 const std::shared_ptr<C2GraphicBlock> &block,
693 std::function<sp<ABuffer>(size_t)> alloc) {
My Name6bd9a7d2022-03-25 12:37:58 -0700694 ATRACE_BEGIN("GraphicBlockBuffer::Allocate block->map()");
Pawin Vongmasa36653902018-11-15 00:10:25 -0800695 C2GraphicView view(block->map().get());
My Name6bd9a7d2022-03-25 12:37:58 -0700696 ATRACE_END();
Pawin Vongmasa36653902018-11-15 00:10:25 -0800697 if (view.error() != C2_OK) {
698 ALOGD("C2GraphicBlock::map failed: %d", view.error());
699 return nullptr;
700 }
701
Wonsik Kimd79ee1f2020-08-27 17:41:56 -0700702 GraphicView2MediaImageConverter converter(view, format, false /* copy */);
Pawin Vongmasa36653902018-11-15 00:10:25 -0800703 if (converter.initCheck() != OK) {
704 ALOGD("Converter init failed: %d", converter.initCheck());
705 return nullptr;
706 }
707 bool wrapped = true;
708 sp<ABuffer> buffer = converter.wrap();
709 if (buffer == nullptr) {
710 buffer = alloc(converter.backBufferSize());
711 if (!converter.setBackBuffer(buffer)) {
712 ALOGD("Converter failed to set back buffer");
713 return nullptr;
714 }
715 wrapped = false;
716 }
717 return new GraphicBlockBuffer(
718 format,
719 buffer,
720 std::move(view),
721 block,
722 converter.imageData(),
723 wrapped);
724}
725
726GraphicBlockBuffer::GraphicBlockBuffer(
727 const sp<AMessage> &format,
728 const sp<ABuffer> &buffer,
729 C2GraphicView &&view,
730 const std::shared_ptr<C2GraphicBlock> &block,
731 const sp<ABuffer> &imageData,
732 bool wrapped)
733 : Codec2Buffer(format, buffer),
734 mView(view),
735 mBlock(block),
Pawin Vongmasa36653902018-11-15 00:10:25 -0800736 mWrapped(wrapped) {
737 setImageData(imageData);
738}
739
740std::shared_ptr<C2Buffer> GraphicBlockBuffer::asC2Buffer() {
My Name6bd9a7d2022-03-25 12:37:58 -0700741 ATRACE_CALL();
Pawin Vongmasa36653902018-11-15 00:10:25 -0800742 uint32_t width = mView.width();
743 uint32_t height = mView.height();
744 if (!mWrapped) {
745 (void)ImageCopy(mView, base(), imageData());
746 }
747 return C2Buffer::CreateGraphicBuffer(
748 mBlock->share(C2Rect(width, height), C2Fence()));
749}
750
751// GraphicMetadataBuffer
752GraphicMetadataBuffer::GraphicMetadataBuffer(
753 const sp<AMessage> &format,
754 const std::shared_ptr<C2Allocator> &alloc)
755 : Codec2Buffer(format, new ABuffer(sizeof(VideoNativeMetadata))),
756 mAlloc(alloc) {
757 ((VideoNativeMetadata *)base())->pBuffer = nullptr;
758}
759
760std::shared_ptr<C2Buffer> GraphicMetadataBuffer::asC2Buffer() {
bohua222c0b2021-01-12 18:54:53 -0800761#ifdef __LP64__
762 static std::once_flag s_checkOnce;
Harish Mahendrakar731e9142021-04-21 17:20:39 -0700763 static bool s_is64bitOk {true};
bohua222c0b2021-01-12 18:54:53 -0800764 std::call_once(s_checkOnce, [&](){
765 const std::string abi32list =
766 ::android::base::GetProperty("ro.product.cpu.abilist32", "");
Harish Mahendrakar731e9142021-04-21 17:20:39 -0700767 if (!abi32list.empty()) {
768 int32_t inputSurfaceSetting =
769 ::android::base::GetIntProperty("debug.stagefright.c2inputsurface", int32_t(0));
770 s_is64bitOk = inputSurfaceSetting != 0;
bohua222c0b2021-01-12 18:54:53 -0800771 }
772 });
773
Harish Mahendrakar731e9142021-04-21 17:20:39 -0700774 if (!s_is64bitOk) {
775 ALOGE("GraphicMetadataBuffer does not work in 32+64 system if compiled as 64-bit object"\
776 "when debug.stagefright.c2inputsurface is set to 0");
bohua222c0b2021-01-12 18:54:53 -0800777 return nullptr;
778 }
779#endif
780
Pawin Vongmasa36653902018-11-15 00:10:25 -0800781 VideoNativeMetadata *meta = (VideoNativeMetadata *)base();
782 ANativeWindowBuffer *buffer = (ANativeWindowBuffer *)meta->pBuffer;
783 if (buffer == nullptr) {
784 ALOGD("VideoNativeMetadata contains null buffer");
785 return nullptr;
786 }
787
788 ALOGV("VideoNativeMetadata: %dx%d", buffer->width, buffer->height);
789 C2Handle *handle = WrapNativeCodec2GrallocHandle(
Sungtak Leea4d13be2019-01-23 15:24:46 -0800790 buffer->handle,
Pawin Vongmasa36653902018-11-15 00:10:25 -0800791 buffer->width,
792 buffer->height,
793 buffer->format,
794 buffer->usage,
795 buffer->stride);
796 std::shared_ptr<C2GraphicAllocation> alloc;
797 c2_status_t err = mAlloc->priorGraphicAllocation(handle, &alloc);
798 if (err != C2_OK) {
799 ALOGD("Failed to wrap VideoNativeMetadata into C2GraphicAllocation");
Chih-Yu Huangc0ac3552021-03-11 14:37:10 +0900800 native_handle_close(handle);
801 native_handle_delete(handle);
Pawin Vongmasa36653902018-11-15 00:10:25 -0800802 return nullptr;
803 }
804 std::shared_ptr<C2GraphicBlock> block = _C2BlockFactory::CreateGraphicBlock(alloc);
805
806 meta->pBuffer = 0;
Wonsik Kimebe0f9e2019-07-03 11:06:51 -0700807 // TODO: wrap this in C2Fence so that the component can wait when it
808 // actually starts processing.
809 if (meta->nFenceFd >= 0) {
810 sp<Fence> fence(new Fence(meta->nFenceFd));
811 fence->waitForever(LOG_TAG);
812 }
Pawin Vongmasa36653902018-11-15 00:10:25 -0800813 return C2Buffer::CreateGraphicBuffer(
814 block->share(C2Rect(buffer->width, buffer->height), C2Fence()));
Pawin Vongmasa36653902018-11-15 00:10:25 -0800815}
816
817// ConstGraphicBlockBuffer
818
819// static
820sp<ConstGraphicBlockBuffer> ConstGraphicBlockBuffer::Allocate(
821 const sp<AMessage> &format,
822 const std::shared_ptr<C2Buffer> &buffer,
823 std::function<sp<ABuffer>(size_t)> alloc) {
824 if (!buffer
825 || buffer->data().type() != C2BufferData::GRAPHIC
826 || buffer->data().graphicBlocks().size() != 1u) {
827 ALOGD("C2Buffer precond fail");
828 return nullptr;
829 }
My Name6bd9a7d2022-03-25 12:37:58 -0700830 ATRACE_BEGIN("ConstGraphicBlockBuffer::Allocate block->map()");
Pawin Vongmasa36653902018-11-15 00:10:25 -0800831 std::unique_ptr<const C2GraphicView> view(std::make_unique<const C2GraphicView>(
832 buffer->data().graphicBlocks()[0].map().get()));
My Name6bd9a7d2022-03-25 12:37:58 -0700833 ATRACE_END();
Pawin Vongmasa36653902018-11-15 00:10:25 -0800834 std::unique_ptr<const C2GraphicView> holder;
835
Wonsik Kimd79ee1f2020-08-27 17:41:56 -0700836 GraphicView2MediaImageConverter converter(*view, format, false /* copy */);
Pawin Vongmasa36653902018-11-15 00:10:25 -0800837 if (converter.initCheck() != OK) {
838 ALOGD("Converter init failed: %d", converter.initCheck());
839 return nullptr;
840 }
841 bool wrapped = true;
842 sp<ABuffer> aBuffer = converter.wrap();
843 if (aBuffer == nullptr) {
844 aBuffer = alloc(converter.backBufferSize());
845 if (!converter.setBackBuffer(aBuffer)) {
846 ALOGD("Converter failed to set back buffer");
847 return nullptr;
848 }
849 wrapped = false;
850 converter.copyToMediaImage();
851 // We don't need the view.
852 holder = std::move(view);
853 }
854 return new ConstGraphicBlockBuffer(
855 format,
856 aBuffer,
857 std::move(view),
858 buffer,
859 converter.imageData(),
860 wrapped);
861}
862
863// static
864sp<ConstGraphicBlockBuffer> ConstGraphicBlockBuffer::AllocateEmpty(
865 const sp<AMessage> &format,
866 std::function<sp<ABuffer>(size_t)> alloc) {
867 int32_t width, height;
868 if (!format->findInt32("width", &width)
869 || !format->findInt32("height", &height)) {
870 ALOGD("format had no width / height");
871 return nullptr;
872 }
Wonsik Kim08a8a2b2021-05-10 19:03:47 -0700873 int32_t colorFormat = COLOR_FormatYUV420Flexible;
874 int32_t bpp = 12; // 8(Y) + 2(U) + 2(V)
875 if (format->findInt32(KEY_COLOR_FORMAT, &colorFormat)) {
876 if (colorFormat == COLOR_FormatYUVP010) {
877 bpp = 24; // 16(Y) + 4(U) + 4(V)
878 }
879 }
880 sp<ABuffer> aBuffer(alloc(align(width, 16) * align(height, 16) * bpp / 8));
Jiajia Cong9ed0ab22020-12-02 12:00:49 +0800881 if (aBuffer == nullptr) {
882 ALOGD("%s: failed to allocate buffer", __func__);
883 return nullptr;
884 }
Pawin Vongmasa36653902018-11-15 00:10:25 -0800885 return new ConstGraphicBlockBuffer(
886 format,
887 aBuffer,
888 nullptr,
889 nullptr,
890 nullptr,
891 false);
892}
893
894ConstGraphicBlockBuffer::ConstGraphicBlockBuffer(
895 const sp<AMessage> &format,
896 const sp<ABuffer> &aBuffer,
897 std::unique_ptr<const C2GraphicView> &&view,
898 const std::shared_ptr<C2Buffer> &buffer,
899 const sp<ABuffer> &imageData,
900 bool wrapped)
901 : Codec2Buffer(format, aBuffer),
902 mView(std::move(view)),
903 mBufferRef(buffer),
904 mWrapped(wrapped) {
Wonsik Kimc48ddcf2019-02-11 16:16:57 -0800905 setImageData(imageData);
Pawin Vongmasa36653902018-11-15 00:10:25 -0800906}
907
908std::shared_ptr<C2Buffer> ConstGraphicBlockBuffer::asC2Buffer() {
Wonsik Kimf9b32122020-04-02 11:30:17 -0700909 return mBufferRef;
910}
911
912void ConstGraphicBlockBuffer::clearC2BufferRefs() {
Pawin Vongmasa36653902018-11-15 00:10:25 -0800913 mView.reset();
Wonsik Kimf9b32122020-04-02 11:30:17 -0700914 mBufferRef.reset();
Pawin Vongmasa36653902018-11-15 00:10:25 -0800915}
916
917bool ConstGraphicBlockBuffer::canCopy(const std::shared_ptr<C2Buffer> &buffer) const {
918 if (mWrapped || mBufferRef) {
919 ALOGD("ConstGraphicBlockBuffer::canCopy: %swrapped ; buffer ref %s",
920 mWrapped ? "" : "not ", mBufferRef ? "exists" : "doesn't exist");
921 return false;
922 }
923 if (!buffer) {
924 // Nothing to copy, so we can copy by doing nothing.
925 return true;
926 }
927 if (buffer->data().type() != C2BufferData::GRAPHIC) {
928 ALOGD("ConstGraphicBlockBuffer::canCopy: buffer precondition unsatisfied");
929 return false;
930 }
931 if (buffer->data().graphicBlocks().size() == 0) {
932 return true;
933 } else if (buffer->data().graphicBlocks().size() != 1u) {
934 ALOGD("ConstGraphicBlockBuffer::canCopy: too many blocks");
935 return false;
936 }
937
My Name6bd9a7d2022-03-25 12:37:58 -0700938 ATRACE_BEGIN("ConstGraphicBlockBuffer::canCopy block->map()");
Pawin Vongmasa36653902018-11-15 00:10:25 -0800939 GraphicView2MediaImageConverter converter(
Wonsik Kimd79ee1f2020-08-27 17:41:56 -0700940 buffer->data().graphicBlocks()[0].map().get(),
941 // FIXME: format() is not const, but we cannot change it, so do a const cast here
942 const_cast<ConstGraphicBlockBuffer *>(this)->format(),
943 true /* copy */);
My Name6bd9a7d2022-03-25 12:37:58 -0700944 ATRACE_END();
Pawin Vongmasa36653902018-11-15 00:10:25 -0800945 if (converter.initCheck() != OK) {
946 ALOGD("ConstGraphicBlockBuffer::canCopy: converter init failed: %d", converter.initCheck());
947 return false;
948 }
949 if (converter.backBufferSize() > capacity()) {
950 ALOGD("ConstGraphicBlockBuffer::canCopy: insufficient capacity: req %u has %zu",
951 converter.backBufferSize(), capacity());
952 return false;
953 }
954 return true;
955}
956
957bool ConstGraphicBlockBuffer::copy(const std::shared_ptr<C2Buffer> &buffer) {
958 if (!buffer || buffer->data().graphicBlocks().size() == 0) {
959 setRange(0, 0);
960 return true;
961 }
Pawin Vongmasa36653902018-11-15 00:10:25 -0800962
963 GraphicView2MediaImageConverter converter(
Wonsik Kimd79ee1f2020-08-27 17:41:56 -0700964 buffer->data().graphicBlocks()[0].map().get(), format(), true /* copy */);
Pawin Vongmasa36653902018-11-15 00:10:25 -0800965 if (converter.initCheck() != OK) {
966 ALOGD("ConstGraphicBlockBuffer::copy: converter init failed: %d", converter.initCheck());
967 return false;
968 }
969 sp<ABuffer> aBuffer = new ABuffer(base(), capacity());
970 if (!converter.setBackBuffer(aBuffer)) {
971 ALOGD("ConstGraphicBlockBuffer::copy: set back buffer failed");
972 return false;
973 }
Pin-chih Lin1971e2c2019-04-15 19:36:26 +0800974 setRange(0, aBuffer->size()); // align size info
Pawin Vongmasa36653902018-11-15 00:10:25 -0800975 converter.copyToMediaImage();
976 setImageData(converter.imageData());
977 mBufferRef = buffer;
978 return true;
979}
980
981// EncryptedLinearBlockBuffer
982
983EncryptedLinearBlockBuffer::EncryptedLinearBlockBuffer(
984 const sp<AMessage> &format,
985 const std::shared_ptr<C2LinearBlock> &block,
986 const sp<IMemory> &memory,
987 int32_t heapSeqNum)
Ytai Ben-Tsvi7dd39722019-09-05 15:14:30 -0700988 // TODO: Using unsecurePointer() has some associated security pitfalls
989 // (see declaration for details).
990 // Either document why it is safe in this case or address the
991 // issue (e.g. by copying).
992 : Codec2Buffer(format, new ABuffer(memory->unsecurePointer(), memory->size())),
Pawin Vongmasa36653902018-11-15 00:10:25 -0800993 mBlock(block),
994 mMemory(memory),
995 mHeapSeqNum(heapSeqNum) {
996}
997
998std::shared_ptr<C2Buffer> EncryptedLinearBlockBuffer::asC2Buffer() {
999 return C2Buffer::CreateLinearBuffer(mBlock->share(offset(), size(), C2Fence()));
1000}
1001
1002void EncryptedLinearBlockBuffer::fillSourceBuffer(
Robert Shih895fba92019-07-16 16:29:44 -07001003 hardware::drm::V1_0::SharedBuffer *source) {
1004 BufferChannelBase::IMemoryToSharedBuffer(mMemory, mHeapSeqNum, source);
Pawin Vongmasa36653902018-11-15 00:10:25 -08001005}
1006
1007void EncryptedLinearBlockBuffer::fillSourceBuffer(
1008 hardware::cas::native::V1_0::SharedBuffer *source) {
1009 ssize_t offset;
1010 size_t size;
1011
1012 mHidlMemory = hardware::fromHeap(mMemory->getMemory(&offset, &size));
1013 source->heapBase = *mHidlMemory;
1014 source->offset = offset;
1015 source->size = size;
1016}
1017
1018bool EncryptedLinearBlockBuffer::copyDecryptedContent(
1019 const sp<IMemory> &decrypted, size_t length) {
1020 C2WriteView view = mBlock->map().get();
1021 if (view.error() != C2_OK) {
1022 return false;
1023 }
1024 if (view.size() < length) {
1025 return false;
1026 }
Ytai Ben-Tsvi7dd39722019-09-05 15:14:30 -07001027 memcpy(view.data(), decrypted->unsecurePointer(), length);
Pawin Vongmasa36653902018-11-15 00:10:25 -08001028 return true;
1029}
1030
1031bool EncryptedLinearBlockBuffer::copyDecryptedContentFromMemory(size_t length) {
1032 return copyDecryptedContent(mMemory, length);
1033}
1034
1035native_handle_t *EncryptedLinearBlockBuffer::handle() const {
1036 return const_cast<native_handle_t *>(mBlock->handle());
1037}
1038
Wonsik Kima79c5522022-01-18 16:29:24 -08001039using ::aidl::android::hardware::graphics::common::Cta861_3;
1040using ::aidl::android::hardware::graphics::common::Smpte2086;
1041
Wonsik Kima79c5522022-01-18 16:29:24 -08001042namespace {
1043
Devin Moore8e506ac2023-08-25 00:13:51 +00001044class GrallocBuffer {
Wonsik Kima79c5522022-01-18 16:29:24 -08001045public:
Devin Moore8e506ac2023-08-25 00:13:51 +00001046 GrallocBuffer(const C2Handle *const handle) : mBuffer(nullptr) {
1047 GraphicBufferMapper& mapper = GraphicBufferMapper::get();
1048
Wonsik Kime2aa2402022-04-08 14:07:14 -07001049 // Unwrap raw buffer handle from the C2Handle
1050 native_handle_t *nh = UnwrapNativeCodec2GrallocHandle(handle);
1051 if (!nh) {
1052 return;
1053 }
1054 // Import the raw handle so IMapper can use the buffer. The imported
1055 // handle must be freed when the client is done with the buffer.
Devin Moore8e506ac2023-08-25 00:13:51 +00001056 status_t status = mapper.importBufferNoValidate(
1057 nh,
1058 &mBuffer);
1059
1060 if (status != OK) {
1061 ALOGE("Failed to import buffer. Status: %d.", status);
1062 return;
1063 }
Wonsik Kime2aa2402022-04-08 14:07:14 -07001064
1065 // TRICKY: UnwrapNativeCodec2GrallocHandle creates a new handle but
1066 // does not clone the fds. Thus we need to delete the handle
1067 // without closing it.
1068 native_handle_delete(nh);
1069 }
1070
Devin Moore8e506ac2023-08-25 00:13:51 +00001071 ~GrallocBuffer() {
1072 GraphicBufferMapper& mapper = GraphicBufferMapper::get();
1073 if (mBuffer) {
Wonsik Kime2aa2402022-04-08 14:07:14 -07001074 // Free the imported buffer handle. This does not release the
1075 // underlying buffer itself.
Devin Moore8e506ac2023-08-25 00:13:51 +00001076 mapper.freeBuffer(mBuffer);
Wonsik Kima79c5522022-01-18 16:29:24 -08001077 }
1078 }
Wonsik Kime2aa2402022-04-08 14:07:14 -07001079
Devin Moore8e506ac2023-08-25 00:13:51 +00001080 buffer_handle_t get() const { return mBuffer; }
Wonsik Kime2aa2402022-04-08 14:07:14 -07001081 operator bool() const { return (mBuffer != nullptr); }
Wonsik Kima79c5522022-01-18 16:29:24 -08001082private:
Devin Moore8e506ac2023-08-25 00:13:51 +00001083 buffer_handle_t mBuffer;
Wonsik Kima79c5522022-01-18 16:29:24 -08001084};
1085
1086} // namspace
1087
1088c2_status_t GetHdrMetadataFromGralloc4Handle(
1089 const C2Handle *const handle,
1090 std::shared_ptr<C2StreamHdrStaticMetadataInfo::input> *staticInfo,
1091 std::shared_ptr<C2StreamHdrDynamicMetadataInfo::input> *dynamicInfo) {
1092 c2_status_t err = C2_OK;
Devin Moore8e506ac2023-08-25 00:13:51 +00001093 GraphicBufferMapper& mapper = GraphicBufferMapper::get();
1094 GrallocBuffer buffer(handle);
1095 if (!buffer) {
Wonsik Kima79c5522022-01-18 16:29:24 -08001096 // Gralloc4 not supported; nothing to do
1097 return err;
1098 }
Wonsik Kima79c5522022-01-18 16:29:24 -08001099 if (staticInfo) {
Devin Moore8e506ac2023-08-25 00:13:51 +00001100 ALOGV("Grabbing static HDR info from gralloc metadata");
Wonsik Kima79c5522022-01-18 16:29:24 -08001101 staticInfo->reset(new C2StreamHdrStaticMetadataInfo::input(0u));
1102 memset(&(*staticInfo)->mastering, 0, sizeof((*staticInfo)->mastering));
1103 (*staticInfo)->maxCll = 0;
1104 (*staticInfo)->maxFall = 0;
Wonsik Kima79c5522022-01-18 16:29:24 -08001105
Devin Moore8e506ac2023-08-25 00:13:51 +00001106 std::optional<Smpte2086> smpte2086;
1107 status_t status = mapper.getSmpte2086(buffer.get(), &smpte2086);
1108 if (status != OK) {
1109 err = C2_CORRUPTED;
1110 } else {
Wonsik Kima79c5522022-01-18 16:29:24 -08001111 if (smpte2086) {
Devin Moore8e506ac2023-08-25 00:13:51 +00001112 (*staticInfo)->mastering.red.x = smpte2086->primaryRed.x;
1113 (*staticInfo)->mastering.red.y = smpte2086->primaryRed.y;
1114 (*staticInfo)->mastering.green.x = smpte2086->primaryGreen.x;
1115 (*staticInfo)->mastering.green.y = smpte2086->primaryGreen.y;
1116 (*staticInfo)->mastering.blue.x = smpte2086->primaryBlue.x;
1117 (*staticInfo)->mastering.blue.y = smpte2086->primaryBlue.y;
1118 (*staticInfo)->mastering.white.x = smpte2086->whitePoint.x;
1119 (*staticInfo)->mastering.white.y = smpte2086->whitePoint.y;
Wonsik Kima79c5522022-01-18 16:29:24 -08001120
Devin Moore8e506ac2023-08-25 00:13:51 +00001121 (*staticInfo)->mastering.maxLuminance = smpte2086->maxLuminance;
1122 (*staticInfo)->mastering.minLuminance = smpte2086->minLuminance;
Wonsik Kima79c5522022-01-18 16:29:24 -08001123 }
Wonsik Kima79c5522022-01-18 16:29:24 -08001124 }
Wonsik Kima79c5522022-01-18 16:29:24 -08001125
Devin Moore8e506ac2023-08-25 00:13:51 +00001126 std::optional<Cta861_3> cta861_3;
1127 status = mapper.getCta861_3(buffer.get(), &cta861_3);
1128 if (status != OK) {
Wonsik Kima79c5522022-01-18 16:29:24 -08001129 err = C2_CORRUPTED;
Devin Moore8e506ac2023-08-25 00:13:51 +00001130 } else {
1131 if (cta861_3) {
1132 (*staticInfo)->maxCll = cta861_3->maxContentLightLevel;
1133 (*staticInfo)->maxFall = cta861_3->maxFrameAverageLightLevel;
1134 }
Wonsik Kima79c5522022-01-18 16:29:24 -08001135 }
1136 }
Jongchan Choibd2ced72023-06-26 19:36:11 +00001137
1138 if (err != C2_OK) {
1139 staticInfo->reset();
1140 }
1141
Wonsik Kima79c5522022-01-18 16:29:24 -08001142 if (dynamicInfo) {
Devin Moore8e506ac2023-08-25 00:13:51 +00001143 ALOGV("Grabbing dynamic HDR info from gralloc metadata");
Wonsik Kima79c5522022-01-18 16:29:24 -08001144 dynamicInfo->reset();
Devin Moore8e506ac2023-08-25 00:13:51 +00001145 std::optional<std::vector<uint8_t>> vec;
1146 status_t status = mapper.getSmpte2094_40(buffer.get(), &vec);
1147 if (status != OK) {
Wonsik Kima79c5522022-01-18 16:29:24 -08001148 dynamicInfo->reset();
Devin Moore8e506ac2023-08-25 00:13:51 +00001149 err = C2_CORRUPTED;
1150 } else {
1151 if (vec) {
1152 *dynamicInfo = C2StreamHdrDynamicMetadataInfo::input::AllocShared(
1153 vec->size(), 0u, C2Config::HDR_DYNAMIC_METADATA_TYPE_SMPTE_2094_40);
1154 memcpy((*dynamicInfo)->m.data, vec->data(), vec->size());
1155 }
Wonsik Kima79c5522022-01-18 16:29:24 -08001156 }
1157 }
1158
1159 return err;
1160}
1161
Hongguangfc1478a2022-07-20 22:56:06 -07001162c2_status_t SetMetadataToGralloc4Handle(
1163 android_dataspace_t dataSpace,
Wonsik Kima79c5522022-01-18 16:29:24 -08001164 const std::shared_ptr<const C2StreamHdrStaticMetadataInfo::output> &staticInfo,
1165 const std::shared_ptr<const C2StreamHdrDynamicMetadataInfo::output> &dynamicInfo,
1166 const C2Handle *const handle) {
1167 c2_status_t err = C2_OK;
Devin Moore8e506ac2023-08-25 00:13:51 +00001168 GraphicBufferMapper& mapper = GraphicBufferMapper::get();
1169 GrallocBuffer buffer(handle);
1170 if (!buffer) {
Wonsik Kima79c5522022-01-18 16:29:24 -08001171 // Gralloc4 not supported; nothing to do
1172 return err;
1173 }
Devin Moore8e506ac2023-08-25 00:13:51 +00001174 status_t status = mapper.setDataspace(buffer.get(), static_cast<ui::Dataspace>(dataSpace));
1175 if (status != OK) {
1176 err = C2_CORRUPTED;
Hongguangfc1478a2022-07-20 22:56:06 -07001177 }
Wonsik Kima79c5522022-01-18 16:29:24 -08001178 if (staticInfo && *staticInfo) {
Devin Moore8e506ac2023-08-25 00:13:51 +00001179 ALOGV("Setting static HDR info as gralloc metadata");
Wonsik Kima79c5522022-01-18 16:29:24 -08001180 std::optional<Smpte2086> smpte2086 = Smpte2086{
1181 {staticInfo->mastering.red.x, staticInfo->mastering.red.y},
1182 {staticInfo->mastering.green.x, staticInfo->mastering.green.y},
1183 {staticInfo->mastering.blue.x, staticInfo->mastering.blue.y},
1184 {staticInfo->mastering.white.x, staticInfo->mastering.white.y},
1185 staticInfo->mastering.maxLuminance,
1186 staticInfo->mastering.minLuminance,
1187 };
Wonsik Kime2aa2402022-04-08 14:07:14 -07001188 if (0.0 <= smpte2086->primaryRed.x && smpte2086->primaryRed.x <= 1.0
1189 && 0.0 <= smpte2086->primaryRed.y && smpte2086->primaryRed.y <= 1.0
1190 && 0.0 <= smpte2086->primaryGreen.x && smpte2086->primaryGreen.x <= 1.0
1191 && 0.0 <= smpte2086->primaryGreen.y && smpte2086->primaryGreen.y <= 1.0
1192 && 0.0 <= smpte2086->primaryBlue.x && smpte2086->primaryBlue.x <= 1.0
1193 && 0.0 <= smpte2086->primaryBlue.y && smpte2086->primaryBlue.y <= 1.0
1194 && 0.0 <= smpte2086->whitePoint.x && smpte2086->whitePoint.x <= 1.0
1195 && 0.0 <= smpte2086->whitePoint.y && smpte2086->whitePoint.y <= 1.0
Devin Moore8e506ac2023-08-25 00:13:51 +00001196 && 0.0 <= smpte2086->maxLuminance && 0.0 <= smpte2086->minLuminance) {
1197 status = mapper.setSmpte2086(buffer.get(), smpte2086);
1198 if (status != OK) {
Wonsik Kima79c5522022-01-18 16:29:24 -08001199 err = C2_CORRUPTED;
1200 }
1201 }
1202 std::optional<Cta861_3> cta861_3 = Cta861_3{
1203 staticInfo->maxCll,
1204 staticInfo->maxFall,
1205 };
Devin Moore8e506ac2023-08-25 00:13:51 +00001206 if (0.0 <= cta861_3->maxContentLightLevel && 0.0 <= cta861_3->maxFrameAverageLightLevel) {
1207 status = mapper.setCta861_3(buffer.get(), cta861_3);
1208 if (status != OK) {
Wonsik Kima79c5522022-01-18 16:29:24 -08001209 err = C2_CORRUPTED;
1210 }
1211 }
1212 }
Wonsik Kime2aa2402022-04-08 14:07:14 -07001213 if (dynamicInfo && *dynamicInfo && dynamicInfo->flexCount() > 0) {
Devin Moore8e506ac2023-08-25 00:13:51 +00001214 ALOGV("Setting dynamic HDR info as gralloc metadata");
1215 if (dynamicInfo->m.type_ == C2Config::HDR_DYNAMIC_METADATA_TYPE_SMPTE_2094_40) {
1216 std::optional<std::vector<uint8_t>> smpte2094_40 = std::vector<uint8_t>();
1217 smpte2094_40->resize(dynamicInfo->flexCount());
1218 memcpy(smpte2094_40->data(), dynamicInfo->m.data, dynamicInfo->flexCount());
Taehwan Kim3f3d1ac2022-05-12 10:40:29 +09001219
Devin Moore8e506ac2023-08-25 00:13:51 +00001220 status = mapper.setSmpte2094_40(buffer.get(), smpte2094_40);
1221 if (status != OK) {
1222 err = C2_CORRUPTED;
Wonsik Kima79c5522022-01-18 16:29:24 -08001223 }
1224 } else {
1225 err = C2_BAD_VALUE;
1226 }
1227 }
1228
1229 return err;
1230}
1231
Pawin Vongmasa36653902018-11-15 00:10:25 -08001232} // namespace android