blob: 19414a0a0c817022a896e0063fcfaa89173fa155 [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
Wonsik Kim41d83432020-04-27 16:40:49 -070021#include <android/hardware/cas/native/1.0/types.h>
22#include <android/hardware/drm/1.0/types.h>
Pawin Vongmasa36653902018-11-15 00:10:25 -080023#include <hidlmemory/FrameworkUtils.h>
24#include <media/hardware/HardwareAPI.h>
Robert Shih895fba92019-07-16 16:29:44 -070025#include <media/stagefright/CodecBase.h>
Pawin Vongmasa36653902018-11-15 00:10:25 -080026#include <media/stagefright/MediaCodecConstants.h>
27#include <media/stagefright/foundation/ABuffer.h>
28#include <media/stagefright/foundation/AMessage.h>
29#include <media/stagefright/foundation/AUtils.h>
Wonsik Kim41d83432020-04-27 16:40:49 -070030#include <mediadrm/ICrypto.h>
Pawin Vongmasa36653902018-11-15 00:10:25 -080031#include <nativebase/nativebase.h>
Wonsik Kimebe0f9e2019-07-03 11:06:51 -070032#include <ui/Fence.h>
Pawin Vongmasa36653902018-11-15 00:10:25 -080033
34#include <C2AllocatorGralloc.h>
35#include <C2BlockInternal.h>
36#include <C2Debug.h>
37
38#include "Codec2Buffer.h"
39
40namespace android {
41
42// Codec2Buffer
43
44bool Codec2Buffer::canCopyLinear(const std::shared_ptr<C2Buffer> &buffer) const {
45 if (const_cast<Codec2Buffer *>(this)->base() == nullptr) {
46 return false;
47 }
48 if (!buffer) {
49 // Nothing to copy, so we can copy by doing nothing.
50 return true;
51 }
52 if (buffer->data().type() != C2BufferData::LINEAR) {
53 return false;
54 }
55 if (buffer->data().linearBlocks().size() == 0u) {
56 // Nothing to copy, so we can copy by doing nothing.
57 return true;
58 } else if (buffer->data().linearBlocks().size() > 1u) {
59 // We don't know how to copy more than one blocks.
60 return false;
61 }
62 if (buffer->data().linearBlocks()[0].size() > capacity()) {
63 // It won't fit.
64 return false;
65 }
66 return true;
67}
68
69bool Codec2Buffer::copyLinear(const std::shared_ptr<C2Buffer> &buffer) {
70 // We assume that all canCopyLinear() checks passed.
71 if (!buffer || buffer->data().linearBlocks().size() == 0u
72 || buffer->data().linearBlocks()[0].size() == 0u) {
73 setRange(0, 0);
74 return true;
75 }
76 C2ReadView view = buffer->data().linearBlocks()[0].map().get();
77 if (view.error() != C2_OK) {
78 ALOGD("Error while mapping: %d", view.error());
79 return false;
80 }
81 if (view.capacity() > capacity()) {
82 ALOGD("C2ConstLinearBlock lied --- it actually doesn't fit: view(%u) > this(%zu)",
83 view.capacity(), capacity());
84 return false;
85 }
86 memcpy(base(), view.data(), view.capacity());
87 setRange(0, view.capacity());
88 return true;
89}
90
91void Codec2Buffer::setImageData(const sp<ABuffer> &imageData) {
Wonsik Kimc48ddcf2019-02-11 16:16:57 -080092 mImageData = imageData;
Pawin Vongmasa36653902018-11-15 00:10:25 -080093}
94
95// LocalLinearBuffer
96
97bool LocalLinearBuffer::canCopy(const std::shared_ptr<C2Buffer> &buffer) const {
98 return canCopyLinear(buffer);
99}
100
101bool LocalLinearBuffer::copy(const std::shared_ptr<C2Buffer> &buffer) {
102 return copyLinear(buffer);
103}
104
105// DummyContainerBuffer
106
Pawin Vongmasa8be93112018-12-11 14:01:42 -0800107static uint8_t sDummyByte[1] = { 0 };
108
Pawin Vongmasa36653902018-11-15 00:10:25 -0800109DummyContainerBuffer::DummyContainerBuffer(
110 const sp<AMessage> &format, const std::shared_ptr<C2Buffer> &buffer)
Pawin Vongmasa8be93112018-12-11 14:01:42 -0800111 : Codec2Buffer(format, new ABuffer(sDummyByte, 1)),
Pawin Vongmasa36653902018-11-15 00:10:25 -0800112 mBufferRef(buffer) {
113 setRange(0, buffer ? 1 : 0);
114}
115
116std::shared_ptr<C2Buffer> DummyContainerBuffer::asC2Buffer() {
Wonsik Kimf9b32122020-04-02 11:30:17 -0700117 return mBufferRef;
118}
119
120void DummyContainerBuffer::clearC2BufferRefs() {
121 mBufferRef.reset();
Pawin Vongmasa36653902018-11-15 00:10:25 -0800122}
123
124bool DummyContainerBuffer::canCopy(const std::shared_ptr<C2Buffer> &) const {
125 return !mBufferRef;
126}
127
128bool DummyContainerBuffer::copy(const std::shared_ptr<C2Buffer> &buffer) {
129 mBufferRef = buffer;
130 setRange(0, mBufferRef ? 1 : 0);
131 return true;
132}
133
134// LinearBlockBuffer
135
136// static
137sp<LinearBlockBuffer> LinearBlockBuffer::Allocate(
138 const sp<AMessage> &format, const std::shared_ptr<C2LinearBlock> &block) {
139 C2WriteView writeView(block->map().get());
140 if (writeView.error() != C2_OK) {
141 return nullptr;
142 }
143 return new LinearBlockBuffer(format, std::move(writeView), block);
144}
145
146std::shared_ptr<C2Buffer> LinearBlockBuffer::asC2Buffer() {
147 return C2Buffer::CreateLinearBuffer(mBlock->share(offset(), size(), C2Fence()));
148}
149
150bool LinearBlockBuffer::canCopy(const std::shared_ptr<C2Buffer> &buffer) const {
151 return canCopyLinear(buffer);
152}
153
154bool LinearBlockBuffer::copy(const std::shared_ptr<C2Buffer> &buffer) {
155 return copyLinear(buffer);
156}
157
158LinearBlockBuffer::LinearBlockBuffer(
159 const sp<AMessage> &format,
160 C2WriteView&& writeView,
161 const std::shared_ptr<C2LinearBlock> &block)
162 : Codec2Buffer(format, new ABuffer(writeView.data(), writeView.size())),
163 mWriteView(writeView),
164 mBlock(block) {
165}
166
167// ConstLinearBlockBuffer
168
169// static
170sp<ConstLinearBlockBuffer> ConstLinearBlockBuffer::Allocate(
171 const sp<AMessage> &format, const std::shared_ptr<C2Buffer> &buffer) {
172 if (!buffer
173 || buffer->data().type() != C2BufferData::LINEAR
174 || buffer->data().linearBlocks().size() != 1u) {
175 return nullptr;
176 }
177 C2ReadView readView(buffer->data().linearBlocks()[0].map().get());
178 if (readView.error() != C2_OK) {
179 return nullptr;
180 }
181 return new ConstLinearBlockBuffer(format, std::move(readView), buffer);
182}
183
184ConstLinearBlockBuffer::ConstLinearBlockBuffer(
185 const sp<AMessage> &format,
186 C2ReadView&& readView,
187 const std::shared_ptr<C2Buffer> &buffer)
188 : Codec2Buffer(format, new ABuffer(
189 // NOTE: ABuffer only takes non-const pointer but this data is
190 // supposed to be read-only.
191 const_cast<uint8_t *>(readView.data()), readView.capacity())),
192 mReadView(readView),
193 mBufferRef(buffer) {
194}
195
196std::shared_ptr<C2Buffer> ConstLinearBlockBuffer::asC2Buffer() {
Wonsik Kimf9b32122020-04-02 11:30:17 -0700197 return mBufferRef;
198}
199
200void ConstLinearBlockBuffer::clearC2BufferRefs() {
201 mBufferRef.reset();
Pawin Vongmasa36653902018-11-15 00:10:25 -0800202}
203
204// GraphicView2MediaImageConverter
205
206namespace {
207
208class GraphicView2MediaImageConverter {
209public:
210 /**
211 * Creates a C2GraphicView <=> MediaImage converter
212 *
213 * \param view C2GraphicView object
214 * \param colorFormat desired SDK color format for the MediaImage (if this is a flexible format,
215 * an attempt is made to simply represent the graphic view as a flexible SDK format
216 * without a memcpy)
Wonsik Kim7d966312019-06-04 14:00:49 -0700217 * \param copy whether the converter is used for copy or not
Pawin Vongmasa36653902018-11-15 00:10:25 -0800218 */
219 GraphicView2MediaImageConverter(
Wonsik Kim7d966312019-06-04 14:00:49 -0700220 const C2GraphicView &view, int32_t colorFormat, bool copy)
Pawin Vongmasa36653902018-11-15 00:10:25 -0800221 : mInitCheck(NO_INIT),
222 mView(view),
223 mWidth(view.width()),
224 mHeight(view.height()),
225 mColorFormat(colorFormat),
226 mAllocatedDepth(0),
227 mBackBufferSize(0),
228 mMediaImage(new ABuffer(sizeof(MediaImage2))) {
229 if (view.error() != C2_OK) {
230 ALOGD("Converter: view.error() = %d", view.error());
231 mInitCheck = BAD_VALUE;
232 return;
233 }
234 MediaImage2 *mediaImage = (MediaImage2 *)mMediaImage->base();
235 const C2PlanarLayout &layout = view.layout();
236 if (layout.numPlanes == 0) {
237 ALOGD("Converter: 0 planes");
238 mInitCheck = BAD_VALUE;
239 return;
240 }
Harish Mahendrakarcac53852019-02-20 10:59:10 -0800241 memset(mediaImage, 0, sizeof(*mediaImage));
Pawin Vongmasa36653902018-11-15 00:10:25 -0800242 mAllocatedDepth = layout.planes[0].allocatedDepth;
243 uint32_t bitDepth = layout.planes[0].bitDepth;
244
245 // align width and height to support subsampling cleanly
Wonsik Kim8bfa17a2019-05-30 22:12:30 -0700246 uint32_t stride = align(view.crop().width, 2) * divUp(layout.planes[0].allocatedDepth, 8u);
247 uint32_t vStride = align(view.crop().height, 2);
Pawin Vongmasa36653902018-11-15 00:10:25 -0800248
249 switch (layout.type) {
250 case C2PlanarLayout::TYPE_YUV:
251 mediaImage->mType = MediaImage2::MEDIA_IMAGE_TYPE_YUV;
252 if (layout.numPlanes != 3) {
253 ALOGD("Converter: %d planes for YUV layout", layout.numPlanes);
254 mInitCheck = BAD_VALUE;
255 return;
256 }
257 if (layout.planes[0].channel != C2PlaneInfo::CHANNEL_Y
258 || layout.planes[1].channel != C2PlaneInfo::CHANNEL_CB
259 || layout.planes[2].channel != C2PlaneInfo::CHANNEL_CR
260 || layout.planes[0].colSampling != 1
261 || layout.planes[0].rowSampling != 1
262 || layout.planes[1].colSampling != 2
263 || layout.planes[1].rowSampling != 2
264 || layout.planes[2].colSampling != 2
265 || layout.planes[2].rowSampling != 2) {
266 ALOGD("Converter: not YUV420 for YUV layout");
267 mInitCheck = BAD_VALUE;
268 return;
269 }
270 switch (mColorFormat) {
271 case COLOR_FormatYUV420Flexible:
Wonsik Kim7d966312019-06-04 14:00:49 -0700272 if (!copy) {
273 // try to map directly. check if the planes are near one another
274 const uint8_t *minPtr = mView.data()[0];
275 const uint8_t *maxPtr = mView.data()[0];
276 int32_t planeSize = 0;
Pawin Vongmasa36653902018-11-15 00:10:25 -0800277 for (uint32_t i = 0; i < layout.numPlanes; ++i) {
278 const C2PlaneInfo &plane = layout.planes[i];
Wonsik Kim2eb06312020-12-03 11:07:58 -0800279 int64_t planeStride = std::abs(plane.rowInc / plane.colInc);
280 ssize_t minOffset = plane.minOffset(
281 mWidth / plane.colSampling, mHeight / plane.rowSampling);
282 ssize_t maxOffset = plane.maxOffset(
283 mWidth / plane.colSampling, mHeight / plane.rowSampling);
Wonsik Kim7d966312019-06-04 14:00:49 -0700284 if (minPtr > mView.data()[i] + minOffset) {
285 minPtr = mView.data()[i] + minOffset;
286 }
287 if (maxPtr < mView.data()[i] + maxOffset) {
288 maxPtr = mView.data()[i] + maxOffset;
289 }
Wonsik Kim2eb06312020-12-03 11:07:58 -0800290 planeSize += planeStride * divUp(mAllocatedDepth, 8u)
291 * align(mHeight, 64) / plane.rowSampling;
Pawin Vongmasa36653902018-11-15 00:10:25 -0800292 }
Wonsik Kim7d966312019-06-04 14:00:49 -0700293
Wonsik Kim2eb06312020-12-03 11:07:58 -0800294 if (minPtr == mView.data()[0] && (maxPtr - minPtr + 1) <= planeSize) {
Wonsik Kim7d966312019-06-04 14:00:49 -0700295 // FIXME: this is risky as reading/writing data out of bound results
296 // in an undefined behavior, but gralloc does assume a
297 // contiguous mapping
298 for (uint32_t i = 0; i < layout.numPlanes; ++i) {
299 const C2PlaneInfo &plane = layout.planes[i];
300 mediaImage->mPlane[i].mOffset = mView.data()[i] - minPtr;
301 mediaImage->mPlane[i].mColInc = plane.colInc;
302 mediaImage->mPlane[i].mRowInc = plane.rowInc;
303 mediaImage->mPlane[i].mHorizSubsampling = plane.colSampling;
304 mediaImage->mPlane[i].mVertSubsampling = plane.rowSampling;
305 }
306 mWrapped = new ABuffer(const_cast<uint8_t *>(minPtr),
307 maxPtr - minPtr + 1);
308 break;
309 }
Pawin Vongmasa36653902018-11-15 00:10:25 -0800310 }
Wonsik Kim7d966312019-06-04 14:00:49 -0700311 [[fallthrough]];
Pawin Vongmasa36653902018-11-15 00:10:25 -0800312
313 case COLOR_FormatYUV420Planar:
314 case COLOR_FormatYUV420PackedPlanar:
315 mediaImage->mPlane[mediaImage->Y].mOffset = 0;
316 mediaImage->mPlane[mediaImage->Y].mColInc = 1;
Wonsik Kim8bfa17a2019-05-30 22:12:30 -0700317 mediaImage->mPlane[mediaImage->Y].mRowInc = stride;
Pawin Vongmasa36653902018-11-15 00:10:25 -0800318 mediaImage->mPlane[mediaImage->Y].mHorizSubsampling = 1;
319 mediaImage->mPlane[mediaImage->Y].mVertSubsampling = 1;
320
Wonsik Kim8bfa17a2019-05-30 22:12:30 -0700321 mediaImage->mPlane[mediaImage->U].mOffset = stride * vStride;
Pawin Vongmasa36653902018-11-15 00:10:25 -0800322 mediaImage->mPlane[mediaImage->U].mColInc = 1;
Wonsik Kim8bfa17a2019-05-30 22:12:30 -0700323 mediaImage->mPlane[mediaImage->U].mRowInc = stride / 2;
Pawin Vongmasa36653902018-11-15 00:10:25 -0800324 mediaImage->mPlane[mediaImage->U].mHorizSubsampling = 2;
325 mediaImage->mPlane[mediaImage->U].mVertSubsampling = 2;
326
Wonsik Kim8bfa17a2019-05-30 22:12:30 -0700327 mediaImage->mPlane[mediaImage->V].mOffset = stride * vStride * 5 / 4;
Pawin Vongmasa36653902018-11-15 00:10:25 -0800328 mediaImage->mPlane[mediaImage->V].mColInc = 1;
Wonsik Kim8bfa17a2019-05-30 22:12:30 -0700329 mediaImage->mPlane[mediaImage->V].mRowInc = stride / 2;
Pawin Vongmasa36653902018-11-15 00:10:25 -0800330 mediaImage->mPlane[mediaImage->V].mHorizSubsampling = 2;
331 mediaImage->mPlane[mediaImage->V].mVertSubsampling = 2;
332 break;
333
334 case COLOR_FormatYUV420SemiPlanar:
335 case COLOR_FormatYUV420PackedSemiPlanar:
336 mediaImage->mPlane[mediaImage->Y].mOffset = 0;
337 mediaImage->mPlane[mediaImage->Y].mColInc = 1;
Wonsik Kim8bfa17a2019-05-30 22:12:30 -0700338 mediaImage->mPlane[mediaImage->Y].mRowInc = stride;
Pawin Vongmasa36653902018-11-15 00:10:25 -0800339 mediaImage->mPlane[mediaImage->Y].mHorizSubsampling = 1;
340 mediaImage->mPlane[mediaImage->Y].mVertSubsampling = 1;
341
Wonsik Kim8bfa17a2019-05-30 22:12:30 -0700342 mediaImage->mPlane[mediaImage->U].mOffset = stride * vStride;
Pawin Vongmasa36653902018-11-15 00:10:25 -0800343 mediaImage->mPlane[mediaImage->U].mColInc = 2;
Wonsik Kim8bfa17a2019-05-30 22:12:30 -0700344 mediaImage->mPlane[mediaImage->U].mRowInc = stride;
Pawin Vongmasa36653902018-11-15 00:10:25 -0800345 mediaImage->mPlane[mediaImage->U].mHorizSubsampling = 2;
346 mediaImage->mPlane[mediaImage->U].mVertSubsampling = 2;
347
Wonsik Kim8bfa17a2019-05-30 22:12:30 -0700348 mediaImage->mPlane[mediaImage->V].mOffset = stride * vStride + 1;
Pawin Vongmasa36653902018-11-15 00:10:25 -0800349 mediaImage->mPlane[mediaImage->V].mColInc = 2;
Wonsik Kim8bfa17a2019-05-30 22:12:30 -0700350 mediaImage->mPlane[mediaImage->V].mRowInc = stride;
Pawin Vongmasa36653902018-11-15 00:10:25 -0800351 mediaImage->mPlane[mediaImage->V].mHorizSubsampling = 2;
352 mediaImage->mPlane[mediaImage->V].mVertSubsampling = 2;
353 break;
354
355 default:
356 ALOGD("Converter: incompactible color format (%d) for YUV layout", mColorFormat);
357 mInitCheck = BAD_VALUE;
358 return;
359 }
360 break;
361 case C2PlanarLayout::TYPE_YUVA:
362 mediaImage->mType = MediaImage2::MEDIA_IMAGE_TYPE_YUVA;
363 // We don't have an SDK YUVA format
364 ALOGD("Converter: incompactible color format (%d) for YUVA layout", mColorFormat);
365 mInitCheck = BAD_VALUE;
366 return;
367 case C2PlanarLayout::TYPE_RGB:
368 mediaImage->mType = MediaImage2::MEDIA_IMAGE_TYPE_RGB;
369 switch (mColorFormat) {
370 // TODO media image
371 case COLOR_FormatRGBFlexible:
372 case COLOR_Format24bitBGR888:
373 case COLOR_Format24bitRGB888:
374 break;
375 default:
376 ALOGD("Converter: incompactible color format (%d) for RGB layout", mColorFormat);
377 mInitCheck = BAD_VALUE;
378 return;
379 }
380 if (layout.numPlanes != 3) {
381 ALOGD("Converter: %d planes for RGB layout", layout.numPlanes);
382 mInitCheck = BAD_VALUE;
383 return;
384 }
385 break;
386 case C2PlanarLayout::TYPE_RGBA:
387 mediaImage->mType = MediaImage2::MEDIA_IMAGE_TYPE_RGBA;
388 switch (mColorFormat) {
389 // TODO media image
390 case COLOR_FormatRGBAFlexible:
391 case COLOR_Format32bitABGR8888:
392 case COLOR_Format32bitARGB8888:
393 case COLOR_Format32bitBGRA8888:
394 break;
395 default:
396 ALOGD("Incompactible color format (%d) for RGBA layout", mColorFormat);
397 mInitCheck = BAD_VALUE;
398 return;
399 }
400 if (layout.numPlanes != 4) {
401 ALOGD("Converter: %d planes for RGBA layout", layout.numPlanes);
402 mInitCheck = BAD_VALUE;
403 return;
404 }
405 break;
406 default:
407 mediaImage->mType = MediaImage2::MEDIA_IMAGE_TYPE_UNKNOWN;
408 ALOGD("Unknown layout");
409 mInitCheck = BAD_VALUE;
410 return;
411 }
412 mediaImage->mNumPlanes = layout.numPlanes;
Harish Mahendrakarf7c49e22019-05-24 14:19:16 -0700413 mediaImage->mWidth = view.crop().width;
414 mediaImage->mHeight = view.crop().height;
Pawin Vongmasa36653902018-11-15 00:10:25 -0800415 mediaImage->mBitDepth = bitDepth;
416 mediaImage->mBitDepthAllocated = mAllocatedDepth;
417
418 uint32_t bufferSize = 0;
419 for (uint32_t i = 0; i < layout.numPlanes; ++i) {
420 const C2PlaneInfo &plane = layout.planes[i];
421 if (plane.allocatedDepth < plane.bitDepth
422 || plane.rightShift != plane.allocatedDepth - plane.bitDepth) {
423 ALOGD("rightShift value of %u unsupported", plane.rightShift);
424 mInitCheck = BAD_VALUE;
425 return;
426 }
427 if (plane.allocatedDepth > 8 && plane.endianness != C2PlaneInfo::NATIVE) {
428 ALOGD("endianness value of %u unsupported", plane.endianness);
429 mInitCheck = BAD_VALUE;
430 return;
431 }
432 if (plane.allocatedDepth != mAllocatedDepth || plane.bitDepth != bitDepth) {
433 ALOGV("different allocatedDepth/bitDepth per plane unsupported");
434 mInitCheck = BAD_VALUE;
435 return;
436 }
Wonsik Kim8bfa17a2019-05-30 22:12:30 -0700437 bufferSize += stride * vStride
Pawin Vongmasa36653902018-11-15 00:10:25 -0800438 / plane.rowSampling / plane.colSampling;
439 }
440
441 mBackBufferSize = bufferSize;
442 mInitCheck = OK;
443 }
444
445 status_t initCheck() const { return mInitCheck; }
446
447 uint32_t backBufferSize() const { return mBackBufferSize; }
448
449 /**
450 * Wrap C2GraphicView using a MediaImage2. Note that if not wrapped, the content is not mapped
451 * in this function --- the caller should use CopyGraphicView2MediaImage() function to copy the
452 * data into a backing buffer explicitly.
453 *
454 * \return media buffer. This is null if wrapping failed.
455 */
456 sp<ABuffer> wrap() const {
457 if (mBackBuffer == nullptr) {
458 return mWrapped;
459 }
460 return nullptr;
461 }
462
463 bool setBackBuffer(const sp<ABuffer> &backBuffer) {
Wonsik Kim186fdbf2019-01-29 13:30:01 -0800464 if (backBuffer == nullptr) {
465 return false;
466 }
Pawin Vongmasa36653902018-11-15 00:10:25 -0800467 if (backBuffer->capacity() < mBackBufferSize) {
468 return false;
469 }
470 backBuffer->setRange(0, mBackBufferSize);
471 mBackBuffer = backBuffer;
472 return true;
473 }
474
475 /**
476 * Copy C2GraphicView to MediaImage2.
477 */
478 status_t copyToMediaImage() {
479 if (mInitCheck != OK) {
480 return mInitCheck;
481 }
482 return ImageCopy(mBackBuffer->base(), getMediaImage(), mView);
483 }
484
485 const sp<ABuffer> &imageData() const { return mMediaImage; }
486
487private:
488 status_t mInitCheck;
489
490 const C2GraphicView mView;
491 uint32_t mWidth;
492 uint32_t mHeight;
493 int32_t mColorFormat; ///< SDK color format for MediaImage
494 sp<ABuffer> mWrapped; ///< wrapped buffer (if we can map C2Buffer to an ABuffer)
495 uint32_t mAllocatedDepth;
496 uint32_t mBackBufferSize;
497 sp<ABuffer> mMediaImage;
498 std::function<sp<ABuffer>(size_t)> mAlloc;
499
500 sp<ABuffer> mBackBuffer; ///< backing buffer if we have to copy C2Buffer <=> ABuffer
501
502 MediaImage2 *getMediaImage() {
503 return (MediaImage2 *)mMediaImage->base();
504 }
505};
506
507} // namespace
508
509// GraphicBlockBuffer
510
511// static
512sp<GraphicBlockBuffer> GraphicBlockBuffer::Allocate(
513 const sp<AMessage> &format,
514 const std::shared_ptr<C2GraphicBlock> &block,
515 std::function<sp<ABuffer>(size_t)> alloc) {
516 C2GraphicView view(block->map().get());
517 if (view.error() != C2_OK) {
518 ALOGD("C2GraphicBlock::map failed: %d", view.error());
519 return nullptr;
520 }
521
522 int32_t colorFormat = COLOR_FormatYUV420Flexible;
523 (void)format->findInt32("color-format", &colorFormat);
524
Wonsik Kim7d966312019-06-04 14:00:49 -0700525 GraphicView2MediaImageConverter converter(view, colorFormat, false /* copy */);
Pawin Vongmasa36653902018-11-15 00:10:25 -0800526 if (converter.initCheck() != OK) {
527 ALOGD("Converter init failed: %d", converter.initCheck());
528 return nullptr;
529 }
530 bool wrapped = true;
531 sp<ABuffer> buffer = converter.wrap();
532 if (buffer == nullptr) {
533 buffer = alloc(converter.backBufferSize());
534 if (!converter.setBackBuffer(buffer)) {
535 ALOGD("Converter failed to set back buffer");
536 return nullptr;
537 }
538 wrapped = false;
539 }
540 return new GraphicBlockBuffer(
541 format,
542 buffer,
543 std::move(view),
544 block,
545 converter.imageData(),
546 wrapped);
547}
548
549GraphicBlockBuffer::GraphicBlockBuffer(
550 const sp<AMessage> &format,
551 const sp<ABuffer> &buffer,
552 C2GraphicView &&view,
553 const std::shared_ptr<C2GraphicBlock> &block,
554 const sp<ABuffer> &imageData,
555 bool wrapped)
556 : Codec2Buffer(format, buffer),
557 mView(view),
558 mBlock(block),
Pawin Vongmasa36653902018-11-15 00:10:25 -0800559 mWrapped(wrapped) {
560 setImageData(imageData);
561}
562
563std::shared_ptr<C2Buffer> GraphicBlockBuffer::asC2Buffer() {
564 uint32_t width = mView.width();
565 uint32_t height = mView.height();
566 if (!mWrapped) {
567 (void)ImageCopy(mView, base(), imageData());
568 }
569 return C2Buffer::CreateGraphicBuffer(
570 mBlock->share(C2Rect(width, height), C2Fence()));
571}
572
573// GraphicMetadataBuffer
574GraphicMetadataBuffer::GraphicMetadataBuffer(
575 const sp<AMessage> &format,
576 const std::shared_ptr<C2Allocator> &alloc)
577 : Codec2Buffer(format, new ABuffer(sizeof(VideoNativeMetadata))),
578 mAlloc(alloc) {
579 ((VideoNativeMetadata *)base())->pBuffer = nullptr;
580}
581
582std::shared_ptr<C2Buffer> GraphicMetadataBuffer::asC2Buffer() {
583#ifndef __LP64__
584 VideoNativeMetadata *meta = (VideoNativeMetadata *)base();
585 ANativeWindowBuffer *buffer = (ANativeWindowBuffer *)meta->pBuffer;
586 if (buffer == nullptr) {
587 ALOGD("VideoNativeMetadata contains null buffer");
588 return nullptr;
589 }
590
591 ALOGV("VideoNativeMetadata: %dx%d", buffer->width, buffer->height);
592 C2Handle *handle = WrapNativeCodec2GrallocHandle(
Sungtak Leea4d13be2019-01-23 15:24:46 -0800593 buffer->handle,
Pawin Vongmasa36653902018-11-15 00:10:25 -0800594 buffer->width,
595 buffer->height,
596 buffer->format,
597 buffer->usage,
598 buffer->stride);
599 std::shared_ptr<C2GraphicAllocation> alloc;
600 c2_status_t err = mAlloc->priorGraphicAllocation(handle, &alloc);
601 if (err != C2_OK) {
602 ALOGD("Failed to wrap VideoNativeMetadata into C2GraphicAllocation");
603 return nullptr;
604 }
605 std::shared_ptr<C2GraphicBlock> block = _C2BlockFactory::CreateGraphicBlock(alloc);
606
607 meta->pBuffer = 0;
Wonsik Kimebe0f9e2019-07-03 11:06:51 -0700608 // TODO: wrap this in C2Fence so that the component can wait when it
609 // actually starts processing.
610 if (meta->nFenceFd >= 0) {
611 sp<Fence> fence(new Fence(meta->nFenceFd));
612 fence->waitForever(LOG_TAG);
613 }
Pawin Vongmasa36653902018-11-15 00:10:25 -0800614 return C2Buffer::CreateGraphicBuffer(
615 block->share(C2Rect(buffer->width, buffer->height), C2Fence()));
616#else
617 ALOGE("GraphicMetadataBuffer does not work on 64-bit arch");
618 return nullptr;
619#endif
620}
621
622// ConstGraphicBlockBuffer
623
624// static
625sp<ConstGraphicBlockBuffer> ConstGraphicBlockBuffer::Allocate(
626 const sp<AMessage> &format,
627 const std::shared_ptr<C2Buffer> &buffer,
628 std::function<sp<ABuffer>(size_t)> alloc) {
629 if (!buffer
630 || buffer->data().type() != C2BufferData::GRAPHIC
631 || buffer->data().graphicBlocks().size() != 1u) {
632 ALOGD("C2Buffer precond fail");
633 return nullptr;
634 }
635 std::unique_ptr<const C2GraphicView> view(std::make_unique<const C2GraphicView>(
636 buffer->data().graphicBlocks()[0].map().get()));
637 std::unique_ptr<const C2GraphicView> holder;
638
639 int32_t colorFormat = COLOR_FormatYUV420Flexible;
640 (void)format->findInt32("color-format", &colorFormat);
641
Wonsik Kim7d966312019-06-04 14:00:49 -0700642 GraphicView2MediaImageConverter converter(*view, colorFormat, false /* copy */);
Pawin Vongmasa36653902018-11-15 00:10:25 -0800643 if (converter.initCheck() != OK) {
644 ALOGD("Converter init failed: %d", converter.initCheck());
645 return nullptr;
646 }
647 bool wrapped = true;
648 sp<ABuffer> aBuffer = converter.wrap();
649 if (aBuffer == nullptr) {
650 aBuffer = alloc(converter.backBufferSize());
651 if (!converter.setBackBuffer(aBuffer)) {
652 ALOGD("Converter failed to set back buffer");
653 return nullptr;
654 }
655 wrapped = false;
656 converter.copyToMediaImage();
657 // We don't need the view.
658 holder = std::move(view);
659 }
660 return new ConstGraphicBlockBuffer(
661 format,
662 aBuffer,
663 std::move(view),
664 buffer,
665 converter.imageData(),
666 wrapped);
667}
668
669// static
670sp<ConstGraphicBlockBuffer> ConstGraphicBlockBuffer::AllocateEmpty(
671 const sp<AMessage> &format,
672 std::function<sp<ABuffer>(size_t)> alloc) {
673 int32_t width, height;
674 if (!format->findInt32("width", &width)
675 || !format->findInt32("height", &height)) {
676 ALOGD("format had no width / height");
677 return nullptr;
678 }
Wonsik Kim8bfa17a2019-05-30 22:12:30 -0700679 // NOTE: we currently only support YUV420 formats for byte-buffer mode.
680 sp<ABuffer> aBuffer(alloc(align(width, 16) * align(height, 16) * 3 / 2));
Pawin Vongmasa36653902018-11-15 00:10:25 -0800681 return new ConstGraphicBlockBuffer(
682 format,
683 aBuffer,
684 nullptr,
685 nullptr,
686 nullptr,
687 false);
688}
689
690ConstGraphicBlockBuffer::ConstGraphicBlockBuffer(
691 const sp<AMessage> &format,
692 const sp<ABuffer> &aBuffer,
693 std::unique_ptr<const C2GraphicView> &&view,
694 const std::shared_ptr<C2Buffer> &buffer,
695 const sp<ABuffer> &imageData,
696 bool wrapped)
697 : Codec2Buffer(format, aBuffer),
698 mView(std::move(view)),
699 mBufferRef(buffer),
700 mWrapped(wrapped) {
Wonsik Kimc48ddcf2019-02-11 16:16:57 -0800701 setImageData(imageData);
Pawin Vongmasa36653902018-11-15 00:10:25 -0800702}
703
704std::shared_ptr<C2Buffer> ConstGraphicBlockBuffer::asC2Buffer() {
Wonsik Kimf9b32122020-04-02 11:30:17 -0700705 return mBufferRef;
706}
707
708void ConstGraphicBlockBuffer::clearC2BufferRefs() {
Pawin Vongmasa36653902018-11-15 00:10:25 -0800709 mView.reset();
Wonsik Kimf9b32122020-04-02 11:30:17 -0700710 mBufferRef.reset();
Pawin Vongmasa36653902018-11-15 00:10:25 -0800711}
712
713bool ConstGraphicBlockBuffer::canCopy(const std::shared_ptr<C2Buffer> &buffer) const {
714 if (mWrapped || mBufferRef) {
715 ALOGD("ConstGraphicBlockBuffer::canCopy: %swrapped ; buffer ref %s",
716 mWrapped ? "" : "not ", mBufferRef ? "exists" : "doesn't exist");
717 return false;
718 }
719 if (!buffer) {
720 // Nothing to copy, so we can copy by doing nothing.
721 return true;
722 }
723 if (buffer->data().type() != C2BufferData::GRAPHIC) {
724 ALOGD("ConstGraphicBlockBuffer::canCopy: buffer precondition unsatisfied");
725 return false;
726 }
727 if (buffer->data().graphicBlocks().size() == 0) {
728 return true;
729 } else if (buffer->data().graphicBlocks().size() != 1u) {
730 ALOGD("ConstGraphicBlockBuffer::canCopy: too many blocks");
731 return false;
732 }
733
734 int32_t colorFormat = COLOR_FormatYUV420Flexible;
735 // FIXME: format() is not const, but we cannot change it, so do a const cast here
736 const_cast<ConstGraphicBlockBuffer *>(this)->format()->findInt32("color-format", &colorFormat);
737
738 GraphicView2MediaImageConverter converter(
Wonsik Kim7d966312019-06-04 14:00:49 -0700739 buffer->data().graphicBlocks()[0].map().get(), colorFormat, true /* copy */);
Pawin Vongmasa36653902018-11-15 00:10:25 -0800740 if (converter.initCheck() != OK) {
741 ALOGD("ConstGraphicBlockBuffer::canCopy: converter init failed: %d", converter.initCheck());
742 return false;
743 }
744 if (converter.backBufferSize() > capacity()) {
745 ALOGD("ConstGraphicBlockBuffer::canCopy: insufficient capacity: req %u has %zu",
746 converter.backBufferSize(), capacity());
747 return false;
748 }
749 return true;
750}
751
752bool ConstGraphicBlockBuffer::copy(const std::shared_ptr<C2Buffer> &buffer) {
753 if (!buffer || buffer->data().graphicBlocks().size() == 0) {
754 setRange(0, 0);
755 return true;
756 }
757 int32_t colorFormat = COLOR_FormatYUV420Flexible;
758 format()->findInt32("color-format", &colorFormat);
759
760 GraphicView2MediaImageConverter converter(
Wonsik Kim7d966312019-06-04 14:00:49 -0700761 buffer->data().graphicBlocks()[0].map().get(), colorFormat, true /* copy */);
Pawin Vongmasa36653902018-11-15 00:10:25 -0800762 if (converter.initCheck() != OK) {
763 ALOGD("ConstGraphicBlockBuffer::copy: converter init failed: %d", converter.initCheck());
764 return false;
765 }
766 sp<ABuffer> aBuffer = new ABuffer(base(), capacity());
767 if (!converter.setBackBuffer(aBuffer)) {
768 ALOGD("ConstGraphicBlockBuffer::copy: set back buffer failed");
769 return false;
770 }
Pin-chih Lin1971e2c2019-04-15 19:36:26 +0800771 setRange(0, aBuffer->size()); // align size info
Pawin Vongmasa36653902018-11-15 00:10:25 -0800772 converter.copyToMediaImage();
773 setImageData(converter.imageData());
774 mBufferRef = buffer;
775 return true;
776}
777
778// EncryptedLinearBlockBuffer
779
780EncryptedLinearBlockBuffer::EncryptedLinearBlockBuffer(
781 const sp<AMessage> &format,
782 const std::shared_ptr<C2LinearBlock> &block,
783 const sp<IMemory> &memory,
784 int32_t heapSeqNum)
Ytai Ben-Tsvi7dd39722019-09-05 15:14:30 -0700785 // TODO: Using unsecurePointer() has some associated security pitfalls
786 // (see declaration for details).
787 // Either document why it is safe in this case or address the
788 // issue (e.g. by copying).
789 : Codec2Buffer(format, new ABuffer(memory->unsecurePointer(), memory->size())),
Pawin Vongmasa36653902018-11-15 00:10:25 -0800790 mBlock(block),
791 mMemory(memory),
792 mHeapSeqNum(heapSeqNum) {
793}
794
795std::shared_ptr<C2Buffer> EncryptedLinearBlockBuffer::asC2Buffer() {
796 return C2Buffer::CreateLinearBuffer(mBlock->share(offset(), size(), C2Fence()));
797}
798
799void EncryptedLinearBlockBuffer::fillSourceBuffer(
Robert Shih895fba92019-07-16 16:29:44 -0700800 hardware::drm::V1_0::SharedBuffer *source) {
801 BufferChannelBase::IMemoryToSharedBuffer(mMemory, mHeapSeqNum, source);
Pawin Vongmasa36653902018-11-15 00:10:25 -0800802}
803
804void EncryptedLinearBlockBuffer::fillSourceBuffer(
805 hardware::cas::native::V1_0::SharedBuffer *source) {
806 ssize_t offset;
807 size_t size;
808
809 mHidlMemory = hardware::fromHeap(mMemory->getMemory(&offset, &size));
810 source->heapBase = *mHidlMemory;
811 source->offset = offset;
812 source->size = size;
813}
814
815bool EncryptedLinearBlockBuffer::copyDecryptedContent(
816 const sp<IMemory> &decrypted, size_t length) {
817 C2WriteView view = mBlock->map().get();
818 if (view.error() != C2_OK) {
819 return false;
820 }
821 if (view.size() < length) {
822 return false;
823 }
Ytai Ben-Tsvi7dd39722019-09-05 15:14:30 -0700824 memcpy(view.data(), decrypted->unsecurePointer(), length);
Pawin Vongmasa36653902018-11-15 00:10:25 -0800825 return true;
826}
827
828bool EncryptedLinearBlockBuffer::copyDecryptedContentFromMemory(size_t length) {
829 return copyDecryptedContent(mMemory, length);
830}
831
832native_handle_t *EncryptedLinearBlockBuffer::handle() const {
833 return const_cast<native_handle_t *>(mBlock->handle());
834}
835
836} // namespace android