blob: bf6062efd54f2e16855c9ac23c022109357bdf42 [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) {
87 meta()->setBuffer("image-data", imageData);
88 format()->setBuffer("image-data", imageData);
89 MediaImage2 *img = (MediaImage2*)imageData->data();
90 if (img->mNumPlanes > 0 && img->mType != img->MEDIA_IMAGE_TYPE_UNKNOWN) {
91 int32_t stride = img->mPlane[0].mRowInc;
92 format()->setInt32(KEY_STRIDE, stride);
93 if (img->mNumPlanes > 1 && stride > 0) {
94 int32_t vstride = (img->mPlane[1].mOffset - img->mPlane[0].mOffset) / stride;
95 format()->setInt32(KEY_SLICE_HEIGHT, vstride);
96 }
97 }
98}
99
100// LocalLinearBuffer
101
102bool LocalLinearBuffer::canCopy(const std::shared_ptr<C2Buffer> &buffer) const {
103 return canCopyLinear(buffer);
104}
105
106bool LocalLinearBuffer::copy(const std::shared_ptr<C2Buffer> &buffer) {
107 return copyLinear(buffer);
108}
109
110// DummyContainerBuffer
111
112DummyContainerBuffer::DummyContainerBuffer(
113 const sp<AMessage> &format, const std::shared_ptr<C2Buffer> &buffer)
114 : Codec2Buffer(format, new ABuffer(nullptr, 1)),
115 mBufferRef(buffer) {
116 setRange(0, buffer ? 1 : 0);
117}
118
119std::shared_ptr<C2Buffer> DummyContainerBuffer::asC2Buffer() {
120 return std::move(mBufferRef);
121}
122
123bool DummyContainerBuffer::canCopy(const std::shared_ptr<C2Buffer> &) const {
124 return !mBufferRef;
125}
126
127bool DummyContainerBuffer::copy(const std::shared_ptr<C2Buffer> &buffer) {
128 mBufferRef = buffer;
129 setRange(0, mBufferRef ? 1 : 0);
130 return true;
131}
132
133// LinearBlockBuffer
134
135// static
136sp<LinearBlockBuffer> LinearBlockBuffer::Allocate(
137 const sp<AMessage> &format, const std::shared_ptr<C2LinearBlock> &block) {
138 C2WriteView writeView(block->map().get());
139 if (writeView.error() != C2_OK) {
140 return nullptr;
141 }
142 return new LinearBlockBuffer(format, std::move(writeView), block);
143}
144
145std::shared_ptr<C2Buffer> LinearBlockBuffer::asC2Buffer() {
146 return C2Buffer::CreateLinearBuffer(mBlock->share(offset(), size(), C2Fence()));
147}
148
149bool LinearBlockBuffer::canCopy(const std::shared_ptr<C2Buffer> &buffer) const {
150 return canCopyLinear(buffer);
151}
152
153bool LinearBlockBuffer::copy(const std::shared_ptr<C2Buffer> &buffer) {
154 return copyLinear(buffer);
155}
156
157LinearBlockBuffer::LinearBlockBuffer(
158 const sp<AMessage> &format,
159 C2WriteView&& writeView,
160 const std::shared_ptr<C2LinearBlock> &block)
161 : Codec2Buffer(format, new ABuffer(writeView.data(), writeView.size())),
162 mWriteView(writeView),
163 mBlock(block) {
164}
165
166// ConstLinearBlockBuffer
167
168// static
169sp<ConstLinearBlockBuffer> ConstLinearBlockBuffer::Allocate(
170 const sp<AMessage> &format, const std::shared_ptr<C2Buffer> &buffer) {
171 if (!buffer
172 || buffer->data().type() != C2BufferData::LINEAR
173 || buffer->data().linearBlocks().size() != 1u) {
174 return nullptr;
175 }
176 C2ReadView readView(buffer->data().linearBlocks()[0].map().get());
177 if (readView.error() != C2_OK) {
178 return nullptr;
179 }
180 return new ConstLinearBlockBuffer(format, std::move(readView), buffer);
181}
182
183ConstLinearBlockBuffer::ConstLinearBlockBuffer(
184 const sp<AMessage> &format,
185 C2ReadView&& readView,
186 const std::shared_ptr<C2Buffer> &buffer)
187 : Codec2Buffer(format, new ABuffer(
188 // NOTE: ABuffer only takes non-const pointer but this data is
189 // supposed to be read-only.
190 const_cast<uint8_t *>(readView.data()), readView.capacity())),
191 mReadView(readView),
192 mBufferRef(buffer) {
193}
194
195std::shared_ptr<C2Buffer> ConstLinearBlockBuffer::asC2Buffer() {
196 return std::move(mBufferRef);
197}
198
199// GraphicView2MediaImageConverter
200
201namespace {
202
203class GraphicView2MediaImageConverter {
204public:
205 /**
206 * Creates a C2GraphicView <=> MediaImage converter
207 *
208 * \param view C2GraphicView object
209 * \param colorFormat desired SDK color format for the MediaImage (if this is a flexible format,
210 * an attempt is made to simply represent the graphic view as a flexible SDK format
211 * without a memcpy)
212 */
213 GraphicView2MediaImageConverter(
214 const C2GraphicView &view, int32_t colorFormat)
215 : mInitCheck(NO_INIT),
216 mView(view),
217 mWidth(view.width()),
218 mHeight(view.height()),
219 mColorFormat(colorFormat),
220 mAllocatedDepth(0),
221 mBackBufferSize(0),
222 mMediaImage(new ABuffer(sizeof(MediaImage2))) {
223 if (view.error() != C2_OK) {
224 ALOGD("Converter: view.error() = %d", view.error());
225 mInitCheck = BAD_VALUE;
226 return;
227 }
228 MediaImage2 *mediaImage = (MediaImage2 *)mMediaImage->base();
229 const C2PlanarLayout &layout = view.layout();
230 if (layout.numPlanes == 0) {
231 ALOGD("Converter: 0 planes");
232 mInitCheck = BAD_VALUE;
233 return;
234 }
235 mAllocatedDepth = layout.planes[0].allocatedDepth;
236 uint32_t bitDepth = layout.planes[0].bitDepth;
237
238 // align width and height to support subsampling cleanly
239 uint32_t mStride = align(mWidth, 2) * divUp(layout.planes[0].allocatedDepth, 8u);
240 uint32_t mVStride = align(mHeight, 2);
241
242 switch (layout.type) {
243 case C2PlanarLayout::TYPE_YUV:
244 mediaImage->mType = MediaImage2::MEDIA_IMAGE_TYPE_YUV;
245 if (layout.numPlanes != 3) {
246 ALOGD("Converter: %d planes for YUV layout", layout.numPlanes);
247 mInitCheck = BAD_VALUE;
248 return;
249 }
250 if (layout.planes[0].channel != C2PlaneInfo::CHANNEL_Y
251 || layout.planes[1].channel != C2PlaneInfo::CHANNEL_CB
252 || layout.planes[2].channel != C2PlaneInfo::CHANNEL_CR
253 || layout.planes[0].colSampling != 1
254 || layout.planes[0].rowSampling != 1
255 || layout.planes[1].colSampling != 2
256 || layout.planes[1].rowSampling != 2
257 || layout.planes[2].colSampling != 2
258 || layout.planes[2].rowSampling != 2) {
259 ALOGD("Converter: not YUV420 for YUV layout");
260 mInitCheck = BAD_VALUE;
261 return;
262 }
263 switch (mColorFormat) {
264 case COLOR_FormatYUV420Flexible:
265 { // try to map directly. check if the planes are near one another
266 const uint8_t *minPtr = mView.data()[0];
267 const uint8_t *maxPtr = mView.data()[0];
268 int32_t planeSize = 0;
269 for (uint32_t i = 0; i < layout.numPlanes; ++i) {
270 const C2PlaneInfo &plane = layout.planes[i];
271 ssize_t minOffset = plane.minOffset(mWidth, mHeight);
272 ssize_t maxOffset = plane.maxOffset(mWidth, mHeight);
273 if (minPtr > mView.data()[i] + minOffset) {
274 minPtr = mView.data()[i] + minOffset;
275 }
276 if (maxPtr < mView.data()[i] + maxOffset) {
277 maxPtr = mView.data()[i] + maxOffset;
278 }
279 planeSize += std::abs(plane.rowInc) * align(mHeight, 64)
280 / plane.rowSampling / plane.colSampling * divUp(mAllocatedDepth, 8u);
281 }
282
283 if ((maxPtr - minPtr + 1) <= planeSize) {
284 // FIXME: this is risky as reading/writing data out of bound results in
285 // an undefined behavior, but gralloc does assume a contiguous
286 // mapping
287 for (uint32_t i = 0; i < layout.numPlanes; ++i) {
288 const C2PlaneInfo &plane = layout.planes[i];
289 mediaImage->mPlane[i].mOffset = mView.data()[i] - minPtr;
290 mediaImage->mPlane[i].mColInc = plane.colInc;
291 mediaImage->mPlane[i].mRowInc = plane.rowInc;
292 mediaImage->mPlane[i].mHorizSubsampling = plane.colSampling;
293 mediaImage->mPlane[i].mVertSubsampling = plane.rowSampling;
294 }
295 mWrapped = new ABuffer(const_cast<uint8_t *>(minPtr), maxPtr - minPtr + 1);
296 break;
297 }
298 }
299 [[fallthrough]];
300
301 case COLOR_FormatYUV420Planar:
302 case COLOR_FormatYUV420PackedPlanar:
303 mediaImage->mPlane[mediaImage->Y].mOffset = 0;
304 mediaImage->mPlane[mediaImage->Y].mColInc = 1;
305 mediaImage->mPlane[mediaImage->Y].mRowInc = mStride;
306 mediaImage->mPlane[mediaImage->Y].mHorizSubsampling = 1;
307 mediaImage->mPlane[mediaImage->Y].mVertSubsampling = 1;
308
309 mediaImage->mPlane[mediaImage->U].mOffset = mStride * mVStride;
310 mediaImage->mPlane[mediaImage->U].mColInc = 1;
311 mediaImage->mPlane[mediaImage->U].mRowInc = mStride / 2;
312 mediaImage->mPlane[mediaImage->U].mHorizSubsampling = 2;
313 mediaImage->mPlane[mediaImage->U].mVertSubsampling = 2;
314
315 mediaImage->mPlane[mediaImage->V].mOffset = mStride * mVStride * 5 / 4;
316 mediaImage->mPlane[mediaImage->V].mColInc = 1;
317 mediaImage->mPlane[mediaImage->V].mRowInc = mStride / 2;
318 mediaImage->mPlane[mediaImage->V].mHorizSubsampling = 2;
319 mediaImage->mPlane[mediaImage->V].mVertSubsampling = 2;
320 break;
321
322 case COLOR_FormatYUV420SemiPlanar:
323 case COLOR_FormatYUV420PackedSemiPlanar:
324 mediaImage->mPlane[mediaImage->Y].mOffset = 0;
325 mediaImage->mPlane[mediaImage->Y].mColInc = 1;
326 mediaImage->mPlane[mediaImage->Y].mRowInc = mStride;
327 mediaImage->mPlane[mediaImage->Y].mHorizSubsampling = 1;
328 mediaImage->mPlane[mediaImage->Y].mVertSubsampling = 1;
329
330 mediaImage->mPlane[mediaImage->U].mOffset = mStride * mVStride;
331 mediaImage->mPlane[mediaImage->U].mColInc = 2;
332 mediaImage->mPlane[mediaImage->U].mRowInc = mStride;
333 mediaImage->mPlane[mediaImage->U].mHorizSubsampling = 2;
334 mediaImage->mPlane[mediaImage->U].mVertSubsampling = 2;
335
336 mediaImage->mPlane[mediaImage->V].mOffset = mStride * mVStride + 1;
337 mediaImage->mPlane[mediaImage->V].mColInc = 2;
338 mediaImage->mPlane[mediaImage->V].mRowInc = mStride;
339 mediaImage->mPlane[mediaImage->V].mHorizSubsampling = 2;
340 mediaImage->mPlane[mediaImage->V].mVertSubsampling = 2;
341 break;
342
343 default:
344 ALOGD("Converter: incompactible color format (%d) for YUV layout", mColorFormat);
345 mInitCheck = BAD_VALUE;
346 return;
347 }
348 break;
349 case C2PlanarLayout::TYPE_YUVA:
350 mediaImage->mType = MediaImage2::MEDIA_IMAGE_TYPE_YUVA;
351 // We don't have an SDK YUVA format
352 ALOGD("Converter: incompactible color format (%d) for YUVA layout", mColorFormat);
353 mInitCheck = BAD_VALUE;
354 return;
355 case C2PlanarLayout::TYPE_RGB:
356 mediaImage->mType = MediaImage2::MEDIA_IMAGE_TYPE_RGB;
357 switch (mColorFormat) {
358 // TODO media image
359 case COLOR_FormatRGBFlexible:
360 case COLOR_Format24bitBGR888:
361 case COLOR_Format24bitRGB888:
362 break;
363 default:
364 ALOGD("Converter: incompactible color format (%d) for RGB layout", mColorFormat);
365 mInitCheck = BAD_VALUE;
366 return;
367 }
368 if (layout.numPlanes != 3) {
369 ALOGD("Converter: %d planes for RGB layout", layout.numPlanes);
370 mInitCheck = BAD_VALUE;
371 return;
372 }
373 break;
374 case C2PlanarLayout::TYPE_RGBA:
375 mediaImage->mType = MediaImage2::MEDIA_IMAGE_TYPE_RGBA;
376 switch (mColorFormat) {
377 // TODO media image
378 case COLOR_FormatRGBAFlexible:
379 case COLOR_Format32bitABGR8888:
380 case COLOR_Format32bitARGB8888:
381 case COLOR_Format32bitBGRA8888:
382 break;
383 default:
384 ALOGD("Incompactible color format (%d) for RGBA layout", mColorFormat);
385 mInitCheck = BAD_VALUE;
386 return;
387 }
388 if (layout.numPlanes != 4) {
389 ALOGD("Converter: %d planes for RGBA layout", layout.numPlanes);
390 mInitCheck = BAD_VALUE;
391 return;
392 }
393 break;
394 default:
395 mediaImage->mType = MediaImage2::MEDIA_IMAGE_TYPE_UNKNOWN;
396 ALOGD("Unknown layout");
397 mInitCheck = BAD_VALUE;
398 return;
399 }
400 mediaImage->mNumPlanes = layout.numPlanes;
401 mediaImage->mWidth = mWidth;
402 mediaImage->mHeight = mHeight;
403 mediaImage->mBitDepth = bitDepth;
404 mediaImage->mBitDepthAllocated = mAllocatedDepth;
405
406 uint32_t bufferSize = 0;
407 for (uint32_t i = 0; i < layout.numPlanes; ++i) {
408 const C2PlaneInfo &plane = layout.planes[i];
409 if (plane.allocatedDepth < plane.bitDepth
410 || plane.rightShift != plane.allocatedDepth - plane.bitDepth) {
411 ALOGD("rightShift value of %u unsupported", plane.rightShift);
412 mInitCheck = BAD_VALUE;
413 return;
414 }
415 if (plane.allocatedDepth > 8 && plane.endianness != C2PlaneInfo::NATIVE) {
416 ALOGD("endianness value of %u unsupported", plane.endianness);
417 mInitCheck = BAD_VALUE;
418 return;
419 }
420 if (plane.allocatedDepth != mAllocatedDepth || plane.bitDepth != bitDepth) {
421 ALOGV("different allocatedDepth/bitDepth per plane unsupported");
422 mInitCheck = BAD_VALUE;
423 return;
424 }
425 bufferSize += mStride * mVStride
426 / plane.rowSampling / plane.colSampling;
427 }
428
429 mBackBufferSize = bufferSize;
430 mInitCheck = OK;
431 }
432
433 status_t initCheck() const { return mInitCheck; }
434
435 uint32_t backBufferSize() const { return mBackBufferSize; }
436
437 /**
438 * Wrap C2GraphicView using a MediaImage2. Note that if not wrapped, the content is not mapped
439 * in this function --- the caller should use CopyGraphicView2MediaImage() function to copy the
440 * data into a backing buffer explicitly.
441 *
442 * \return media buffer. This is null if wrapping failed.
443 */
444 sp<ABuffer> wrap() const {
445 if (mBackBuffer == nullptr) {
446 return mWrapped;
447 }
448 return nullptr;
449 }
450
451 bool setBackBuffer(const sp<ABuffer> &backBuffer) {
452 if (backBuffer->capacity() < mBackBufferSize) {
453 return false;
454 }
455 backBuffer->setRange(0, mBackBufferSize);
456 mBackBuffer = backBuffer;
457 return true;
458 }
459
460 /**
461 * Copy C2GraphicView to MediaImage2.
462 */
463 status_t copyToMediaImage() {
464 if (mInitCheck != OK) {
465 return mInitCheck;
466 }
467 return ImageCopy(mBackBuffer->base(), getMediaImage(), mView);
468 }
469
470 const sp<ABuffer> &imageData() const { return mMediaImage; }
471
472private:
473 status_t mInitCheck;
474
475 const C2GraphicView mView;
476 uint32_t mWidth;
477 uint32_t mHeight;
478 int32_t mColorFormat; ///< SDK color format for MediaImage
479 sp<ABuffer> mWrapped; ///< wrapped buffer (if we can map C2Buffer to an ABuffer)
480 uint32_t mAllocatedDepth;
481 uint32_t mBackBufferSize;
482 sp<ABuffer> mMediaImage;
483 std::function<sp<ABuffer>(size_t)> mAlloc;
484
485 sp<ABuffer> mBackBuffer; ///< backing buffer if we have to copy C2Buffer <=> ABuffer
486
487 MediaImage2 *getMediaImage() {
488 return (MediaImage2 *)mMediaImage->base();
489 }
490};
491
492} // namespace
493
494// GraphicBlockBuffer
495
496// static
497sp<GraphicBlockBuffer> GraphicBlockBuffer::Allocate(
498 const sp<AMessage> &format,
499 const std::shared_ptr<C2GraphicBlock> &block,
500 std::function<sp<ABuffer>(size_t)> alloc) {
501 C2GraphicView view(block->map().get());
502 if (view.error() != C2_OK) {
503 ALOGD("C2GraphicBlock::map failed: %d", view.error());
504 return nullptr;
505 }
506
507 int32_t colorFormat = COLOR_FormatYUV420Flexible;
508 (void)format->findInt32("color-format", &colorFormat);
509
510 GraphicView2MediaImageConverter converter(view, colorFormat);
511 if (converter.initCheck() != OK) {
512 ALOGD("Converter init failed: %d", converter.initCheck());
513 return nullptr;
514 }
515 bool wrapped = true;
516 sp<ABuffer> buffer = converter.wrap();
517 if (buffer == nullptr) {
518 buffer = alloc(converter.backBufferSize());
519 if (!converter.setBackBuffer(buffer)) {
520 ALOGD("Converter failed to set back buffer");
521 return nullptr;
522 }
523 wrapped = false;
524 }
525 return new GraphicBlockBuffer(
526 format,
527 buffer,
528 std::move(view),
529 block,
530 converter.imageData(),
531 wrapped);
532}
533
534GraphicBlockBuffer::GraphicBlockBuffer(
535 const sp<AMessage> &format,
536 const sp<ABuffer> &buffer,
537 C2GraphicView &&view,
538 const std::shared_ptr<C2GraphicBlock> &block,
539 const sp<ABuffer> &imageData,
540 bool wrapped)
541 : Codec2Buffer(format, buffer),
542 mView(view),
543 mBlock(block),
544 mImageData(imageData),
545 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(
579 native_handle_clone(buffer->handle),
580 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;
594 // TODO: fence
595 return C2Buffer::CreateGraphicBuffer(
596 block->share(C2Rect(buffer->width, buffer->height), C2Fence()));
597#else
598 ALOGE("GraphicMetadataBuffer does not work on 64-bit arch");
599 return nullptr;
600#endif
601}
602
603// ConstGraphicBlockBuffer
604
605// static
606sp<ConstGraphicBlockBuffer> ConstGraphicBlockBuffer::Allocate(
607 const sp<AMessage> &format,
608 const std::shared_ptr<C2Buffer> &buffer,
609 std::function<sp<ABuffer>(size_t)> alloc) {
610 if (!buffer
611 || buffer->data().type() != C2BufferData::GRAPHIC
612 || buffer->data().graphicBlocks().size() != 1u) {
613 ALOGD("C2Buffer precond fail");
614 return nullptr;
615 }
616 std::unique_ptr<const C2GraphicView> view(std::make_unique<const C2GraphicView>(
617 buffer->data().graphicBlocks()[0].map().get()));
618 std::unique_ptr<const C2GraphicView> holder;
619
620 int32_t colorFormat = COLOR_FormatYUV420Flexible;
621 (void)format->findInt32("color-format", &colorFormat);
622
623 GraphicView2MediaImageConverter converter(*view, colorFormat);
624 if (converter.initCheck() != OK) {
625 ALOGD("Converter init failed: %d", converter.initCheck());
626 return nullptr;
627 }
628 bool wrapped = true;
629 sp<ABuffer> aBuffer = converter.wrap();
630 if (aBuffer == nullptr) {
631 aBuffer = alloc(converter.backBufferSize());
632 if (!converter.setBackBuffer(aBuffer)) {
633 ALOGD("Converter failed to set back buffer");
634 return nullptr;
635 }
636 wrapped = false;
637 converter.copyToMediaImage();
638 // We don't need the view.
639 holder = std::move(view);
640 }
641 return new ConstGraphicBlockBuffer(
642 format,
643 aBuffer,
644 std::move(view),
645 buffer,
646 converter.imageData(),
647 wrapped);
648}
649
650// static
651sp<ConstGraphicBlockBuffer> ConstGraphicBlockBuffer::AllocateEmpty(
652 const sp<AMessage> &format,
653 std::function<sp<ABuffer>(size_t)> alloc) {
654 int32_t width, height;
655 if (!format->findInt32("width", &width)
656 || !format->findInt32("height", &height)) {
657 ALOGD("format had no width / height");
658 return nullptr;
659 }
660 sp<ABuffer> aBuffer(alloc(width * height * 4));
661 return new ConstGraphicBlockBuffer(
662 format,
663 aBuffer,
664 nullptr,
665 nullptr,
666 nullptr,
667 false);
668}
669
670ConstGraphicBlockBuffer::ConstGraphicBlockBuffer(
671 const sp<AMessage> &format,
672 const sp<ABuffer> &aBuffer,
673 std::unique_ptr<const C2GraphicView> &&view,
674 const std::shared_ptr<C2Buffer> &buffer,
675 const sp<ABuffer> &imageData,
676 bool wrapped)
677 : Codec2Buffer(format, aBuffer),
678 mView(std::move(view)),
679 mBufferRef(buffer),
680 mWrapped(wrapped) {
681 if (imageData != nullptr) {
682 setImageData(imageData);
683 }
684}
685
686std::shared_ptr<C2Buffer> ConstGraphicBlockBuffer::asC2Buffer() {
687 mView.reset();
688 return std::move(mBufferRef);
689}
690
691bool ConstGraphicBlockBuffer::canCopy(const std::shared_ptr<C2Buffer> &buffer) const {
692 if (mWrapped || mBufferRef) {
693 ALOGD("ConstGraphicBlockBuffer::canCopy: %swrapped ; buffer ref %s",
694 mWrapped ? "" : "not ", mBufferRef ? "exists" : "doesn't exist");
695 return false;
696 }
697 if (!buffer) {
698 // Nothing to copy, so we can copy by doing nothing.
699 return true;
700 }
701 if (buffer->data().type() != C2BufferData::GRAPHIC) {
702 ALOGD("ConstGraphicBlockBuffer::canCopy: buffer precondition unsatisfied");
703 return false;
704 }
705 if (buffer->data().graphicBlocks().size() == 0) {
706 return true;
707 } else if (buffer->data().graphicBlocks().size() != 1u) {
708 ALOGD("ConstGraphicBlockBuffer::canCopy: too many blocks");
709 return false;
710 }
711
712 int32_t colorFormat = COLOR_FormatYUV420Flexible;
713 // FIXME: format() is not const, but we cannot change it, so do a const cast here
714 const_cast<ConstGraphicBlockBuffer *>(this)->format()->findInt32("color-format", &colorFormat);
715
716 GraphicView2MediaImageConverter converter(
717 buffer->data().graphicBlocks()[0].map().get(), colorFormat);
718 if (converter.initCheck() != OK) {
719 ALOGD("ConstGraphicBlockBuffer::canCopy: converter init failed: %d", converter.initCheck());
720 return false;
721 }
722 if (converter.backBufferSize() > capacity()) {
723 ALOGD("ConstGraphicBlockBuffer::canCopy: insufficient capacity: req %u has %zu",
724 converter.backBufferSize(), capacity());
725 return false;
726 }
727 return true;
728}
729
730bool ConstGraphicBlockBuffer::copy(const std::shared_ptr<C2Buffer> &buffer) {
731 if (!buffer || buffer->data().graphicBlocks().size() == 0) {
732 setRange(0, 0);
733 return true;
734 }
735 int32_t colorFormat = COLOR_FormatYUV420Flexible;
736 format()->findInt32("color-format", &colorFormat);
737
738 GraphicView2MediaImageConverter converter(
739 buffer->data().graphicBlocks()[0].map().get(), colorFormat);
740 if (converter.initCheck() != OK) {
741 ALOGD("ConstGraphicBlockBuffer::copy: converter init failed: %d", converter.initCheck());
742 return false;
743 }
744 sp<ABuffer> aBuffer = new ABuffer(base(), capacity());
745 if (!converter.setBackBuffer(aBuffer)) {
746 ALOGD("ConstGraphicBlockBuffer::copy: set back buffer failed");
747 return false;
748 }
749 converter.copyToMediaImage();
750 setImageData(converter.imageData());
751 mBufferRef = buffer;
752 return true;
753}
754
755// EncryptedLinearBlockBuffer
756
757EncryptedLinearBlockBuffer::EncryptedLinearBlockBuffer(
758 const sp<AMessage> &format,
759 const std::shared_ptr<C2LinearBlock> &block,
760 const sp<IMemory> &memory,
761 int32_t heapSeqNum)
762 : Codec2Buffer(format, new ABuffer(memory->pointer(), memory->size())),
763 mBlock(block),
764 mMemory(memory),
765 mHeapSeqNum(heapSeqNum) {
766}
767
768std::shared_ptr<C2Buffer> EncryptedLinearBlockBuffer::asC2Buffer() {
769 return C2Buffer::CreateLinearBuffer(mBlock->share(offset(), size(), C2Fence()));
770}
771
772void EncryptedLinearBlockBuffer::fillSourceBuffer(
773 ICrypto::SourceBuffer *source) {
774 source->mSharedMemory = mMemory;
775 source->mHeapSeqNum = mHeapSeqNum;
776}
777
778void EncryptedLinearBlockBuffer::fillSourceBuffer(
779 hardware::cas::native::V1_0::SharedBuffer *source) {
780 ssize_t offset;
781 size_t size;
782
783 mHidlMemory = hardware::fromHeap(mMemory->getMemory(&offset, &size));
784 source->heapBase = *mHidlMemory;
785 source->offset = offset;
786 source->size = size;
787}
788
789bool EncryptedLinearBlockBuffer::copyDecryptedContent(
790 const sp<IMemory> &decrypted, size_t length) {
791 C2WriteView view = mBlock->map().get();
792 if (view.error() != C2_OK) {
793 return false;
794 }
795 if (view.size() < length) {
796 return false;
797 }
798 memcpy(view.data(), decrypted->pointer(), length);
799 return true;
800}
801
802bool EncryptedLinearBlockBuffer::copyDecryptedContentFromMemory(size_t length) {
803 return copyDecryptedContent(mMemory, length);
804}
805
806native_handle_t *EncryptedLinearBlockBuffer::handle() const {
807 return const_cast<native_handle_t *>(mBlock->handle());
808}
809
810} // namespace android