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

Commit bf220f3e authored by Ronghua Wu's avatar Ronghua Wu
Browse files

stagefright: add adaptive playback support to SoftAVC decoder.

Also change SoftVPX decoder to use common handlePortSettingsChanged
and copyYV12FrameToOutputBuffer method.

Bug: 17326758
Change-Id: I6fb2ee8fb9291f69c70493b8558af341adc1f4b2
parent 90073050
Loading
Loading
Loading
Loading
+11 −52
Original line number Diff line number Diff line
@@ -137,29 +137,10 @@ void SoftVPX::onQueueFilled(OMX_U32 /* portIndex */) {

            uint32_t width = mImg->d_w;
            uint32_t height = mImg->d_h;

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

                if (!mIsAdaptive || width > mAdaptiveMaxWidth || height > mAdaptiveMaxHeight) {
                    if (mIsAdaptive) {
                        if (width > mAdaptiveMaxWidth) {
                            mAdaptiveMaxWidth = width;
                        }
                        if (height > mAdaptiveMaxHeight) {
                            mAdaptiveMaxHeight = height;
                        }
                    }
                    updatePortDefinitions();
                    notify(OMX_EventPortSettingsChanged, kOutputPortIndex, 0, NULL);
                    mOutputPortSettingsChange = AWAITING_DISABLED;
            bool portWillReset = false;
            handlePortSettingsChange(&portWillReset, width, height);
            if (portWillReset) {
                return;
                } else {
                    updatePortDefinitions();
                    notify(OMX_EventPortSettingsChanged, kOutputPortIndex,
                           OMX_IndexConfigCommonOutputCrop, NULL);
                }
            }

            outHeader->nOffset = 0;
@@ -167,36 +148,14 @@ void SoftVPX::onQueueFilled(OMX_U32 /* portIndex */) {
            outHeader->nFlags = EOSseen ? OMX_BUFFERFLAG_EOS : 0;
            outHeader->nTimeStamp = inHeader->nTimeStamp;

            uint32_t buffer_stride = mIsAdaptive ? mAdaptiveMaxWidth : mWidth;
            uint32_t buffer_height = mIsAdaptive ? mAdaptiveMaxHeight : mHeight;

            const uint8_t *srcLine = (const uint8_t *)mImg->planes[PLANE_Y];
            uint8_t *dst = outHeader->pBuffer;
            for (size_t i = 0; i < buffer_height; ++i) {
                if (i < mImg->d_h) {
                    memcpy(dst, srcLine, mImg->d_w);
                    srcLine += mImg->stride[PLANE_Y];
                }
                dst += buffer_stride;
            }

            srcLine = (const uint8_t *)mImg->planes[PLANE_U];
            for (size_t i = 0; i < buffer_height / 2; ++i) {
                if (i < mImg->d_h / 2) {
                    memcpy(dst, srcLine, mImg->d_w / 2);
                    srcLine += mImg->stride[PLANE_U];
                }
                dst += buffer_stride / 2;
            }

            srcLine = (const uint8_t *)mImg->planes[PLANE_V];
            for (size_t i = 0; i < buffer_height / 2; ++i) {
                if (i < mImg->d_h / 2) {
                    memcpy(dst, srcLine, mImg->d_w / 2);
                    srcLine += mImg->stride[PLANE_V];
                }
                dst += buffer_stride / 2;
            }
            const uint8_t *srcY = (const uint8_t *)mImg->planes[PLANE_Y];
            const uint8_t *srcU = (const uint8_t *)mImg->planes[PLANE_U];
            const uint8_t *srcV = (const uint8_t *)mImg->planes[PLANE_V];
            size_t srcYStride = mImg->stride[PLANE_Y];
            size_t srcUStride = mImg->stride[PLANE_U];
            size_t srcVStride = mImg->stride[PLANE_V];
            copyYV12FrameToOutputBuffer(dst, srcY, srcU, srcV, srcYStride, srcUStride, srcVStride);

            mImg = NULL;
            outInfo->mOwnedByUs = false;
+36 −45
Original line number Diff line number Diff line
@@ -58,7 +58,6 @@ SoftAVC::SoftAVC(
            320 /* width */, 240 /* height */, callbacks, appData, component),
      mHandle(NULL),
      mInputBufferCount(0),
      mPictureSize(mWidth * mHeight * 3 / 2),
      mFirstPicture(NULL),
      mFirstPictureId(-1),
      mPicId(0),
@@ -118,7 +117,7 @@ void SoftAVC::onQueueFilled(OMX_U32 /* portIndex */) {
    }

    H264SwDecRet ret = H264SWDEC_PIC_RDY;
    bool portSettingsChanged = false;
    bool portWillReset = false;
    while ((mEOSStatus != INPUT_DATA_AVAILABLE || !inQueue.empty())
            && outQueue.size() == kNumOutputBuffers) {

@@ -161,17 +160,13 @@ void SoftAVC::onQueueFilled(OMX_U32 /* portIndex */) {
                    H264SwDecInfo decoderInfo;
                    CHECK(H264SwDecGetInfo(mHandle, &decoderInfo) == H264SWDEC_OK);

                    if (handlePortSettingChangeEvent(&decoderInfo)) {
                        portSettingsChanged = true;
                    }

                    if (decoderInfo.croppingFlag &&
                        handleCropRectEvent(&decoderInfo.cropParams)) {
                        portSettingsChanged = true;
                    }
                    bool cropChanged = handleCropChange(decoderInfo);
                    handlePortSettingsChange(
                            &portWillReset, decoderInfo.picWidth, decoderInfo.picHeight,
                            cropChanged);
                }
            } else {
                if (portSettingsChanged) {
                if (portWillReset) {
                    if (H264SwDecNextPicture(mHandle, &decodedPicture, 0)
                        == H264SWDEC_PIC_RDY) {

@@ -199,8 +194,7 @@ void SoftAVC::onQueueFilled(OMX_U32 /* portIndex */) {
        inInfo->mOwnedByUs = false;
        notifyEmptyBufferDone(inHeader);

        if (portSettingsChanged) {
            portSettingsChanged = false;
        if (portWillReset) {
            return;
        }

@@ -215,44 +209,33 @@ void SoftAVC::onQueueFilled(OMX_U32 /* portIndex */) {
    }
}

bool SoftAVC::handlePortSettingChangeEvent(const H264SwDecInfo *info) {
    if (mWidth != info->picWidth || mHeight != info->picHeight) {
        mWidth  = info->picWidth;
        mHeight = info->picHeight;
        mPictureSize = mWidth * mHeight * 3 / 2;
        updatePortDefinitions();
        notify(OMX_EventPortSettingsChanged, 1, 0, NULL);
        mOutputPortSettingsChange = AWAITING_DISABLED;
        return true;
bool SoftAVC::handleCropChange(const H264SwDecInfo& decInfo) {
    if (!decInfo.croppingFlag) {
        return false;
    }

    const CropParams& crop = decInfo.cropParams;
    if (mCropLeft == crop.cropLeftOffset &&
        mCropTop == crop.cropTopOffset &&
        mCropWidth == crop.cropOutWidth &&
        mCropHeight == crop.cropOutHeight) {
        return false;
    }

bool SoftAVC::handleCropRectEvent(const CropParams *crop) {
    if (mCropLeft != crop->cropLeftOffset ||
        mCropTop != crop->cropTopOffset ||
        mCropWidth != crop->cropOutWidth ||
        mCropHeight != crop->cropOutHeight) {
        mCropLeft = crop->cropLeftOffset;
        mCropTop = crop->cropTopOffset;
        mCropWidth = crop->cropOutWidth;
        mCropHeight = crop->cropOutHeight;

        notify(OMX_EventPortSettingsChanged, 1,
                OMX_IndexConfigCommonOutputCrop, NULL);

    mCropLeft = crop.cropLeftOffset;
    mCropTop = crop.cropTopOffset;
    mCropWidth = crop.cropOutWidth;
    mCropHeight = crop.cropOutHeight;
    return true;
}
    return false;
}

void SoftAVC::saveFirstOutputBuffer(int32_t picId, uint8_t *data) {
    CHECK(mFirstPicture == NULL);
    mFirstPictureId = picId;

    mFirstPicture = new uint8_t[mPictureSize];
    memcpy(mFirstPicture, data, mPictureSize);
    uint32_t pictureSize = mWidth * mHeight * 3 / 2;
    mFirstPicture = new uint8_t[pictureSize];
    memcpy(mFirstPicture, data, pictureSize);
}

void SoftAVC::drainOneOutputBuffer(int32_t picId, uint8_t* data) {
@@ -263,9 +246,17 @@ void SoftAVC::drainOneOutputBuffer(int32_t picId, uint8_t* data) {
    OMX_BUFFERHEADERTYPE *header = mPicToHeaderMap.valueFor(picId);
    outHeader->nTimeStamp = header->nTimeStamp;
    outHeader->nFlags = header->nFlags;
    outHeader->nFilledLen = mPictureSize;
    memcpy(outHeader->pBuffer + outHeader->nOffset,
            data, mPictureSize);
    outHeader->nFilledLen = mWidth * mHeight * 3 / 2;

    uint8_t *dst = outHeader->pBuffer + outHeader->nOffset;
    const uint8_t *srcY = data;
    const uint8_t *srcU = srcY + mWidth * mHeight;
    const uint8_t *srcV = srcU + mWidth * mHeight / 4;
    size_t srcYStride = mWidth;
    size_t srcUStride = mWidth / 2;
    size_t srcVStride = srcUStride;
    copyYV12FrameToOutputBuffer(dst, srcY, srcU, srcV, srcYStride, srcUStride, srcVStride);

    mPicToHeaderMap.removeItem(picId);
    delete header;
    outInfo->mOwnedByUs = false;
+1 −4
Original line number Diff line number Diff line
@@ -55,8 +55,6 @@ private:

    size_t mInputBufferCount;

    uint32_t mPictureSize;

    uint8_t *mFirstPicture;
    int32_t mFirstPictureId;

@@ -75,8 +73,7 @@ private:
    void drainAllOutputBuffers(bool eos);
    void drainOneOutputBuffer(int32_t picId, uint8_t *data);
    void saveFirstOutputBuffer(int32_t pidId, uint8_t *data);
    bool handleCropRectEvent(const CropParams* crop);
    bool handlePortSettingChangeEvent(const H264SwDecInfo *info);
    bool handleCropChange(const H264SwDecInfo& decInfo);

    DISALLOW_EVIL_CONSTRUCTORS(SoftAVC);
};
+8 −1
Original line number Diff line number Diff line
@@ -63,7 +63,14 @@ protected:
            OMX_U32 numOutputBuffers,
            const char *mimeType);

    virtual void updatePortDefinitions();
    virtual void updatePortDefinitions(bool updateCrop = true);

    void handlePortSettingsChange(
            bool *portWillReset, uint32_t width, uint32_t height, bool cropChanged = false);

    void copyYV12FrameToOutputBuffer(
            uint8_t *dst, const uint8_t *srcY, const uint8_t *srcU, const uint8_t *srcV,
            size_t srcYStride, size_t srcUStride, size_t srcVStride);

    enum {
        kInputPortIndex  = 0,
+74 −5
Original line number Diff line number Diff line
@@ -123,13 +123,15 @@ void SoftVideoDecoderOMXComponent::initPorts(
    updatePortDefinitions();
}

void SoftVideoDecoderOMXComponent::updatePortDefinitions() {
void SoftVideoDecoderOMXComponent::updatePortDefinitions(bool updateCrop) {
    OMX_PARAM_PORTDEFINITIONTYPE *def = &editPortInfo(kInputPortIndex)->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;

    def = &editPortInfo(kOutputPortIndex)->mDef;
    def->format.video.nFrameWidth = mIsAdaptive ? mAdaptiveMaxWidth : mWidth;
    def->format.video.nFrameHeight = mIsAdaptive ? mAdaptiveMaxHeight : mHeight;
@@ -140,11 +142,78 @@ void SoftVideoDecoderOMXComponent::updatePortDefinitions() {
            (def->format.video.nFrameWidth *
             def->format.video.nFrameHeight * 3) / 2;

    if (updateCrop) {
        mCropLeft = 0;
        mCropTop = 0;
        mCropWidth = mWidth;
        mCropHeight = mHeight;
    }
}

void SoftVideoDecoderOMXComponent::handlePortSettingsChange(
        bool *portWillReset, uint32_t width, uint32_t height, bool cropChanged) {
    *portWillReset = false;
    bool sizeChanged = (width != mWidth || height != mHeight);

    if (sizeChanged || cropChanged) {
        mWidth = width;
        mHeight = height;

        bool updateCrop = !cropChanged;
        if ((sizeChanged && !mIsAdaptive)
            || width > mAdaptiveMaxWidth
            || height > mAdaptiveMaxHeight) {
            if (mIsAdaptive) {
                if (width > mAdaptiveMaxWidth) {
                    mAdaptiveMaxWidth = width;
                }
                if (height > mAdaptiveMaxHeight) {
                    mAdaptiveMaxHeight = height;
                }
            }
            updatePortDefinitions(updateCrop);
            notify(OMX_EventPortSettingsChanged, kOutputPortIndex, 0, NULL);
            mOutputPortSettingsChange = AWAITING_DISABLED;
            *portWillReset = true;
        } else {
            updatePortDefinitions(updateCrop);
            notify(OMX_EventPortSettingsChanged, kOutputPortIndex,
                   OMX_IndexConfigCommonOutputCrop, NULL);
        }
    }
}

void SoftVideoDecoderOMXComponent::copyYV12FrameToOutputBuffer(
        uint8_t *dst, const uint8_t *srcY, const uint8_t *srcU, const uint8_t *srcV,
        size_t srcYStride, size_t srcUStride, size_t srcVStride) {
    size_t dstYStride = mIsAdaptive ? mAdaptiveMaxWidth : mWidth;
    size_t dstUVStride = dstYStride / 2;
    size_t dstHeight = mIsAdaptive ? mAdaptiveMaxHeight : mHeight;

    for (size_t i = 0; i < dstHeight; ++i) {
        if (i < mHeight) {
            memcpy(dst, srcY, mWidth);
            srcY += srcYStride;
        }
        dst += dstYStride;
    }

    for (size_t i = 0; i < dstHeight / 2; ++i) {
        if (i < mHeight / 2) {
            memcpy(dst, srcU, mWidth / 2);
            srcU += srcUStride;
        }
        dst += dstUVStride;
    }

    for (size_t i = 0; i < dstHeight / 2; ++i) {
        if (i < mHeight / 2) {
            memcpy(dst, srcV, mWidth / 2);
            srcV += srcVStride;
        }
        dst += dstUVStride;
    }
}

OMX_ERRORTYPE SoftVideoDecoderOMXComponent::internalGetParameter(
        OMX_INDEXTYPE index, OMX_PTR params) {