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