• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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