blob: 34e6a8845a06a690e8b7d98d073ffb3b35d04a5d [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"
19#include <utils/Log.h>
20
bohua222c0b2021-01-12 18:54:53 -080021#include <android-base/properties.h>
Wonsik Kim41d83432020-04-27 16:40:49 -070022#include <android/hardware/cas/native/1.0/types.h>
23#include <android/hardware/drm/1.0/types.h>
Pawin Vongmasa36653902018-11-15 00:10:25 -080024#include <hidlmemory/FrameworkUtils.h>
25#include <media/hardware/HardwareAPI.h>
Robert Shih895fba92019-07-16 16:29:44 -070026#include <media/stagefright/CodecBase.h>
Pawin Vongmasa36653902018-11-15 00:10:25 -080027#include <media/stagefright/MediaCodecConstants.h>
28#include <media/stagefright/foundation/ABuffer.h>
29#include <media/stagefright/foundation/AMessage.h>
30#include <media/stagefright/foundation/AUtils.h>
Wonsik Kim41d83432020-04-27 16:40:49 -070031#include <mediadrm/ICrypto.h>
Pawin Vongmasa36653902018-11-15 00:10:25 -080032#include <nativebase/nativebase.h>
Wonsik Kimebe0f9e2019-07-03 11:06:51 -070033#include <ui/Fence.h>
Pawin Vongmasa36653902018-11-15 00:10:25 -080034
35#include <C2AllocatorGralloc.h>
36#include <C2BlockInternal.h>
37#include <C2Debug.h>
38
39#include "Codec2Buffer.h"
40
41namespace android {
42
43// Codec2Buffer
44
45bool Codec2Buffer::canCopyLinear(const std::shared_ptr<C2Buffer> &buffer) const {
46 if (const_cast<Codec2Buffer *>(this)->base() == nullptr) {
47 return false;
48 }
49 if (!buffer) {
50 // Nothing to copy, so we can copy by doing nothing.
51 return true;
52 }
53 if (buffer->data().type() != C2BufferData::LINEAR) {
54 return false;
55 }
56 if (buffer->data().linearBlocks().size() == 0u) {
57 // Nothing to copy, so we can copy by doing nothing.
58 return true;
59 } else if (buffer->data().linearBlocks().size() > 1u) {
60 // We don't know how to copy more than one blocks.
61 return false;
62 }
63 if (buffer->data().linearBlocks()[0].size() > capacity()) {
64 // It won't fit.
65 return false;
66 }
67 return true;
68}
69
70bool Codec2Buffer::copyLinear(const std::shared_ptr<C2Buffer> &buffer) {
71 // We assume that all canCopyLinear() checks passed.
72 if (!buffer || buffer->data().linearBlocks().size() == 0u
73 || buffer->data().linearBlocks()[0].size() == 0u) {
74 setRange(0, 0);
75 return true;
76 }
77 C2ReadView view = buffer->data().linearBlocks()[0].map().get();
78 if (view.error() != C2_OK) {
79 ALOGD("Error while mapping: %d", view.error());
80 return false;
81 }
82 if (view.capacity() > capacity()) {
83 ALOGD("C2ConstLinearBlock lied --- it actually doesn't fit: view(%u) > this(%zu)",
84 view.capacity(), capacity());
85 return false;
86 }
87 memcpy(base(), view.data(), view.capacity());
88 setRange(0, view.capacity());
89 return true;
90}
91
92void Codec2Buffer::setImageData(const sp<ABuffer> &imageData) {
Wonsik Kimc48ddcf2019-02-11 16:16:57 -080093 mImageData = imageData;
Pawin Vongmasa36653902018-11-15 00:10:25 -080094}
95
96// LocalLinearBuffer
97
98bool LocalLinearBuffer::canCopy(const std::shared_ptr<C2Buffer> &buffer) const {
99 return canCopyLinear(buffer);
100}
101
102bool LocalLinearBuffer::copy(const std::shared_ptr<C2Buffer> &buffer) {
103 return copyLinear(buffer);
104}
105
106// DummyContainerBuffer
107
Pawin Vongmasa8be93112018-12-11 14:01:42 -0800108static uint8_t sDummyByte[1] = { 0 };
109
Pawin Vongmasa36653902018-11-15 00:10:25 -0800110DummyContainerBuffer::DummyContainerBuffer(
111 const sp<AMessage> &format, const std::shared_ptr<C2Buffer> &buffer)
Pawin Vongmasa8be93112018-12-11 14:01:42 -0800112 : Codec2Buffer(format, new ABuffer(sDummyByte, 1)),
Pawin Vongmasa36653902018-11-15 00:10:25 -0800113 mBufferRef(buffer) {
114 setRange(0, buffer ? 1 : 0);
115}
116
117std::shared_ptr<C2Buffer> DummyContainerBuffer::asC2Buffer() {
Wonsik Kimf9b32122020-04-02 11:30:17 -0700118 return mBufferRef;
119}
120
121void DummyContainerBuffer::clearC2BufferRefs() {
122 mBufferRef.reset();
Pawin Vongmasa36653902018-11-15 00:10:25 -0800123}
124
125bool DummyContainerBuffer::canCopy(const std::shared_ptr<C2Buffer> &) const {
126 return !mBufferRef;
127}
128
129bool DummyContainerBuffer::copy(const std::shared_ptr<C2Buffer> &buffer) {
130 mBufferRef = buffer;
131 setRange(0, mBufferRef ? 1 : 0);
132 return true;
133}
134
135// LinearBlockBuffer
136
137// static
138sp<LinearBlockBuffer> LinearBlockBuffer::Allocate(
139 const sp<AMessage> &format, const std::shared_ptr<C2LinearBlock> &block) {
140 C2WriteView writeView(block->map().get());
141 if (writeView.error() != C2_OK) {
142 return nullptr;
143 }
144 return new LinearBlockBuffer(format, std::move(writeView), block);
145}
146
147std::shared_ptr<C2Buffer> LinearBlockBuffer::asC2Buffer() {
148 return C2Buffer::CreateLinearBuffer(mBlock->share(offset(), size(), C2Fence()));
149}
150
151bool LinearBlockBuffer::canCopy(const std::shared_ptr<C2Buffer> &buffer) const {
152 return canCopyLinear(buffer);
153}
154
155bool LinearBlockBuffer::copy(const std::shared_ptr<C2Buffer> &buffer) {
156 return copyLinear(buffer);
157}
158
159LinearBlockBuffer::LinearBlockBuffer(
160 const sp<AMessage> &format,
161 C2WriteView&& writeView,
162 const std::shared_ptr<C2LinearBlock> &block)
163 : Codec2Buffer(format, new ABuffer(writeView.data(), writeView.size())),
164 mWriteView(writeView),
165 mBlock(block) {
166}
167
168// ConstLinearBlockBuffer
169
170// static
171sp<ConstLinearBlockBuffer> ConstLinearBlockBuffer::Allocate(
172 const sp<AMessage> &format, const std::shared_ptr<C2Buffer> &buffer) {
173 if (!buffer
174 || buffer->data().type() != C2BufferData::LINEAR
175 || buffer->data().linearBlocks().size() != 1u) {
176 return nullptr;
177 }
178 C2ReadView readView(buffer->data().linearBlocks()[0].map().get());
179 if (readView.error() != C2_OK) {
180 return nullptr;
181 }
182 return new ConstLinearBlockBuffer(format, std::move(readView), buffer);
183}
184
185ConstLinearBlockBuffer::ConstLinearBlockBuffer(
186 const sp<AMessage> &format,
187 C2ReadView&& readView,
188 const std::shared_ptr<C2Buffer> &buffer)
189 : Codec2Buffer(format, new ABuffer(
190 // NOTE: ABuffer only takes non-const pointer but this data is
191 // supposed to be read-only.
192 const_cast<uint8_t *>(readView.data()), readView.capacity())),
193 mReadView(readView),
194 mBufferRef(buffer) {
195}
196
197std::shared_ptr<C2Buffer> ConstLinearBlockBuffer::asC2Buffer() {
Wonsik Kimf9b32122020-04-02 11:30:17 -0700198 return mBufferRef;
199}
200
201void ConstLinearBlockBuffer::clearC2BufferRefs() {
202 mBufferRef.reset();
Pawin Vongmasa36653902018-11-15 00:10:25 -0800203}
204
205// GraphicView2MediaImageConverter
206
207namespace {
208
209class GraphicView2MediaImageConverter {
210public:
211 /**
212 * Creates a C2GraphicView <=> MediaImage converter
213 *
214 * \param view C2GraphicView object
Wonsik Kimd79ee1f2020-08-27 17:41:56 -0700215 * \param format buffer format
Wonsik Kim7d966312019-06-04 14:00:49 -0700216 * \param copy whether the converter is used for copy or not
Pawin Vongmasa36653902018-11-15 00:10:25 -0800217 */
218 GraphicView2MediaImageConverter(
Wonsik Kimd79ee1f2020-08-27 17:41:56 -0700219 const C2GraphicView &view, const sp<AMessage> &format, bool copy)
Pawin Vongmasa36653902018-11-15 00:10:25 -0800220 : mInitCheck(NO_INIT),
221 mView(view),
222 mWidth(view.width()),
223 mHeight(view.height()),
Pawin Vongmasa36653902018-11-15 00:10:25 -0800224 mAllocatedDepth(0),
225 mBackBufferSize(0),
226 mMediaImage(new ABuffer(sizeof(MediaImage2))) {
Wonsik Kimd79ee1f2020-08-27 17:41:56 -0700227 if (!format->findInt32(KEY_COLOR_FORMAT, &mClientColorFormat)) {
228 mClientColorFormat = COLOR_FormatYUV420Flexible;
229 }
230 if (!format->findInt32("android._color-format", &mComponentColorFormat)) {
231 mComponentColorFormat = COLOR_FormatYUV420Flexible;
232 }
Pawin Vongmasa36653902018-11-15 00:10:25 -0800233 if (view.error() != C2_OK) {
234 ALOGD("Converter: view.error() = %d", view.error());
235 mInitCheck = BAD_VALUE;
236 return;
237 }
238 MediaImage2 *mediaImage = (MediaImage2 *)mMediaImage->base();
239 const C2PlanarLayout &layout = view.layout();
240 if (layout.numPlanes == 0) {
241 ALOGD("Converter: 0 planes");
242 mInitCheck = BAD_VALUE;
243 return;
244 }
Harish Mahendrakarcac53852019-02-20 10:59:10 -0800245 memset(mediaImage, 0, sizeof(*mediaImage));
Pawin Vongmasa36653902018-11-15 00:10:25 -0800246 mAllocatedDepth = layout.planes[0].allocatedDepth;
247 uint32_t bitDepth = layout.planes[0].bitDepth;
248
249 // align width and height to support subsampling cleanly
Wonsik Kim8bfa17a2019-05-30 22:12:30 -0700250 uint32_t stride = align(view.crop().width, 2) * divUp(layout.planes[0].allocatedDepth, 8u);
251 uint32_t vStride = align(view.crop().height, 2);
Pawin Vongmasa36653902018-11-15 00:10:25 -0800252
Wonsik Kimd79ee1f2020-08-27 17:41:56 -0700253 bool tryWrapping = !copy;
254
Pawin Vongmasa36653902018-11-15 00:10:25 -0800255 switch (layout.type) {
Wonsik Kimd79ee1f2020-08-27 17:41:56 -0700256 case C2PlanarLayout::TYPE_YUV: {
Pawin Vongmasa36653902018-11-15 00:10:25 -0800257 mediaImage->mType = MediaImage2::MEDIA_IMAGE_TYPE_YUV;
258 if (layout.numPlanes != 3) {
259 ALOGD("Converter: %d planes for YUV layout", layout.numPlanes);
260 mInitCheck = BAD_VALUE;
261 return;
262 }
Wonsik Kimd79ee1f2020-08-27 17:41:56 -0700263 C2PlaneInfo yPlane = layout.planes[C2PlanarLayout::PLANE_Y];
264 C2PlaneInfo uPlane = layout.planes[C2PlanarLayout::PLANE_U];
265 C2PlaneInfo vPlane = layout.planes[C2PlanarLayout::PLANE_V];
266 if (yPlane.channel != C2PlaneInfo::CHANNEL_Y
267 || uPlane.channel != C2PlaneInfo::CHANNEL_CB
268 || vPlane.channel != C2PlaneInfo::CHANNEL_CR) {
269 ALOGD("Converter: not YUV layout");
Pawin Vongmasa36653902018-11-15 00:10:25 -0800270 mInitCheck = BAD_VALUE;
271 return;
272 }
Wonsik Kimd79ee1f2020-08-27 17:41:56 -0700273 bool yuv420888 = yPlane.rowSampling == 1 && yPlane.colSampling == 1
274 && uPlane.rowSampling == 2 && uPlane.colSampling == 2
275 && vPlane.rowSampling == 2 && vPlane.colSampling == 2;
276 if (yuv420888) {
277 for (uint32_t i = 0; i < 3; ++i) {
278 const C2PlaneInfo &plane = layout.planes[i];
279 if (plane.allocatedDepth != 8 || plane.bitDepth != 8) {
280 yuv420888 = false;
281 break;
Pawin Vongmasa36653902018-11-15 00:10:25 -0800282 }
Wonsik Kimd79ee1f2020-08-27 17:41:56 -0700283 }
284 yuv420888 = yuv420888 && yPlane.colInc == 1 && uPlane.rowInc == vPlane.rowInc;
285 }
286 int32_t copyFormat = mClientColorFormat;
287 if (yuv420888 && mClientColorFormat == COLOR_FormatYUV420Flexible) {
288 if (uPlane.colInc == 2 && vPlane.colInc == 2
289 && yPlane.rowInc == uPlane.rowInc) {
290 copyFormat = COLOR_FormatYUV420PackedSemiPlanar;
291 } else if (uPlane.colInc == 1 && vPlane.colInc == 1
292 && yPlane.rowInc == uPlane.rowInc * 2) {
293 copyFormat = COLOR_FormatYUV420PackedPlanar;
294 }
295 }
296 ALOGV("client_fmt=0x%x y:{colInc=%d rowInc=%d} u:{colInc=%d rowInc=%d} "
297 "v:{colInc=%d rowInc=%d}",
298 mClientColorFormat,
299 yPlane.colInc, yPlane.rowInc,
300 uPlane.colInc, uPlane.rowInc,
301 vPlane.colInc, vPlane.rowInc);
302 switch (copyFormat) {
303 case COLOR_FormatYUV420Flexible:
Pawin Vongmasa36653902018-11-15 00:10:25 -0800304 case COLOR_FormatYUV420Planar:
305 case COLOR_FormatYUV420PackedPlanar:
306 mediaImage->mPlane[mediaImage->Y].mOffset = 0;
307 mediaImage->mPlane[mediaImage->Y].mColInc = 1;
Wonsik Kim8bfa17a2019-05-30 22:12:30 -0700308 mediaImage->mPlane[mediaImage->Y].mRowInc = stride;
Pawin Vongmasa36653902018-11-15 00:10:25 -0800309 mediaImage->mPlane[mediaImage->Y].mHorizSubsampling = 1;
310 mediaImage->mPlane[mediaImage->Y].mVertSubsampling = 1;
311
Wonsik Kim8bfa17a2019-05-30 22:12:30 -0700312 mediaImage->mPlane[mediaImage->U].mOffset = stride * vStride;
Pawin Vongmasa36653902018-11-15 00:10:25 -0800313 mediaImage->mPlane[mediaImage->U].mColInc = 1;
Wonsik Kim8bfa17a2019-05-30 22:12:30 -0700314 mediaImage->mPlane[mediaImage->U].mRowInc = stride / 2;
Pawin Vongmasa36653902018-11-15 00:10:25 -0800315 mediaImage->mPlane[mediaImage->U].mHorizSubsampling = 2;
316 mediaImage->mPlane[mediaImage->U].mVertSubsampling = 2;
317
Wonsik Kim8bfa17a2019-05-30 22:12:30 -0700318 mediaImage->mPlane[mediaImage->V].mOffset = stride * vStride * 5 / 4;
Pawin Vongmasa36653902018-11-15 00:10:25 -0800319 mediaImage->mPlane[mediaImage->V].mColInc = 1;
Wonsik Kim8bfa17a2019-05-30 22:12:30 -0700320 mediaImage->mPlane[mediaImage->V].mRowInc = stride / 2;
Pawin Vongmasa36653902018-11-15 00:10:25 -0800321 mediaImage->mPlane[mediaImage->V].mHorizSubsampling = 2;
322 mediaImage->mPlane[mediaImage->V].mVertSubsampling = 2;
Wonsik Kimd79ee1f2020-08-27 17:41:56 -0700323
324 if (tryWrapping && mClientColorFormat != COLOR_FormatYUV420Flexible) {
325 tryWrapping = yuv420888 && uPlane.colInc == 1 && vPlane.colInc == 1
326 && yPlane.rowInc == uPlane.rowInc * 2
327 && view.data()[0] < view.data()[1]
328 && view.data()[1] < view.data()[2];
329 }
Pawin Vongmasa36653902018-11-15 00:10:25 -0800330 break;
331
332 case COLOR_FormatYUV420SemiPlanar:
333 case COLOR_FormatYUV420PackedSemiPlanar:
334 mediaImage->mPlane[mediaImage->Y].mOffset = 0;
335 mediaImage->mPlane[mediaImage->Y].mColInc = 1;
Wonsik Kim8bfa17a2019-05-30 22:12:30 -0700336 mediaImage->mPlane[mediaImage->Y].mRowInc = stride;
Pawin Vongmasa36653902018-11-15 00:10:25 -0800337 mediaImage->mPlane[mediaImage->Y].mHorizSubsampling = 1;
338 mediaImage->mPlane[mediaImage->Y].mVertSubsampling = 1;
339
Wonsik Kim8bfa17a2019-05-30 22:12:30 -0700340 mediaImage->mPlane[mediaImage->U].mOffset = stride * vStride;
Pawin Vongmasa36653902018-11-15 00:10:25 -0800341 mediaImage->mPlane[mediaImage->U].mColInc = 2;
Wonsik Kim8bfa17a2019-05-30 22:12:30 -0700342 mediaImage->mPlane[mediaImage->U].mRowInc = stride;
Pawin Vongmasa36653902018-11-15 00:10:25 -0800343 mediaImage->mPlane[mediaImage->U].mHorizSubsampling = 2;
344 mediaImage->mPlane[mediaImage->U].mVertSubsampling = 2;
345
Wonsik Kim8bfa17a2019-05-30 22:12:30 -0700346 mediaImage->mPlane[mediaImage->V].mOffset = stride * vStride + 1;
Pawin Vongmasa36653902018-11-15 00:10:25 -0800347 mediaImage->mPlane[mediaImage->V].mColInc = 2;
Wonsik Kim8bfa17a2019-05-30 22:12:30 -0700348 mediaImage->mPlane[mediaImage->V].mRowInc = stride;
Pawin Vongmasa36653902018-11-15 00:10:25 -0800349 mediaImage->mPlane[mediaImage->V].mHorizSubsampling = 2;
350 mediaImage->mPlane[mediaImage->V].mVertSubsampling = 2;
Wonsik Kimd79ee1f2020-08-27 17:41:56 -0700351
352 if (tryWrapping && mClientColorFormat != COLOR_FormatYUV420Flexible) {
353 tryWrapping = yuv420888 && uPlane.colInc == 2 && vPlane.colInc == 2
354 && yPlane.rowInc == uPlane.rowInc
355 && view.data()[0] < view.data()[1]
356 && view.data()[1] < view.data()[2];
357 }
Pawin Vongmasa36653902018-11-15 00:10:25 -0800358 break;
359
Wonsik Kim29e3c4d2020-09-02 12:19:44 -0700360 case COLOR_FormatYUVP010:
Wonsik Kim29e3c4d2020-09-02 12:19:44 -0700361 mediaImage->mPlane[mediaImage->Y].mOffset = 0;
362 mediaImage->mPlane[mediaImage->Y].mColInc = 2;
363 mediaImage->mPlane[mediaImage->Y].mRowInc = stride * 2;
364 mediaImage->mPlane[mediaImage->Y].mHorizSubsampling = 1;
365 mediaImage->mPlane[mediaImage->Y].mVertSubsampling = 1;
366
367 mediaImage->mPlane[mediaImage->U].mOffset = stride * vStride * 2;
368 mediaImage->mPlane[mediaImage->U].mColInc = 4;
369 mediaImage->mPlane[mediaImage->U].mRowInc = stride * 2;
370 mediaImage->mPlane[mediaImage->U].mHorizSubsampling = 2;
371 mediaImage->mPlane[mediaImage->U].mVertSubsampling = 2;
372
373 mediaImage->mPlane[mediaImage->V].mOffset = stride * vStride * 2 + 2;
374 mediaImage->mPlane[mediaImage->V].mColInc = 4;
375 mediaImage->mPlane[mediaImage->V].mRowInc = stride * 2;
376 mediaImage->mPlane[mediaImage->V].mHorizSubsampling = 2;
377 mediaImage->mPlane[mediaImage->V].mVertSubsampling = 2;
Wonsik Kimd79ee1f2020-08-27 17:41:56 -0700378 if (tryWrapping) {
379 tryWrapping = yPlane.allocatedDepth == 16
380 && uPlane.allocatedDepth == 16
381 && vPlane.allocatedDepth == 16
382 && yPlane.bitDepth == 10
383 && uPlane.bitDepth == 10
384 && vPlane.bitDepth == 10
385 && yPlane.rightShift == 6
386 && uPlane.rightShift == 6
387 && vPlane.rightShift == 6
388 && yPlane.rowSampling == 1 && yPlane.colSampling == 1
389 && uPlane.rowSampling == 2 && uPlane.colSampling == 2
390 && vPlane.rowSampling == 2 && vPlane.colSampling == 2
391 && yPlane.colInc == 2
392 && uPlane.colInc == 4
393 && vPlane.colInc == 4
394 && yPlane.rowInc == uPlane.rowInc
395 && yPlane.rowInc == vPlane.rowInc;
396 }
Wonsik Kim29e3c4d2020-09-02 12:19:44 -0700397 break;
398
Wonsik Kimd79ee1f2020-08-27 17:41:56 -0700399 default: {
400 // default to fully planar format --- this will be overridden if wrapping
401 // TODO: keep interleaved format
402 int32_t colInc = divUp(mAllocatedDepth, 8u);
403 int32_t rowInc = stride * colInc / yPlane.colSampling;
404 mediaImage->mPlane[mediaImage->Y].mOffset = 0;
405 mediaImage->mPlane[mediaImage->Y].mColInc = colInc;
406 mediaImage->mPlane[mediaImage->Y].mRowInc = rowInc;
407 mediaImage->mPlane[mediaImage->Y].mHorizSubsampling = yPlane.colSampling;
408 mediaImage->mPlane[mediaImage->Y].mVertSubsampling = yPlane.rowSampling;
409 int32_t offset = rowInc * vStride / yPlane.rowSampling;
410
411 rowInc = stride * colInc / uPlane.colSampling;
412 mediaImage->mPlane[mediaImage->U].mOffset = offset;
413 mediaImage->mPlane[mediaImage->U].mColInc = colInc;
414 mediaImage->mPlane[mediaImage->U].mRowInc = rowInc;
415 mediaImage->mPlane[mediaImage->U].mHorizSubsampling = uPlane.colSampling;
416 mediaImage->mPlane[mediaImage->U].mVertSubsampling = uPlane.rowSampling;
417 offset += rowInc * vStride / uPlane.rowSampling;
418
419 rowInc = stride * colInc / vPlane.colSampling;
420 mediaImage->mPlane[mediaImage->V].mOffset = offset;
421 mediaImage->mPlane[mediaImage->V].mColInc = colInc;
422 mediaImage->mPlane[mediaImage->V].mRowInc = rowInc;
423 mediaImage->mPlane[mediaImage->V].mHorizSubsampling = vPlane.colSampling;
424 mediaImage->mPlane[mediaImage->V].mVertSubsampling = vPlane.rowSampling;
425 break;
426 }
Pawin Vongmasa36653902018-11-15 00:10:25 -0800427 }
428 break;
Wonsik Kimd79ee1f2020-08-27 17:41:56 -0700429 }
430
Pawin Vongmasa36653902018-11-15 00:10:25 -0800431 case C2PlanarLayout::TYPE_YUVA:
Wonsik Kimd79ee1f2020-08-27 17:41:56 -0700432 ALOGD("Converter: unrecognized color format "
433 "(client %d component %d) for YUVA layout",
434 mClientColorFormat, mComponentColorFormat);
435 mInitCheck = NO_INIT;
Pawin Vongmasa36653902018-11-15 00:10:25 -0800436 return;
437 case C2PlanarLayout::TYPE_RGB:
Wonsik Kimd79ee1f2020-08-27 17:41:56 -0700438 ALOGD("Converter: unrecognized color format "
439 "(client %d component %d) for RGB layout",
440 mClientColorFormat, mComponentColorFormat);
441 mInitCheck = NO_INIT;
442 // TODO: support MediaImage layout
443 return;
Pawin Vongmasa36653902018-11-15 00:10:25 -0800444 case C2PlanarLayout::TYPE_RGBA:
Wonsik Kimd79ee1f2020-08-27 17:41:56 -0700445 ALOGD("Converter: unrecognized color format "
446 "(client %d component %d) for RGBA layout",
447 mClientColorFormat, mComponentColorFormat);
448 mInitCheck = NO_INIT;
449 // TODO: support MediaImage layout
450 return;
Pawin Vongmasa36653902018-11-15 00:10:25 -0800451 default:
452 mediaImage->mType = MediaImage2::MEDIA_IMAGE_TYPE_UNKNOWN;
Wonsik Kimd79ee1f2020-08-27 17:41:56 -0700453 if (layout.numPlanes == 1) {
454 const C2PlaneInfo &plane = layout.planes[0];
455 if (plane.colInc < 0 || plane.rowInc < 0) {
456 // Copy-only if we have negative colInc/rowInc
457 tryWrapping = false;
458 }
459 mediaImage->mPlane[0].mOffset = 0;
460 mediaImage->mPlane[0].mColInc = std::abs(plane.colInc);
461 mediaImage->mPlane[0].mRowInc = std::abs(plane.rowInc);
462 mediaImage->mPlane[0].mHorizSubsampling = plane.colSampling;
463 mediaImage->mPlane[0].mVertSubsampling = plane.rowSampling;
464 } else {
465 ALOGD("Converter: unrecognized layout: color format (client %d component %d)",
466 mClientColorFormat, mComponentColorFormat);
467 mInitCheck = NO_INIT;
468 return;
469 }
470 break;
471 }
472 if (tryWrapping) {
473 // try to map directly. check if the planes are near one another
474 const uint8_t *minPtr = mView.data()[0];
475 const uint8_t *maxPtr = mView.data()[0];
476 int32_t planeSize = 0;
477 for (uint32_t i = 0; i < layout.numPlanes; ++i) {
478 const C2PlaneInfo &plane = layout.planes[i];
479 int64_t planeStride = std::abs(plane.rowInc / plane.colInc);
480 ssize_t minOffset = plane.minOffset(
481 mWidth / plane.colSampling, mHeight / plane.rowSampling);
482 ssize_t maxOffset = plane.maxOffset(
483 mWidth / plane.colSampling, mHeight / plane.rowSampling);
484 if (minPtr > mView.data()[i] + minOffset) {
485 minPtr = mView.data()[i] + minOffset;
486 }
487 if (maxPtr < mView.data()[i] + maxOffset) {
488 maxPtr = mView.data()[i] + maxOffset;
489 }
490 planeSize += planeStride * divUp(mAllocatedDepth, 8u)
491 * align(mHeight, 64) / plane.rowSampling;
492 }
493
494 if ((maxPtr - minPtr + 1) <= planeSize) {
495 // FIXME: this is risky as reading/writing data out of bound results
496 // in an undefined behavior, but gralloc does assume a
497 // contiguous mapping
498 for (uint32_t i = 0; i < layout.numPlanes; ++i) {
499 const C2PlaneInfo &plane = layout.planes[i];
500 mediaImage->mPlane[i].mOffset = mView.data()[i] - minPtr;
501 mediaImage->mPlane[i].mColInc = plane.colInc;
502 mediaImage->mPlane[i].mRowInc = plane.rowInc;
503 mediaImage->mPlane[i].mHorizSubsampling = plane.colSampling;
504 mediaImage->mPlane[i].mVertSubsampling = plane.rowSampling;
505 }
506 mWrapped = new ABuffer(const_cast<uint8_t *>(minPtr),
507 maxPtr - minPtr + 1);
508 ALOGV("Converter: wrapped (capacity=%zu)", mWrapped->capacity());
509 }
Pawin Vongmasa36653902018-11-15 00:10:25 -0800510 }
511 mediaImage->mNumPlanes = layout.numPlanes;
Harish Mahendrakarf7c49e22019-05-24 14:19:16 -0700512 mediaImage->mWidth = view.crop().width;
513 mediaImage->mHeight = view.crop().height;
Pawin Vongmasa36653902018-11-15 00:10:25 -0800514 mediaImage->mBitDepth = bitDepth;
515 mediaImage->mBitDepthAllocated = mAllocatedDepth;
516
517 uint32_t bufferSize = 0;
518 for (uint32_t i = 0; i < layout.numPlanes; ++i) {
519 const C2PlaneInfo &plane = layout.planes[i];
520 if (plane.allocatedDepth < plane.bitDepth
521 || plane.rightShift != plane.allocatedDepth - plane.bitDepth) {
522 ALOGD("rightShift value of %u unsupported", plane.rightShift);
523 mInitCheck = BAD_VALUE;
524 return;
525 }
526 if (plane.allocatedDepth > 8 && plane.endianness != C2PlaneInfo::NATIVE) {
527 ALOGD("endianness value of %u unsupported", plane.endianness);
528 mInitCheck = BAD_VALUE;
529 return;
530 }
531 if (plane.allocatedDepth != mAllocatedDepth || plane.bitDepth != bitDepth) {
Wonsik Kimd79ee1f2020-08-27 17:41:56 -0700532 ALOGD("different allocatedDepth/bitDepth per plane unsupported");
Pawin Vongmasa36653902018-11-15 00:10:25 -0800533 mInitCheck = BAD_VALUE;
534 return;
535 }
Wonsik Kim8bfa17a2019-05-30 22:12:30 -0700536 bufferSize += stride * vStride
Wonsik Kimd79ee1f2020-08-27 17:41:56 -0700537 / plane.rowSampling / plane.colSampling * divUp(mAllocatedDepth, 8u);
Pawin Vongmasa36653902018-11-15 00:10:25 -0800538 }
539
540 mBackBufferSize = bufferSize;
541 mInitCheck = OK;
542 }
543
544 status_t initCheck() const { return mInitCheck; }
545
546 uint32_t backBufferSize() const { return mBackBufferSize; }
547
548 /**
549 * Wrap C2GraphicView using a MediaImage2. Note that if not wrapped, the content is not mapped
550 * in this function --- the caller should use CopyGraphicView2MediaImage() function to copy the
551 * data into a backing buffer explicitly.
552 *
553 * \return media buffer. This is null if wrapping failed.
554 */
555 sp<ABuffer> wrap() const {
556 if (mBackBuffer == nullptr) {
557 return mWrapped;
558 }
559 return nullptr;
560 }
561
562 bool setBackBuffer(const sp<ABuffer> &backBuffer) {
Wonsik Kim186fdbf2019-01-29 13:30:01 -0800563 if (backBuffer == nullptr) {
564 return false;
565 }
Pawin Vongmasa36653902018-11-15 00:10:25 -0800566 if (backBuffer->capacity() < mBackBufferSize) {
567 return false;
568 }
569 backBuffer->setRange(0, mBackBufferSize);
570 mBackBuffer = backBuffer;
571 return true;
572 }
573
574 /**
575 * Copy C2GraphicView to MediaImage2.
576 */
577 status_t copyToMediaImage() {
578 if (mInitCheck != OK) {
579 return mInitCheck;
580 }
581 return ImageCopy(mBackBuffer->base(), getMediaImage(), mView);
582 }
583
584 const sp<ABuffer> &imageData() const { return mMediaImage; }
585
586private:
587 status_t mInitCheck;
588
589 const C2GraphicView mView;
590 uint32_t mWidth;
591 uint32_t mHeight;
Wonsik Kimd79ee1f2020-08-27 17:41:56 -0700592 int32_t mClientColorFormat; ///< SDK color format for MediaImage
593 int32_t mComponentColorFormat; ///< SDK color format from component
Pawin Vongmasa36653902018-11-15 00:10:25 -0800594 sp<ABuffer> mWrapped; ///< wrapped buffer (if we can map C2Buffer to an ABuffer)
595 uint32_t mAllocatedDepth;
596 uint32_t mBackBufferSize;
597 sp<ABuffer> mMediaImage;
598 std::function<sp<ABuffer>(size_t)> mAlloc;
599
600 sp<ABuffer> mBackBuffer; ///< backing buffer if we have to copy C2Buffer <=> ABuffer
601
602 MediaImage2 *getMediaImage() {
603 return (MediaImage2 *)mMediaImage->base();
604 }
605};
606
607} // namespace
608
609// GraphicBlockBuffer
610
611// static
612sp<GraphicBlockBuffer> GraphicBlockBuffer::Allocate(
613 const sp<AMessage> &format,
614 const std::shared_ptr<C2GraphicBlock> &block,
615 std::function<sp<ABuffer>(size_t)> alloc) {
616 C2GraphicView view(block->map().get());
617 if (view.error() != C2_OK) {
618 ALOGD("C2GraphicBlock::map failed: %d", view.error());
619 return nullptr;
620 }
621
Wonsik Kimd79ee1f2020-08-27 17:41:56 -0700622 GraphicView2MediaImageConverter converter(view, format, false /* copy */);
Pawin Vongmasa36653902018-11-15 00:10:25 -0800623 if (converter.initCheck() != OK) {
624 ALOGD("Converter init failed: %d", converter.initCheck());
625 return nullptr;
626 }
627 bool wrapped = true;
628 sp<ABuffer> buffer = converter.wrap();
629 if (buffer == nullptr) {
630 buffer = alloc(converter.backBufferSize());
631 if (!converter.setBackBuffer(buffer)) {
632 ALOGD("Converter failed to set back buffer");
633 return nullptr;
634 }
635 wrapped = false;
636 }
637 return new GraphicBlockBuffer(
638 format,
639 buffer,
640 std::move(view),
641 block,
642 converter.imageData(),
643 wrapped);
644}
645
646GraphicBlockBuffer::GraphicBlockBuffer(
647 const sp<AMessage> &format,
648 const sp<ABuffer> &buffer,
649 C2GraphicView &&view,
650 const std::shared_ptr<C2GraphicBlock> &block,
651 const sp<ABuffer> &imageData,
652 bool wrapped)
653 : Codec2Buffer(format, buffer),
654 mView(view),
655 mBlock(block),
Pawin Vongmasa36653902018-11-15 00:10:25 -0800656 mWrapped(wrapped) {
657 setImageData(imageData);
658}
659
660std::shared_ptr<C2Buffer> GraphicBlockBuffer::asC2Buffer() {
661 uint32_t width = mView.width();
662 uint32_t height = mView.height();
663 if (!mWrapped) {
664 (void)ImageCopy(mView, base(), imageData());
665 }
666 return C2Buffer::CreateGraphicBuffer(
667 mBlock->share(C2Rect(width, height), C2Fence()));
668}
669
670// GraphicMetadataBuffer
671GraphicMetadataBuffer::GraphicMetadataBuffer(
672 const sp<AMessage> &format,
673 const std::shared_ptr<C2Allocator> &alloc)
674 : Codec2Buffer(format, new ABuffer(sizeof(VideoNativeMetadata))),
675 mAlloc(alloc) {
676 ((VideoNativeMetadata *)base())->pBuffer = nullptr;
677}
678
679std::shared_ptr<C2Buffer> GraphicMetadataBuffer::asC2Buffer() {
bohua222c0b2021-01-12 18:54:53 -0800680#ifdef __LP64__
681 static std::once_flag s_checkOnce;
682 static bool s_64bitonly {false};
683 std::call_once(s_checkOnce, [&](){
684 const std::string abi32list =
685 ::android::base::GetProperty("ro.product.cpu.abilist32", "");
686 if (abi32list.empty()) {
687 s_64bitonly = true;
688 }
689 });
690
691 if (!s_64bitonly) {
692 ALOGE("GraphicMetadataBuffer does not work in 32+64 system if compiled as 64-bit object");
693 return nullptr;
694 }
695#endif
696
Pawin Vongmasa36653902018-11-15 00:10:25 -0800697 VideoNativeMetadata *meta = (VideoNativeMetadata *)base();
698 ANativeWindowBuffer *buffer = (ANativeWindowBuffer *)meta->pBuffer;
699 if (buffer == nullptr) {
700 ALOGD("VideoNativeMetadata contains null buffer");
701 return nullptr;
702 }
703
704 ALOGV("VideoNativeMetadata: %dx%d", buffer->width, buffer->height);
705 C2Handle *handle = WrapNativeCodec2GrallocHandle(
Sungtak Leea4d13be2019-01-23 15:24:46 -0800706 buffer->handle,
Pawin Vongmasa36653902018-11-15 00:10:25 -0800707 buffer->width,
708 buffer->height,
709 buffer->format,
710 buffer->usage,
711 buffer->stride);
712 std::shared_ptr<C2GraphicAllocation> alloc;
713 c2_status_t err = mAlloc->priorGraphicAllocation(handle, &alloc);
714 if (err != C2_OK) {
715 ALOGD("Failed to wrap VideoNativeMetadata into C2GraphicAllocation");
Chih-Yu Huangc0ac3552021-03-11 14:37:10 +0900716 native_handle_close(handle);
717 native_handle_delete(handle);
Pawin Vongmasa36653902018-11-15 00:10:25 -0800718 return nullptr;
719 }
720 std::shared_ptr<C2GraphicBlock> block = _C2BlockFactory::CreateGraphicBlock(alloc);
721
722 meta->pBuffer = 0;
Wonsik Kimebe0f9e2019-07-03 11:06:51 -0700723 // TODO: wrap this in C2Fence so that the component can wait when it
724 // actually starts processing.
725 if (meta->nFenceFd >= 0) {
726 sp<Fence> fence(new Fence(meta->nFenceFd));
727 fence->waitForever(LOG_TAG);
728 }
Pawin Vongmasa36653902018-11-15 00:10:25 -0800729 return C2Buffer::CreateGraphicBuffer(
730 block->share(C2Rect(buffer->width, buffer->height), C2Fence()));
Pawin Vongmasa36653902018-11-15 00:10:25 -0800731}
732
733// ConstGraphicBlockBuffer
734
735// static
736sp<ConstGraphicBlockBuffer> ConstGraphicBlockBuffer::Allocate(
737 const sp<AMessage> &format,
738 const std::shared_ptr<C2Buffer> &buffer,
739 std::function<sp<ABuffer>(size_t)> alloc) {
740 if (!buffer
741 || buffer->data().type() != C2BufferData::GRAPHIC
742 || buffer->data().graphicBlocks().size() != 1u) {
743 ALOGD("C2Buffer precond fail");
744 return nullptr;
745 }
746 std::unique_ptr<const C2GraphicView> view(std::make_unique<const C2GraphicView>(
747 buffer->data().graphicBlocks()[0].map().get()));
748 std::unique_ptr<const C2GraphicView> holder;
749
Wonsik Kimd79ee1f2020-08-27 17:41:56 -0700750 GraphicView2MediaImageConverter converter(*view, format, false /* copy */);
Pawin Vongmasa36653902018-11-15 00:10:25 -0800751 if (converter.initCheck() != OK) {
752 ALOGD("Converter init failed: %d", converter.initCheck());
753 return nullptr;
754 }
755 bool wrapped = true;
756 sp<ABuffer> aBuffer = converter.wrap();
757 if (aBuffer == nullptr) {
758 aBuffer = alloc(converter.backBufferSize());
759 if (!converter.setBackBuffer(aBuffer)) {
760 ALOGD("Converter failed to set back buffer");
761 return nullptr;
762 }
763 wrapped = false;
764 converter.copyToMediaImage();
765 // We don't need the view.
766 holder = std::move(view);
767 }
768 return new ConstGraphicBlockBuffer(
769 format,
770 aBuffer,
771 std::move(view),
772 buffer,
773 converter.imageData(),
774 wrapped);
775}
776
777// static
778sp<ConstGraphicBlockBuffer> ConstGraphicBlockBuffer::AllocateEmpty(
779 const sp<AMessage> &format,
780 std::function<sp<ABuffer>(size_t)> alloc) {
781 int32_t width, height;
782 if (!format->findInt32("width", &width)
783 || !format->findInt32("height", &height)) {
784 ALOGD("format had no width / height");
785 return nullptr;
786 }
Wonsik Kim8bfa17a2019-05-30 22:12:30 -0700787 // NOTE: we currently only support YUV420 formats for byte-buffer mode.
788 sp<ABuffer> aBuffer(alloc(align(width, 16) * align(height, 16) * 3 / 2));
Pawin Vongmasa36653902018-11-15 00:10:25 -0800789 return new ConstGraphicBlockBuffer(
790 format,
791 aBuffer,
792 nullptr,
793 nullptr,
794 nullptr,
795 false);
796}
797
798ConstGraphicBlockBuffer::ConstGraphicBlockBuffer(
799 const sp<AMessage> &format,
800 const sp<ABuffer> &aBuffer,
801 std::unique_ptr<const C2GraphicView> &&view,
802 const std::shared_ptr<C2Buffer> &buffer,
803 const sp<ABuffer> &imageData,
804 bool wrapped)
805 : Codec2Buffer(format, aBuffer),
806 mView(std::move(view)),
807 mBufferRef(buffer),
808 mWrapped(wrapped) {
Wonsik Kimc48ddcf2019-02-11 16:16:57 -0800809 setImageData(imageData);
Pawin Vongmasa36653902018-11-15 00:10:25 -0800810}
811
812std::shared_ptr<C2Buffer> ConstGraphicBlockBuffer::asC2Buffer() {
Wonsik Kimf9b32122020-04-02 11:30:17 -0700813 return mBufferRef;
814}
815
816void ConstGraphicBlockBuffer::clearC2BufferRefs() {
Pawin Vongmasa36653902018-11-15 00:10:25 -0800817 mView.reset();
Wonsik Kimf9b32122020-04-02 11:30:17 -0700818 mBufferRef.reset();
Pawin Vongmasa36653902018-11-15 00:10:25 -0800819}
820
821bool ConstGraphicBlockBuffer::canCopy(const std::shared_ptr<C2Buffer> &buffer) const {
822 if (mWrapped || mBufferRef) {
823 ALOGD("ConstGraphicBlockBuffer::canCopy: %swrapped ; buffer ref %s",
824 mWrapped ? "" : "not ", mBufferRef ? "exists" : "doesn't exist");
825 return false;
826 }
827 if (!buffer) {
828 // Nothing to copy, so we can copy by doing nothing.
829 return true;
830 }
831 if (buffer->data().type() != C2BufferData::GRAPHIC) {
832 ALOGD("ConstGraphicBlockBuffer::canCopy: buffer precondition unsatisfied");
833 return false;
834 }
835 if (buffer->data().graphicBlocks().size() == 0) {
836 return true;
837 } else if (buffer->data().graphicBlocks().size() != 1u) {
838 ALOGD("ConstGraphicBlockBuffer::canCopy: too many blocks");
839 return false;
840 }
841
Pawin Vongmasa36653902018-11-15 00:10:25 -0800842 GraphicView2MediaImageConverter converter(
Wonsik Kimd79ee1f2020-08-27 17:41:56 -0700843 buffer->data().graphicBlocks()[0].map().get(),
844 // FIXME: format() is not const, but we cannot change it, so do a const cast here
845 const_cast<ConstGraphicBlockBuffer *>(this)->format(),
846 true /* copy */);
Pawin Vongmasa36653902018-11-15 00:10:25 -0800847 if (converter.initCheck() != OK) {
848 ALOGD("ConstGraphicBlockBuffer::canCopy: converter init failed: %d", converter.initCheck());
849 return false;
850 }
851 if (converter.backBufferSize() > capacity()) {
852 ALOGD("ConstGraphicBlockBuffer::canCopy: insufficient capacity: req %u has %zu",
853 converter.backBufferSize(), capacity());
854 return false;
855 }
856 return true;
857}
858
859bool ConstGraphicBlockBuffer::copy(const std::shared_ptr<C2Buffer> &buffer) {
860 if (!buffer || buffer->data().graphicBlocks().size() == 0) {
861 setRange(0, 0);
862 return true;
863 }
Pawin Vongmasa36653902018-11-15 00:10:25 -0800864
865 GraphicView2MediaImageConverter converter(
Wonsik Kimd79ee1f2020-08-27 17:41:56 -0700866 buffer->data().graphicBlocks()[0].map().get(), format(), true /* copy */);
Pawin Vongmasa36653902018-11-15 00:10:25 -0800867 if (converter.initCheck() != OK) {
868 ALOGD("ConstGraphicBlockBuffer::copy: converter init failed: %d", converter.initCheck());
869 return false;
870 }
871 sp<ABuffer> aBuffer = new ABuffer(base(), capacity());
872 if (!converter.setBackBuffer(aBuffer)) {
873 ALOGD("ConstGraphicBlockBuffer::copy: set back buffer failed");
874 return false;
875 }
Pin-chih Lin1971e2c2019-04-15 19:36:26 +0800876 setRange(0, aBuffer->size()); // align size info
Pawin Vongmasa36653902018-11-15 00:10:25 -0800877 converter.copyToMediaImage();
878 setImageData(converter.imageData());
879 mBufferRef = buffer;
880 return true;
881}
882
883// EncryptedLinearBlockBuffer
884
885EncryptedLinearBlockBuffer::EncryptedLinearBlockBuffer(
886 const sp<AMessage> &format,
887 const std::shared_ptr<C2LinearBlock> &block,
888 const sp<IMemory> &memory,
889 int32_t heapSeqNum)
Ytai Ben-Tsvi7dd39722019-09-05 15:14:30 -0700890 // TODO: Using unsecurePointer() has some associated security pitfalls
891 // (see declaration for details).
892 // Either document why it is safe in this case or address the
893 // issue (e.g. by copying).
894 : Codec2Buffer(format, new ABuffer(memory->unsecurePointer(), memory->size())),
Pawin Vongmasa36653902018-11-15 00:10:25 -0800895 mBlock(block),
896 mMemory(memory),
897 mHeapSeqNum(heapSeqNum) {
898}
899
900std::shared_ptr<C2Buffer> EncryptedLinearBlockBuffer::asC2Buffer() {
901 return C2Buffer::CreateLinearBuffer(mBlock->share(offset(), size(), C2Fence()));
902}
903
904void EncryptedLinearBlockBuffer::fillSourceBuffer(
Robert Shih895fba92019-07-16 16:29:44 -0700905 hardware::drm::V1_0::SharedBuffer *source) {
906 BufferChannelBase::IMemoryToSharedBuffer(mMemory, mHeapSeqNum, source);
Pawin Vongmasa36653902018-11-15 00:10:25 -0800907}
908
909void EncryptedLinearBlockBuffer::fillSourceBuffer(
910 hardware::cas::native::V1_0::SharedBuffer *source) {
911 ssize_t offset;
912 size_t size;
913
914 mHidlMemory = hardware::fromHeap(mMemory->getMemory(&offset, &size));
915 source->heapBase = *mHidlMemory;
916 source->offset = offset;
917 source->size = size;
918}
919
920bool EncryptedLinearBlockBuffer::copyDecryptedContent(
921 const sp<IMemory> &decrypted, size_t length) {
922 C2WriteView view = mBlock->map().get();
923 if (view.error() != C2_OK) {
924 return false;
925 }
926 if (view.size() < length) {
927 return false;
928 }
Ytai Ben-Tsvi7dd39722019-09-05 15:14:30 -0700929 memcpy(view.data(), decrypted->unsecurePointer(), length);
Pawin Vongmasa36653902018-11-15 00:10:25 -0800930 return true;
931}
932
933bool EncryptedLinearBlockBuffer::copyDecryptedContentFromMemory(size_t length) {
934 return copyDecryptedContent(mMemory, length);
935}
936
937native_handle_t *EncryptedLinearBlockBuffer::handle() const {
938 return const_cast<native_handle_t *>(mBlock->handle());
939}
940
941} // namespace android