1 /*
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 #include <ui/Fence.h>
29
30 #include <C2AllocatorGralloc.h>
31 #include <C2BlockInternal.h>
32 #include <C2Debug.h>
33
34 #include "Codec2Buffer.h"
35
36 namespace android {
37
38 // Codec2Buffer
39
canCopyLinear(const std::shared_ptr<C2Buffer> & buffer) const40 bool 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
copyLinear(const std::shared_ptr<C2Buffer> & buffer)65 bool 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
setImageData(const sp<ABuffer> & imageData)87 void Codec2Buffer::setImageData(const sp<ABuffer> &imageData) {
88 mImageData = imageData;
89 }
90
91 // LocalLinearBuffer
92
canCopy(const std::shared_ptr<C2Buffer> & buffer) const93 bool LocalLinearBuffer::canCopy(const std::shared_ptr<C2Buffer> &buffer) const {
94 return canCopyLinear(buffer);
95 }
96
copy(const std::shared_ptr<C2Buffer> & buffer)97 bool LocalLinearBuffer::copy(const std::shared_ptr<C2Buffer> &buffer) {
98 return copyLinear(buffer);
99 }
100
101 // DummyContainerBuffer
102
103 static uint8_t sDummyByte[1] = { 0 };
104
DummyContainerBuffer(const sp<AMessage> & format,const std::shared_ptr<C2Buffer> & buffer)105 DummyContainerBuffer::DummyContainerBuffer(
106 const sp<AMessage> &format, const std::shared_ptr<C2Buffer> &buffer)
107 : Codec2Buffer(format, new ABuffer(sDummyByte, 1)),
108 mBufferRef(buffer) {
109 setRange(0, buffer ? 1 : 0);
110 }
111
asC2Buffer()112 std::shared_ptr<C2Buffer> DummyContainerBuffer::asC2Buffer() {
113 return std::move(mBufferRef);
114 }
115
canCopy(const std::shared_ptr<C2Buffer> &) const116 bool DummyContainerBuffer::canCopy(const std::shared_ptr<C2Buffer> &) const {
117 return !mBufferRef;
118 }
119
copy(const std::shared_ptr<C2Buffer> & buffer)120 bool 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
Allocate(const sp<AMessage> & format,const std::shared_ptr<C2LinearBlock> & block)129 sp<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
asC2Buffer()138 std::shared_ptr<C2Buffer> LinearBlockBuffer::asC2Buffer() {
139 return C2Buffer::CreateLinearBuffer(mBlock->share(offset(), size(), C2Fence()));
140 }
141
canCopy(const std::shared_ptr<C2Buffer> & buffer) const142 bool LinearBlockBuffer::canCopy(const std::shared_ptr<C2Buffer> &buffer) const {
143 return canCopyLinear(buffer);
144 }
145
copy(const std::shared_ptr<C2Buffer> & buffer)146 bool LinearBlockBuffer::copy(const std::shared_ptr<C2Buffer> &buffer) {
147 return copyLinear(buffer);
148 }
149
LinearBlockBuffer(const sp<AMessage> & format,C2WriteView && writeView,const std::shared_ptr<C2LinearBlock> & block)150 LinearBlockBuffer::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
Allocate(const sp<AMessage> & format,const std::shared_ptr<C2Buffer> & buffer)162 sp<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
ConstLinearBlockBuffer(const sp<AMessage> & format,C2ReadView && readView,const std::shared_ptr<C2Buffer> & buffer)176 ConstLinearBlockBuffer::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
asC2Buffer()188 std::shared_ptr<C2Buffer> ConstLinearBlockBuffer::asC2Buffer() {
189 return std::move(mBufferRef);
190 }
191
192 // GraphicView2MediaImageConverter
193
194 namespace {
195
196 class GraphicView2MediaImageConverter {
197 public:
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)
205 * \param copy whether the converter is used for copy or not
206 */
GraphicView2MediaImageConverter(const C2GraphicView & view,int32_t colorFormat,bool copy)207 GraphicView2MediaImageConverter(
208 const C2GraphicView &view, int32_t colorFormat, bool copy)
209 : 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 }
229 memset(mediaImage, 0, sizeof(*mediaImage));
230 mAllocatedDepth = layout.planes[0].allocatedDepth;
231 uint32_t bitDepth = layout.planes[0].bitDepth;
232
233 // align width and height to support subsampling cleanly
234 uint32_t stride = align(view.crop().width, 2) * divUp(layout.planes[0].allocatedDepth, 8u);
235 uint32_t vStride = align(view.crop().height, 2);
236
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:
260 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;
265 for (uint32_t i = 0; i < layout.numPlanes; ++i) {
266 const C2PlaneInfo &plane = layout.planes[i];
267 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);
278 }
279
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 }
296 }
297 [[fallthrough]];
298
299 case COLOR_FormatYUV420Planar:
300 case COLOR_FormatYUV420PackedPlanar:
301 mediaImage->mPlane[mediaImage->Y].mOffset = 0;
302 mediaImage->mPlane[mediaImage->Y].mColInc = 1;
303 mediaImage->mPlane[mediaImage->Y].mRowInc = stride;
304 mediaImage->mPlane[mediaImage->Y].mHorizSubsampling = 1;
305 mediaImage->mPlane[mediaImage->Y].mVertSubsampling = 1;
306
307 mediaImage->mPlane[mediaImage->U].mOffset = stride * vStride;
308 mediaImage->mPlane[mediaImage->U].mColInc = 1;
309 mediaImage->mPlane[mediaImage->U].mRowInc = stride / 2;
310 mediaImage->mPlane[mediaImage->U].mHorizSubsampling = 2;
311 mediaImage->mPlane[mediaImage->U].mVertSubsampling = 2;
312
313 mediaImage->mPlane[mediaImage->V].mOffset = stride * vStride * 5 / 4;
314 mediaImage->mPlane[mediaImage->V].mColInc = 1;
315 mediaImage->mPlane[mediaImage->V].mRowInc = stride / 2;
316 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;
324 mediaImage->mPlane[mediaImage->Y].mRowInc = stride;
325 mediaImage->mPlane[mediaImage->Y].mHorizSubsampling = 1;
326 mediaImage->mPlane[mediaImage->Y].mVertSubsampling = 1;
327
328 mediaImage->mPlane[mediaImage->U].mOffset = stride * vStride;
329 mediaImage->mPlane[mediaImage->U].mColInc = 2;
330 mediaImage->mPlane[mediaImage->U].mRowInc = stride;
331 mediaImage->mPlane[mediaImage->U].mHorizSubsampling = 2;
332 mediaImage->mPlane[mediaImage->U].mVertSubsampling = 2;
333
334 mediaImage->mPlane[mediaImage->V].mOffset = stride * vStride + 1;
335 mediaImage->mPlane[mediaImage->V].mColInc = 2;
336 mediaImage->mPlane[mediaImage->V].mRowInc = stride;
337 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;
399 mediaImage->mWidth = view.crop().width;
400 mediaImage->mHeight = view.crop().height;
401 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 }
423 bufferSize += stride * vStride
424 / plane.rowSampling / plane.colSampling;
425 }
426
427 mBackBufferSize = bufferSize;
428 mInitCheck = OK;
429 }
430
initCheck() const431 status_t initCheck() const { return mInitCheck; }
432
backBufferSize() const433 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 */
wrap() const442 sp<ABuffer> wrap() const {
443 if (mBackBuffer == nullptr) {
444 return mWrapped;
445 }
446 return nullptr;
447 }
448
setBackBuffer(const sp<ABuffer> & backBuffer)449 bool setBackBuffer(const sp<ABuffer> &backBuffer) {
450 if (backBuffer == nullptr) {
451 return false;
452 }
453 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 */
copyToMediaImage()464 status_t copyToMediaImage() {
465 if (mInitCheck != OK) {
466 return mInitCheck;
467 }
468 return ImageCopy(mBackBuffer->base(), getMediaImage(), mView);
469 }
470
imageData() const471 const sp<ABuffer> &imageData() const { return mMediaImage; }
472
473 private:
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
getMediaImage()488 MediaImage2 *getMediaImage() {
489 return (MediaImage2 *)mMediaImage->base();
490 }
491 };
492
493 } // namespace
494
495 // GraphicBlockBuffer
496
497 // static
Allocate(const sp<AMessage> & format,const std::shared_ptr<C2GraphicBlock> & block,std::function<sp<ABuffer> (size_t)> alloc)498 sp<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
511 GraphicView2MediaImageConverter converter(view, colorFormat, false /* copy */);
512 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
GraphicBlockBuffer(const sp<AMessage> & format,const sp<ABuffer> & buffer,C2GraphicView && view,const std::shared_ptr<C2GraphicBlock> & block,const sp<ABuffer> & imageData,bool wrapped)535 GraphicBlockBuffer::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),
545 mWrapped(wrapped) {
546 setImageData(imageData);
547 }
548
asC2Buffer()549 std::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
GraphicMetadataBuffer(const sp<AMessage> & format,const std::shared_ptr<C2Allocator> & alloc)560 GraphicMetadataBuffer::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
asC2Buffer()568 std::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 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: 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 }
600 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
Allocate(const sp<AMessage> & format,const std::shared_ptr<C2Buffer> & buffer,std::function<sp<ABuffer> (size_t)> alloc)611 sp<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
628 GraphicView2MediaImageConverter converter(*view, colorFormat, false /* copy */);
629 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
AllocateEmpty(const sp<AMessage> & format,std::function<sp<ABuffer> (size_t)> alloc)656 sp<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 }
665 // NOTE: we currently only support YUV420 formats for byte-buffer mode.
666 sp<ABuffer> aBuffer(alloc(align(width, 16) * align(height, 16) * 3 / 2));
667 return new ConstGraphicBlockBuffer(
668 format,
669 aBuffer,
670 nullptr,
671 nullptr,
672 nullptr,
673 false);
674 }
675
ConstGraphicBlockBuffer(const sp<AMessage> & format,const sp<ABuffer> & aBuffer,std::unique_ptr<const C2GraphicView> && view,const std::shared_ptr<C2Buffer> & buffer,const sp<ABuffer> & imageData,bool wrapped)676 ConstGraphicBlockBuffer::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) {
687 setImageData(imageData);
688 }
689
asC2Buffer()690 std::shared_ptr<C2Buffer> ConstGraphicBlockBuffer::asC2Buffer() {
691 mView.reset();
692 return std::move(mBufferRef);
693 }
694
canCopy(const std::shared_ptr<C2Buffer> & buffer) const695 bool 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(
721 buffer->data().graphicBlocks()[0].map().get(), colorFormat, true /* copy */);
722 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
copy(const std::shared_ptr<C2Buffer> & buffer)734 bool 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(
743 buffer->data().graphicBlocks()[0].map().get(), colorFormat, true /* copy */);
744 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 }
753 setRange(0, aBuffer->size()); // align size info
754 converter.copyToMediaImage();
755 setImageData(converter.imageData());
756 mBufferRef = buffer;
757 return true;
758 }
759
760 // EncryptedLinearBlockBuffer
761
EncryptedLinearBlockBuffer(const sp<AMessage> & format,const std::shared_ptr<C2LinearBlock> & block,const sp<IMemory> & memory,int32_t heapSeqNum)762 EncryptedLinearBlockBuffer::EncryptedLinearBlockBuffer(
763 const sp<AMessage> &format,
764 const std::shared_ptr<C2LinearBlock> &block,
765 const sp<IMemory> &memory,
766 int32_t heapSeqNum)
767 : Codec2Buffer(format, new ABuffer(memory->pointer(), memory->size())),
768 mBlock(block),
769 mMemory(memory),
770 mHeapSeqNum(heapSeqNum) {
771 }
772
asC2Buffer()773 std::shared_ptr<C2Buffer> EncryptedLinearBlockBuffer::asC2Buffer() {
774 return C2Buffer::CreateLinearBuffer(mBlock->share(offset(), size(), C2Fence()));
775 }
776
fillSourceBuffer(ICrypto::SourceBuffer * source)777 void EncryptedLinearBlockBuffer::fillSourceBuffer(
778 ICrypto::SourceBuffer *source) {
779 source->mSharedMemory = mMemory;
780 source->mHeapSeqNum = mHeapSeqNum;
781 }
782
fillSourceBuffer(hardware::cas::native::V1_0::SharedBuffer * source)783 void EncryptedLinearBlockBuffer::fillSourceBuffer(
784 hardware::cas::native::V1_0::SharedBuffer *source) {
785 ssize_t offset;
786 size_t size;
787
788 mHidlMemory = hardware::fromHeap(mMemory->getMemory(&offset, &size));
789 source->heapBase = *mHidlMemory;
790 source->offset = offset;
791 source->size = size;
792 }
793
copyDecryptedContent(const sp<IMemory> & decrypted,size_t length)794 bool EncryptedLinearBlockBuffer::copyDecryptedContent(
795 const sp<IMemory> &decrypted, size_t length) {
796 C2WriteView view = mBlock->map().get();
797 if (view.error() != C2_OK) {
798 return false;
799 }
800 if (view.size() < length) {
801 return false;
802 }
803 memcpy(view.data(), decrypted->pointer(), length);
804 return true;
805 }
806
copyDecryptedContentFromMemory(size_t length)807 bool EncryptedLinearBlockBuffer::copyDecryptedContentFromMemory(size_t length) {
808 return copyDecryptedContent(mMemory, length);
809 }
810
handle() const811 native_handle_t *EncryptedLinearBlockBuffer::handle() const {
812 return const_cast<native_handle_t *>(mBlock->handle());
813 }
814
815 } // namespace android
816