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