Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 134a59ed authored by Treehugger Robot's avatar Treehugger Robot Committed by Automerger Merge Worker
Browse files

Merge "codec2: Move GraphicView2MediaImageConverter to Codec2BufferUtils" into...

Merge "codec2: Move GraphicView2MediaImageConverter to Codec2BufferUtils" into main am: 2b9429b9 am: c69c900c

Original change: https://android-review.googlesource.com/c/platform/frameworks/av/+/3218719



Change-Id: I3ca7c999b90c985c4c74041e3a5d93c765686d93
Signed-off-by: default avatarAutomerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
parents aa12b679 c69c900c
Loading
Loading
Loading
Loading
+1 −476
Original line number Diff line number Diff line
@@ -43,6 +43,7 @@
#include <C2Debug.h>

#include "Codec2Buffer.h"
#include "Codec2BufferUtils.h"

namespace android {

@@ -215,482 +216,6 @@ void ConstLinearBlockBuffer::clearC2BufferRefs() {
    mBufferRef.reset();
}

// GraphicView2MediaImageConverter

namespace {

class GraphicView2MediaImageConverter {
public:
    /**
     * Creates a C2GraphicView <=> MediaImage converter
     *
     * \param view C2GraphicView object
     * \param format buffer format
     * \param copy whether the converter is used for copy or not
     */
    GraphicView2MediaImageConverter(
            const C2GraphicView &view, const sp<AMessage> &format, bool copy)
        : mInitCheck(NO_INIT),
          mView(view),
          mWidth(view.width()),
          mHeight(view.height()),
          mAllocatedDepth(0),
          mBackBufferSize(0),
          mMediaImage(new ABuffer(sizeof(MediaImage2))) {
        ATRACE_CALL();
        if (!format->findInt32(KEY_COLOR_FORMAT, &mClientColorFormat)) {
            mClientColorFormat = COLOR_FormatYUV420Flexible;
        }
        if (!format->findInt32("android._color-format", &mComponentColorFormat)) {
            mComponentColorFormat = COLOR_FormatYUV420Flexible;
        }
        if (view.error() != C2_OK) {
            ALOGD("Converter: view.error() = %d", view.error());
            mInitCheck = BAD_VALUE;
            return;
        }
        MediaImage2 *mediaImage = (MediaImage2 *)mMediaImage->base();
        const C2PlanarLayout &layout = view.layout();
        if (layout.numPlanes == 0) {
            ALOGD("Converter: 0 planes");
            mInitCheck = BAD_VALUE;
            return;
        }
        memset(mediaImage, 0, sizeof(*mediaImage));
        mAllocatedDepth = layout.planes[0].allocatedDepth;
        uint32_t bitDepth = layout.planes[0].bitDepth;

        // align width and height to support subsampling cleanly
        uint32_t stride = align(view.crop().width, 2) * divUp(layout.planes[0].allocatedDepth, 8u);
        uint32_t vStride = align(view.crop().height, 2);

        bool tryWrapping = !copy;

        switch (layout.type) {
            case C2PlanarLayout::TYPE_YUV: {
                mediaImage->mType = MediaImage2::MEDIA_IMAGE_TYPE_YUV;
                if (layout.numPlanes != 3) {
                    ALOGD("Converter: %d planes for YUV layout", layout.numPlanes);
                    mInitCheck = BAD_VALUE;
                    return;
                }
                std::optional<int> clientBitDepth = {};
                switch (mClientColorFormat) {
                    case COLOR_FormatYUVP010:
                        clientBitDepth = 10;
                        break;
                    case COLOR_FormatYUV411PackedPlanar:
                    case COLOR_FormatYUV411Planar:
                    case COLOR_FormatYUV420Flexible:
                    case COLOR_FormatYUV420PackedPlanar:
                    case COLOR_FormatYUV420PackedSemiPlanar:
                    case COLOR_FormatYUV420Planar:
                    case COLOR_FormatYUV420SemiPlanar:
                    case COLOR_FormatYUV422Flexible:
                    case COLOR_FormatYUV422PackedPlanar:
                    case COLOR_FormatYUV422PackedSemiPlanar:
                    case COLOR_FormatYUV422Planar:
                    case COLOR_FormatYUV422SemiPlanar:
                    case COLOR_FormatYUV444Flexible:
                    case COLOR_FormatYUV444Interleaved:
                        clientBitDepth = 8;
                        break;
                    default:
                        // no-op; used with optional
                        break;

                }
                // conversion fails if client bit-depth and the component bit-depth differs
                if ((clientBitDepth) && (bitDepth != clientBitDepth.value())) {
                    ALOGD("Bit depth of client: %d and component: %d differs",
                        *clientBitDepth, bitDepth);
                    mInitCheck = BAD_VALUE;
                    return;
                }
                C2PlaneInfo yPlane = layout.planes[C2PlanarLayout::PLANE_Y];
                C2PlaneInfo uPlane = layout.planes[C2PlanarLayout::PLANE_U];
                C2PlaneInfo vPlane = layout.planes[C2PlanarLayout::PLANE_V];
                if (yPlane.channel != C2PlaneInfo::CHANNEL_Y
                        || uPlane.channel != C2PlaneInfo::CHANNEL_CB
                        || vPlane.channel != C2PlaneInfo::CHANNEL_CR) {
                    ALOGD("Converter: not YUV layout");
                    mInitCheck = BAD_VALUE;
                    return;
                }
                bool yuv420888 = yPlane.rowSampling == 1 && yPlane.colSampling == 1
                        && uPlane.rowSampling == 2 && uPlane.colSampling == 2
                        && vPlane.rowSampling == 2 && vPlane.colSampling == 2;
                if (yuv420888) {
                    for (uint32_t i = 0; i < 3; ++i) {
                        const C2PlaneInfo &plane = layout.planes[i];
                        if (plane.allocatedDepth != 8 || plane.bitDepth != 8) {
                            yuv420888 = false;
                            break;
                        }
                    }
                    yuv420888 = yuv420888 && yPlane.colInc == 1 && uPlane.rowInc == vPlane.rowInc;
                }
                int32_t copyFormat = mClientColorFormat;
                if (yuv420888 && mClientColorFormat == COLOR_FormatYUV420Flexible) {
                    if (uPlane.colInc == 2 && vPlane.colInc == 2
                            && yPlane.rowInc == uPlane.rowInc) {
                        copyFormat = COLOR_FormatYUV420PackedSemiPlanar;
                    } else if (uPlane.colInc == 1 && vPlane.colInc == 1
                            && yPlane.rowInc == uPlane.rowInc * 2) {
                        copyFormat = COLOR_FormatYUV420PackedPlanar;
                    }
                }
                ALOGV("client_fmt=0x%x y:{colInc=%d rowInc=%d} u:{colInc=%d rowInc=%d} "
                        "v:{colInc=%d rowInc=%d}",
                        mClientColorFormat,
                        yPlane.colInc, yPlane.rowInc,
                        uPlane.colInc, uPlane.rowInc,
                        vPlane.colInc, vPlane.rowInc);
                switch (copyFormat) {
                    case COLOR_FormatYUV420Flexible:
                    case COLOR_FormatYUV420Planar:
                    case COLOR_FormatYUV420PackedPlanar:
                        mediaImage->mPlane[mediaImage->Y].mOffset = 0;
                        mediaImage->mPlane[mediaImage->Y].mColInc = 1;
                        mediaImage->mPlane[mediaImage->Y].mRowInc = stride;
                        mediaImage->mPlane[mediaImage->Y].mHorizSubsampling = 1;
                        mediaImage->mPlane[mediaImage->Y].mVertSubsampling = 1;

                        mediaImage->mPlane[mediaImage->U].mOffset = stride * vStride;
                        mediaImage->mPlane[mediaImage->U].mColInc = 1;
                        mediaImage->mPlane[mediaImage->U].mRowInc = stride / 2;
                        mediaImage->mPlane[mediaImage->U].mHorizSubsampling = 2;
                        mediaImage->mPlane[mediaImage->U].mVertSubsampling = 2;

                        mediaImage->mPlane[mediaImage->V].mOffset = stride * vStride * 5 / 4;
                        mediaImage->mPlane[mediaImage->V].mColInc = 1;
                        mediaImage->mPlane[mediaImage->V].mRowInc = stride / 2;
                        mediaImage->mPlane[mediaImage->V].mHorizSubsampling = 2;
                        mediaImage->mPlane[mediaImage->V].mVertSubsampling = 2;

                        if (tryWrapping && mClientColorFormat != COLOR_FormatYUV420Flexible) {
                            tryWrapping = yuv420888 && uPlane.colInc == 1 && vPlane.colInc == 1
                                    && yPlane.rowInc == uPlane.rowInc * 2
                                    && view.data()[0] < view.data()[1]
                                    && view.data()[1] < view.data()[2];
                        }
                        break;

                    case COLOR_FormatYUV420SemiPlanar:
                    case COLOR_FormatYUV420PackedSemiPlanar:
                        mediaImage->mPlane[mediaImage->Y].mOffset = 0;
                        mediaImage->mPlane[mediaImage->Y].mColInc = 1;
                        mediaImage->mPlane[mediaImage->Y].mRowInc = stride;
                        mediaImage->mPlane[mediaImage->Y].mHorizSubsampling = 1;
                        mediaImage->mPlane[mediaImage->Y].mVertSubsampling = 1;

                        mediaImage->mPlane[mediaImage->U].mOffset = stride * vStride;
                        mediaImage->mPlane[mediaImage->U].mColInc = 2;
                        mediaImage->mPlane[mediaImage->U].mRowInc = stride;
                        mediaImage->mPlane[mediaImage->U].mHorizSubsampling = 2;
                        mediaImage->mPlane[mediaImage->U].mVertSubsampling = 2;

                        mediaImage->mPlane[mediaImage->V].mOffset = stride * vStride + 1;
                        mediaImage->mPlane[mediaImage->V].mColInc = 2;
                        mediaImage->mPlane[mediaImage->V].mRowInc = stride;
                        mediaImage->mPlane[mediaImage->V].mHorizSubsampling = 2;
                        mediaImage->mPlane[mediaImage->V].mVertSubsampling = 2;

                        if (tryWrapping && mClientColorFormat != COLOR_FormatYUV420Flexible) {
                            tryWrapping = yuv420888 && uPlane.colInc == 2 && vPlane.colInc == 2
                                    && yPlane.rowInc == uPlane.rowInc
                                    && view.data()[0] < view.data()[1]
                                    && view.data()[1] < view.data()[2];
                        }
                        break;

                    case COLOR_FormatYUVP010:
                        // stride is in bytes
                        mediaImage->mPlane[mediaImage->Y].mOffset = 0;
                        mediaImage->mPlane[mediaImage->Y].mColInc = 2;
                        mediaImage->mPlane[mediaImage->Y].mRowInc = stride;
                        mediaImage->mPlane[mediaImage->Y].mHorizSubsampling = 1;
                        mediaImage->mPlane[mediaImage->Y].mVertSubsampling = 1;

                        mediaImage->mPlane[mediaImage->U].mOffset = stride * vStride;
                        mediaImage->mPlane[mediaImage->U].mColInc = 4;
                        mediaImage->mPlane[mediaImage->U].mRowInc = stride;
                        mediaImage->mPlane[mediaImage->U].mHorizSubsampling = 2;
                        mediaImage->mPlane[mediaImage->U].mVertSubsampling = 2;

                        mediaImage->mPlane[mediaImage->V].mOffset = stride * vStride + 2;
                        mediaImage->mPlane[mediaImage->V].mColInc = 4;
                        mediaImage->mPlane[mediaImage->V].mRowInc = stride;
                        mediaImage->mPlane[mediaImage->V].mHorizSubsampling = 2;
                        mediaImage->mPlane[mediaImage->V].mVertSubsampling = 2;
                        if (tryWrapping) {
                            tryWrapping = yPlane.allocatedDepth == 16
                                    && uPlane.allocatedDepth == 16
                                    && vPlane.allocatedDepth == 16
                                    && yPlane.bitDepth == 10
                                    && uPlane.bitDepth == 10
                                    && vPlane.bitDepth == 10
                                    && yPlane.rightShift == 6
                                    && uPlane.rightShift == 6
                                    && vPlane.rightShift == 6
                                    && yPlane.rowSampling == 1 && yPlane.colSampling == 1
                                    && uPlane.rowSampling == 2 && uPlane.colSampling == 2
                                    && vPlane.rowSampling == 2 && vPlane.colSampling == 2
                                    && yPlane.colInc == 2
                                    && uPlane.colInc == 4
                                    && vPlane.colInc == 4
                                    && yPlane.rowInc == uPlane.rowInc
                                    && yPlane.rowInc == vPlane.rowInc;
                        }
                        break;

                    default: {
                        // default to fully planar format --- this will be overridden if wrapping
                        // TODO: keep interleaved format
                        int32_t colInc = divUp(mAllocatedDepth, 8u);
                        int32_t rowInc = stride * colInc / yPlane.colSampling;
                        mediaImage->mPlane[mediaImage->Y].mOffset = 0;
                        mediaImage->mPlane[mediaImage->Y].mColInc = colInc;
                        mediaImage->mPlane[mediaImage->Y].mRowInc = rowInc;
                        mediaImage->mPlane[mediaImage->Y].mHorizSubsampling = yPlane.colSampling;
                        mediaImage->mPlane[mediaImage->Y].mVertSubsampling = yPlane.rowSampling;
                        int32_t offset = rowInc * vStride / yPlane.rowSampling;

                        rowInc = stride * colInc / uPlane.colSampling;
                        mediaImage->mPlane[mediaImage->U].mOffset = offset;
                        mediaImage->mPlane[mediaImage->U].mColInc = colInc;
                        mediaImage->mPlane[mediaImage->U].mRowInc = rowInc;
                        mediaImage->mPlane[mediaImage->U].mHorizSubsampling = uPlane.colSampling;
                        mediaImage->mPlane[mediaImage->U].mVertSubsampling = uPlane.rowSampling;
                        offset += rowInc * vStride / uPlane.rowSampling;

                        rowInc = stride * colInc / vPlane.colSampling;
                        mediaImage->mPlane[mediaImage->V].mOffset = offset;
                        mediaImage->mPlane[mediaImage->V].mColInc = colInc;
                        mediaImage->mPlane[mediaImage->V].mRowInc = rowInc;
                        mediaImage->mPlane[mediaImage->V].mHorizSubsampling = vPlane.colSampling;
                        mediaImage->mPlane[mediaImage->V].mVertSubsampling = vPlane.rowSampling;
                        break;
                    }
                }
                break;
            }

            case C2PlanarLayout::TYPE_YUVA:
                ALOGD("Converter: unrecognized color format "
                        "(client %d component %d) for YUVA layout",
                        mClientColorFormat, mComponentColorFormat);
                mInitCheck = NO_INIT;
                return;
            case C2PlanarLayout::TYPE_RGB:
                mediaImage->mType = MediaImage2::MEDIA_IMAGE_TYPE_RGB;
                // TODO: support MediaImage layout
                switch (mClientColorFormat) {
                    case COLOR_FormatSurface:
                    case COLOR_FormatRGBFlexible:
                    case COLOR_Format24bitBGR888:
                    case COLOR_Format24bitRGB888:
                        ALOGD("Converter: accept color format "
                                "(client %d component %d) for RGB layout",
                                mClientColorFormat, mComponentColorFormat);
                        break;
                    default:
                        ALOGD("Converter: unrecognized color format "
                                "(client %d component %d) for RGB layout",
                                mClientColorFormat, mComponentColorFormat);
                        mInitCheck = BAD_VALUE;
                        return;
                }
                if (layout.numPlanes != 3) {
                    ALOGD("Converter: %d planes for RGB layout", layout.numPlanes);
                    mInitCheck = BAD_VALUE;
                    return;
                }
                break;
            case C2PlanarLayout::TYPE_RGBA:
                mediaImage->mType = MediaImage2::MEDIA_IMAGE_TYPE_RGBA;
                // TODO: support MediaImage layout
                switch (mClientColorFormat) {
                    case COLOR_FormatSurface:
                    case COLOR_FormatRGBAFlexible:
                    case COLOR_Format32bitABGR8888:
                    case COLOR_Format32bitARGB8888:
                    case COLOR_Format32bitBGRA8888:
                        ALOGD("Converter: accept color format "
                                "(client %d component %d) for RGBA layout",
                                mClientColorFormat, mComponentColorFormat);
                        break;
                    default:
                        ALOGD("Converter: unrecognized color format "
                                "(client %d component %d) for RGBA layout",
                                mClientColorFormat, mComponentColorFormat);
                        mInitCheck = BAD_VALUE;
                        return;
                }
                if (layout.numPlanes != 4) {
                    ALOGD("Converter: %d planes for RGBA layout", layout.numPlanes);
                    mInitCheck = BAD_VALUE;
                    return;
                }
                break;
            default:
                mediaImage->mType = MediaImage2::MEDIA_IMAGE_TYPE_UNKNOWN;
                if (layout.numPlanes == 1) {
                    const C2PlaneInfo &plane = layout.planes[0];
                    if (plane.colInc < 0 || plane.rowInc < 0) {
                        // Copy-only if we have negative colInc/rowInc
                        tryWrapping = false;
                    }
                    mediaImage->mPlane[0].mOffset = 0;
                    mediaImage->mPlane[0].mColInc = std::abs(plane.colInc);
                    mediaImage->mPlane[0].mRowInc = std::abs(plane.rowInc);
                    mediaImage->mPlane[0].mHorizSubsampling = plane.colSampling;
                    mediaImage->mPlane[0].mVertSubsampling = plane.rowSampling;
                } else {
                    ALOGD("Converter: unrecognized layout: color format (client %d component %d)",
                            mClientColorFormat, mComponentColorFormat);
                    mInitCheck = NO_INIT;
                    return;
                }
                break;
        }
        if (tryWrapping) {
            // try to map directly. check if the planes are near one another
            const uint8_t *minPtr = mView.data()[0];
            const uint8_t *maxPtr = mView.data()[0];
            int32_t planeSize = 0;
            for (uint32_t i = 0; i < layout.numPlanes; ++i) {
                const C2PlaneInfo &plane = layout.planes[i];
                int64_t planeStride = std::abs(plane.rowInc / plane.colInc);
                ssize_t minOffset = plane.minOffset(
                        mWidth / plane.colSampling, mHeight / plane.rowSampling);
                ssize_t maxOffset = plane.maxOffset(
                        mWidth / plane.colSampling, mHeight / plane.rowSampling);
                if (minPtr > mView.data()[i] + minOffset) {
                    minPtr = mView.data()[i] + minOffset;
                }
                if (maxPtr < mView.data()[i] + maxOffset) {
                    maxPtr = mView.data()[i] + maxOffset;
                }
                planeSize += planeStride * divUp(mAllocatedDepth, 8u)
                        * align(mHeight, 64) / plane.rowSampling;
            }

            if (minPtr == mView.data()[0] && (maxPtr - minPtr) <= planeSize) {
                // FIXME: this is risky as reading/writing data out of bound results
                //        in an undefined behavior, but gralloc does assume a
                //        contiguous mapping
                for (uint32_t i = 0; i < layout.numPlanes; ++i) {
                    const C2PlaneInfo &plane = layout.planes[i];
                    mediaImage->mPlane[i].mOffset = mView.data()[i] - minPtr;
                    mediaImage->mPlane[i].mColInc = plane.colInc;
                    mediaImage->mPlane[i].mRowInc = plane.rowInc;
                    mediaImage->mPlane[i].mHorizSubsampling = plane.colSampling;
                    mediaImage->mPlane[i].mVertSubsampling = plane.rowSampling;
                }
                mWrapped = new ABuffer(const_cast<uint8_t *>(minPtr), maxPtr - minPtr);
                ALOGV("Converter: wrapped (capacity=%zu)", mWrapped->capacity());
            }
        }
        mediaImage->mNumPlanes = layout.numPlanes;
        mediaImage->mWidth = view.crop().width;
        mediaImage->mHeight = view.crop().height;
        mediaImage->mBitDepth = bitDepth;
        mediaImage->mBitDepthAllocated = mAllocatedDepth;

        uint32_t bufferSize = 0;
        for (uint32_t i = 0; i < layout.numPlanes; ++i) {
            const C2PlaneInfo &plane = layout.planes[i];
            if (plane.allocatedDepth < plane.bitDepth
                    || plane.rightShift != plane.allocatedDepth - plane.bitDepth) {
                ALOGD("rightShift value of %u unsupported", plane.rightShift);
                mInitCheck = BAD_VALUE;
                return;
            }
            if (plane.allocatedDepth > 8 && plane.endianness != C2PlaneInfo::NATIVE) {
                ALOGD("endianness value of %u unsupported", plane.endianness);
                mInitCheck = BAD_VALUE;
                return;
            }
            if (plane.allocatedDepth != mAllocatedDepth || plane.bitDepth != bitDepth) {
                ALOGD("different allocatedDepth/bitDepth per plane unsupported");
                mInitCheck = BAD_VALUE;
                return;
            }
            // stride is in bytes
            bufferSize += stride * vStride / plane.rowSampling / plane.colSampling;
        }

        mBackBufferSize = bufferSize;
        mInitCheck = OK;
    }

    status_t initCheck() const { return mInitCheck; }

    uint32_t backBufferSize() const { return mBackBufferSize; }

    /**
     * Wrap C2GraphicView using a MediaImage2. Note that if not wrapped, the content is not mapped
     * in this function --- the caller should use CopyGraphicView2MediaImage() function to copy the
     * data into a backing buffer explicitly.
     *
     * \return media buffer. This is null if wrapping failed.
     */
    sp<ABuffer> wrap() const {
        if (mBackBuffer == nullptr) {
            return mWrapped;
        }
        return nullptr;
    }

    bool setBackBuffer(const sp<ABuffer> &backBuffer) {
        if (backBuffer == nullptr) {
            return false;
        }
        if (backBuffer->capacity() < mBackBufferSize) {
            return false;
        }
        backBuffer->setRange(0, mBackBufferSize);
        mBackBuffer = backBuffer;
        return true;
    }

    /**
     * Copy C2GraphicView to MediaImage2.
     */
    status_t copyToMediaImage() {
        ATRACE_CALL();
        if (mInitCheck != OK) {
            return mInitCheck;
        }
        return ImageCopy(mBackBuffer->base(), getMediaImage(), mView);
    }

    const sp<ABuffer> &imageData() const { return mMediaImage; }

private:
    status_t mInitCheck;

    const C2GraphicView mView;
    uint32_t mWidth;
    uint32_t mHeight;
    int32_t mClientColorFormat;  ///< SDK color format for MediaImage
    int32_t mComponentColorFormat;  ///< SDK color format from component
    sp<ABuffer> mWrapped;  ///< wrapped buffer (if we can map C2Buffer to an ABuffer)
    uint32_t mAllocatedDepth;
    uint32_t mBackBufferSize;
    sp<ABuffer> mMediaImage;
    std::function<sp<ABuffer>(size_t)> mAlloc;

    sp<ABuffer> mBackBuffer;    ///< backing buffer if we have to copy C2Buffer <=> ABuffer

    MediaImage2 *getMediaImage() {
        return (MediaImage2 *)mMediaImage->base();
    }
};

}  // namespace

// GraphicBlockBuffer

// static
+0 −22
Original line number Diff line number Diff line
@@ -44,28 +44,6 @@ struct SharedBuffer;
}  // namespace drm
}  // namespace hardware

/**
 * Copies a graphic view into a media image.
 *
 * \param imgBase base of MediaImage
 * \param img MediaImage data
 * \param view graphic view
 *
 * \return OK on success
 */
status_t ImageCopy(uint8_t *imgBase, const MediaImage2 *img, const C2GraphicView &view);

/**
 * Copies a media image into a graphic view.
 *
 * \param view graphic view
 * \param imgBase base of MediaImage
 * \param img MediaImage data
 *
 * \return OK on success
 */
status_t ImageCopy(C2GraphicView &view, const uint8_t *imgBase, const MediaImage2 *img);

class Codec2Buffer : public MediaCodecBuffer {
public:
    using MediaCodecBuffer::MediaCodecBuffer;
+437 −0

File changed.

Preview size limit exceeded, changes collapsed.

+56 −0

File changed.

Preview size limit exceeded, changes collapsed.