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