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