OMX_ERRORTYPE VideoFilter::ReturnOutputBuffer(OMX_BUFFERHEADERTYPE *pBufferHdr,OMX_U32 flags)
{
    if(nDecodeOnly > 0)
    {
        LOG_INFO("VideoFilter drop frame as decode only: %d\n", nDecodeOnly);
        nDecodeOnly --;
        pBufferHdr->nFilledLen = 0;
        tsmGetFrmTs(hTsHandle, pBufferHdr->pBuffer);
        SetOutputBuffer(pBufferHdr->pBuffer);
        OutBufferHdrList.Add(pBufferHdr);
        return OMX_ErrorNone;
    }

    if(bNewSegment == OMX_TRUE)
    {
        pBufferHdr->nFlags |= OMX_BUFFERFLAG_STARTTIME;
        bNewSegment = OMX_FALSE;
    }

    pBufferHdr->nOffset = 0;
    if(flags!=OMX_BUFFERFLAG_CODECCONFIG)    //check for encoder
    {
        pBufferHdr->nTimeStamp = tsmGetFrmTs(hTsHandle, pBufferHdr->pBuffer);
    }

    LOG_DEBUG("VideoDecoder send bufer: %p:%lld:%x\n", pBufferHdr->pBuffer, pBufferHdr->nTimeStamp, pBufferHdr->nFlags);

    if(0)
    {
        static int iiCnt=0;
        static FILE *pfTest = NULL;
        iiCnt ++;
        if (iiCnt==1)
        {
            pfTest = fopen("/sdcard/DumpData.yuv", "wb");
            if(pfTest == NULL)
                printf("Unable to open test file! \n");
        }
        if(iiCnt > 0 && pfTest != NULL)
        {
            if(pBufferHdr->nFilledLen > 0)
            {
                printf("dump data %d\n", pBufferHdr->nFilledLen);
                fwrite(pBufferHdr->pBuffer, sizeof(char), pBufferHdr->nFilledLen, pfTest);
                fflush(pfTest);
                fclose(pfTest);
                pfTest = NULL;
            }
        }
    }

    ports[OUT_PORT]->SendBuffer(pBufferHdr);

    return OMX_ErrorNone;
}
OMX_ERRORTYPE VideoFilter::ProcessOutputBuffer()
{
    OMX_ERRORTYPE ret = OMX_ErrorNone;

    if(bLastOutput == OMX_TRUE)
        return OMX_ErrorNoMore;

    LOG_DEBUG("Filter Out port has #%d buffers.\n", ports[OUT_PORT]->BufferNum());

    if(bNeedOutBuffer != OMX_FALSE) {
        if(ports[OUT_PORT]->BufferNum() > 0) {
            OMX_BUFFERHEADERTYPE *pBufferHdr = NULL;
            ports[OUT_PORT]->GetBuffer(&pBufferHdr);
            if(pBufferHdr == NULL)
                return OMX_ErrorUnderflow;

            if(bNewSegment == OMX_TRUE && bLastInput == OMX_TRUE) {
                bLastOutput = OMX_TRUE;
                pBufferHdr->nFlags = OMX_BUFFERFLAG_EOS | OMX_BUFFERFLAG_STARTTIME;
                pBufferHdr->nTimeStamp = tsmGetFrmTs(hTsHandle, NULL);
                ports[OUT_PORT]->SendBuffer(pBufferHdr);
                return OMX_ErrorNoMore;
            }

            ret = SetOutputBuffer(pBufferHdr->pBuffer);
            if(ret != OMX_ErrorNone) {
                pBufferHdr->nFilledLen = 0;
                ports[OUT_PORT]->SendBuffer(pBufferHdr);
                bNeedOutBuffer = OMX_FALSE;
                return OMX_ErrorNone;
            }

            LOG_DEBUG("Get Outbuffer: %p\n", pBufferHdr->pBuffer);

          

            OutBufferHdrList.Add(pBufferHdr);
            bNeedOutBuffer = OMX_FALSE;
        }
        else {
            OMX_S32 nCnt = OutBufferHdrList.GetNodeCnt();
            LOG_DEBUG("No more OutBuffer, #%d buffers holded by filter.\n", nCnt);
            return OMX_ErrorNoMore;
        }
    }

    return OMX_ErrorNone;
}
OMX_ERRORTYPE VideoFilter::ProcessDataBuffer()
{
    OMX_ERRORTYPE ret = OMX_ErrorNone;
    OMX_U32 flags=0;

    if(bInReturnBufferState == OMX_TRUE)
        return OMX_ErrorNoMore;

    ret = ProcessInputBuffer();
    if(ret == OMX_ErrorNotReady)
        return OMX_ErrorNone;
    if(ret != OMX_ErrorNone)
        return ret;

    ret = ProcessOutputBuffer();
    if(ret != OMX_ErrorNone)
        return ret;

    FilterBufRetCode DecRet = FILTER_OK;
    DecRet = FilterOneBuffer();
    if(DecRet & FILTER_INPUT_CONSUMED)
    {
        DecRet = (FilterBufRetCode)(DecRet & ~FILTER_INPUT_CONSUMED);
        ReturnInputBuffer();
    }

    if(DecRet & FILTER_ONE_FRM_DECODED)
    {
        OMX_S32 nStuffSize;
        OMX_S32 nFrmSize;
        OMX_PTR pFrm;
        ret=GetDecBuffer(&pFrm, &nStuffSize, &nFrmSize);
        if(ret == OMX_ErrorNone)
        {
            LOG_DEBUG("%s: get one decoded frm: 0x%X(%d,%d) \n",__FUNCTION__,(int)pFrm,(int)nStuffSize,(int)nFrmSize);
            tsmSetFrmBoundary(hTsHandle, nStuffSize, nFrmSize, pFrm);
        }
        else
        {
            LOG_ERROR("%s: get decoded buffer failure !\n",__FUNCTION__);
        }
        DecRet = (FilterBufRetCode)(DecRet & ~FILTER_ONE_FRM_DECODED);
    }

    switch(DecRet & FILTER_FLAGS_MASK)
    {
    case FILTER_FLAG_CODEC_DATA:
        flags=OMX_BUFFERFLAG_CODECCONFIG;
        break;
    case FILTER_FLAG_NONKEY_FRAME:
        flags=OMX_BUFFERFLAG_ENDOFFRAME;
        break;
    case FILTER_FLAG_KEY_FRAME:
        flags=OMX_BUFFERFLAG_SYNCFRAME|OMX_BUFFERFLAG_ENDOFFRAME;
        break;
    default:
        flags=0;
        break;
    }
    DecRet = (FilterBufRetCode)(DecRet & ~FILTER_FLAGS_MASK);

    if(DecRet > 0)
    {
        LOG_DEBUG("DecRet: %d\n", DecRet);
    }

    switch(DecRet)
    {
    case FILTER_OK:
        break;
    case FILTER_NO_INPUT_BUFFER:
        if(pInBufferHdr != NULL)
            SetInputBuffer(pInBufferHdr->pBuffer + pInBufferHdr->nOffset, pInBufferHdr->nFilledLen, bLastInput);
        else
            bNeedInputBuffer = OMX_TRUE;
        break;
    case FILTER_NO_OUTPUT_BUFFER:
        bNeedOutBuffer = OMX_TRUE;
        break;
    case FILTER_DO_INIT:
        ret = InitFilter();
        if(ret == OMX_ErrorNone)
            bInit = OMX_TRUE;
        break;
    case FILTER_LAST_OUTPUT:
        HandleLastOutput(flags);
        ret = OMX_ErrorNoMore;
        break;
    case FILTER_HAS_OUTPUT:
    {
        OMX_PTR pBuffer = NULL;
        OMX_S32 nOutSize=0;
        OMX_BUFFERHEADERTYPE *pBufferHdr = NULL;
        GetOutputBuffer(&pBuffer,&nOutSize);
        pBufferHdr = GetOutBufferHdrFromList(pBuffer);
        if(pBufferHdr != NULL)
        {
            pBufferHdr->nFlags = flags;
            pBufferHdr->nFilledLen = nOutSize;//pBufferHdr->nAllocLen;
            ReturnOutputBuffer(pBufferHdr,flags);
        }
        else
        {
            SetOutputBuffer(pBuffer);	//still need to return it to vpu to avoid the frame is isolated in the pipeline
            LOG_ERROR("Can't find related bufferhdr with frame: %p\n", pBuffer);
        }
    }
    break;
    case FILTER_SKIP_OUTPUT:
        tsmGetFrmTs(hTsHandle, NULL);
        break;
    case FILTER_ERROR:
        SendEvent(OMX_EventError, OMX_ErrorStreamCorrupt, 0, NULL);
        ret=OMX_ErrorStreamCorrupt;
        break;
    default:
        break;
    }

    return ret;
}
OMX_ERRORTYPE VideoFilter::ProcessDataBuffer()
{
    OMX_ERRORTYPE ret = OMX_ErrorNone;
    OMX_U32 flags=0;

    if(bInReturnBufferState == OMX_TRUE)
        return OMX_ErrorNoMore;

    ret = ProcessInputBuffer();
    if(ret == OMX_ErrorNotReady)
        return OMX_ErrorNone;
    if(ret != OMX_ErrorNone)
        return ret;

    ret = ProcessOutputBuffer();
    if(ret != OMX_ErrorNone)
        return ret;

    FilterBufRetCode DecRet = FILTER_OK;
    DecRet = FilterOneBuffer();
    if(DecRet & FILTER_INPUT_CONSUMED) {
        DecRet = (FilterBufRetCode)(DecRet & ~FILTER_INPUT_CONSUMED);
        ReturnInputBuffer();
    }
    if(DecRet & FILTER_INPUT_CONSUMED_EXT_READ) {
        DecRet = (FilterBufRetCode)(DecRet & ~FILTER_INPUT_CONSUMED_EXT_READ);        
        if(pInBufferHdr){
            InBufferHdrList.Add(pInBufferHdr);
            pInBufferHdr = NULL;
        }
        else{
            //for eos buffer with size=0, pInBufferHdr may be retured aleady before (in ProcessInputBuffer()) 
        }
    }
    if(DecRet & FILTER_INPUT_CONSUMED_EXT_RETURN) {
        OMX_PTR ptr;
        DecRet = (FilterBufRetCode)(DecRet & ~FILTER_INPUT_CONSUMED_EXT_RETURN);
        GetReturnedInputDataPtr(&ptr);
        //since the list is FIFO, we needn't map ptr and pHdr
        if(InBufferHdrList.GetNodeCnt()>0){
            OMX_BUFFERHEADERTYPE* pHdr;
            pHdr=InBufferHdrList.GetNode(0);
            if(pHdr==NULL){
                LOG_ERROR("warning: get one null hdr from InBufferHdrList !\n");
            }
            if(pHdr->pBuffer!=ptr){
                LOG_ERROR("warning: the address doesn't match between ptr and pHdr->pBuffer !\n");
            }
            InBufferHdrList.Remove(pHdr);
            ports[IN_PORT]->SendBuffer(pHdr);
        }
        else{
            //this path is only for eos
            if((DecRet&FILTER_LAST_OUTPUT)==0){
                LOG_ERROR("warning: the numbers between insert and get doesn't matched !\n");
            }
        }
    }

    if(DecRet & FILTER_ONE_FRM_DECODED){
        OMX_S32 nStuffSize;
        OMX_S32 nFrmSize;
        OMX_PTR pFrm;
        ret=GetDecBuffer(&pFrm, &nStuffSize, &nFrmSize);
        if(ret == OMX_ErrorNone){
            LOG_DEBUG("%s: get one decoded frm: 0x%X(%d,%d) \n",__FUNCTION__,(int)pFrm,(int)nStuffSize,(int)nFrmSize);	
            tsmSetFrmBoundary(hTsHandle, nStuffSize, nFrmSize, pFrm);
        }
        else{
            LOG_ERROR("%s: get decoded buffer failure !\n",__FUNCTION__);
        }
        DecRet = (FilterBufRetCode)(DecRet & ~FILTER_ONE_FRM_DECODED);
    }

    switch(DecRet & FILTER_FLAGS_MASK) {
        case FILTER_FLAG_CODEC_DATA:
            flags=OMX_BUFFERFLAG_CODECCONFIG;
            break;
        case FILTER_FLAG_NONKEY_FRAME:
            flags=OMX_BUFFERFLAG_ENDOFFRAME;
            break;
        case FILTER_FLAG_KEY_FRAME:
            flags=OMX_BUFFERFLAG_SYNCFRAME|OMX_BUFFERFLAG_ENDOFFRAME;
            break;
        default:
            flags=0;
            break;
    }
    DecRet = (FilterBufRetCode)(DecRet & ~FILTER_FLAGS_MASK);

    if(DecRet > 0) {
        LOG_DEBUG("DecRet: %d\n", DecRet);
    }

    switch(DecRet) {
        case FILTER_OK:
            break;
        case FILTER_NO_INPUT_BUFFER:
            if(pInBufferHdr != NULL)
                SetInputBuffer(pInBufferHdr->pBuffer + pInBufferHdr->nOffset, pInBufferHdr->nFilledLen, bLastInput);
            else
                bNeedInputBuffer = OMX_TRUE;
            break;
        case FILTER_NO_OUTPUT_BUFFER:
            bNeedOutBuffer = OMX_TRUE;
            break;
        case FILTER_DO_INIT:
            ret = InitFilter();
            if(ret == OMX_ErrorNone)
                bInit = OMX_TRUE;
            break;
        case FILTER_LAST_OUTPUT:
            HandleLastOutput(flags);
            ret = OMX_ErrorNoMore;
            break;
        case FILTER_HAS_OUTPUT:
            {
                OMX_PTR pBuffer = NULL;
                OMX_S32 nOutSize=0;
                OMX_BUFFERHEADERTYPE *pBufferHdr = NULL;
                GetOutputBuffer(&pBuffer,&nOutSize);
				if (nOutSize == 0) {
					nInvalidFrameCnt ++;
					if (nInvalidFrameCnt <= MOSAIC_COUNT) {
						SetOutputBuffer(pBuffer);	//still need to return it to vpu to avoid the frame is isolated in the pipeline
						tsmGetFrmTs(hTsHandle, NULL);
						break;
					}
				} else {
					nInvalidFrameCnt = 0;
				}
                pBufferHdr = GetOutBufferHdrFromList(pBuffer);
                if(pBufferHdr != NULL) {
                    pBufferHdr->nFlags = flags;
                    pBufferHdr->nFilledLen = nOutSize;//pBufferHdr->nAllocLen;
                    ReturnOutputBuffer(pBufferHdr,flags);
                }
                else{
                    SetOutputBuffer(pBuffer);	//still need to return it to vpu to avoid the frame is isolated in the pipeline
                    LOG_ERROR("Can't find related bufferhdr with frame: %p\n", pBuffer);
                }
            }
            break;
        case FILTER_SKIP_OUTPUT:
            tsmGetFrmTs(hTsHandle, NULL);
            break;
        case FILTER_ERROR:
            SendEvent(OMX_EventError, OMX_ErrorStreamCorrupt, 0, NULL);
            ret=OMX_ErrorStreamCorrupt;
            break;
        default: 
            break;
    }

    return ret;
}