blob: 25e7da9206ae18cb38bffc5f2abbbec387aa8657 [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 Kim7d966312019-06-04 14:00:49 -0700279 ssize_t minOffset = plane.minOffset(mWidth, mHeight);
280 ssize_t maxOffset = plane.maxOffset(mWidth, mHeight);
281 if (minPtr > mView.data()[i] + minOffset) {
282 minPtr = mView.data()[i] + minOffset;
283 }
284 if (maxPtr < mView.data()[i] + maxOffset) {
285 maxPtr = mView.data()[i] + maxOffset;
286 }
287 planeSize += std::abs(plane.rowInc) * align(mHeight, 64)
288 / plane.rowSampling / plane.colSampling
289 * divUp(mAllocatedDepth, 8u);
Pawin Vongmasa36653902018-11-15 00:10:25 -0800290 }
Wonsik Kim7d966312019-06-04 14:00:49 -0700291
292 if ((maxPtr - minPtr + 1) <= planeSize) {
293 // FIXME: this is risky as reading/writing data out of bound results
294 // in an undefined behavior, but gralloc does assume a
295 // contiguous mapping
296 for (uint32_t i = 0; i < layout.numPlanes; ++i) {
297 const C2PlaneInfo &plane = layout.planes[i];
298 mediaImage->mPlane[i].mOffset = mView.data()[i] - minPtr;
299 mediaImage->mPlane[i].mColInc = plane.colInc;
300 mediaImage->mPlane[i].mRowInc = plane.rowInc;
301 mediaImage->mPlane[i].mHorizSubsampling = plane.colSampling;
302 mediaImage->mPlane[i].mVertSubsampling = plane.rowSampling;
303 }
304 mWrapped = new ABuffer(const_cast<uint8_t *>(minPtr),
305 maxPtr - minPtr + 1);
306 break;
307 }
Pawin Vongmasa36653902018-11-15 00:10:25 -0800308 }
Wonsik Kim7d966312019-06-04 14:00:49 -0700309 [[fallthrough]];
Pawin Vongmasa36653902018-11-15 00:10:25 -0800310
311 case COLOR_FormatYUV420Planar:
312 case COLOR_FormatYUV420PackedPlanar:
313 mediaImage->mPlane[mediaImage->Y].mOffset = 0;
314 mediaImage->mPlane[mediaImage->Y].mColInc = 1;
Wonsik Kim8bfa17a2019-05-30 22:12:30 -0700315 mediaImage->mPlane[mediaImage->Y].mRowInc = stride;
Pawin Vongmasa36653902018-11-15 00:10:25 -0800316 mediaImage->mPlane[mediaImage->Y].mHorizSubsampling = 1;
317 mediaImage->mPlane[mediaImage->Y].mVertSubsampling = 1;
318
Wonsik Kim8bfa17a2019-05-30 22:12:30 -0700319 mediaImage->mPlane[mediaImage->U].mOffset = stride * vStride;
Pawin Vongmasa36653902018-11-15 00:10:25 -0800320 mediaImage->mPlane[mediaImage->U].mColInc = 1;
Wonsik Kim8bfa17a2019-05-30 22:12:30 -0700321 mediaImage->mPlane[mediaImage->U].mRowInc = stride / 2;
Pawin Vongmasa36653902018-11-15 00:10:25 -0800322 mediaImage->mPlane[mediaImage->U].mHorizSubsampling = 2;
323 mediaImage->mPlane[mediaImage->U].mVertSubsampling = 2;
324
Wonsik Kim8bfa17a2019-05-30 22:12:30 -0700325 mediaImage->mPlane[mediaImage->V].mOffset = stride * vStride * 5 / 4;
Pawin Vongmasa36653902018-11-15 00:10:25 -0800326 mediaImage->mPlane[mediaImage->V].mColInc = 1;
Wonsik Kim8bfa17a2019-05-30 22:12:30 -0700327 mediaImage->mPlane[mediaImage->V].mRowInc = stride / 2;
Pawin Vongmasa36653902018-11-15 00:10:25 -0800328 mediaImage->mPlane[mediaImage->V].mHorizSubsampling = 2;
329 mediaImage->mPlane[mediaImage->V].mVertSubsampling = 2;
330 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;
351 break;
352
353 default:
354 ALOGD("Converter: incompactible color format (%d) for YUV layout", mColorFormat);
355 mInitCheck = BAD_VALUE;
356 return;
357 }
358 break;
359 case C2PlanarLayout::TYPE_YUVA:
360 mediaImage->mType = MediaImage2::MEDIA_IMAGE_TYPE_YUVA;
361 // We don't have an SDK YUVA format
362 ALOGD("Converter: incompactible color format (%d) for YUVA layout", mColorFormat);
363 mInitCheck = BAD_VALUE;
364 return;
365 case C2PlanarLayout::TYPE_RGB:
366 mediaImage->mType = MediaImage2::MEDIA_IMAGE_TYPE_RGB;
367 switch (mColorFormat) {
368 // TODO media image
369 case COLOR_FormatRGBFlexible:
370 case COLOR_Format24bitBGR888:
371 case COLOR_Format24bitRGB888:
372 break;
373 default:
374 ALOGD("Converter: incompactible color format (%d) for RGB layout", mColorFormat);
375 mInitCheck = BAD_VALUE;
376 return;
377 }
378 if (layout.numPlanes != 3) {
379 ALOGD("Converter: %d planes for RGB layout", layout.numPlanes);
380 mInitCheck = BAD_VALUE;
381 return;
382 }
383 break;
384 case C2PlanarLayout::TYPE_RGBA:
385 mediaImage->mType = MediaImage2::MEDIA_IMAGE_TYPE_RGBA;
386 switch (mColorFormat) {
387 // TODO media image
388 case COLOR_FormatRGBAFlexible:
389 case COLOR_Format32bitABGR8888:
390 case COLOR_Format32bitARGB8888:
391 case COLOR_Format32bitBGRA8888:
392 break;
393 default:
394 ALOGD("Incompactible color format (%d) for RGBA layout", mColorFormat);
395 mInitCheck = BAD_VALUE;
396 return;
397 }
398 if (layout.numPlanes != 4) {
399 ALOGD("Converter: %d planes for RGBA layout", layout.numPlanes);
400 mInitCheck = BAD_VALUE;
401 return;
402 }
403 break;
404 default:
405 mediaImage->mType = MediaImage2::MEDIA_IMAGE_TYPE_UNKNOWN;
406 ALOGD("Unknown layout");
407 mInitCheck = BAD_VALUE;
408 return;
409 }
410 mediaImage->mNumPlanes = layout.numPlanes;
Harish Mahendrakarf7c49e22019-05-24 14:19:16 -0700411 mediaImage->mWidth = view.crop().width;
412 mediaImage->mHeight = view.crop().height;
Pawin Vongmasa36653902018-11-15 00:10:25 -0800413 mediaImage->mBitDepth = bitDepth;
414 mediaImage->mBitDepthAllocated = mAllocatedDepth;
415
416 uint32_t bufferSize = 0;
417 for (uint32_t i = 0; i < layout.numPlanes; ++i) {
418 const C2PlaneInfo &plane = layout.planes[i];
419 if (plane.allocatedDepth < plane.bitDepth
420 || plane.rightShift != plane.allocatedDepth - plane.bitDepth) {
421 ALOGD("rightShift value of %u unsupported", plane.rightShift);
422 mInitCheck = BAD_VALUE;
423 return;
424 }
425 if (plane.allocatedDepth > 8 && plane.endianness != C2PlaneInfo::NATIVE) {
426 ALOGD("endianness value of %u unsupported", plane.endianness);
427 mInitCheck = BAD_VALUE;
428 return;
429 }
430 if (plane.allocatedDepth != mAllocatedDepth || plane.bitDepth != bitDepth) {
431 ALOGV("different allocatedDepth/bitDepth per plane unsupported");
432 mInitCheck = BAD_VALUE;
433 return;
434 }
Wonsik Kim8bfa17a2019-05-30 22:12:30 -0700435 bufferSize += stride * vStride
Pawin Vongmasa36653902018-11-15 00:10:25 -0800436 / plane.rowSampling / plane.colSampling;
437 }
438
439 mBackBufferSize = bufferSize;
440 mInitCheck = OK;
441 }
442
443 status_t initCheck() const { return mInitCheck; }
444
445 uint32_t backBufferSize() const { return mBackBufferSize; }
446
447 /**
448 * Wrap C2GraphicView using a MediaImage2. Note that if not wrapped, the content is not mapped
449 * in this function --- the caller should use CopyGraphicView2MediaImage() function to copy the
450 * data into a backing buffer explicitly.
451 *
452 * \return media buffer. This is null if wrapping failed.
453 */
454 sp<ABuffer> wrap() const {
455 if (mBackBuffer == nullptr) {
456 return mWrapped;
457 }
458 return nullptr;
459 }
460
461 bool setBackBuffer(const sp<ABuffer> &backBuffer) {
Wonsik Kim186fdbf2019-01-29 13:30:01 -0800462 if (backBuffer == nullptr) {
463 return false;
464 }
Pawin Vongmasa36653902018-11-15 00:10:25 -0800465 if (backBuffer->capacity() < mBackBufferSize) {
466 return false;
467 }
468 backBuffer->setRange(0, mBackBufferSize);
469 mBackBuffer = backBuffer;
470 return true;
471 }
472
473 /**
474 * Copy C2GraphicView to MediaImage2.
475 */
476 status_t copyToMediaImage() {
477 if (mInitCheck != OK) {
478 return mInitCheck;
479 }
480 return ImageCopy(mBackBuffer->base(), getMediaImage(), mView);
481 }
482
483 const sp<ABuffer> &imageData() const { return mMediaImage; }
484
485private:
486 status_t mInitCheck;
487
488 const C2GraphicView mView;
489 uint32_t mWidth;
490 uint32_t mHeight;
491 int32_t mColorFormat; ///< SDK color format for MediaImage
492 sp<ABuffer> mWrapped; ///< wrapped buffer (if we can map C2Buffer to an ABuffer)
493 uint32_t mAllocatedDepth;
494 uint32_t mBackBufferSize;
495 sp<ABuffer> mMediaImage;
496 std::function<sp<ABuffer>(size_t)> mAlloc;
497
498 sp<ABuffer> mBackBuffer; ///< backing buffer if we have to copy C2Buffer <=> ABuffer
499
500 MediaImage2 *getMediaImage() {
501 return (MediaImage2 *)mMediaImage->base();
502 }
503};
504
505} // namespace
506
507// GraphicBlockBuffer
508
509// static
510sp<GraphicBlockBuffer> GraphicBlockBuffer::Allocate(
511 const sp<AMessage> &format,
512 const std::shared_ptr<C2GraphicBlock> &block,
513 std::function<sp<ABuffer>(size_t)> alloc) {
514 C2GraphicView view(block->map().get());
515 if (view.error() != C2_OK) {
516 ALOGD("C2GraphicBlock::map failed: %d", view.error());
517 return nullptr;
518 }
519
520 int32_t colorFormat = COLOR_FormatYUV420Flexible;
521 (void)format->findInt32("color-format", &colorFormat);
522
Wonsik Kim7d966312019-06-04 14:00:49 -0700523 GraphicView2MediaImageConverter converter(view, colorFormat, false /* copy */);
Pawin Vongmasa36653902018-11-15 00:10:25 -0800524 if (converter.initCheck() != OK) {
525 ALOGD("Converter init failed: %d", converter.initCheck());
526 return nullptr;
527 }
528 bool wrapped = true;
529 sp<ABuffer> buffer = converter.wrap();
530 if (buffer == nullptr) {
531 buffer = alloc(converter.backBufferSize());
532 if (!converter.setBackBuffer(buffer)) {
533 ALOGD("Converter failed to set back buffer");
534 return nullptr;
535 }
536 wrapped = false;
537 }
538 return new GraphicBlockBuffer(
539 format,
540 buffer,
541 std::move(view),
542 block,
543 converter.imageData(),
544 wrapped);
545}
546
547GraphicBlockBuffer::GraphicBlockBuffer(
548 const sp<AMessage> &format,
549 const sp<ABuffer> &buffer,
550 C2GraphicView &&view,
551 const std::shared_ptr<C2GraphicBlock> &block,
552 const sp<ABuffer> &imageData,
553 bool wrapped)
554 : Codec2Buffer(format, buffer),
555 mView(view),
556 mBlock(block),
Pawin Vongmasa36653902018-11-15 00:10:25 -0800557 mWrapped(wrapped) {
558 setImageData(imageData);
559}
560
561std::shared_ptr<C2Buffer> GraphicBlockBuffer::asC2Buffer() {
562 uint32_t width = mView.width();
563 uint32_t height = mView.height();
564 if (!mWrapped) {
565 (void)ImageCopy(mView, base(), imageData());
566 }
567 return C2Buffer::CreateGraphicBuffer(
568 mBlock->share(C2Rect(width, height), C2Fence()));
569}
570
571// GraphicMetadataBuffer
572GraphicMetadataBuffer::GraphicMetadataBuffer(
573 const sp<AMessage> &format,
574 const std::shared_ptr<C2Allocator> &alloc)
575 : Codec2Buffer(format, new ABuffer(sizeof(VideoNativeMetadata))),
576 mAlloc(alloc) {
577 ((VideoNativeMetadata *)base())->pBuffer = nullptr;
578}
579
580std::shared_ptr<C2Buffer> GraphicMetadataBuffer::asC2Buffer() {
581#ifndef __LP64__
582 VideoNativeMetadata *meta = (VideoNativeMetadata *)base();
583 ANativeWindowBuffer *buffer = (ANativeWindowBuffer *)meta->pBuffer;
584 if (buffer == nullptr) {
585 ALOGD("VideoNativeMetadata contains null buffer");
586 return nullptr;
587 }
588
589 ALOGV("VideoNativeMetadata: %dx%d", buffer->width, buffer->height);
590 C2Handle *handle = WrapNativeCodec2GrallocHandle(
Sungtak Leea4d13be2019-01-23 15:24:46 -0800591 buffer->handle,
Pawin Vongmasa36653902018-11-15 00:10:25 -0800592 buffer->width,
593 buffer->height,
594 buffer->format,
595 buffer->usage,
596 buffer->stride);
597 std::shared_ptr<C2GraphicAllocation> alloc;
598 c2_status_t err = mAlloc->priorGraphicAllocation(handle, &alloc);
599 if (err != C2_OK) {
600 ALOGD("Failed to wrap VideoNativeMetadata into C2GraphicAllocation");
601 return nullptr;
602 }
603 std::shared_ptr<C2GraphicBlock> block = _C2BlockFactory::CreateGraphicBlock(alloc);
604
605 meta->pBuffer = 0;
Wonsik Kimebe0f9e2019-07-03 11:06:51 -0700606 // TODO: wrap this in C2Fence so that the component can wait when it
607 // actually starts processing.
608 if (meta->nFenceFd >= 0) {
609 sp<Fence> fence(new Fence(meta->nFenceFd));
610 fence->waitForever(LOG_TAG);
611 }
Pawin Vongmasa36653902018-11-15 00:10:25 -0800612 return C2Buffer::CreateGraphicBuffer(
613 block->share(C2Rect(buffer->width, buffer->height), C2Fence()));
614#else
615 ALOGE("GraphicMetadataBuffer does not work on 64-bit arch");
616 return nullptr;
617#endif
618}
619
620// ConstGraphicBlockBuffer
621
622// static
623sp<ConstGraphicBlockBuffer> ConstGraphicBlockBuffer::Allocate(
624 const sp<AMessage> &format,
625 const std::shared_ptr<C2Buffer> &buffer,
626 std::function<sp<ABuffer>(size_t)> alloc) {
627 if (!buffer
628 || buffer->data().type() != C2BufferData::GRAPHIC
629 || buffer->data().graphicBlocks().size() != 1u) {
630 ALOGD("C2Buffer precond fail");
631 return nullptr;
632 }
633 std::unique_ptr<const C2GraphicView> view(std::make_unique<const C2GraphicView>(
634 buffer->data().graphicBlocks()[0].map().get()));
635 std::unique_ptr<const C2GraphicView> holder;
636
637 int32_t colorFormat = COLOR_FormatYUV420Flexible;
638 (void)format->findInt32("color-format", &colorFormat);
639
Wonsik Kim7d966312019-06-04 14:00:49 -0700640 GraphicView2MediaImageConverter converter(*view, colorFormat, false /* copy */);
Pawin Vongmasa36653902018-11-15 00:10:25 -0800641 if (converter.initCheck() != OK) {
642 ALOGD("Converter init failed: %d", converter.initCheck());
643 return nullptr;
644 }
645 bool wrapped = true;
646 sp<ABuffer> aBuffer = converter.wrap();
647 if (aBuffer == nullptr) {
648 aBuffer = alloc(converter.backBufferSize());
649 if (!converter.setBackBuffer(aBuffer)) {
650 ALOGD("Converter failed to set back buffer");
651 return nullptr;
652 }
653 wrapped = false;
654 converter.copyToMediaImage();
655 // We don't need the view.
656 holder = std::move(view);
657 }
658 return new ConstGraphicBlockBuffer(
659 format,
660 aBuffer,
661 std::move(view),
662 buffer,
663 converter.imageData(),
664 wrapped);
665}
666
667// static
668sp<ConstGraphicBlockBuffer> ConstGraphicBlockBuffer::AllocateEmpty(
669 const sp<AMessage> &format,
670 std::function<sp<ABuffer>(size_t)> alloc) {
671 int32_t width, height;
672 if (!format->findInt32("width", &width)
673 || !format->findInt32("height", &height)) {
674 ALOGD("format had no width / height");
675 return nullptr;
676 }
Wonsik Kim8bfa17a2019-05-30 22:12:30 -0700677 // NOTE: we currently only support YUV420 formats for byte-buffer mode.
678 sp<ABuffer> aBuffer(alloc(align(width, 16) * align(height, 16) * 3 / 2));
Pawin Vongmasa36653902018-11-15 00:10:25 -0800679 return new ConstGraphicBlockBuffer(
680 format,
681 aBuffer,
682 nullptr,
683 nullptr,
684 nullptr,
685 false);
686}
687
688ConstGraphicBlockBuffer::ConstGraphicBlockBuffer(
689 const sp<AMessage> &format,
690 const sp<ABuffer> &aBuffer,
691 std::unique_ptr<const C2GraphicView> &&view,
692 const std::shared_ptr<C2Buffer> &buffer,
693 const sp<ABuffer> &imageData,
694 bool wrapped)
695 : Codec2Buffer(format, aBuffer),
696 mView(std::move(view)),
697 mBufferRef(buffer),
698 mWrapped(wrapped) {
Wonsik Kimc48ddcf2019-02-11 16:16:57 -0800699 setImageData(imageData);
Pawin Vongmasa36653902018-11-15 00:10:25 -0800700}
701
702std::shared_ptr<C2Buffer> ConstGraphicBlockBuffer::asC2Buffer() {
Wonsik Kimf9b32122020-04-02 11:30:17 -0700703 return mBufferRef;
704}
705
706void ConstGraphicBlockBuffer::clearC2BufferRefs() {
Pawin Vongmasa36653902018-11-15 00:10:25 -0800707 mView.reset();
Wonsik Kimf9b32122020-04-02 11:30:17 -0700708 mBufferRef.reset();
Pawin Vongmasa36653902018-11-15 00:10:25 -0800709}
710
711bool ConstGraphicBlockBuffer::canCopy(const std::shared_ptr<C2Buffer> &buffer) const {
712 if (mWrapped || mBufferRef) {
713 ALOGD("ConstGraphicBlockBuffer::canCopy: %swrapped ; buffer ref %s",
714 mWrapped ? "" : "not ", mBufferRef ? "exists" : "doesn't exist");
715 return false;
716 }
717 if (!buffer) {
718 // Nothing to copy, so we can copy by doing nothing.
719 return true;
720 }
721 if (buffer->data().type() != C2BufferData::GRAPHIC) {
722 ALOGD("ConstGraphicBlockBuffer::canCopy: buffer precondition unsatisfied");
723 return false;
724 }
725 if (buffer->data().graphicBlocks().size() == 0) {
726 return true;
727 } else if (buffer->data().graphicBlocks().size() != 1u) {
728 ALOGD("ConstGraphicBlockBuffer::canCopy: too many blocks");
729 return false;
730 }
731
732 int32_t colorFormat = COLOR_FormatYUV420Flexible;
733 // FIXME: format() is not const, but we cannot change it, so do a const cast here
734 const_cast<ConstGraphicBlockBuffer *>(this)->format()->findInt32("color-format", &colorFormat);
735
736 GraphicView2MediaImageConverter converter(
Wonsik Kim7d966312019-06-04 14:00:49 -0700737 buffer->data().graphicBlocks()[0].map().get(), colorFormat, true /* copy */);
Pawin Vongmasa36653902018-11-15 00:10:25 -0800738 if (converter.initCheck() != OK) {
739 ALOGD("ConstGraphicBlockBuffer::canCopy: converter init failed: %d", converter.initCheck());
740 return false;
741 }
742 if (converter.backBufferSize() > capacity()) {
743 ALOGD("ConstGraphicBlockBuffer::canCopy: insufficient capacity: req %u has %zu",
744 converter.backBufferSize(), capacity());
745 return false;
746 }
747 return true;
748}
749
750bool ConstGraphicBlockBuffer::copy(const std::shared_ptr<C2Buffer> &buffer) {
751 if (!buffer || buffer->data().graphicBlocks().size() == 0) {
752 setRange(0, 0);
753 return true;
754 }
755 int32_t colorFormat = COLOR_FormatYUV420Flexible;
756 format()->findInt32("color-format", &colorFormat);
757
758 GraphicView2MediaImageConverter converter(
Wonsik Kim7d966312019-06-04 14:00:49 -0700759 buffer->data().graphicBlocks()[0].map().get(), colorFormat, true /* copy */);
Pawin Vongmasa36653902018-11-15 00:10:25 -0800760 if (converter.initCheck() != OK) {
761 ALOGD("ConstGraphicBlockBuffer::copy: converter init failed: %d", converter.initCheck());
762 return false;
763 }
764 sp<ABuffer> aBuffer = new ABuffer(base(), capacity());
765 if (!converter.setBackBuffer(aBuffer)) {
766 ALOGD("ConstGraphicBlockBuffer::copy: set back buffer failed");
767 return false;
768 }
Pin-chih Lin1971e2c2019-04-15 19:36:26 +0800769 setRange(0, aBuffer->size()); // align size info
Pawin Vongmasa36653902018-11-15 00:10:25 -0800770 converter.copyToMediaImage();
771 setImageData(converter.imageData());
772 mBufferRef = buffer;
773 return true;
774}
775
776// EncryptedLinearBlockBuffer
777
778EncryptedLinearBlockBuffer::EncryptedLinearBlockBuffer(
779 const sp<AMessage> &format,
780 const std::shared_ptr<C2LinearBlock> &block,
781 const sp<IMemory> &memory,
782 int32_t heapSeqNum)
Ytai Ben-Tsvi7dd39722019-09-05 15:14:30 -0700783 // TODO: Using unsecurePointer() has some associated security pitfalls
784 // (see declaration for details).
785 // Either document why it is safe in this case or address the
786 // issue (e.g. by copying).
787 : Codec2Buffer(format, new ABuffer(memory->unsecurePointer(), memory->size())),
Pawin Vongmasa36653902018-11-15 00:10:25 -0800788 mBlock(block),
789 mMemory(memory),
790 mHeapSeqNum(heapSeqNum) {
791}
792
793std::shared_ptr<C2Buffer> EncryptedLinearBlockBuffer::asC2Buffer() {
794 return C2Buffer::CreateLinearBuffer(mBlock->share(offset(), size(), C2Fence()));
795}
796
797void EncryptedLinearBlockBuffer::fillSourceBuffer(
Robert Shih895fba92019-07-16 16:29:44 -0700798 hardware::drm::V1_0::SharedBuffer *source) {
799 BufferChannelBase::IMemoryToSharedBuffer(mMemory, mHeapSeqNum, source);
Pawin Vongmasa36653902018-11-15 00:10:25 -0800800}
801
802void EncryptedLinearBlockBuffer::fillSourceBuffer(
803 hardware::cas::native::V1_0::SharedBuffer *source) {
804 ssize_t offset;
805 size_t size;
806
807 mHidlMemory = hardware::fromHeap(mMemory->getMemory(&offset, &size));
808 source->heapBase = *mHidlMemory;
809 source->offset = offset;
810 source->size = size;
811}
812
813bool EncryptedLinearBlockBuffer::copyDecryptedContent(
814 const sp<IMemory> &decrypted, size_t length) {
815 C2WriteView view = mBlock->map().get();
816 if (view.error() != C2_OK) {
817 return false;
818 }
819 if (view.size() < length) {
820 return false;
821 }
Ytai Ben-Tsvi7dd39722019-09-05 15:14:30 -0700822 memcpy(view.data(), decrypted->unsecurePointer(), length);
Pawin Vongmasa36653902018-11-15 00:10:25 -0800823 return true;
824}
825
826bool EncryptedLinearBlockBuffer::copyDecryptedContentFromMemory(size_t length) {
827 return copyDecryptedContent(mMemory, length);
828}
829
830native_handle_t *EncryptedLinearBlockBuffer::handle() const {
831 return const_cast<native_handle_t *>(mBlock->handle());
832}
833
834} // namespace android