blob: 13b63c9f93d2bf71bee7d47e6eb82bd0f56b4313 [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 }
227 mAllocatedDepth = layout.planes[0].allocatedDepth;
228 uint32_t bitDepth = layout.planes[0].bitDepth;
229
230 // align width and height to support subsampling cleanly
231 uint32_t mStride = align(mWidth, 2) * divUp(layout.planes[0].allocatedDepth, 8u);
232 uint32_t mVStride = align(mHeight, 2);
233
234 switch (layout.type) {
235 case C2PlanarLayout::TYPE_YUV:
236 mediaImage->mType = MediaImage2::MEDIA_IMAGE_TYPE_YUV;
237 if (layout.numPlanes != 3) {
238 ALOGD("Converter: %d planes for YUV layout", layout.numPlanes);
239 mInitCheck = BAD_VALUE;
240 return;
241 }
242 if (layout.planes[0].channel != C2PlaneInfo::CHANNEL_Y
243 || layout.planes[1].channel != C2PlaneInfo::CHANNEL_CB
244 || layout.planes[2].channel != C2PlaneInfo::CHANNEL_CR
245 || layout.planes[0].colSampling != 1
246 || layout.planes[0].rowSampling != 1
247 || layout.planes[1].colSampling != 2
248 || layout.planes[1].rowSampling != 2
249 || layout.planes[2].colSampling != 2
250 || layout.planes[2].rowSampling != 2) {
251 ALOGD("Converter: not YUV420 for YUV layout");
252 mInitCheck = BAD_VALUE;
253 return;
254 }
255 switch (mColorFormat) {
256 case COLOR_FormatYUV420Flexible:
257 { // try to map directly. check if the planes are near one another
258 const uint8_t *minPtr = mView.data()[0];
259 const uint8_t *maxPtr = mView.data()[0];
260 int32_t planeSize = 0;
261 for (uint32_t i = 0; i < layout.numPlanes; ++i) {
262 const C2PlaneInfo &plane = layout.planes[i];
263 ssize_t minOffset = plane.minOffset(mWidth, mHeight);
264 ssize_t maxOffset = plane.maxOffset(mWidth, mHeight);
265 if (minPtr > mView.data()[i] + minOffset) {
266 minPtr = mView.data()[i] + minOffset;
267 }
268 if (maxPtr < mView.data()[i] + maxOffset) {
269 maxPtr = mView.data()[i] + maxOffset;
270 }
271 planeSize += std::abs(plane.rowInc) * align(mHeight, 64)
272 / plane.rowSampling / plane.colSampling * divUp(mAllocatedDepth, 8u);
273 }
274
275 if ((maxPtr - minPtr + 1) <= planeSize) {
276 // FIXME: this is risky as reading/writing data out of bound results in
277 // an undefined behavior, but gralloc does assume a contiguous
278 // mapping
279 for (uint32_t i = 0; i < layout.numPlanes; ++i) {
280 const C2PlaneInfo &plane = layout.planes[i];
281 mediaImage->mPlane[i].mOffset = mView.data()[i] - minPtr;
282 mediaImage->mPlane[i].mColInc = plane.colInc;
283 mediaImage->mPlane[i].mRowInc = plane.rowInc;
284 mediaImage->mPlane[i].mHorizSubsampling = plane.colSampling;
285 mediaImage->mPlane[i].mVertSubsampling = plane.rowSampling;
286 }
287 mWrapped = new ABuffer(const_cast<uint8_t *>(minPtr), maxPtr - minPtr + 1);
288 break;
289 }
290 }
291 [[fallthrough]];
292
293 case COLOR_FormatYUV420Planar:
294 case COLOR_FormatYUV420PackedPlanar:
295 mediaImage->mPlane[mediaImage->Y].mOffset = 0;
296 mediaImage->mPlane[mediaImage->Y].mColInc = 1;
297 mediaImage->mPlane[mediaImage->Y].mRowInc = mStride;
298 mediaImage->mPlane[mediaImage->Y].mHorizSubsampling = 1;
299 mediaImage->mPlane[mediaImage->Y].mVertSubsampling = 1;
300
301 mediaImage->mPlane[mediaImage->U].mOffset = mStride * mVStride;
302 mediaImage->mPlane[mediaImage->U].mColInc = 1;
303 mediaImage->mPlane[mediaImage->U].mRowInc = mStride / 2;
304 mediaImage->mPlane[mediaImage->U].mHorizSubsampling = 2;
305 mediaImage->mPlane[mediaImage->U].mVertSubsampling = 2;
306
307 mediaImage->mPlane[mediaImage->V].mOffset = mStride * mVStride * 5 / 4;
308 mediaImage->mPlane[mediaImage->V].mColInc = 1;
309 mediaImage->mPlane[mediaImage->V].mRowInc = mStride / 2;
310 mediaImage->mPlane[mediaImage->V].mHorizSubsampling = 2;
311 mediaImage->mPlane[mediaImage->V].mVertSubsampling = 2;
312 break;
313
314 case COLOR_FormatYUV420SemiPlanar:
315 case COLOR_FormatYUV420PackedSemiPlanar:
316 mediaImage->mPlane[mediaImage->Y].mOffset = 0;
317 mediaImage->mPlane[mediaImage->Y].mColInc = 1;
318 mediaImage->mPlane[mediaImage->Y].mRowInc = mStride;
319 mediaImage->mPlane[mediaImage->Y].mHorizSubsampling = 1;
320 mediaImage->mPlane[mediaImage->Y].mVertSubsampling = 1;
321
322 mediaImage->mPlane[mediaImage->U].mOffset = mStride * mVStride;
323 mediaImage->mPlane[mediaImage->U].mColInc = 2;
324 mediaImage->mPlane[mediaImage->U].mRowInc = mStride;
325 mediaImage->mPlane[mediaImage->U].mHorizSubsampling = 2;
326 mediaImage->mPlane[mediaImage->U].mVertSubsampling = 2;
327
328 mediaImage->mPlane[mediaImage->V].mOffset = mStride * mVStride + 1;
329 mediaImage->mPlane[mediaImage->V].mColInc = 2;
330 mediaImage->mPlane[mediaImage->V].mRowInc = mStride;
331 mediaImage->mPlane[mediaImage->V].mHorizSubsampling = 2;
332 mediaImage->mPlane[mediaImage->V].mVertSubsampling = 2;
333 break;
334
335 default:
336 ALOGD("Converter: incompactible color format (%d) for YUV layout", mColorFormat);
337 mInitCheck = BAD_VALUE;
338 return;
339 }
340 break;
341 case C2PlanarLayout::TYPE_YUVA:
342 mediaImage->mType = MediaImage2::MEDIA_IMAGE_TYPE_YUVA;
343 // We don't have an SDK YUVA format
344 ALOGD("Converter: incompactible color format (%d) for YUVA layout", mColorFormat);
345 mInitCheck = BAD_VALUE;
346 return;
347 case C2PlanarLayout::TYPE_RGB:
348 mediaImage->mType = MediaImage2::MEDIA_IMAGE_TYPE_RGB;
349 switch (mColorFormat) {
350 // TODO media image
351 case COLOR_FormatRGBFlexible:
352 case COLOR_Format24bitBGR888:
353 case COLOR_Format24bitRGB888:
354 break;
355 default:
356 ALOGD("Converter: incompactible color format (%d) for RGB layout", mColorFormat);
357 mInitCheck = BAD_VALUE;
358 return;
359 }
360 if (layout.numPlanes != 3) {
361 ALOGD("Converter: %d planes for RGB layout", layout.numPlanes);
362 mInitCheck = BAD_VALUE;
363 return;
364 }
365 break;
366 case C2PlanarLayout::TYPE_RGBA:
367 mediaImage->mType = MediaImage2::MEDIA_IMAGE_TYPE_RGBA;
368 switch (mColorFormat) {
369 // TODO media image
370 case COLOR_FormatRGBAFlexible:
371 case COLOR_Format32bitABGR8888:
372 case COLOR_Format32bitARGB8888:
373 case COLOR_Format32bitBGRA8888:
374 break;
375 default:
376 ALOGD("Incompactible color format (%d) for RGBA layout", mColorFormat);
377 mInitCheck = BAD_VALUE;
378 return;
379 }
380 if (layout.numPlanes != 4) {
381 ALOGD("Converter: %d planes for RGBA layout", layout.numPlanes);
382 mInitCheck = BAD_VALUE;
383 return;
384 }
385 break;
386 default:
387 mediaImage->mType = MediaImage2::MEDIA_IMAGE_TYPE_UNKNOWN;
388 ALOGD("Unknown layout");
389 mInitCheck = BAD_VALUE;
390 return;
391 }
392 mediaImage->mNumPlanes = layout.numPlanes;
393 mediaImage->mWidth = mWidth;
394 mediaImage->mHeight = mHeight;
395 mediaImage->mBitDepth = bitDepth;
396 mediaImage->mBitDepthAllocated = mAllocatedDepth;
397
398 uint32_t bufferSize = 0;
399 for (uint32_t i = 0; i < layout.numPlanes; ++i) {
400 const C2PlaneInfo &plane = layout.planes[i];
401 if (plane.allocatedDepth < plane.bitDepth
402 || plane.rightShift != plane.allocatedDepth - plane.bitDepth) {
403 ALOGD("rightShift value of %u unsupported", plane.rightShift);
404 mInitCheck = BAD_VALUE;
405 return;
406 }
407 if (plane.allocatedDepth > 8 && plane.endianness != C2PlaneInfo::NATIVE) {
408 ALOGD("endianness value of %u unsupported", plane.endianness);
409 mInitCheck = BAD_VALUE;
410 return;
411 }
412 if (plane.allocatedDepth != mAllocatedDepth || plane.bitDepth != bitDepth) {
413 ALOGV("different allocatedDepth/bitDepth per plane unsupported");
414 mInitCheck = BAD_VALUE;
415 return;
416 }
417 bufferSize += mStride * mVStride
418 / plane.rowSampling / plane.colSampling;
419 }
420
421 mBackBufferSize = bufferSize;
422 mInitCheck = OK;
423 }
424
425 status_t initCheck() const { return mInitCheck; }
426
427 uint32_t backBufferSize() const { return mBackBufferSize; }
428
429 /**
430 * Wrap C2GraphicView using a MediaImage2. Note that if not wrapped, the content is not mapped
431 * in this function --- the caller should use CopyGraphicView2MediaImage() function to copy the
432 * data into a backing buffer explicitly.
433 *
434 * \return media buffer. This is null if wrapping failed.
435 */
436 sp<ABuffer> wrap() const {
437 if (mBackBuffer == nullptr) {
438 return mWrapped;
439 }
440 return nullptr;
441 }
442
443 bool setBackBuffer(const sp<ABuffer> &backBuffer) {
Wonsik Kim186fdbf2019-01-29 13:30:01 -0800444 if (backBuffer == nullptr) {
445 return false;
446 }
Pawin Vongmasa36653902018-11-15 00:10:25 -0800447 if (backBuffer->capacity() < mBackBufferSize) {
448 return false;
449 }
450 backBuffer->setRange(0, mBackBufferSize);
451 mBackBuffer = backBuffer;
452 return true;
453 }
454
455 /**
456 * Copy C2GraphicView to MediaImage2.
457 */
458 status_t copyToMediaImage() {
459 if (mInitCheck != OK) {
460 return mInitCheck;
461 }
462 return ImageCopy(mBackBuffer->base(), getMediaImage(), mView);
463 }
464
465 const sp<ABuffer> &imageData() const { return mMediaImage; }
466
467private:
468 status_t mInitCheck;
469
470 const C2GraphicView mView;
471 uint32_t mWidth;
472 uint32_t mHeight;
473 int32_t mColorFormat; ///< SDK color format for MediaImage
474 sp<ABuffer> mWrapped; ///< wrapped buffer (if we can map C2Buffer to an ABuffer)
475 uint32_t mAllocatedDepth;
476 uint32_t mBackBufferSize;
477 sp<ABuffer> mMediaImage;
478 std::function<sp<ABuffer>(size_t)> mAlloc;
479
480 sp<ABuffer> mBackBuffer; ///< backing buffer if we have to copy C2Buffer <=> ABuffer
481
482 MediaImage2 *getMediaImage() {
483 return (MediaImage2 *)mMediaImage->base();
484 }
485};
486
487} // namespace
488
489// GraphicBlockBuffer
490
491// static
492sp<GraphicBlockBuffer> GraphicBlockBuffer::Allocate(
493 const sp<AMessage> &format,
494 const std::shared_ptr<C2GraphicBlock> &block,
495 std::function<sp<ABuffer>(size_t)> alloc) {
496 C2GraphicView view(block->map().get());
497 if (view.error() != C2_OK) {
498 ALOGD("C2GraphicBlock::map failed: %d", view.error());
499 return nullptr;
500 }
501
502 int32_t colorFormat = COLOR_FormatYUV420Flexible;
503 (void)format->findInt32("color-format", &colorFormat);
504
505 GraphicView2MediaImageConverter converter(view, colorFormat);
506 if (converter.initCheck() != OK) {
507 ALOGD("Converter init failed: %d", converter.initCheck());
508 return nullptr;
509 }
510 bool wrapped = true;
511 sp<ABuffer> buffer = converter.wrap();
512 if (buffer == nullptr) {
513 buffer = alloc(converter.backBufferSize());
514 if (!converter.setBackBuffer(buffer)) {
515 ALOGD("Converter failed to set back buffer");
516 return nullptr;
517 }
518 wrapped = false;
519 }
520 return new GraphicBlockBuffer(
521 format,
522 buffer,
523 std::move(view),
524 block,
525 converter.imageData(),
526 wrapped);
527}
528
529GraphicBlockBuffer::GraphicBlockBuffer(
530 const sp<AMessage> &format,
531 const sp<ABuffer> &buffer,
532 C2GraphicView &&view,
533 const std::shared_ptr<C2GraphicBlock> &block,
534 const sp<ABuffer> &imageData,
535 bool wrapped)
536 : Codec2Buffer(format, buffer),
537 mView(view),
538 mBlock(block),
Pawin Vongmasa36653902018-11-15 00:10:25 -0800539 mWrapped(wrapped) {
540 setImageData(imageData);
541}
542
543std::shared_ptr<C2Buffer> GraphicBlockBuffer::asC2Buffer() {
544 uint32_t width = mView.width();
545 uint32_t height = mView.height();
546 if (!mWrapped) {
547 (void)ImageCopy(mView, base(), imageData());
548 }
549 return C2Buffer::CreateGraphicBuffer(
550 mBlock->share(C2Rect(width, height), C2Fence()));
551}
552
553// GraphicMetadataBuffer
554GraphicMetadataBuffer::GraphicMetadataBuffer(
555 const sp<AMessage> &format,
556 const std::shared_ptr<C2Allocator> &alloc)
557 : Codec2Buffer(format, new ABuffer(sizeof(VideoNativeMetadata))),
558 mAlloc(alloc) {
559 ((VideoNativeMetadata *)base())->pBuffer = nullptr;
560}
561
562std::shared_ptr<C2Buffer> GraphicMetadataBuffer::asC2Buffer() {
563#ifndef __LP64__
564 VideoNativeMetadata *meta = (VideoNativeMetadata *)base();
565 ANativeWindowBuffer *buffer = (ANativeWindowBuffer *)meta->pBuffer;
566 if (buffer == nullptr) {
567 ALOGD("VideoNativeMetadata contains null buffer");
568 return nullptr;
569 }
570
571 ALOGV("VideoNativeMetadata: %dx%d", buffer->width, buffer->height);
572 C2Handle *handle = WrapNativeCodec2GrallocHandle(
Sungtak Leea4d13be2019-01-23 15:24:46 -0800573 buffer->handle,
Pawin Vongmasa36653902018-11-15 00:10:25 -0800574 buffer->width,
575 buffer->height,
576 buffer->format,
577 buffer->usage,
578 buffer->stride);
579 std::shared_ptr<C2GraphicAllocation> alloc;
580 c2_status_t err = mAlloc->priorGraphicAllocation(handle, &alloc);
581 if (err != C2_OK) {
582 ALOGD("Failed to wrap VideoNativeMetadata into C2GraphicAllocation");
583 return nullptr;
584 }
585 std::shared_ptr<C2GraphicBlock> block = _C2BlockFactory::CreateGraphicBlock(alloc);
586
587 meta->pBuffer = 0;
588 // TODO: fence
589 return C2Buffer::CreateGraphicBuffer(
590 block->share(C2Rect(buffer->width, buffer->height), C2Fence()));
591#else
592 ALOGE("GraphicMetadataBuffer does not work on 64-bit arch");
593 return nullptr;
594#endif
595}
596
597// ConstGraphicBlockBuffer
598
599// static
600sp<ConstGraphicBlockBuffer> ConstGraphicBlockBuffer::Allocate(
601 const sp<AMessage> &format,
602 const std::shared_ptr<C2Buffer> &buffer,
603 std::function<sp<ABuffer>(size_t)> alloc) {
604 if (!buffer
605 || buffer->data().type() != C2BufferData::GRAPHIC
606 || buffer->data().graphicBlocks().size() != 1u) {
607 ALOGD("C2Buffer precond fail");
608 return nullptr;
609 }
610 std::unique_ptr<const C2GraphicView> view(std::make_unique<const C2GraphicView>(
611 buffer->data().graphicBlocks()[0].map().get()));
612 std::unique_ptr<const C2GraphicView> holder;
613
614 int32_t colorFormat = COLOR_FormatYUV420Flexible;
615 (void)format->findInt32("color-format", &colorFormat);
616
617 GraphicView2MediaImageConverter converter(*view, colorFormat);
618 if (converter.initCheck() != OK) {
619 ALOGD("Converter init failed: %d", converter.initCheck());
620 return nullptr;
621 }
622 bool wrapped = true;
623 sp<ABuffer> aBuffer = converter.wrap();
624 if (aBuffer == nullptr) {
625 aBuffer = alloc(converter.backBufferSize());
626 if (!converter.setBackBuffer(aBuffer)) {
627 ALOGD("Converter failed to set back buffer");
628 return nullptr;
629 }
630 wrapped = false;
631 converter.copyToMediaImage();
632 // We don't need the view.
633 holder = std::move(view);
634 }
635 return new ConstGraphicBlockBuffer(
636 format,
637 aBuffer,
638 std::move(view),
639 buffer,
640 converter.imageData(),
641 wrapped);
642}
643
644// static
645sp<ConstGraphicBlockBuffer> ConstGraphicBlockBuffer::AllocateEmpty(
646 const sp<AMessage> &format,
647 std::function<sp<ABuffer>(size_t)> alloc) {
648 int32_t width, height;
649 if (!format->findInt32("width", &width)
650 || !format->findInt32("height", &height)) {
651 ALOGD("format had no width / height");
652 return nullptr;
653 }
654 sp<ABuffer> aBuffer(alloc(width * height * 4));
655 return new ConstGraphicBlockBuffer(
656 format,
657 aBuffer,
658 nullptr,
659 nullptr,
660 nullptr,
661 false);
662}
663
664ConstGraphicBlockBuffer::ConstGraphicBlockBuffer(
665 const sp<AMessage> &format,
666 const sp<ABuffer> &aBuffer,
667 std::unique_ptr<const C2GraphicView> &&view,
668 const std::shared_ptr<C2Buffer> &buffer,
669 const sp<ABuffer> &imageData,
670 bool wrapped)
671 : Codec2Buffer(format, aBuffer),
672 mView(std::move(view)),
673 mBufferRef(buffer),
674 mWrapped(wrapped) {
Wonsik Kimc48ddcf2019-02-11 16:16:57 -0800675 setImageData(imageData);
Pawin Vongmasa36653902018-11-15 00:10:25 -0800676}
677
678std::shared_ptr<C2Buffer> ConstGraphicBlockBuffer::asC2Buffer() {
679 mView.reset();
680 return std::move(mBufferRef);
681}
682
683bool ConstGraphicBlockBuffer::canCopy(const std::shared_ptr<C2Buffer> &buffer) const {
684 if (mWrapped || mBufferRef) {
685 ALOGD("ConstGraphicBlockBuffer::canCopy: %swrapped ; buffer ref %s",
686 mWrapped ? "" : "not ", mBufferRef ? "exists" : "doesn't exist");
687 return false;
688 }
689 if (!buffer) {
690 // Nothing to copy, so we can copy by doing nothing.
691 return true;
692 }
693 if (buffer->data().type() != C2BufferData::GRAPHIC) {
694 ALOGD("ConstGraphicBlockBuffer::canCopy: buffer precondition unsatisfied");
695 return false;
696 }
697 if (buffer->data().graphicBlocks().size() == 0) {
698 return true;
699 } else if (buffer->data().graphicBlocks().size() != 1u) {
700 ALOGD("ConstGraphicBlockBuffer::canCopy: too many blocks");
701 return false;
702 }
703
704 int32_t colorFormat = COLOR_FormatYUV420Flexible;
705 // FIXME: format() is not const, but we cannot change it, so do a const cast here
706 const_cast<ConstGraphicBlockBuffer *>(this)->format()->findInt32("color-format", &colorFormat);
707
708 GraphicView2MediaImageConverter converter(
709 buffer->data().graphicBlocks()[0].map().get(), colorFormat);
710 if (converter.initCheck() != OK) {
711 ALOGD("ConstGraphicBlockBuffer::canCopy: converter init failed: %d", converter.initCheck());
712 return false;
713 }
714 if (converter.backBufferSize() > capacity()) {
715 ALOGD("ConstGraphicBlockBuffer::canCopy: insufficient capacity: req %u has %zu",
716 converter.backBufferSize(), capacity());
717 return false;
718 }
719 return true;
720}
721
722bool ConstGraphicBlockBuffer::copy(const std::shared_ptr<C2Buffer> &buffer) {
723 if (!buffer || buffer->data().graphicBlocks().size() == 0) {
724 setRange(0, 0);
725 return true;
726 }
727 int32_t colorFormat = COLOR_FormatYUV420Flexible;
728 format()->findInt32("color-format", &colorFormat);
729
730 GraphicView2MediaImageConverter converter(
731 buffer->data().graphicBlocks()[0].map().get(), colorFormat);
732 if (converter.initCheck() != OK) {
733 ALOGD("ConstGraphicBlockBuffer::copy: converter init failed: %d", converter.initCheck());
734 return false;
735 }
736 sp<ABuffer> aBuffer = new ABuffer(base(), capacity());
737 if (!converter.setBackBuffer(aBuffer)) {
738 ALOGD("ConstGraphicBlockBuffer::copy: set back buffer failed");
739 return false;
740 }
741 converter.copyToMediaImage();
742 setImageData(converter.imageData());
743 mBufferRef = buffer;
744 return true;
745}
746
747// EncryptedLinearBlockBuffer
748
749EncryptedLinearBlockBuffer::EncryptedLinearBlockBuffer(
750 const sp<AMessage> &format,
751 const std::shared_ptr<C2LinearBlock> &block,
752 const sp<IMemory> &memory,
753 int32_t heapSeqNum)
754 : Codec2Buffer(format, new ABuffer(memory->pointer(), memory->size())),
755 mBlock(block),
756 mMemory(memory),
757 mHeapSeqNum(heapSeqNum) {
758}
759
760std::shared_ptr<C2Buffer> EncryptedLinearBlockBuffer::asC2Buffer() {
761 return C2Buffer::CreateLinearBuffer(mBlock->share(offset(), size(), C2Fence()));
762}
763
764void EncryptedLinearBlockBuffer::fillSourceBuffer(
765 ICrypto::SourceBuffer *source) {
766 source->mSharedMemory = mMemory;
767 source->mHeapSeqNum = mHeapSeqNum;
768}
769
770void EncryptedLinearBlockBuffer::fillSourceBuffer(
771 hardware::cas::native::V1_0::SharedBuffer *source) {
772 ssize_t offset;
773 size_t size;
774
775 mHidlMemory = hardware::fromHeap(mMemory->getMemory(&offset, &size));
776 source->heapBase = *mHidlMemory;
777 source->offset = offset;
778 source->size = size;
779}
780
781bool EncryptedLinearBlockBuffer::copyDecryptedContent(
782 const sp<IMemory> &decrypted, size_t length) {
783 C2WriteView view = mBlock->map().get();
784 if (view.error() != C2_OK) {
785 return false;
786 }
787 if (view.size() < length) {
788 return false;
789 }
790 memcpy(view.data(), decrypted->pointer(), length);
791 return true;
792}
793
794bool EncryptedLinearBlockBuffer::copyDecryptedContentFromMemory(size_t length) {
795 return copyDecryptedContent(mMemory, length);
796}
797
798native_handle_t *EncryptedLinearBlockBuffer::handle() const {
799 return const_cast<native_handle_t *>(mBlock->handle());
800}
801
802} // namespace android