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

Commit 8a08b0c5 authored by James Dong's avatar James Dong Committed by Android (Google) Code Review
Browse files

Merge "Remove PV AVC decoder"

parents 9c79becb d2a9852c
Loading
Loading
Loading
Loading
+0 −55
Original line number Diff line number Diff line
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)

LOCAL_SRC_FILES := \
        src/avcdec_api.cpp \
        src/avc_bitstream.cpp \
        src/header.cpp \
        src/itrans.cpp \
        src/pred_inter.cpp \
        src/pred_intra.cpp \
        src/residual.cpp \
        src/slice.cpp \
        src/vlc.cpp

LOCAL_MODULE := libstagefright_avcdec

LOCAL_C_INCLUDES := \
        $(LOCAL_PATH)/src \
        $(LOCAL_PATH)/include \
        $(LOCAL_PATH)/../common/include \
        $(TOP)/frameworks/base/media/libstagefright/include \
        frameworks/base/include/media/stagefright/openmax \

LOCAL_CFLAGS := -DOSCL_IMPORT_REF= -DOSCL_UNUSED_ARG= -DOSCL_EXPORT_REF=

include $(BUILD_STATIC_LIBRARY)

################################################################################

include $(CLEAR_VARS)

LOCAL_SRC_FILES := \
        SoftAVC.cpp

LOCAL_C_INCLUDES := \
        $(LOCAL_PATH)/src \
        $(LOCAL_PATH)/include \
        $(LOCAL_PATH)/../common/include \
        frameworks/base/media/libstagefright/include \
        frameworks/base/include/media/stagefright/openmax \

LOCAL_CFLAGS := -DOSCL_IMPORT_REF=

LOCAL_STATIC_LIBRARIES := \
        libstagefright_avcdec

LOCAL_SHARED_LIBRARIES := \
        libstagefright_avc_common \
        libstagefright libstagefright_omx libstagefright_foundation libutils

LOCAL_MODULE := libstagefright_soft_avcdec
LOCAL_MODULE_TAGS := optional

include $(BUILD_SHARED_LIBRARY)
+0 −720
Original line number Diff line number Diff line
/*
 * Copyright (C) 2011 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

//#define LOG_NDEBUG 0
#define LOG_TAG "SoftAVC"
#include <utils/Log.h>

#include "SoftAVC.h"

#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MediaErrors.h>
#include <media/IOMX.h>

#include "avcdec_api.h"
#include "avcdec_int.h"

namespace android {

static const char kStartCode[4] = { 0x00, 0x00, 0x00, 0x01 };

static const CodecProfileLevel kProfileLevels[] = {
    { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel1 },
    { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel1b },
    { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel11 },
    { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel12 },
};

template<class T>
static void InitOMXParams(T *params) {
    params->nSize = sizeof(T);
    params->nVersion.s.nVersionMajor = 1;
    params->nVersion.s.nVersionMinor = 0;
    params->nVersion.s.nRevision = 0;
    params->nVersion.s.nStep = 0;
}

static int32_t Malloc(void *userData, int32_t size, int32_t attrs) {
    return reinterpret_cast<int32_t>(malloc(size));
}

static void Free(void *userData, int32_t ptr) {
    free(reinterpret_cast<void *>(ptr));
}

SoftAVC::SoftAVC(
        const char *name,
        const OMX_CALLBACKTYPE *callbacks,
        OMX_PTR appData,
        OMX_COMPONENTTYPE **component)
    : SimpleSoftOMXComponent(name, callbacks, appData, component),
      mHandle(new tagAVCHandle),
      mInputBufferCount(0),
      mWidth(160),
      mHeight(120),
      mCropLeft(0),
      mCropTop(0),
      mCropRight(mWidth - 1),
      mCropBottom(mHeight - 1),
      mSPSSeen(false),
      mPPSSeen(false),
      mCurrentTimeUs(-1),
      mEOSStatus(INPUT_DATA_AVAILABLE),
      mOutputPortSettingsChange(NONE) {
    initPorts();
    CHECK_EQ(initDecoder(), (status_t)OK);
}

SoftAVC::~SoftAVC() {
    PVAVCCleanUpDecoder(mHandle);

    delete mHandle;
    mHandle = NULL;
}

void SoftAVC::initPorts() {
    OMX_PARAM_PORTDEFINITIONTYPE def;
    InitOMXParams(&def);

    def.nPortIndex = 0;
    def.eDir = OMX_DirInput;
    def.nBufferCountMin = kNumInputBuffers;
    def.nBufferCountActual = def.nBufferCountMin;
    def.nBufferSize = 8192;
    def.bEnabled = OMX_TRUE;
    def.bPopulated = OMX_FALSE;
    def.eDomain = OMX_PortDomainVideo;
    def.bBuffersContiguous = OMX_FALSE;
    def.nBufferAlignment = 1;

    def.format.video.cMIMEType = const_cast<char *>(MEDIA_MIMETYPE_VIDEO_AVC);
    def.format.video.pNativeRender = NULL;
    def.format.video.nFrameWidth = mWidth;
    def.format.video.nFrameHeight = mHeight;
    def.format.video.nStride = def.format.video.nFrameWidth;
    def.format.video.nSliceHeight = def.format.video.nFrameHeight;
    def.format.video.nBitrate = 0;
    def.format.video.xFramerate = 0;
    def.format.video.bFlagErrorConcealment = OMX_FALSE;
    def.format.video.eCompressionFormat = OMX_VIDEO_CodingAVC;
    def.format.video.eColorFormat = OMX_COLOR_FormatUnused;
    def.format.video.pNativeWindow = NULL;

    addPort(def);

    def.nPortIndex = 1;
    def.eDir = OMX_DirOutput;
    def.nBufferCountMin = kNumOutputBuffers;
    def.nBufferCountActual = def.nBufferCountMin;
    def.bEnabled = OMX_TRUE;
    def.bPopulated = OMX_FALSE;
    def.eDomain = OMX_PortDomainVideo;
    def.bBuffersContiguous = OMX_FALSE;
    def.nBufferAlignment = 2;

    def.format.video.cMIMEType = const_cast<char *>(MEDIA_MIMETYPE_VIDEO_RAW);
    def.format.video.pNativeRender = NULL;
    def.format.video.nFrameWidth = mWidth;
    def.format.video.nFrameHeight = mHeight;
    def.format.video.nStride = def.format.video.nFrameWidth;
    def.format.video.nSliceHeight = def.format.video.nFrameHeight;
    def.format.video.nBitrate = 0;
    def.format.video.xFramerate = 0;
    def.format.video.bFlagErrorConcealment = OMX_FALSE;
    def.format.video.eCompressionFormat = OMX_VIDEO_CodingUnused;
    def.format.video.eColorFormat = OMX_COLOR_FormatYUV420Planar;
    def.format.video.pNativeWindow = NULL;

    def.nBufferSize =
        (def.format.video.nFrameWidth * def.format.video.nFrameHeight * 3) / 2;

    addPort(def);
}

status_t SoftAVC::initDecoder() {
    memset(mHandle, 0, sizeof(tagAVCHandle));
    mHandle->AVCObject = NULL;
    mHandle->userData = this;
    mHandle->CBAVC_DPBAlloc = ActivateSPSWrapper;
    mHandle->CBAVC_FrameBind = BindFrameWrapper;
    mHandle->CBAVC_FrameUnbind = UnbindFrame;
    mHandle->CBAVC_Malloc = Malloc;
    mHandle->CBAVC_Free = Free;

    return OK;
}

OMX_ERRORTYPE SoftAVC::internalGetParameter(
        OMX_INDEXTYPE index, OMX_PTR params) {
    switch (index) {
        case OMX_IndexParamVideoPortFormat:
        {
            OMX_VIDEO_PARAM_PORTFORMATTYPE *formatParams =
                (OMX_VIDEO_PARAM_PORTFORMATTYPE *)params;

            if (formatParams->nPortIndex > 1) {
                return OMX_ErrorUndefined;
            }

            if (formatParams->nIndex != 0) {
                return OMX_ErrorNoMore;
            }

            if (formatParams->nPortIndex == 0) {
                formatParams->eCompressionFormat = OMX_VIDEO_CodingAVC;
                formatParams->eColorFormat = OMX_COLOR_FormatUnused;
                formatParams->xFramerate = 0;
            } else {
                CHECK_EQ(formatParams->nPortIndex, 1u);

                formatParams->eCompressionFormat = OMX_VIDEO_CodingUnused;
                formatParams->eColorFormat = OMX_COLOR_FormatYUV420Planar;
                formatParams->xFramerate = 0;
            }

            return OMX_ErrorNone;
        }

        case OMX_IndexParamVideoProfileLevelQuerySupported:
        {
            OMX_VIDEO_PARAM_PROFILELEVELTYPE *profileLevel =
                    (OMX_VIDEO_PARAM_PROFILELEVELTYPE *) params;

            if (profileLevel->nPortIndex != 0) {  // Input port only
                LOGE("Invalid port index: %ld", profileLevel->nPortIndex);
                return OMX_ErrorUnsupportedIndex;
            }

            size_t index = profileLevel->nProfileIndex;
            size_t nProfileLevels =
                    sizeof(kProfileLevels) / sizeof(kProfileLevels[0]);
            if (index >= nProfileLevels) {
                return OMX_ErrorNoMore;
            }

            profileLevel->eProfile = kProfileLevels[index].mProfile;
            profileLevel->eLevel = kProfileLevels[index].mLevel;
            return OMX_ErrorNone;
        }

        default:
            return SimpleSoftOMXComponent::internalGetParameter(index, params);
    }
}

OMX_ERRORTYPE SoftAVC::internalSetParameter(
        OMX_INDEXTYPE index, const OMX_PTR params) {
    switch (index) {
        case OMX_IndexParamStandardComponentRole:
        {
            const OMX_PARAM_COMPONENTROLETYPE *roleParams =
                (const OMX_PARAM_COMPONENTROLETYPE *)params;

            if (strncmp((const char *)roleParams->cRole,
                        "video_decoder.avc",
                        OMX_MAX_STRINGNAME_SIZE - 1)) {
                return OMX_ErrorUndefined;
            }

            return OMX_ErrorNone;
        }

        case OMX_IndexParamVideoPortFormat:
        {
            OMX_VIDEO_PARAM_PORTFORMATTYPE *formatParams =
                (OMX_VIDEO_PARAM_PORTFORMATTYPE *)params;

            if (formatParams->nPortIndex > 1) {
                return OMX_ErrorUndefined;
            }

            if (formatParams->nIndex != 0) {
                return OMX_ErrorNoMore;
            }

            return OMX_ErrorNone;
        }

        default:
            return SimpleSoftOMXComponent::internalSetParameter(index, params);
    }
}

OMX_ERRORTYPE SoftAVC::getConfig(
        OMX_INDEXTYPE index, OMX_PTR params) {
    switch (index) {
        case OMX_IndexConfigCommonOutputCrop:
        {
            OMX_CONFIG_RECTTYPE *rectParams = (OMX_CONFIG_RECTTYPE *)params;

            if (rectParams->nPortIndex != 1) {
                return OMX_ErrorUndefined;
            }

            rectParams->nLeft = mCropLeft;
            rectParams->nTop = mCropTop;
            rectParams->nWidth = mCropRight - mCropLeft + 1;
            rectParams->nHeight = mCropBottom - mCropTop + 1;

            return OMX_ErrorNone;
        }

        default:
            return OMX_ErrorUnsupportedIndex;
    }
}

static void findNALFragment(
        const OMX_BUFFERHEADERTYPE *inHeader,
        const uint8_t **fragPtr, size_t *fragSize) {
    const uint8_t *data = inHeader->pBuffer + inHeader->nOffset;

    size_t size = inHeader->nFilledLen;

    CHECK(size >= 4);
    CHECK(!memcmp(kStartCode, data, 4));

    size_t offset = 4;
    while (offset + 3 < size && memcmp(kStartCode, &data[offset], 4)) {
        ++offset;
    }

    *fragPtr = &data[4];
    if (offset + 3 >= size) {
        *fragSize = size - 4;
    } else {
        *fragSize = offset - 4;
    }
}

void SoftAVC::onQueueFilled(OMX_U32 portIndex) {
    if (mOutputPortSettingsChange != NONE) {
        return;
    }

    List<BufferInfo *> &inQueue = getPortQueue(0);
    List<BufferInfo *> &outQueue = getPortQueue(1);

    if (mEOSStatus == OUTPUT_FRAMES_FLUSHED) {
        return;
    }

    while ((mEOSStatus != INPUT_DATA_AVAILABLE || !inQueue.empty())
            && outQueue.size() == kNumOutputBuffers) {
        if (mEOSStatus == INPUT_EOS_SEEN) {
            OMX_BUFFERHEADERTYPE *outHeader;
            if (drainOutputBuffer(&outHeader)) {
                List<BufferInfo *>::iterator it = outQueue.begin();
                while ((*it)->mHeader != outHeader) {
                    ++it;
                }

                BufferInfo *outInfo = *it;
                outInfo->mOwnedByUs = false;
                outQueue.erase(it);
                outInfo = NULL;

                notifyFillBufferDone(outHeader);
                outHeader = NULL;
                return;
            }

            BufferInfo *outInfo = *outQueue.begin();
            outHeader = outInfo->mHeader;

            outHeader->nOffset = 0;
            outHeader->nFilledLen = 0;
            outHeader->nFlags = OMX_BUFFERFLAG_EOS;
            outHeader->nTimeStamp = 0;

            outQueue.erase(outQueue.begin());
            outInfo->mOwnedByUs = false;
            notifyFillBufferDone(outHeader);

            mEOSStatus = OUTPUT_FRAMES_FLUSHED;
            return;
        }

        BufferInfo *inInfo = *inQueue.begin();
        OMX_BUFFERHEADERTYPE *inHeader = inInfo->mHeader;

        if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) {
            inQueue.erase(inQueue.begin());
            inInfo->mOwnedByUs = false;
            notifyEmptyBufferDone(inHeader);

            mEOSStatus = INPUT_EOS_SEEN;
            continue;
        }

        mCurrentTimeUs = inHeader->nTimeStamp;

        const uint8_t *fragPtr;
        size_t fragSize;
        findNALFragment(inHeader, &fragPtr, &fragSize);

        bool releaseFragment;
        OMX_BUFFERHEADERTYPE *outHeader;
        status_t err = decodeFragment(
                fragPtr, fragSize,
                &releaseFragment, &outHeader);

        if (releaseFragment) {
            CHECK_GE(inHeader->nFilledLen, fragSize + 4);

            inHeader->nOffset += fragSize + 4;
            inHeader->nFilledLen -= fragSize + 4;

            if (inHeader->nFilledLen == 0) {
                inInfo->mOwnedByUs = false;
                inQueue.erase(inQueue.begin());
                inInfo = NULL;
                notifyEmptyBufferDone(inHeader);
                inHeader = NULL;
            }
        }

        if (outHeader != NULL) {
            List<BufferInfo *>::iterator it = outQueue.begin();
            while ((*it)->mHeader != outHeader) {
                ++it;
            }

            BufferInfo *outInfo = *it;
            outInfo->mOwnedByUs = false;
            outQueue.erase(it);
            outInfo = NULL;

            notifyFillBufferDone(outHeader);
            outHeader = NULL;
            return;
        }

        if (err == INFO_FORMAT_CHANGED) {
            return;
        }

        if (err != OK) {
            notify(OMX_EventError, OMX_ErrorUndefined, err, NULL);
            return;
        }
    }
}

status_t SoftAVC::decodeFragment(
        const uint8_t *fragPtr, size_t fragSize,
        bool *releaseFragment,
        OMX_BUFFERHEADERTYPE **outHeader) {
    *releaseFragment = true;
    *outHeader = NULL;

    int nalType;
    int nalRefIdc;
    AVCDec_Status res =
        PVAVCDecGetNALType(
                const_cast<uint8_t *>(fragPtr), fragSize,
                &nalType, &nalRefIdc);

    if (res != AVCDEC_SUCCESS) {
        LOGV("cannot determine nal type");
        return ERROR_MALFORMED;
    }

    if (nalType != AVC_NALTYPE_SPS && nalType != AVC_NALTYPE_PPS
            && (!mSPSSeen || !mPPSSeen)) {
        // We haven't seen SPS or PPS yet.
        return OK;
    }

    switch (nalType) {
        case AVC_NALTYPE_SPS:
        {
            mSPSSeen = true;

            res = PVAVCDecSeqParamSet(
                    mHandle, const_cast<uint8_t *>(fragPtr),
                    fragSize);

            if (res != AVCDEC_SUCCESS) {
                return ERROR_MALFORMED;
            }

            AVCDecObject *pDecVid = (AVCDecObject *)mHandle->AVCObject;

            int32_t width =
                (pDecVid->seqParams[0]->pic_width_in_mbs_minus1 + 1) * 16;

            int32_t height =
                (pDecVid->seqParams[0]->pic_height_in_map_units_minus1 + 1) * 16;

            int32_t crop_left, crop_right, crop_top, crop_bottom;
            if (pDecVid->seqParams[0]->frame_cropping_flag)
            {
                crop_left = 2 * pDecVid->seqParams[0]->frame_crop_left_offset;
                crop_right =
                    width - (2 * pDecVid->seqParams[0]->frame_crop_right_offset + 1);

                if (pDecVid->seqParams[0]->frame_mbs_only_flag)
                {
                    crop_top = 2 * pDecVid->seqParams[0]->frame_crop_top_offset;
                    crop_bottom =
                        height -
                        (2 * pDecVid->seqParams[0]->frame_crop_bottom_offset + 1);
                }
                else
                {
                    crop_top = 4 * pDecVid->seqParams[0]->frame_crop_top_offset;
                    crop_bottom =
                        height -
                        (4 * pDecVid->seqParams[0]->frame_crop_bottom_offset + 1);
                }
            } else {
                crop_bottom = height - 1;
                crop_right = width - 1;
                crop_top = crop_left = 0;
            }

            status_t err = OK;

            if (mWidth != width || mHeight != height) {
                mWidth = width;
                mHeight = height;

                updatePortDefinitions();

                notify(OMX_EventPortSettingsChanged, 1, 0, NULL);
                mOutputPortSettingsChange = AWAITING_DISABLED;

                err = INFO_FORMAT_CHANGED;
            }

            if (mCropLeft != crop_left
                    || mCropTop != crop_top
                    || mCropRight != crop_right
                    || mCropBottom != crop_bottom) {
                mCropLeft = crop_left;
                mCropTop = crop_top;
                mCropRight = crop_right;
                mCropBottom = crop_bottom;

                notify(OMX_EventPortSettingsChanged,
                       1,
                       OMX_IndexConfigCommonOutputCrop,
                       NULL);
            }

            return err;
        }

        case AVC_NALTYPE_PPS:
        {
            mPPSSeen = true;

            res = PVAVCDecPicParamSet(
                    mHandle, const_cast<uint8_t *>(fragPtr),
                    fragSize);

            if (res != AVCDEC_SUCCESS) {
                LOGV("PVAVCDecPicParamSet returned error %d", res);
                return ERROR_MALFORMED;
            }

            return OK;
        }

        case AVC_NALTYPE_SLICE:
        case AVC_NALTYPE_IDR:
        {
            res = PVAVCDecodeSlice(
                    mHandle, const_cast<uint8_t *>(fragPtr),
                    fragSize);

            if (res == AVCDEC_PICTURE_OUTPUT_READY) {
                *releaseFragment = false;

                if (!drainOutputBuffer(outHeader)) {
                    return UNKNOWN_ERROR;
                }

                return OK;
            }

            if (res == AVCDEC_PICTURE_READY || res == AVCDEC_SUCCESS) {
                return OK;
            } else {
                LOGV("PVAVCDecodeSlice returned error %d", res);
                return ERROR_MALFORMED;
            }
        }

        case AVC_NALTYPE_SEI:
        {
            res = PVAVCDecSEI(
                    mHandle, const_cast<uint8_t *>(fragPtr),
                    fragSize);

            if (res != AVCDEC_SUCCESS) {
                return ERROR_MALFORMED;
            }

            return OK;
        }

        case AVC_NALTYPE_AUD:
        case AVC_NALTYPE_FILL:
        case AVC_NALTYPE_EOSEQ:
        {
            return OK;
        }

        default:
        {
            LOGE("Should not be here, unknown nalType %d", nalType);

            return ERROR_MALFORMED;
        }
    }

    return OK;
}

bool SoftAVC::drainOutputBuffer(OMX_BUFFERHEADERTYPE **outHeader) {
    int32_t index;
    int32_t Release;
    AVCFrameIO Output;
    Output.YCbCr[0] = Output.YCbCr[1] = Output.YCbCr[2] = NULL;
    AVCDec_Status status =
        PVAVCDecGetOutput(mHandle, &index, &Release, &Output);

    if (status != AVCDEC_SUCCESS) {
        return false;
    }

    PortInfo *port = editPortInfo(1);
    CHECK_GE(index, 0);
    CHECK_LT((size_t)index, port->mBuffers.size());
    CHECK(port->mBuffers.editItemAt(index).mOwnedByUs);

    *outHeader = port->mBuffers.editItemAt(index).mHeader;
    (*outHeader)->nOffset = 0;
    (*outHeader)->nFilledLen = port->mDef.nBufferSize;
    (*outHeader)->nFlags = 0;

    return true;
}

void SoftAVC::onPortFlushCompleted(OMX_U32 portIndex) {
    if (portIndex == 0) {
        PVAVCDecReset(mHandle);

        mEOSStatus = INPUT_DATA_AVAILABLE;
    }
}

void SoftAVC::onPortEnableCompleted(OMX_U32 portIndex, bool enabled) {
    if (portIndex != 1) {
        return;
    }

    switch (mOutputPortSettingsChange) {
        case NONE:
            break;

        case AWAITING_DISABLED:
        {
            CHECK(!enabled);
            mOutputPortSettingsChange = AWAITING_ENABLED;
            break;
        }

        default:
        {
            CHECK_EQ((int)mOutputPortSettingsChange, (int)AWAITING_ENABLED);
            CHECK(enabled);
            mOutputPortSettingsChange = NONE;
            break;
        }
    }
}

void SoftAVC::updatePortDefinitions() {
    OMX_PARAM_PORTDEFINITIONTYPE *def = &editPortInfo(0)->mDef;
    def->format.video.nFrameWidth = mWidth;
    def->format.video.nFrameHeight = mHeight;
    def->format.video.nStride = def->format.video.nFrameWidth;
    def->format.video.nSliceHeight = def->format.video.nFrameHeight;

    def = &editPortInfo(1)->mDef;
    def->format.video.nFrameWidth = mWidth;
    def->format.video.nFrameHeight = mHeight;
    def->format.video.nStride = def->format.video.nFrameWidth;
    def->format.video.nSliceHeight = def->format.video.nFrameHeight;

    def->nBufferSize =
        (def->format.video.nFrameWidth
            * def->format.video.nFrameHeight * 3) / 2;
}

// static
int32_t SoftAVC::ActivateSPSWrapper(
        void *userData, unsigned int sizeInMbs, unsigned int numBuffers) {
    return static_cast<SoftAVC *>(userData)->activateSPS(sizeInMbs, numBuffers);
}

// static
int32_t SoftAVC::BindFrameWrapper(
        void *userData, int32_t index, uint8_t **yuv) {
    return static_cast<SoftAVC *>(userData)->bindFrame(index, yuv);
}

// static
void SoftAVC::UnbindFrame(void *userData, int32_t index) {
}

int32_t SoftAVC::activateSPS(
        unsigned int sizeInMbs, unsigned int numBuffers) {
    PortInfo *port = editPortInfo(1);
    CHECK_GE(port->mBuffers.size(), numBuffers);
    CHECK_GE(port->mDef.nBufferSize, (sizeInMbs << 7) * 3);

    return 1;
}

int32_t SoftAVC::bindFrame(int32_t index, uint8_t **yuv) {
    PortInfo *port = editPortInfo(1);

    CHECK_GE(index, 0);
    CHECK_LT((size_t)index, port->mBuffers.size());

    BufferInfo *outBuffer =
        &port->mBuffers.editItemAt(index);

    CHECK(outBuffer->mOwnedByUs);

    outBuffer->mHeader->nTimeStamp = mCurrentTimeUs;
    *yuv = outBuffer->mHeader->pBuffer;

    return 1;
}

}  // namespace android

android::SoftOMXComponent *createSoftOMXComponent(
        const char *name, const OMX_CALLBACKTYPE *callbacks,
        OMX_PTR appData, OMX_COMPONENTTYPE **component) {
    return new android::SoftAVC(name, callbacks, appData, component);
}
Loading