blob: b339a922df6004ebd5989a8142f348911e372cfd [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
21#include <hidlmemory/FrameworkUtils.h>
22#include <media/hardware/HardwareAPI.h>
23#include <media/stagefright/MediaCodecConstants.h>
24#include <media/stagefright/foundation/ABuffer.h>
25#include <media/stagefright/foundation/AMessage.h>
26#include <media/stagefright/foundation/AUtils.h>
27#include <nativebase/nativebase.h>
Wonsik Kimebe0f9e2019-07-03 11:06:51 -070028#include <ui/Fence.h>
Pawin Vongmasa36653902018-11-15 00:10:25 -080029
30#include <C2AllocatorGralloc.h>
31#include <C2BlockInternal.h>
32#include <C2Debug.h>
33
34#include "Codec2Buffer.h"
35
36namespace android {
37
38// Codec2Buffer
39
40bool Codec2Buffer::canCopyLinear(const std::shared_ptr<C2Buffer> &buffer) const {
41 if (const_cast<Codec2Buffer *>(this)->base() == nullptr) {
42 return false;
43 }
44 if (!buffer) {
45 // Nothing to copy, so we can copy by doing nothing.
46 return true;
47 }
48 if (buffer->data().type() != C2BufferData::LINEAR) {
49 return false;
50 }
51 if (buffer->data().linearBlocks().size() == 0u) {
52 // Nothing to copy, so we can copy by doing nothing.
53 return true;
54 } else if (buffer->data().linearBlocks().size() > 1u) {
55 // We don't know how to copy more than one blocks.
56 return false;
57 }
58 if (buffer->data().linearBlocks()[0].size() > capacity()) {
59 // It won't fit.
60 return false;
61 }
62 return true;
63}
64
65bool Codec2Buffer::copyLinear(const std::shared_ptr<C2Buffer> &buffer) {
66 // We assume that all canCopyLinear() checks passed.
67 if (!buffer || buffer->data().linearBlocks().size() == 0u
68 || buffer->data().linearBlocks()[0].size() == 0u) {
69 setRange(0, 0);
70 return true;
71 }
72 C2ReadView view = buffer->data().linearBlocks()[0].map().get();
73 if (view.error() != C2_OK) {
74 ALOGD("Error while mapping: %d", view.error());
75 return false;
76 }
77 if (view.capacity() > capacity()) {
78 ALOGD("C2ConstLinearBlock lied --- it actually doesn't fit: view(%u) > this(%zu)",
79 view.capacity(), capacity());
80 return false;
81 }
82 memcpy(base(), view.data(), view.capacity());
83 setRange(0, view.capacity());
84 return true;
85}
86
87void Codec2Buffer::setImageData(const sp<ABuffer> &imageData) {
Wonsik Kimc48ddcf2019-02-11 16:16:57 -080088 mImageData = imageData;
Pawin Vongmasa36653902018-11-15 00:10:25 -080089}
90
91// LocalLinearBuffer
92
93bool LocalLinearBuffer::canCopy(const std::shared_ptr<C2Buffer> &buffer) const {
94 return canCopyLinear(buffer);
95}
96
97bool LocalLinearBuffer::copy(const std::shared_ptr<C2Buffer> &buffer) {
98 return copyLinear(buffer);
99}
100
101// DummyContainerBuffer
102
Pawin Vongmasa8be93112018-12-11 14:01:42 -0800103static uint8_t sDummyByte[1] = { 0 };
104
Pawin Vongmasa36653902018-11-15 00:10:25 -0800105DummyContainerBuffer::DummyContainerBuffer(
106 const sp<AMessage> &format, const std::shared_ptr<C2Buffer> &buffer)
Pawin Vongmasa8be93112018-12-11 14:01:42 -0800107 : Codec2Buffer(format, new ABuffer(sDummyByte, 1)),
Pawin Vongmasa36653902018-11-15 00:10:25 -0800108 mBufferRef(buffer) {
109 setRange(0, buffer ? 1 : 0);
110}
111
112std::shared_ptr<C2Buffer> DummyContainerBuffer::asC2Buffer() {
113 return std::move(mBufferRef);
114}
115
116bool DummyContainerBuffer::canCopy(const std::shared_ptr<C2Buffer> &) const {
117 return !mBufferRef;
118}
119
120bool DummyContainerBuffer::copy(const std::shared_ptr<C2Buffer> &buffer) {
121 mBufferRef = buffer;
122 setRange(0, mBufferRef ? 1 : 0);
123 return true;
124}
125
126// LinearBlockBuffer
127
128// static
129sp<LinearBlockBuffer> LinearBlockBuffer::Allocate(
130 const sp<AMessage> &format, const std::shared_ptr<C2LinearBlock> &block) {
131 C2WriteView writeView(block->map().get());
132 if (writeView.error() != C2_OK) {
133 return nullptr;
134 }
135 return new LinearBlockBuffer(format, std::move(writeView), block);
136}
137
138std::shared_ptr<C2Buffer> LinearBlockBuffer::asC2Buffer() {
139 return C2Buffer::CreateLinearBuffer(mBlock->share(offset(), size(), C2Fence()));
140}
141
142bool LinearBlockBuffer::canCopy(const std::shared_ptr<C2Buffer> &buffer) const {
143 return canCopyLinear(buffer);
144}
145
146bool LinearBlockBuffer::copy(const std::shared_ptr<C2Buffer> &buffer) {
147 return copyLinear(buffer);
148}
149
150LinearBlockBuffer::LinearBlockBuffer(
151 const sp<AMessage> &format,
152 C2WriteView&& writeView,
153 const std::shared_ptr<C2LinearBlock> &block)
154 : Codec2Buffer(format, new ABuffer(writeView.data(), writeView.size())),
155 mWriteView(writeView),
156 mBlock(block) {
157}
158
159// ConstLinearBlockBuffer
160
161// static
162sp<ConstLinearBlockBuffer> ConstLinearBlockBuffer::Allocate(
163 const sp<AMessage> &format, const std::shared_ptr<C2Buffer> &buffer) {
164 if (!buffer
165 || buffer->data().type() != C2BufferData::LINEAR
166 || buffer->data().linearBlocks().size() != 1u) {
167 return nullptr;
168 }
169 C2ReadView readView(buffer->data().linearBlocks()[0].map().get());
170 if (readView.error() != C2_OK) {
171 return nullptr;
172 }
173 return new ConstLinearBlockBuffer(format, std::move(readView), buffer);
174}
175
176ConstLinearBlockBuffer::ConstLinearBlockBuffer(
177 const sp<AMessage> &format,
178 C2ReadView&& readView,
179 const std::shared_ptr<C2Buffer> &buffer)
180 : Codec2Buffer(format, new ABuffer(
181 // NOTE: ABuffer only takes non-const pointer but this data is
182 // supposed to be read-only.
183 const_cast<uint8_t *>(readView.data()), readView.capacity())),
184 mReadView(readView),
185 mBufferRef(buffer) {
186}
187
188std::shared_ptr<C2Buffer> ConstLinearBlockBuffer::asC2Buffer() {
189 return std::move(mBufferRef);
190}
191
192// GraphicView2MediaImageConverter
193
194namespace {
195
196class GraphicView2MediaImageConverter {
197public:
198 /**
199 * Creates a C2GraphicView <=> MediaImage converter
200 *
201 * \param view C2GraphicView object
202 * \param colorFormat desired SDK color format for the MediaImage (if this is a flexible format,
203 * an attempt is made to simply represent the graphic view as a flexible SDK format
204 * without a memcpy)
Wonsik Kim7d966312019-06-04 14:00:49 -0700205 * \param copy whether the converter is used for copy or not
Pawin Vongmasa36653902018-11-15 00:10:25 -0800206 */
207 GraphicView2MediaImageConverter(
Wonsik Kim7d966312019-06-04 14:00:49 -0700208 const C2GraphicView &view, int32_t colorFormat, bool copy)
Pawin Vongmasa36653902018-11-15 00:10:25 -0800209 : mInitCheck(NO_INIT),
210 mView(view),
211 mWidth(view.width()),
212 mHeight(view.height()),
213 mColorFormat(colorFormat),
214 mAllocatedDepth(0),
215 mBackBufferSize(0),
216 mMediaImage(new ABuffer(sizeof(MediaImage2))) {
217 if (view.error() != C2_OK) {
218 ALOGD("Converter: view.error() = %d", view.error());
219 mInitCheck = BAD_VALUE;
220 return;
221 }
222 MediaImage2 *mediaImage = (MediaImage2 *)mMediaImage->base();
223 const C2PlanarLayout &layout = view.layout();
224 if (layout.numPlanes == 0) {
225 ALOGD("Converter: 0 planes");
226 mInitCheck = BAD_VALUE;
227 return;
228 }
Harish Mahendrakarcac53852019-02-20 10:59:10 -0800229 memset(mediaImage, 0, sizeof(*mediaImage));
Pawin Vongmasa36653902018-11-15 00:10:25 -0800230 mAllocatedDepth = layout.planes[0].allocatedDepth;
231 uint32_t bitDepth = layout.planes[0].bitDepth;
232
233 // align width and height to support subsampling cleanly
Wonsik Kim8bfa17a2019-05-30 22:12:30 -0700234 uint32_t stride = align(view.crop().width, 2) * divUp(layout.planes[0].allocatedDepth, 8u);
235 uint32_t vStride = align(view.crop().height, 2);
Pawin Vongmasa36653902018-11-15 00:10:25 -0800236
237 switch (layout.type) {
238 case C2PlanarLayout::TYPE_YUV:
239 mediaImage->mType = MediaImage2::MEDIA_IMAGE_TYPE_YUV;
240 if (layout.numPlanes != 3) {
241 ALOGD("Converter: %d planes for YUV layout", layout.numPlanes);
242 mInitCheck = BAD_VALUE;
243 return;
244 }
245 if (layout.planes[0].channel != C2PlaneInfo::CHANNEL_Y
246 || layout.planes[1].channel != C2PlaneInfo::CHANNEL_CB
247 || layout.planes[2].channel != C2PlaneInfo::CHANNEL_CR
248 || layout.planes[0].colSampling != 1
249 || layout.planes[0].rowSampling != 1
250 || layout.planes[1].colSampling != 2
251 || layout.planes[1].rowSampling != 2
252 || layout.planes[2].colSampling != 2
253 || layout.planes[2].rowSampling != 2) {
254 ALOGD("Converter: not YUV420 for YUV layout");
255 mInitCheck = BAD_VALUE;
256 return;
257 }
258 switch (mColorFormat) {
259 case COLOR_FormatYUV420Flexible:
Wonsik Kim7d966312019-06-04 14:00:49 -0700260 if (!copy) {
261 // try to map directly. check if the planes are near one another
262 const uint8_t *minPtr = mView.data()[0];
263 const uint8_t *maxPtr = mView.data()[0];
264 int32_t planeSize = 0;
Pawin Vongmasa36653902018-11-15 00:10:25 -0800265 for (uint32_t i = 0; i < layout.numPlanes; ++i) {
266 const C2PlaneInfo &plane = layout.planes[i];
Wonsik Kim7d966312019-06-04 14:00:49 -0700267 ssize_t minOffset = plane.minOffset(mWidth, mHeight);
268 ssize_t maxOffset = plane.maxOffset(mWidth, mHeight);
269 if (minPtr > mView.data()[i] + minOffset) {
270 minPtr = mView.data()[i] + minOffset;
271 }
272 if (maxPtr < mView.data()[i] + maxOffset) {
273 maxPtr = mView.data()[i] + maxOffset;
274 }
275 planeSize += std::abs(plane.rowInc) * align(mHeight, 64)
276 / plane.rowSampling / plane.colSampling
277 * divUp(mAllocatedDepth, 8u);
Pawin Vongmasa36653902018-11-15 00:10:25 -0800278 }
Wonsik Kim7d966312019-06-04 14:00:49 -0700279
280 if ((maxPtr - minPtr + 1) <= planeSize) {
281 // FIXME: this is risky as reading/writing data out of bound results
282 // in an undefined behavior, but gralloc does assume a
283 // contiguous mapping
284 for (uint32_t i = 0; i < layout.numPlanes; ++i) {
285 const C2PlaneInfo &plane = layout.planes[i];
286 mediaImage->mPlane[i].mOffset = mView.data()[i] - minPtr;
287 mediaImage->mPlane[i].mColInc = plane.colInc;
288 mediaImage->mPlane[i].mRowInc = plane.rowInc;
289 mediaImage->mPlane[i].mHorizSubsampling = plane.colSampling;
290 mediaImage->mPlane[i].mVertSubsampling = plane.rowSampling;
291 }
292 mWrapped = new ABuffer(const_cast<uint8_t *>(minPtr),
293 maxPtr - minPtr + 1);
294 break;
295 }
Pawin Vongmasa36653902018-11-15 00:10:25 -0800296 }
Wonsik Kim7d966312019-06-04 14:00:49 -0700297 [[fallthrough]];
Pawin Vongmasa36653902018-11-15 00:10:25 -0800298
299 case COLOR_FormatYUV420Planar:
300 case COLOR_FormatYUV420PackedPlanar:
301 mediaImage->mPlane[mediaImage->Y].mOffset = 0;
302 mediaImage->mPlane[mediaImage->Y].mColInc = 1;
Wonsik Kim8bfa17a2019-05-30 22:12:30 -0700303 mediaImage->mPlane[mediaImage->Y].mRowInc = stride;
Pawin Vongmasa36653902018-11-15 00:10:25 -0800304 mediaImage->mPlane[mediaImage->Y].mHorizSubsampling = 1;
305 mediaImage->mPlane[mediaImage->Y].mVertSubsampling = 1;
306
Wonsik Kim8bfa17a2019-05-30 22:12:30 -0700307 mediaImage->mPlane[mediaImage->U].mOffset = stride * vStride;
Pawin Vongmasa36653902018-11-15 00:10:25 -0800308 mediaImage->mPlane[mediaImage->U].mColInc = 1;
Wonsik Kim8bfa17a2019-05-30 22:12:30 -0700309 mediaImage->mPlane[mediaImage->U].mRowInc = stride / 2;
Pawin Vongmasa36653902018-11-15 00:10:25 -0800310 mediaImage->mPlane[mediaImage->U].mHorizSubsampling = 2;
311 mediaImage->mPlane[mediaImage->U].mVertSubsampling = 2;
312
Wonsik Kim8bfa17a2019-05-30 22:12:30 -0700313 mediaImage->mPlane[mediaImage->V].mOffset = stride * vStride * 5 / 4;
Pawin Vongmasa36653902018-11-15 00:10:25 -0800314 mediaImage->mPlane[mediaImage->V].mColInc = 1;
Wonsik Kim8bfa17a2019-05-30 22:12:30 -0700315 mediaImage->mPlane[mediaImage->V].mRowInc = stride / 2;
Pawin Vongmasa36653902018-11-15 00:10:25 -0800316 mediaImage->mPlane[mediaImage->V].mHorizSubsampling = 2;
317 mediaImage->mPlane[mediaImage->V].mVertSubsampling = 2;
318 break;
319
320 case COLOR_FormatYUV420SemiPlanar:
321 case COLOR_FormatYUV420PackedSemiPlanar:
322 mediaImage->mPlane[mediaImage->Y].mOffset = 0;
323 mediaImage->mPlane[mediaImage->Y].mColInc = 1;
Wonsik Kim8bfa17a2019-05-30 22:12:30 -0700324 mediaImage->mPlane[mediaImage->Y].mRowInc = stride;
Pawin Vongmasa36653902018-11-15 00:10:25 -0800325 mediaImage->mPlane[mediaImage->Y].mHorizSubsampling = 1;
326 mediaImage->mPlane[mediaImage->Y].mVertSubsampling = 1;
327
Wonsik Kim8bfa17a2019-05-30 22:12:30 -0700328 mediaImage->mPlane[mediaImage->U].mOffset = stride * vStride;
Pawin Vongmasa36653902018-11-15 00:10:25 -0800329 mediaImage->mPlane[mediaImage->U].mColInc = 2;
Wonsik Kim8bfa17a2019-05-30 22:12:30 -0700330 mediaImage->mPlane[mediaImage->U].mRowInc = stride;
Pawin Vongmasa36653902018-11-15 00:10:25 -0800331 mediaImage->mPlane[mediaImage->U].mHorizSubsampling = 2;
332 mediaImage->mPlane[mediaImage->U].mVertSubsampling = 2;
333
Wonsik Kim8bfa17a2019-05-30 22:12:30 -0700334 mediaImage->mPlane[mediaImage->V].mOffset = stride * vStride + 1;
Pawin Vongmasa36653902018-11-15 00:10:25 -0800335 mediaImage->mPlane[mediaImage->V].mColInc = 2;
Wonsik Kim8bfa17a2019-05-30 22:12:30 -0700336 mediaImage->mPlane[mediaImage->V].mRowInc = stride;
Pawin Vongmasa36653902018-11-15 00:10:25 -0800337 mediaImage->mPlane[mediaImage->V].mHorizSubsampling = 2;
338 mediaImage->mPlane[mediaImage->V].mVertSubsampling = 2;
339 break;
340
341 default:
342 ALOGD("Converter: incompactible color format (%d) for YUV layout", mColorFormat);
343 mInitCheck = BAD_VALUE;
344 return;
345 }
346 break;
347 case C2PlanarLayout::TYPE_YUVA:
348 mediaImage->mType = MediaImage2::MEDIA_IMAGE_TYPE_YUVA;
349 // We don't have an SDK YUVA format
350 ALOGD("Converter: incompactible color format (%d) for YUVA layout", mColorFormat);
351 mInitCheck = BAD_VALUE;
352 return;
353 case C2PlanarLayout::TYPE_RGB:
354 mediaImage->mType = MediaImage2::MEDIA_IMAGE_TYPE_RGB;
355 switch (mColorFormat) {
356 // TODO media image
357 case COLOR_FormatRGBFlexible:
358 case COLOR_Format24bitBGR888:
359 case COLOR_Format24bitRGB888:
360 break;
361 default:
362 ALOGD("Converter: incompactible color format (%d) for RGB layout", mColorFormat);
363 mInitCheck = BAD_VALUE;
364 return;
365 }
366 if (layout.numPlanes != 3) {
367 ALOGD("Converter: %d planes for RGB layout", layout.numPlanes);
368 mInitCheck = BAD_VALUE;
369 return;
370 }
371 break;
372 case C2PlanarLayout::TYPE_RGBA:
373 mediaImage->mType = MediaImage2::MEDIA_IMAGE_TYPE_RGBA;
374 switch (mColorFormat) {
375 // TODO media image
376 case COLOR_FormatRGBAFlexible:
377 case COLOR_Format32bitABGR8888:
378 case COLOR_Format32bitARGB8888:
379 case COLOR_Format32bitBGRA8888:
380 break;
381 default:
382 ALOGD("Incompactible color format (%d) for RGBA layout", mColorFormat);
383 mInitCheck = BAD_VALUE;
384 return;
385 }
386 if (layout.numPlanes != 4) {
387 ALOGD("Converter: %d planes for RGBA layout", layout.numPlanes);
388 mInitCheck = BAD_VALUE;
389 return;
390 }
391 break;
392 default:
393 mediaImage->mType = MediaImage2::MEDIA_IMAGE_TYPE_UNKNOWN;
394 ALOGD("Unknown layout");
395 mInitCheck = BAD_VALUE;
396 return;
397 }
398 mediaImage->mNumPlanes = layout.numPlanes;
Harish Mahendrakarf7c49e22019-05-24 14:19:16 -0700399 mediaImage->mWidth = view.crop().width;
400 mediaImage->mHeight = view.crop().height;
Pawin Vongmasa36653902018-11-15 00:10:25 -0800401 mediaImage->mBitDepth = bitDepth;
402 mediaImage->mBitDepthAllocated = mAllocatedDepth;
403
404 uint32_t bufferSize = 0;
405 for (uint32_t i = 0; i < layout.numPlanes; ++i) {
406 const C2PlaneInfo &plane = layout.planes[i];
407 if (plane.allocatedDepth < plane.bitDepth
408 || plane.rightShift != plane.allocatedDepth - plane.bitDepth) {
409 ALOGD("rightShift value of %u unsupported", plane.rightShift);
410 mInitCheck = BAD_VALUE;
411 return;
412 }
413 if (plane.allocatedDepth > 8 && plane.endianness != C2PlaneInfo::NATIVE) {
414 ALOGD("endianness value of %u unsupported", plane.endianness);
415 mInitCheck = BAD_VALUE;
416 return;
417 }
418 if (plane.allocatedDepth != mAllocatedDepth || plane.bitDepth != bitDepth) {
419 ALOGV("different allocatedDepth/bitDepth per plane unsupported");
420 mInitCheck = BAD_VALUE;
421 return;
422 }
Wonsik Kim8bfa17a2019-05-30 22:12:30 -0700423 bufferSize += stride * vStride
Pawin Vongmasa36653902018-11-15 00:10:25 -0800424 / plane.rowSampling / plane.colSampling;
425 }
426
427 mBackBufferSize = bufferSize;
428 mInitCheck = OK;
429 }
430
431 status_t initCheck() const { return mInitCheck; }
432
433 uint32_t backBufferSize() const { return mBackBufferSize; }
434
435 /**
436 * Wrap C2GraphicView using a MediaImage2. Note that if not wrapped, the content is not mapped
437 * in this function --- the caller should use CopyGraphicView2MediaImage() function to copy the
438 * data into a backing buffer explicitly.
439 *
440 * \return media buffer. This is null if wrapping failed.
441 */
442 sp<ABuffer> wrap() const {
443 if (mBackBuffer == nullptr) {
444 return mWrapped;
445 }
446 return nullptr;
447 }
448
449 bool setBackBuffer(const sp<ABuffer> &backBuffer) {
Wonsik Kim186fdbf2019-01-29 13:30:01 -0800450 if (backBuffer == nullptr) {
451 return false;
452 }
Pawin Vongmasa36653902018-11-15 00:10:25 -0800453 if (backBuffer->capacity() < mBackBufferSize) {
454 return false;
455 }
456 backBuffer->setRange(0, mBackBufferSize);
457 mBackBuffer = backBuffer;
458 return true;
459 }
460
461 /**
462 * Copy C2GraphicView to MediaImage2.
463 */
464 status_t copyToMediaImage() {
465 if (mInitCheck != OK) {
466 return mInitCheck;
467 }
468 return ImageCopy(mBackBuffer->base(), getMediaImage(), mView);
469 }
470
471 const sp<ABuffer> &imageData() const { return mMediaImage; }
472
473private:
474 status_t mInitCheck;
475
476 const C2GraphicView mView;
477 uint32_t mWidth;
478 uint32_t mHeight;
479 int32_t mColorFormat; ///< SDK color format for MediaImage
480 sp<ABuffer> mWrapped; ///< wrapped buffer (if we can map C2Buffer to an ABuffer)
481 uint32_t mAllocatedDepth;
482 uint32_t mBackBufferSize;
483 sp<ABuffer> mMediaImage;
484 std::function<sp<ABuffer>(size_t)> mAlloc;
485
486 sp<ABuffer> mBackBuffer; ///< backing buffer if we have to copy C2Buffer <=> ABuffer
487
488 MediaImage2 *getMediaImage() {
489 return (MediaImage2 *)mMediaImage->base();
490 }
491};
492
493} // namespace
494
495// GraphicBlockBuffer
496
497// static
498sp<GraphicBlockBuffer> GraphicBlockBuffer::Allocate(
499 const sp<AMessage> &format,
500 const std::shared_ptr<C2GraphicBlock> &block,
501 std::function<sp<ABuffer>(size_t)> alloc) {
502 C2GraphicView view(block->map().get());
503 if (view.error() != C2_OK) {
504 ALOGD("C2GraphicBlock::map failed: %d", view.error());
505 return nullptr;
506 }
507
508 int32_t colorFormat = COLOR_FormatYUV420Flexible;
509 (void)format->findInt32("color-format", &colorFormat);
510
Wonsik Kim7d966312019-06-04 14:00:49 -0700511 GraphicView2MediaImageConverter converter(view, colorFormat, false /* copy */);
Pawin Vongmasa36653902018-11-15 00:10:25 -0800512 if (converter.initCheck() != OK) {
513 ALOGD("Converter init failed: %d", converter.initCheck());
514 return nullptr;
515 }
516 bool wrapped = true;
517 sp<ABuffer> buffer = converter.wrap();
518 if (buffer == nullptr) {
519 buffer = alloc(converter.backBufferSize());
520 if (!converter.setBackBuffer(buffer)) {
521 ALOGD("Converter failed to set back buffer");
522 return nullptr;
523 }
524 wrapped = false;
525 }
526 return new GraphicBlockBuffer(
527 format,
528 buffer,
529 std::move(view),
530 block,
531 converter.imageData(),
532 wrapped);
533}
534
535GraphicBlockBuffer::GraphicBlockBuffer(
536 const sp<AMessage> &format,
537 const sp<ABuffer> &buffer,
538 C2GraphicView &&view,
539 const std::shared_ptr<C2GraphicBlock> &block,
540 const sp<ABuffer> &imageData,
541 bool wrapped)
542 : Codec2Buffer(format, buffer),
543 mView(view),
544 mBlock(block),
Pawin Vongmasa36653902018-11-15 00:10:25 -0800545 mWrapped(wrapped) {
546 setImageData(imageData);
547}
548
549std::shared_ptr<C2Buffer> GraphicBlockBuffer::asC2Buffer() {
550 uint32_t width = mView.width();
551 uint32_t height = mView.height();
552 if (!mWrapped) {
553 (void)ImageCopy(mView, base(), imageData());
554 }
555 return C2Buffer::CreateGraphicBuffer(
556 mBlock->share(C2Rect(width, height), C2Fence()));
557}
558
559// GraphicMetadataBuffer
560GraphicMetadataBuffer::GraphicMetadataBuffer(
561 const sp<AMessage> &format,
562 const std::shared_ptr<C2Allocator> &alloc)
563 : Codec2Buffer(format, new ABuffer(sizeof(VideoNativeMetadata))),
564 mAlloc(alloc) {
565 ((VideoNativeMetadata *)base())->pBuffer = nullptr;
566}
567
568std::shared_ptr<C2Buffer> GraphicMetadataBuffer::asC2Buffer() {
569#ifndef __LP64__
570 VideoNativeMetadata *meta = (VideoNativeMetadata *)base();
571 ANativeWindowBuffer *buffer = (ANativeWindowBuffer *)meta->pBuffer;
572 if (buffer == nullptr) {
573 ALOGD("VideoNativeMetadata contains null buffer");
574 return nullptr;
575 }
576
577 ALOGV("VideoNativeMetadata: %dx%d", buffer->width, buffer->height);
578 C2Handle *handle = WrapNativeCodec2GrallocHandle(
Sungtak Leea4d13be2019-01-23 15:24:46 -0800579 buffer->handle,
Pawin Vongmasa36653902018-11-15 00:10:25 -0800580 buffer->width,
581 buffer->height,
582 buffer->format,
583 buffer->usage,
584 buffer->stride);
585 std::shared_ptr<C2GraphicAllocation> alloc;
586 c2_status_t err = mAlloc->priorGraphicAllocation(handle, &alloc);
587 if (err != C2_OK) {
588 ALOGD("Failed to wrap VideoNativeMetadata into C2GraphicAllocation");
589 return nullptr;
590 }
591 std::shared_ptr<C2GraphicBlock> block = _C2BlockFactory::CreateGraphicBlock(alloc);
592
593 meta->pBuffer = 0;
Wonsik Kimebe0f9e2019-07-03 11:06:51 -0700594 // TODO: wrap this in C2Fence so that the component can wait when it
595 // actually starts processing.
596 if (meta->nFenceFd >= 0) {
597 sp<Fence> fence(new Fence(meta->nFenceFd));
598 fence->waitForever(LOG_TAG);
599 }
Pawin Vongmasa36653902018-11-15 00:10:25 -0800600 return C2Buffer::CreateGraphicBuffer(
601 block->share(C2Rect(buffer->width, buffer->height), C2Fence()));
602#else
603 ALOGE("GraphicMetadataBuffer does not work on 64-bit arch");
604 return nullptr;
605#endif
606}
607
608// ConstGraphicBlockBuffer
609
610// static
611sp<ConstGraphicBlockBuffer> ConstGraphicBlockBuffer::Allocate(
612 const sp<AMessage> &format,
613 const std::shared_ptr<C2Buffer> &buffer,
614 std::function<sp<ABuffer>(size_t)> alloc) {
615 if (!buffer
616 || buffer->data().type() != C2BufferData::GRAPHIC
617 || buffer->data().graphicBlocks().size() != 1u) {
618 ALOGD("C2Buffer precond fail");
619 return nullptr;
620 }
621 std::unique_ptr<const C2GraphicView> view(std::make_unique<const C2GraphicView>(
622 buffer->data().graphicBlocks()[0].map().get()));
623 std::unique_ptr<const C2GraphicView> holder;
624
625 int32_t colorFormat = COLOR_FormatYUV420Flexible;
626 (void)format->findInt32("color-format", &colorFormat);
627
Wonsik Kim7d966312019-06-04 14:00:49 -0700628 GraphicView2MediaImageConverter converter(*view, colorFormat, false /* copy */);
Pawin Vongmasa36653902018-11-15 00:10:25 -0800629 if (converter.initCheck() != OK) {
630 ALOGD("Converter init failed: %d", converter.initCheck());
631 return nullptr;
632 }
633 bool wrapped = true;
634 sp<ABuffer> aBuffer = converter.wrap();
635 if (aBuffer == nullptr) {
636 aBuffer = alloc(converter.backBufferSize());
637 if (!converter.setBackBuffer(aBuffer)) {
638 ALOGD("Converter failed to set back buffer");
639 return nullptr;
640 }
641 wrapped = false;
642 converter.copyToMediaImage();
643 // We don't need the view.
644 holder = std::move(view);
645 }
646 return new ConstGraphicBlockBuffer(
647 format,
648 aBuffer,
649 std::move(view),
650 buffer,
651 converter.imageData(),
652 wrapped);
653}
654
655// static
656sp<ConstGraphicBlockBuffer> ConstGraphicBlockBuffer::AllocateEmpty(
657 const sp<AMessage> &format,
658 std::function<sp<ABuffer>(size_t)> alloc) {
659 int32_t width, height;
660 if (!format->findInt32("width", &width)
661 || !format->findInt32("height", &height)) {
662 ALOGD("format had no width / height");
663 return nullptr;
664 }
Wonsik Kim8bfa17a2019-05-30 22:12:30 -0700665 // NOTE: we currently only support YUV420 formats for byte-buffer mode.
666 sp<ABuffer> aBuffer(alloc(align(width, 16) * align(height, 16) * 3 / 2));
Pawin Vongmasa36653902018-11-15 00:10:25 -0800667 return new ConstGraphicBlockBuffer(
668 format,
669 aBuffer,
670 nullptr,
671 nullptr,
672 nullptr,
673 false);
674}
675
676ConstGraphicBlockBuffer::ConstGraphicBlockBuffer(
677 const sp<AMessage> &format,
678 const sp<ABuffer> &aBuffer,
679 std::unique_ptr<const C2GraphicView> &&view,
680 const std::shared_ptr<C2Buffer> &buffer,
681 const sp<ABuffer> &imageData,
682 bool wrapped)
683 : Codec2Buffer(format, aBuffer),
684 mView(std::move(view)),
685 mBufferRef(buffer),
686 mWrapped(wrapped) {
Wonsik Kimc48ddcf2019-02-11 16:16:57 -0800687 setImageData(imageData);
Pawin Vongmasa36653902018-11-15 00:10:25 -0800688}
689
690std::shared_ptr<C2Buffer> ConstGraphicBlockBuffer::asC2Buffer() {
691 mView.reset();
692 return std::move(mBufferRef);
693}
694
695bool ConstGraphicBlockBuffer::canCopy(const std::shared_ptr<C2Buffer> &buffer) const {
696 if (mWrapped || mBufferRef) {
697 ALOGD("ConstGraphicBlockBuffer::canCopy: %swrapped ; buffer ref %s",
698 mWrapped ? "" : "not ", mBufferRef ? "exists" : "doesn't exist");
699 return false;
700 }
701 if (!buffer) {
702 // Nothing to copy, so we can copy by doing nothing.
703 return true;
704 }
705 if (buffer->data().type() != C2BufferData::GRAPHIC) {
706 ALOGD("ConstGraphicBlockBuffer::canCopy: buffer precondition unsatisfied");
707 return false;
708 }
709 if (buffer->data().graphicBlocks().size() == 0) {
710 return true;
711 } else if (buffer->data().graphicBlocks().size() != 1u) {
712 ALOGD("ConstGraphicBlockBuffer::canCopy: too many blocks");
713 return false;
714 }
715
716 int32_t colorFormat = COLOR_FormatYUV420Flexible;
717 // FIXME: format() is not const, but we cannot change it, so do a const cast here
718 const_cast<ConstGraphicBlockBuffer *>(this)->format()->findInt32("color-format", &colorFormat);
719
720 GraphicView2MediaImageConverter converter(
Wonsik Kim7d966312019-06-04 14:00:49 -0700721 buffer->data().graphicBlocks()[0].map().get(), colorFormat, true /* copy */);
Pawin Vongmasa36653902018-11-15 00:10:25 -0800722 if (converter.initCheck() != OK) {
723 ALOGD("ConstGraphicBlockBuffer::canCopy: converter init failed: %d", converter.initCheck());
724 return false;
725 }
726 if (converter.backBufferSize() > capacity()) {
727 ALOGD("ConstGraphicBlockBuffer::canCopy: insufficient capacity: req %u has %zu",
728 converter.backBufferSize(), capacity());
729 return false;
730 }
731 return true;
732}
733
734bool ConstGraphicBlockBuffer::copy(const std::shared_ptr<C2Buffer> &buffer) {
735 if (!buffer || buffer->data().graphicBlocks().size() == 0) {
736 setRange(0, 0);
737 return true;
738 }
739 int32_t colorFormat = COLOR_FormatYUV420Flexible;
740 format()->findInt32("color-format", &colorFormat);
741
742 GraphicView2MediaImageConverter converter(
Wonsik Kim7d966312019-06-04 14:00:49 -0700743 buffer->data().graphicBlocks()[0].map().get(), colorFormat, true /* copy */);
Pawin Vongmasa36653902018-11-15 00:10:25 -0800744 if (converter.initCheck() != OK) {
745 ALOGD("ConstGraphicBlockBuffer::copy: converter init failed: %d", converter.initCheck());
746 return false;
747 }
748 sp<ABuffer> aBuffer = new ABuffer(base(), capacity());
749 if (!converter.setBackBuffer(aBuffer)) {
750 ALOGD("ConstGraphicBlockBuffer::copy: set back buffer failed");
751 return false;
752 }
Pin-chih Lin1971e2c2019-04-15 19:36:26 +0800753 setRange(0, aBuffer->size()); // align size info
Pawin Vongmasa36653902018-11-15 00:10:25 -0800754 converter.copyToMediaImage();
755 setImageData(converter.imageData());
756 mBufferRef = buffer;
757 return true;
758}
759
760// EncryptedLinearBlockBuffer
761
762EncryptedLinearBlockBuffer::EncryptedLinearBlockBuffer(
763 const sp<AMessage> &format,
764 const std::shared_ptr<C2LinearBlock> &block,
765 const sp<IMemory> &memory,
766 int32_t heapSeqNum)
Ytai Ben-Tsvi7dd39722019-09-05 15:14:30 -0700767 // TODO: Using unsecurePointer() has some associated security pitfalls
768 // (see declaration for details).
769 // Either document why it is safe in this case or address the
770 // issue (e.g. by copying).
771 : Codec2Buffer(format, new ABuffer(memory->unsecurePointer(), memory->size())),
Pawin Vongmasa36653902018-11-15 00:10:25 -0800772 mBlock(block),
773 mMemory(memory),
774 mHeapSeqNum(heapSeqNum) {
775}
776
777std::shared_ptr<C2Buffer> EncryptedLinearBlockBuffer::asC2Buffer() {
778 return C2Buffer::CreateLinearBuffer(mBlock->share(offset(), size(), C2Fence()));
779}
780
781void EncryptedLinearBlockBuffer::fillSourceBuffer(
782 ICrypto::SourceBuffer *source) {
783 source->mSharedMemory = mMemory;
784 source->mHeapSeqNum = mHeapSeqNum;
785}
786
787void EncryptedLinearBlockBuffer::fillSourceBuffer(
788 hardware::cas::native::V1_0::SharedBuffer *source) {
789 ssize_t offset;
790 size_t size;
791
792 mHidlMemory = hardware::fromHeap(mMemory->getMemory(&offset, &size));
793 source->heapBase = *mHidlMemory;
794 source->offset = offset;
795 source->size = size;
796}
797
798bool EncryptedLinearBlockBuffer::copyDecryptedContent(
799 const sp<IMemory> &decrypted, size_t length) {
800 C2WriteView view = mBlock->map().get();
801 if (view.error() != C2_OK) {
802 return false;
803 }
804 if (view.size() < length) {
805 return false;
806 }
Ytai Ben-Tsvi7dd39722019-09-05 15:14:30 -0700807 memcpy(view.data(), decrypted->unsecurePointer(), length);
Pawin Vongmasa36653902018-11-15 00:10:25 -0800808 return true;
809}
810
811bool EncryptedLinearBlockBuffer::copyDecryptedContentFromMemory(size_t length) {
812 return copyDecryptedContent(mMemory, length);
813}
814
815native_handle_t *EncryptedLinearBlockBuffer::handle() const {
816 return const_cast<native_handle_t *>(mBlock->handle());
817}
818
819} // namespace android