/*
* Copyright (c) 2017-2021, Intel Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
//!
//! \file     media_ddi_decode_base.cpp
//! \brief    The class implementation of DdiDecodeBase  for all decoders
//!

#include "media_libva_decoder.h"
#include "media_libva_vp.h"
#include "media_libva_util.h"
#include "media_ddi_decode_base.h"
#include "codechal.h"
#include "codechal_memdecomp.h"
#include "media_interfaces_codechal.h"
#include "media_interfaces_mmd.h"
#include "mos_solo_generic.h"

DdiMediaDecode::DdiMediaDecode(DDI_DECODE_CONFIG_ATTR *ddiDecodeAttr)
    : DdiMediaBase()
{
    m_ddiDecodeAttr = ddiDecodeAttr;
    m_ddiDecodeCtx  = nullptr;
    MOS_ZeroMemory(&m_destSurface, sizeof(m_destSurface));
    m_groupIndex = 0;
    m_picWidthInMB = 0;
    m_picHeightInMB = 0;
    m_decProcessingType = 0;
    m_width = 0;
    m_height = 0;
    m_streamOutEnabled = false;
    m_sliceParamBufNum = 0;
    m_sliceCtrlBufNum = 0;
    m_codechalSettings = CodechalSetting::CreateCodechalSetting();
}

VAStatus DdiMediaDecode::BasicInit(
    DDI_DECODE_CONFIG_ATTR *ddiConfAttr)
{
    if (ddiConfAttr == nullptr)
    {
        return VA_STATUS_ERROR_ALLOCATION_FAILED;
    }

    m_ddiDecodeAttr = (DDI_DECODE_CONFIG_ATTR *)MOS_AllocAndZeroMemory(
        sizeof(DDI_DECODE_CONFIG_ATTR));
    if (m_ddiDecodeAttr && ddiConfAttr)
    {
        MOS_SecureMemcpy(m_ddiDecodeAttr, sizeof(DDI_DECODE_CONFIG_ATTR), ddiConfAttr, sizeof(DDI_DECODE_CONFIG_ATTR));
    }

    m_ddiDecodeCtx = (DDI_DECODE_CONTEXT *)MOS_AllocAndZeroMemory(
        sizeof(DDI_DECODE_CONTEXT));

    if ((m_ddiDecodeAttr == nullptr) ||
        (m_ddiDecodeCtx == nullptr))
    {
        MOS_FreeMemory(m_ddiDecodeAttr);
        m_ddiDecodeAttr = nullptr;
        MOS_FreeMemory(m_ddiDecodeCtx);
        m_ddiDecodeCtx = nullptr;
        return VA_STATUS_ERROR_ALLOCATION_FAILED;
    }

    return VA_STATUS_SUCCESS;
}

uint32_t DdiMediaDecode::GetBsBufOffset(int32_t sliceGroup)
{
    return m_ddiDecodeCtx->BufMgr.pSliceData[sliceGroup].uiOffset;
}

VAStatus DdiMediaDecode::ParseProcessingBuffer(
    DDI_MEDIA_CONTEXT *mediaCtx,
    void              *bufAddr)
{
#ifdef _DECODE_PROCESSING_SUPPORTED
    VAProcPipelineParameterBuffer *procBuf =
        (VAProcPipelineParameterBuffer *)bufAddr;

    DDI_CHK_NULL(procBuf, "nullptr Processing buffer", VA_STATUS_ERROR_INVALID_PARAMETER)

    if (m_decProcessingType == VA_DEC_PROCESSING)
    {
        if(m_procBuf == nullptr)
        {
            m_procBuf = (VAProcPipelineParameterBuffer*)MOS_AllocAndZeroMemory(sizeof(VAProcPipelineParameterBuffer));
            DDI_CHK_NULL(m_procBuf, "nullptr m_procBuf", VA_STATUS_ERROR_ALLOCATION_FAILED);
            MOS_SecureMemcpy(m_procBuf, sizeof(VAProcPipelineParameterBuffer), procBuf, sizeof(VAProcPipelineParameterBuffer));
        }
        auto decProcessingParams =
            (DecodeProcessingParams *)m_ddiDecodeCtx->DecodeParams.m_procParams;

        auto decProcessingSurface = decProcessingParams->m_outputSurface;

        memset(decProcessingSurface, 0, sizeof(MOS_SURFACE));

        PDDI_MEDIA_SURFACE surface =
            DdiMedia_GetSurfaceFromVASurfaceID(mediaCtx, procBuf->additional_outputs[0]);

        DDI_CHK_NULL(surface, "Null surface in Processing buffer", VA_STATUS_ERROR_INVALID_PARAMETER)

        DdiMedia_MediaSurfaceToMosResource(surface, &(decProcessingSurface->OsResource));

        decProcessingSurface->dwWidth  = decProcessingSurface->OsResource.iWidth;
        decProcessingSurface->dwHeight = decProcessingSurface->OsResource.iHeight;
        decProcessingSurface->dwPitch  = decProcessingSurface->OsResource.iPitch;
        decProcessingSurface->TileType = decProcessingSurface->OsResource.TileType;
        decProcessingSurface->Format   = decProcessingSurface->OsResource.Format;

        if(procBuf->surface_region != nullptr)
        {
            m_requireInputRegion                               = false;
            decProcessingParams->m_inputSurfaceRegion.m_x      = procBuf->surface_region->x;
            decProcessingParams->m_inputSurfaceRegion.m_y      = procBuf->surface_region->y;
            decProcessingParams->m_inputSurfaceRegion.m_width  = procBuf->surface_region->width;
            decProcessingParams->m_inputSurfaceRegion.m_height = procBuf->surface_region->height;
        }
        else
        {
            m_requireInputRegion = true;
        }

        decProcessingParams->m_outputSurface                = decProcessingSurface;
        if(procBuf->output_region != nullptr)
        {
            decProcessingParams->m_outputSurfaceRegion.m_x      = procBuf->output_region->x;
            decProcessingParams->m_outputSurfaceRegion.m_y      = procBuf->output_region->y;
            decProcessingParams->m_outputSurfaceRegion.m_width  = procBuf->output_region->width;
            decProcessingParams->m_outputSurfaceRegion.m_height = procBuf->output_region->height;
        }
        else
        {
            decProcessingParams->m_outputSurfaceRegion.m_x      = 0;
            decProcessingParams->m_outputSurfaceRegion.m_y      = 0;
            decProcessingParams->m_outputSurfaceRegion.m_width  = decProcessingSurface->dwWidth;
            decProcessingParams->m_outputSurfaceRegion.m_height = decProcessingSurface->dwHeight;
        }

        // Interpolation flags
        // Set the vdbox scaling mode
        uint32_t uInterpolationflags = 0;
#if VA_CHECK_VERSION(1, 9, 0)
        uInterpolationflags = procBuf->filter_flags & VA_FILTER_INTERPOLATION_MASK;
#endif

        switch (uInterpolationflags)
        {
#if VA_CHECK_VERSION(1, 9, 0)
        case VA_FILTER_INTERPOLATION_NEAREST_NEIGHBOR:
            decProcessingParams->m_scalingMode = CODECHAL_SCALING_NEAREST;
            break;
        case VA_FILTER_INTERPOLATION_BILINEAR:
            decProcessingParams->m_scalingMode = CODECHAL_SCALING_BILINEAR;
            break;
        case VA_FILTER_INTERPOLATION_ADVANCED:
        case VA_FILTER_INTERPOLATION_DEFAULT:
#endif
        default:
            decProcessingParams->m_scalingMode = CODECHAL_SCALING_AVS;
           break;
        }

        // Chroma siting
        // Set the vertical chroma siting info
        uint32_t chromaSitingFlags = 0;
        chromaSitingFlags                       = procBuf->input_color_properties.chroma_sample_location & 0x3;
        decProcessingParams->m_chromaSitingType = CODECHAL_CHROMA_SITING_NONE;
        decProcessingParams->m_rotationState    = 0;
        decProcessingParams->m_blendState       = 0;
        decProcessingParams->m_mirrorState      = 0;

        switch (chromaSitingFlags)
        {
        case VA_CHROMA_SITING_VERTICAL_TOP:
            decProcessingParams->m_chromaSitingType = CODECHAL_CHROMA_SITING_VERT_TOP;
            break;
        case VA_CHROMA_SITING_VERTICAL_CENTER:
            decProcessingParams->m_chromaSitingType = CODECHAL_CHROMA_SITING_VERT_CENTER;
            break;
        case VA_CHROMA_SITING_VERTICAL_BOTTOM:
            decProcessingParams->m_chromaSitingType = CODECHAL_CHROMA_SITING_VERT_BOTTOM;
            break;
        default:
            decProcessingParams->m_chromaSitingType = CODECHAL_CHROMA_SITING_NONE;
            break;
        }

        if (decProcessingParams->m_chromaSitingType != CODECHAL_CHROMA_SITING_NONE)
        {
            // Set the horizontal chroma siting info
            chromaSitingFlags = procBuf->input_color_properties.chroma_sample_location & 0xc;

            switch (chromaSitingFlags)
            {
            case VA_CHROMA_SITING_HORIZONTAL_LEFT:
                decProcessingParams->m_chromaSitingType |= CODECHAL_CHROMA_SITING_HORZ_LEFT;
                break;
            case VA_CHROMA_SITING_HORIZONTAL_CENTER:
                decProcessingParams->m_chromaSitingType |= CODECHAL_CHROMA_SITING_HORZ_CENTER;
                break;
            default:
                decProcessingParams->m_chromaSitingType = CODECHAL_CHROMA_SITING_NONE;
                break;
            }
        }
    }

    return VA_STATUS_SUCCESS;
#else
    return VA_STATUS_ERROR_INVALID_PARAMETER;
#endif
}

VAStatus DdiMediaDecode::BeginPicture(
    VADriverContextP ctx,
    VAContextID      context,
    VASurfaceID      renderTarget)
{
    DDI_FUNCTION_ENTER();

    PDDI_MEDIA_CONTEXT mediaCtx;

    /* As it is already checked in the upper caller, skip the check */
    mediaCtx = DdiMedia_GetMediaContext(ctx);

#ifdef _DECODE_PROCESSING_SUPPORTED
    //renderTarget is decode output surface; set renderTarget as vp sfc input surface m_procBuf->surface = rederTarget
    if(m_procBuf)
    {
        m_procBuf->surface = renderTarget;
    }
#endif

    DDI_MEDIA_SURFACE *curRT;
    curRT = (DDI_MEDIA_SURFACE *)DdiMedia_GetSurfaceFromVASurfaceID(mediaCtx, renderTarget);
    DDI_CHK_NULL(curRT, "nullptr pCurRT", VA_STATUS_ERROR_INVALID_SURFACE);
    curRT->pDecCtx = m_ddiDecodeCtx;

    DDI_CODEC_RENDER_TARGET_TABLE *RTtbl;
    RTtbl             = &(m_ddiDecodeCtx->RTtbl);
    RTtbl->pCurrentRT = curRT;

    m_streamOutEnabled              = false;
    m_ddiDecodeCtx->DecodeParams.m_numSlices       = 0;
    m_ddiDecodeCtx->DecodeParams.m_dataSize        = 0;
    m_ddiDecodeCtx->DecodeParams.m_dataOffset      = 0;
    m_ddiDecodeCtx->DecodeParams.m_deblockDataSize = 0;
    m_ddiDecodeCtx->DecodeParams.m_executeCallIndex = 0;
    m_ddiDecodeCtx->DecodeParams.m_cencBuf         = nullptr;
    m_groupIndex                                   = 0;

    // register render targets
    DDI_CHK_RET(RegisterRTSurfaces(&m_ddiDecodeCtx->RTtbl, curRT),"RegisterRTSurfaces failed!");

    if (nullptr == m_ddiDecodeCtx->pCodecHal)
    {
        return VA_STATUS_ERROR_ALLOCATION_FAILED;
    }

    MOS_STATUS eStatus = m_ddiDecodeCtx->pCodecHal->BeginFrame();
    if (eStatus != MOS_STATUS_SUCCESS)
    {
        return VA_STATUS_ERROR_DECODING_ERROR;
    }

    DDI_FUNCTION_EXIT(VA_STATUS_SUCCESS);
    return VA_STATUS_SUCCESS;
}

VAStatus DdiMediaDecode::DecodeCombineBitstream(DDI_MEDIA_CONTEXT *mediaCtx)
{
    DDI_CODEC_COM_BUFFER_MGR *bufMgr;
    /* As it is checked in previous caller, it is skipped. */
    bufMgr = &(m_ddiDecodeCtx->BufMgr);

    if (bufMgr && (bufMgr->bIsSliceOverSize == false))
    {
        return VA_STATUS_SUCCESS;
    }

    PDDI_MEDIA_BUFFER newBitstreamBuffer;
    //allocate a new bit stream buffer
    newBitstreamBuffer = (DDI_MEDIA_BUFFER *)MOS_AllocAndZeroMemory(sizeof(DDI_MEDIA_BUFFER));
    if (newBitstreamBuffer == nullptr)
    {
        DDI_ASSERTMESSAGE("DDI:AllocAndZeroMem return failure.");
        return VA_STATUS_ERROR_DECODING_ERROR;
    }

    newBitstreamBuffer->iSize     = m_ddiDecodeCtx->DecodeParams.m_dataSize;
    newBitstreamBuffer->uiType    = VASliceDataBufferType;
    newBitstreamBuffer->format    = Media_Format_Buffer;
    newBitstreamBuffer->uiOffset  = 0;
    newBitstreamBuffer->pMediaCtx = mediaCtx;

    VAStatus vaStatus;
    vaStatus = DdiMediaUtil_CreateBuffer(newBitstreamBuffer,
        mediaCtx->pDrmBufMgr);
    if (vaStatus != VA_STATUS_SUCCESS)
    {
        MOS_FreeMemory(newBitstreamBuffer);
        newBitstreamBuffer = nullptr;
        return VA_STATUS_ERROR_ALLOCATION_FAILED;
    }

    uint8_t *newBitStreamBase;
    newBitStreamBase = (uint8_t *)DdiMediaUtil_LockBuffer(newBitstreamBuffer, MOS_LOCKFLAG_WRITEONLY);

    if (newBitStreamBase == nullptr)
    {
        DdiMediaUtil_FreeBuffer(newBitstreamBuffer);
        MOS_FreeMemory(newBitstreamBuffer);
        newBitstreamBuffer = nullptr;
        return VA_STATUS_ERROR_ALLOCATION_FAILED;
    }

    uint32_t slcInd;
    //copy data to new bit stream
    for (slcInd = 0; slcInd < bufMgr->dwNumSliceData; slcInd++)
    {
        if (bufMgr->pSliceData[slcInd].bIsUseExtBuf == true)
        {
            if (bufMgr->pSliceData[slcInd].pSliceBuf)
            {
                MOS_SecureMemcpy(newBitStreamBase + bufMgr->pSliceData[slcInd].uiOffset,
                    bufMgr->pSliceData[slcInd].uiLength,
                    bufMgr->pSliceData[slcInd].pSliceBuf,
                    bufMgr->pSliceData[slcInd].uiLength);
                MOS_FreeMemory(bufMgr->pSliceData[slcInd].pSliceBuf);
                bufMgr->pSliceData[slcInd].pSliceBuf    = nullptr;
                bufMgr->pSliceData[slcInd].bIsUseExtBuf = false;
            }
        }
        else
        {
            MOS_SecureMemcpy(newBitStreamBase + bufMgr->pSliceData[slcInd].uiOffset,
                bufMgr->pSliceData[slcInd].uiLength,
                bufMgr->pBitStreamBase[bufMgr->dwBitstreamIndex] + bufMgr->pSliceData[slcInd].uiOffset,
                bufMgr->pSliceData[slcInd].uiLength);
        }
    }

    //free original buffers
    if (bufMgr->pBitStreamBase[bufMgr->dwBitstreamIndex])
    {
        DdiMediaUtil_UnlockBuffer(bufMgr->pBitStreamBuffObject[bufMgr->dwBitstreamIndex]);
        bufMgr->pBitStreamBase[bufMgr->dwBitstreamIndex] = nullptr;
    }

    if (bufMgr->pBitStreamBuffObject[bufMgr->dwBitstreamIndex])
    {
        DdiMediaUtil_FreeBuffer(bufMgr->pBitStreamBuffObject[bufMgr->dwBitstreamIndex]);
        MOS_FreeMemory(bufMgr->pBitStreamBuffObject[bufMgr->dwBitstreamIndex]);
        bufMgr->pBitStreamBuffObject[bufMgr->dwBitstreamIndex] = nullptr;
    }

    //set new bitstream buffer
    bufMgr->pBitStreamBuffObject[bufMgr->dwBitstreamIndex] = newBitstreamBuffer;
    bufMgr->pBitStreamBase[bufMgr->dwBitstreamIndex]       = newBitStreamBase;
    DdiMedia_MediaBufferToMosResource(m_ddiDecodeCtx->BufMgr.pBitStreamBuffObject[bufMgr->dwBitstreamIndex], &m_ddiDecodeCtx->BufMgr.resBitstreamBuffer);

    return VA_STATUS_SUCCESS;
}

void DdiMediaDecode::DestroyContext(VADriverContextP ctx)
{
    Codechal *codecHal;
    /* as they are already checked in caller, this is skipped */
    codecHal = m_ddiDecodeCtx->pCodecHal;

    if (codecHal != nullptr)
    {
        if (codecHal->GetOsInterface() && codecHal->GetOsInterface()->pOsContext)
        {
            MOS_FreeMemory(codecHal->GetOsInterface()->pOsContext->pPerfData);
            codecHal->GetOsInterface()->pOsContext->pPerfData = nullptr;
        }

        // destroy codechal
        codecHal->Destroy();
        MOS_Delete(codecHal);

        m_ddiDecodeCtx->pCodecHal = nullptr;
    }

    int32_t i;
    for (i = 0; i < DDI_MEDIA_MAX_SURFACE_NUMBER_CONTEXT; i++)
    {
        if ((m_ddiDecodeCtx->RTtbl.pRT[i] != nullptr) &&
            (m_ddiDecodeCtx->RTtbl.pRT[i]->pDecCtx == m_ddiDecodeCtx))
        {
            m_ddiDecodeCtx->RTtbl.pRT[i]->pDecCtx = nullptr;
        }
    }

    if (m_ddiDecodeCtx->pCpDdiInterface)
    {
        Delete_DdiCpInterface(m_ddiDecodeCtx->pCpDdiInterface);
        m_ddiDecodeCtx->pCpDdiInterface = nullptr;
    }

    MOS_FreeMemory(m_ddiDecodeCtx->DecodeParams.m_iqMatrixBuffer);
    m_ddiDecodeCtx->DecodeParams.m_iqMatrixBuffer = nullptr;

    MOS_FreeMemory(m_ddiDecodeCtx->DecodeParams.m_huffmanTable);
    m_ddiDecodeCtx->DecodeParams.m_huffmanTable = nullptr;

    MOS_FreeMemory(m_ddiDecodeCtx->DecodeParams.m_picParams);
    m_ddiDecodeCtx->DecodeParams.m_picParams = nullptr;

    MOS_FreeMemory(m_ddiDecodeCtx->DecodeParams.m_sliceParams);
    m_ddiDecodeCtx->DecodeParams.m_sliceParams = nullptr;

    MOS_FreeMemory(m_ddiDecodeCtx->DecodeParams.m_extPicParams);
    m_ddiDecodeCtx->DecodeParams.m_sliceParams = nullptr;

    MOS_FreeMemory(m_ddiDecodeCtx->DecodeParams.m_advPicParams);
    m_ddiDecodeCtx->DecodeParams.m_sliceParams = nullptr;

    MOS_FreeMemory(m_ddiDecodeCtx->DecodeParams.m_extSliceParams);
    m_ddiDecodeCtx->DecodeParams.m_sliceParams = nullptr;

    MOS_FreeMemory(m_ddiDecodeCtx->DecodeParams.m_subsetParams);
    m_ddiDecodeCtx->DecodeParams.m_sliceParams = nullptr;

#ifdef _DECODE_PROCESSING_SUPPORTED
    if (m_ddiDecodeCtx->DecodeParams.m_procParams != nullptr)
    {
        auto procParams =
            (DecodeProcessingParams *)m_ddiDecodeCtx->DecodeParams.m_procParams;
        MOS_FreeMemory(procParams->m_outputSurface);
        procParams->m_outputSurface = nullptr;

        MOS_FreeMemory(m_ddiDecodeCtx->DecodeParams.m_procParams);
        m_ddiDecodeCtx->DecodeParams.m_procParams = nullptr;
    }
#endif

    return;
}

int32_t DdiMediaDecode::GetBitstreamBufIndexFromBuffer(DDI_CODEC_COM_BUFFER_MGR *bufMgr, DDI_MEDIA_BUFFER *buf)
{
    int32_t i;
    for(i = 0; i < DDI_CODEC_MAX_BITSTREAM_BUFFER; i++)
    {
        if(bufMgr->pBitStreamBuffObject[i]->bo == buf->bo)
        {
            return i;
        }
    }

    return DDI_CODEC_INVALID_BUFFER_INDEX;
}

VAStatus DdiMediaDecode::AllocBsBuffer(
    DDI_CODEC_COM_BUFFER_MGR    *bufMgr,
    DDI_MEDIA_BUFFER            *buf)
{
    uint32_t          index, i;
    VAStatus          vaStatus;
    uint8_t          *sliceBuf;
    DDI_MEDIA_BUFFER *bsBufObj = nullptr;
    uint8_t          *bsBufBaseAddr = nullptr;
    bool              createBsBuffer = false;

    if ( nullptr == bufMgr || nullptr == buf || nullptr == (m_ddiDecodeCtx->pMediaCtx) )
    {
        DDI_ASSERTMESSAGE("invalidate input parameters.");
        return VA_STATUS_ERROR_ALLOCATION_FAILED;
    }

    index       = bufMgr->dwNumSliceData;
    vaStatus    = VA_STATUS_SUCCESS;
    sliceBuf   = nullptr;

    /* the pSliceData needs to be reallocated in order to contain more SliceDataBuf */
    if (index >= bufMgr->m_maxNumSliceData)
    {
        /* In theroy it can resize the m_maxNumSliceData one by one. But in order to
         * avoid calling realloc frequently, it will try to allocate 10 to  hold more
         * SliceDataBuf. This is only for the optimized purpose.
         */
        int32_t reallocSize = bufMgr->m_maxNumSliceData + 10;

        bufMgr->pSliceData = (DDI_CODEC_BITSTREAM_BUFFER_INFO *)realloc(bufMgr->pSliceData, sizeof(bufMgr->pSliceData[0]) * reallocSize);

        if (bufMgr->pSliceData == nullptr)
        {
            DDI_ASSERTMESSAGE("fail to reallocate pSliceData\n.");
            return VA_STATUS_ERROR_ALLOCATION_FAILED;
        }
        memset(bufMgr->pSliceData + bufMgr->m_maxNumSliceData, 0,
               sizeof(bufMgr->pSliceData[0]) * 10);

        bufMgr->m_maxNumSliceData += 10;
    }

    if(index >= 1)
    {
        buf->uiOffset = bufMgr->pSliceData[index-1].uiOffset + bufMgr->pSliceData[index-1].uiLength;
        if((buf->uiOffset + buf->iSize) > bufMgr->pBitStreamBuffObject[bufMgr->dwBitstreamIndex]->iSize)
        {
            sliceBuf = (uint8_t*)MOS_AllocAndZeroMemory(buf->iSize);
            if(sliceBuf == nullptr)
            {
                DDI_ASSERTMESSAGE("DDI:AllocAndZeroMem return failure.")
                return VA_STATUS_ERROR_ALLOCATION_FAILED;
            }
            bufMgr->bIsSliceOverSize = true;
        }
        else
        {
            bufMgr->bIsSliceOverSize = false;
        }
    }
    else
    {
        bufMgr->bIsSliceOverSize = false;
        for (i = 0; i < DDI_CODEC_MAX_BITSTREAM_BUFFER; i++)
        {
            if (bufMgr->pBitStreamBuffObject[i]->bo != nullptr)
            {
                if (!mos_bo_busy(bufMgr->pBitStreamBuffObject[i]->bo))
                {
                    //find a bitstream buffer whoes graphic memory is allocated but not used by HW now.
                    break;
                }
            }
            else
            {
                //find a new bitstream buffer whoes graphic memory is not allocated yet
                break;
            }
        }

        if (i == DDI_CODEC_MAX_BITSTREAM_BUFFER)
        {
            //find the oldest bistream buffer which is the most possible one to become free in the shortest time.
            bufMgr->dwBitstreamIndex = (bufMgr->ui64BitstreamOrder >> (DDI_CODEC_BITSTREAM_BUFFER_INDEX_BITS * DDI_CODEC_MAX_BITSTREAM_BUFFER_MINUS1)) & DDI_CODEC_MAX_BITSTREAM_BUFFER_INDEX;
            // wait until decode complete
            mos_bo_wait_rendering(bufMgr->pBitStreamBuffObject[bufMgr->dwBitstreamIndex]->bo);
        }
        else
        {
            bufMgr->dwBitstreamIndex = i;
        }
        bufMgr->ui64BitstreamOrder = (bufMgr->ui64BitstreamOrder << 4) + bufMgr->dwBitstreamIndex;

        bsBufObj                   = bufMgr->pBitStreamBuffObject[bufMgr->dwBitstreamIndex];
        bsBufObj ->pMediaCtx       = m_ddiDecodeCtx->pMediaCtx;
        bsBufBaseAddr              = bufMgr->pBitStreamBase[bufMgr->dwBitstreamIndex];

        if(bsBufBaseAddr == nullptr)
        {
            createBsBuffer = true;
            if (buf->iSize > bsBufObj->iSize)
            {
                bsBufObj->iSize = buf->iSize;
            }
        }
        else if(buf->iSize > bsBufObj->iSize)
        {
           //free bo
            DdiMediaUtil_UnlockBuffer(bsBufObj);
            DdiMediaUtil_FreeBuffer(bsBufObj);
            bsBufBaseAddr = nullptr;

            createBsBuffer = true;
            bsBufObj->iSize = buf->iSize;
        }

        if (createBsBuffer)
        {
            if(VA_STATUS_SUCCESS != DdiMediaUtil_CreateBuffer(bsBufObj, m_ddiDecodeCtx->pMediaCtx->pDrmBufMgr))
            {
               return VA_STATUS_ERROR_ALLOCATION_FAILED;
            }

            bsBufBaseAddr = (uint8_t*)DdiMediaUtil_LockBuffer(bsBufObj, MOS_LOCKFLAG_WRITEONLY);
            if(bsBufBaseAddr == nullptr)
            {
                DdiMediaUtil_FreeBuffer(bsBufObj);
                return VA_STATUS_ERROR_ALLOCATION_FAILED;
            }
            bufMgr->pBitStreamBase[bufMgr->dwBitstreamIndex] = bsBufBaseAddr;
        }
    }

    if(bufMgr->pBitStreamBase[bufMgr->dwBitstreamIndex] == nullptr)
    {
        return VA_STATUS_ERROR_ALLOCATION_FAILED;
    }

    bufMgr->pSliceData[index].uiLength = buf->iSize;
    bufMgr->pSliceData[index].uiOffset = buf->uiOffset;

    if(bufMgr->bIsSliceOverSize == true)
    {
        buf->pData                              = sliceBuf;
        buf->uiOffset                           = 0;
        bufMgr->pSliceData[index].bIsUseExtBuf  = true;
        bufMgr->pSliceData[index].pSliceBuf     = sliceBuf;
        buf->bCFlushReq                         = false;
    }
    else
    {
        buf->pData                              = (uint8_t*)(bufMgr->pBitStreamBase[bufMgr->dwBitstreamIndex]);
        bufMgr->pSliceData[index].bIsUseExtBuf  = false;
        bufMgr->pSliceData[index].pSliceBuf     = nullptr;
        buf->bCFlushReq                         = true;
    }

    bufMgr->dwNumSliceData ++;
    buf->bo                            = bufMgr->pBitStreamBuffObject[bufMgr->dwBitstreamIndex]->bo;

    return VA_STATUS_SUCCESS;
}

MOS_FORMAT DdiMediaDecode::GetFormat()
{
    return  Format_NV12;
}

VAStatus DdiMediaDecode::InitDecodeParams(
    VADriverContextP ctx,
    VAContextID      context)
{
    /* skip the mediaCtx check as it is checked in caller */
    PDDI_MEDIA_CONTEXT mediaCtx;
    mediaCtx = DdiMedia_GetMediaContext(ctx);
    DDI_CHK_RET(DecodeCombineBitstream(mediaCtx),"DecodeCombineBitstream failed!");
    DDI_CODEC_COM_BUFFER_MGR *bufMgr = &(m_ddiDecodeCtx->BufMgr);
    bufMgr->dwNumSliceData    = 0;
    bufMgr->dwNumSliceControl = 0;
    memset(&m_destSurface, 0, sizeof(MOS_SURFACE));
    m_destSurface.dwOffset = 0;

    DDI_CODEC_RENDER_TARGET_TABLE *rtTbl = &(m_ddiDecodeCtx->RTtbl);

    if ((rtTbl == nullptr) || (rtTbl->pCurrentRT == nullptr))
    {
        return VA_STATUS_ERROR_INVALID_PARAMETER;
    }
    return VA_STATUS_SUCCESS;

}

VAStatus DdiMediaDecode::SetDecodeParams()
{
    DDI_CODEC_COM_BUFFER_MGR *bufMgr = &(m_ddiDecodeCtx->BufMgr);
    if ((&m_ddiDecodeCtx->DecodeParams)->m_numSlices == 0)
    {
        return VA_STATUS_ERROR_INVALID_PARAMETER;
    }

    MOS_FORMAT expectedFormat = GetFormat();
    m_destSurface.Format   = expectedFormat;
    DdiMedia_MediaSurfaceToMosResource((&(m_ddiDecodeCtx->RTtbl))->pCurrentRT, &(m_destSurface.OsResource));

    if (m_destSurface.OsResource.Format != expectedFormat)
    {
        DDI_NORMALMESSAGE("Surface fomrat of decoded surface is inconsistent with Codec bitstream\n");
        return VA_STATUS_ERROR_INVALID_PARAMETER;
    }

    m_ddiDecodeCtx->DecodeParams.m_destSurface = &m_destSurface;
    m_ddiDecodeCtx->DecodeParams.m_deblockSurface = nullptr;

    m_ddiDecodeCtx->DecodeParams.m_dataBuffer    = &bufMgr->resBitstreamBuffer;
    m_ddiDecodeCtx->DecodeParams.m_bitStreamBufData = bufMgr->pBitstreamBuffer;

    m_ddiDecodeCtx->DecodeParams.m_bitplaneBuffer = nullptr;

    if (m_streamOutEnabled)
    {
        m_ddiDecodeCtx->DecodeParams.m_streamOutEnabled           = true;
        m_ddiDecodeCtx->DecodeParams.m_externalStreamOutBuffer    = &bufMgr->resExternalStreamOutBuffer;
    }
    else
    {
        m_ddiDecodeCtx->DecodeParams.m_streamOutEnabled           = false;
        m_ddiDecodeCtx->DecodeParams.m_externalStreamOutBuffer    = nullptr;
    }

    if (m_ddiDecodeCtx->pCpDdiInterface)
    {
        DDI_CHK_RET(m_ddiDecodeCtx->pCpDdiInterface->SetDecodeParams(m_ddiDecodeCtx, m_codechalSettings),"SetDecodeParams failed!");
    }

    Mos_Solo_OverrideBufferSize(m_ddiDecodeCtx->DecodeParams.m_dataSize, m_ddiDecodeCtx->DecodeParams.m_dataBuffer);

    return VA_STATUS_SUCCESS;
}

VAStatus DdiMediaDecode::ExtraDownScaling(
        VADriverContextP         ctx,
        VAContextID              context)
{
#ifdef _DECODE_PROCESSING_SUPPORTED
    DDI_CHK_NULL(ctx, "nullptr ctx", VA_STATUS_ERROR_INVALID_CONTEXT);
    VAStatus vaStatus = MOS_STATUS_SUCCESS;
    PDDI_MEDIA_CONTEXT mediaCtx = DdiMedia_GetMediaContext(ctx);
    DDI_CHK_NULL(mediaCtx, "nullptr ctx", VA_STATUS_ERROR_INVALID_CONTEXT);
    DDI_CHK_NULL(m_ddiDecodeCtx, "nullptr ctx", VA_STATUS_ERROR_INVALID_CONTEXT);

    bool isDecodeDownScalingSupported = false;
    if (m_ddiDecodeCtx->pCodecHal->IsApogeiosEnabled())
    {
        DecodePipelineAdapter *decoder = dynamic_cast<DecodePipelineAdapter *>(m_ddiDecodeCtx->pCodecHal);
        DDI_CHK_NULL(decoder, "nullptr decoder", VA_STATUS_ERROR_INVALID_PARAMETER);
        isDecodeDownScalingSupported = decoder->IsDownSamplingSupported();
    }
    else
    {
        CodechalDecode *decoder = dynamic_cast<CodechalDecode *>(m_ddiDecodeCtx->pCodecHal);
        DDI_CHK_NULL(decoder, "nullptr decoder", VA_STATUS_ERROR_INVALID_PARAMETER);
        isDecodeDownScalingSupported = decoder->IsVdSfcSupported();
    }

    if(m_ddiDecodeCtx->DecodeParams.m_procParams != nullptr &&
       m_procBuf &&
       !isDecodeDownScalingSupported)
    {
        //check vp context
        VAContextID vpCtxID = VA_INVALID_ID;
        if (mediaCtx->pVpCtxHeap != nullptr && mediaCtx->pVpCtxHeap->pHeapBase != nullptr)
        {
            //Get VP Context from heap.
            vpCtxID = (VAContextID)(0 + DDI_MEDIA_VACONTEXTID_OFFSET_VP);
        }
        else
        {
            //Create VP Context.
            vaStatus = DdiVp_CreateContext(ctx, 0, 0, 0, 0, 0, 0, &vpCtxID);
            DDI_CHK_RET(vaStatus, "Create VP Context failed.");
        }

        uint32_t        ctxType;
        PDDI_VP_CONTEXT pVpCtx = (PDDI_VP_CONTEXT)DdiMedia_GetContextFromContextID(ctx, vpCtxID, &ctxType);
        DDI_CHK_NULL(pVpCtx, "nullptr pVpCtx", VA_STATUS_ERROR_INVALID_CONTEXT);

        //Set parameters
        VAProcPipelineParameterBuffer* pInputPipelineParam = m_procBuf;
        DDI_CHK_NULL(pInputPipelineParam, "nullptr pInputPipelineParam", VA_STATUS_ERROR_ALLOCATION_FAILED);

        vaStatus = DdiVp_BeginPicture(ctx, vpCtxID, pInputPipelineParam->additional_outputs[0]);
        DDI_CHK_RET(vaStatus, "VP BeginPicture failed");

        vaStatus = DdiVp_SetProcPipelineParams(ctx, pVpCtx, pInputPipelineParam);
        DDI_CHK_RET(vaStatus, "VP SetProcPipelineParams failed.");

        vaStatus = DdiVp_EndPicture(ctx, vpCtxID);
        DDI_CHK_RET(vaStatus, "VP EndPicture failed.");
    }
#endif
    return MOS_STATUS_SUCCESS;
}

VAStatus DdiMediaDecode::InitDummyReference(CodechalDecode& decoder)
{
    PMOS_SURFACE dummyReference = decoder.GetDummyReference();

    // If dummy reference is from decode output surface, need to update frame by frame
    if (decoder.GetDummyReferenceStatus() == CODECHAL_DUMMY_REFERENCE_DEST_SURFACE)
    {
        MOS_ZeroMemory(dummyReference, sizeof(MOS_SURFACE));
        decoder.SetDummyReferenceStatus(CODECHAL_DUMMY_REFERENCE_INVALID);
    }

    if (!Mos_ResourceIsNull(&dummyReference->OsResource))
    {
        Mos_Specific_GetResourceInfo(decoder.GetOsInterface(), &dummyReference->OsResource, dummyReference);

        // Check if need to re-get dummy reference from DPB or re-allocated
        if (dummyReference->dwWidth < m_ddiDecodeCtx->DecodeParams.m_destSurface->dwWidth ||
            dummyReference->dwHeight < m_ddiDecodeCtx->DecodeParams.m_destSurface->dwHeight)
        {
            // Check if the dummy reference needs to be re-allocated
            if (decoder.GetDummyReferenceStatus() == CODECHAL_DUMMY_REFERENCE_ALLOCATED)
            {
                decoder.GetOsInterface()->pfnFreeResource(decoder.GetOsInterface(), &dummyReference->OsResource);
            }

            // Reset dummy reference
            MOS_ZeroMemory(dummyReference, sizeof(MOS_SURFACE));
            decoder.SetDummyReferenceStatus(CODECHAL_DUMMY_REFERENCE_INVALID);

            // Considering potential risk, disable the dummy reference from DPB path temporarily
            //GetDummyReferenceFromDPB(m_ddiDecodeCtx);

            //if (!Mos_ResourceIsNull(&dummyReference->OsResource))
            //{
            //    decoder->SetDummyReferenceStatus(CODECHAL_DUMMY_REFERENCE_DPB);
            //}
        }
    }
    else
    {
        // Init dummy reference
        MOS_ZeroMemory(dummyReference, sizeof(MOS_SURFACE));
        decoder.SetDummyReferenceStatus(CODECHAL_DUMMY_REFERENCE_INVALID);

        // Considering potential risk, disable the dummy reference from DPB path temporarily
        //GetDummyReferenceFromDPB(m_ddiDecodeCtx);
        //if (!Mos_ResourceIsNull(&dummyReference->OsResource))
        //{
        //    decoder->SetDummyReferenceStatus(CODECHAL_DUMMY_REFERENCE_DPB);
        //}
    }

    return VA_STATUS_SUCCESS;
}

VAStatus DdiMediaDecode::InitDummyReference(DecodePipelineAdapter& decoder)
{
    PMOS_SURFACE dummyReference = decoder.GetDummyReference();

    // If dummy reference is from decode output surface, need to update frame by frame
    if (decoder.GetDummyReferenceStatus() == CODECHAL_DUMMY_REFERENCE_DEST_SURFACE)
    {
        MOS_ZeroMemory(dummyReference, sizeof(MOS_SURFACE));
        decoder.SetDummyReferenceStatus(CODECHAL_DUMMY_REFERENCE_INVALID);
    }

    if (!Mos_ResourceIsNull(&dummyReference->OsResource))
    {
        Mos_Specific_GetResourceInfo(decoder.GetOsInterface(), &dummyReference->OsResource, dummyReference);

        // Check if need to re-get dummy reference from DPB or re-allocated
        if (dummyReference->dwWidth < m_ddiDecodeCtx->DecodeParams.m_destSurface->dwWidth ||
            dummyReference->dwHeight < m_ddiDecodeCtx->DecodeParams.m_destSurface->dwHeight)
        {
            // Check if the dummy reference needs to be re-allocated
            if (decoder.GetDummyReferenceStatus() == CODECHAL_DUMMY_REFERENCE_ALLOCATED)
            {
                decoder.GetOsInterface()->pfnFreeResource(decoder.GetOsInterface(), &dummyReference->OsResource);
            }

            // Reset dummy reference
            MOS_ZeroMemory(dummyReference, sizeof(MOS_SURFACE));
            decoder.SetDummyReferenceStatus(CODECHAL_DUMMY_REFERENCE_INVALID);

            // Considering potential risk, disable the dummy reference from DPB path temporarily
            //GetDummyReferenceFromDPB(m_ddiDecodeCtx);

            //if (!Mos_ResourceIsNull(&dummyReference->OsResource))
            //{
            //    decoder->SetDummyReferenceStatus(CODECHAL_DUMMY_REFERENCE_DPB);
            //}
        }
    }
    else
    {
        // Init dummy reference
        MOS_ZeroMemory(dummyReference, sizeof(MOS_SURFACE));
        decoder.SetDummyReferenceStatus(CODECHAL_DUMMY_REFERENCE_INVALID);

        // Considering potential risk, disable the dummy reference from DPB path temporarily
        //GetDummyReferenceFromDPB(m_ddiDecodeCtx);
        //if (!Mos_ResourceIsNull(&dummyReference->OsResource))
        //{
        //    decoder->SetDummyReferenceStatus(CODECHAL_DUMMY_REFERENCE_DPB);
        //}
    }

    return VA_STATUS_SUCCESS;
}

VAStatus DdiMediaDecode::EndPicture(
    VADriverContextP ctx,
    VAContextID      context)
{
    DDI_FUNCTION_ENTER();

    if (m_ddiDecodeCtx->bDecodeModeReported == false)
    {
        ReportDecodeMode(m_ddiDecodeCtx->wMode);
        m_ddiDecodeCtx->bDecodeModeReported = true;
    }

    DDI_CHK_RET(InitDecodeParams(ctx,context),"InitDecodeParams failed!");

    DDI_CHK_RET(SetDecodeParams(), "SetDecodeParams failed!");
    DDI_CHK_RET(ClearRefList(&(m_ddiDecodeCtx->RTtbl), m_withDpb), "ClearRefList failed!");
    if (m_ddiDecodeCtx->pCodecHal == nullptr)
    {
        return VA_STATUS_ERROR_ALLOCATION_FAILED;
    }

    if (MEDIA_IS_WA(&m_ddiDecodeCtx->pMediaCtx->WaTable, WaDummyReference))
    {
        Mos_Specific_GetResourceInfo(
            m_ddiDecodeCtx->pCodecHal->GetOsInterface(), 
            &m_ddiDecodeCtx->DecodeParams.m_destSurface->OsResource,
            m_ddiDecodeCtx->DecodeParams.m_destSurface);

        if(m_ddiDecodeCtx->pCodecHal->IsApogeiosEnabled())
        {
            DecodePipelineAdapter *decoder = dynamic_cast<DecodePipelineAdapter *>(m_ddiDecodeCtx->pCodecHal);
            DDI_CHK_NULL(decoder, "Null decoder", VA_STATUS_ERROR_INVALID_PARAMETER);
            DDI_CHK_RET(InitDummyReference(*decoder), "InitDummyReference failed!");
        }
        else
        {
            CodechalDecode *decoder = dynamic_cast<CodechalDecode *>(m_ddiDecodeCtx->pCodecHal);
            DDI_CHK_NULL(decoder, "Null decoder", VA_STATUS_ERROR_INVALID_PARAMETER);
            DDI_CHK_RET(InitDummyReference(*decoder), "InitDummyReference failed!");
        }
    }

    MOS_STATUS status = m_ddiDecodeCtx->pCodecHal->Execute((void *)(&m_ddiDecodeCtx->DecodeParams));
    if (status != MOS_STATUS_SUCCESS)
    {
        DDI_ASSERTMESSAGE("DDI:DdiDecode_DecodeInCodecHal return failure.");
        return VA_STATUS_ERROR_DECODING_ERROR;
    }

    m_ddiDecodeCtx->DecodeParams.m_executeCallIndex++;

    (&(m_ddiDecodeCtx->RTtbl))->pCurrentRT = nullptr;

    status = m_ddiDecodeCtx->pCodecHal->EndFrame();
    if (status != MOS_STATUS_SUCCESS)
    {
        return VA_STATUS_ERROR_DECODING_ERROR;
    }

#ifdef _DECODE_PROCESSING_SUPPORTED
    if (ExtraDownScaling(ctx,context) != VA_STATUS_SUCCESS)
    {
        return VA_STATUS_ERROR_DECODING_ERROR;
    }
#endif

    DDI_FUNCTION_EXIT(VA_STATUS_SUCCESS);
    return VA_STATUS_SUCCESS;
}

VAStatus DdiMediaDecode::CreateBuffer(
    VABufferType             type,
    uint32_t                 size,
    uint32_t                 numElements,
    void                    *data,
    VABufferID              *bufId)
{
    DDI_MEDIA_BUFFER                *buf;
    PDDI_MEDIA_BUFFER_HEAP_ELEMENT   bufferHeapElement;
    uint16_t                         segMapWidth, segMapHeight;
    MOS_STATUS                       status = MOS_STATUS_SUCCESS;
    VAStatus                         va = VA_STATUS_SUCCESS;

    segMapWidth = m_picWidthInMB;
    segMapHeight= m_picHeightInMB;

    // only for VASliceParameterBufferType of buffer, the number of elements can be greater than 1
    if(type != VASliceParameterBufferType && numElements > 1)
    {
        return VA_STATUS_ERROR_INVALID_PARAMETER;
    }

    buf               = (DDI_MEDIA_BUFFER *)MOS_AllocAndZeroMemory(sizeof(DDI_MEDIA_BUFFER));
    if (buf == nullptr)
    {
        return VA_STATUS_ERROR_ALLOCATION_FAILED;
    }
    buf->iSize         = size * numElements;
    buf->uiNumElements = numElements;
    buf->uiType        = type;
    buf->format        = Media_Format_Buffer;
    buf->uiOffset      = 0;
    buf->bCFlushReq    = false;
    buf->pMediaCtx     = m_ddiDecodeCtx->pMediaCtx;

    switch ((int32_t)type)
    {
        case VABitPlaneBufferType:
            buf->pData = (uint8_t*)((m_ddiDecodeCtx->BufMgr.Codec_Param.Codec_Param_VC1.pBitPlaneBuffer));
            break;
        case VASliceDataBufferType:
        case VAProtectedSliceDataBufferType:
            va = AllocBsBuffer(&(m_ddiDecodeCtx->BufMgr), buf);
            if(va != VA_STATUS_SUCCESS)
            {
                goto CleanUpandReturn;
            }

            break;
        case VASliceParameterBufferType:
            va = AllocSliceControlBuffer(buf);
            if(va != VA_STATUS_SUCCESS)
            {
                goto CleanUpandReturn;
            }
            buf->format     = Media_Format_CPU;
            break;
        case VAPictureParameterBufferType:
            buf->pData      = GetPicParamBuf(&(m_ddiDecodeCtx->BufMgr));
            buf->format     = Media_Format_CPU;
            break;
        case VASubsetsParameterBufferType:
            //maximum entry point supported should not be more than 440
            if(numElements > 440)
            {
                va = VA_STATUS_ERROR_INVALID_PARAMETER;
                goto CleanUpandReturn;
            }
            buf->pData      = (uint8_t*)MOS_AllocAndZeroMemory(size * numElements);
            buf->format     = Media_Format_CPU;
            break;
        case VAIQMatrixBufferType:
            buf->pData      = (uint8_t*)MOS_AllocAndZeroMemory(size * numElements);
            buf->format     = Media_Format_CPU;
            break;
        case VAProbabilityBufferType:
            buf->pData      = (uint8_t*)(&(m_ddiDecodeCtx->BufMgr.Codec_Param.Codec_Param_VP8.ProbabilityDataVP8));
            break;
        case VAProcFilterParameterBufferType:
            buf->pData      = (uint8_t*)MOS_AllocAndZeroMemory(sizeof(VAProcPipelineCaps));
            buf->format     = Media_Format_CPU;
            break;
        case VAProcPipelineParameterBufferType:
            buf->pData      = (uint8_t*)MOS_AllocAndZeroMemory(sizeof(VAProcPipelineParameterBuffer));
            buf->format     = Media_Format_CPU;
            break;
        case VADecodeStreamoutBufferType:
        {
            segMapHeight = ((segMapHeight + 1) >> 1);   //uiSize must be equal and bigger than size for interlaced case

            if (size < MOS_ALIGN_CEIL(segMapHeight * segMapWidth * CODEC_SIZE_MFX_STREAMOUT_DATA, 64))
            {
                va = VA_STATUS_ERROR_INVALID_PARAMETER;
                goto CleanUpandReturn;
            }
            buf->iSize  = size * numElements;
            buf->format = Media_Format_Buffer;
            va = DdiMediaUtil_CreateBuffer(buf, m_ddiDecodeCtx->pMediaCtx->pDrmBufMgr);
            if(va != VA_STATUS_SUCCESS)
            {
                goto CleanUpandReturn;
            }
            break;
        }
        case VAHuffmanTableBufferType:
            buf->pData      = (uint8_t*)MOS_AllocAndZeroMemory(size * numElements);
            buf->format     = Media_Format_CPU;
            break;
#if VA_CHECK_VERSION(1, 10, 0)
        case VAContextParameterUpdateBufferType:
        {
            buf->pData      = (uint8_t*)MOS_AllocAndZeroMemory(size * numElements);
            buf->format     = Media_Format_CPU;
            break;
        }
#endif
        default:
            va = m_ddiDecodeCtx->pCpDdiInterface->CreateBuffer(type, buf, size, numElements);
            if (va  == VA_STATUS_ERROR_UNSUPPORTED_BUFFERTYPE)
            {
                DDI_ASSERTMESSAGE("DDI:Decode CreateBuffer unsuppoted buffer type.");
                buf->pData      = (uint8_t*)MOS_AllocAndZeroMemory(size * numElements);
                buf->format     = Media_Format_CPU;
                if(buf->pData != NULL)
                {
                    va = VA_STATUS_SUCCESS;
                }
            }
            break;
    }

    bufferHeapElement  = DdiMediaUtil_AllocPMediaBufferFromHeap(m_ddiDecodeCtx->pMediaCtx->pBufferHeap);
    if (nullptr == bufferHeapElement)
    {
        va = VA_STATUS_ERROR_MAX_NUM_EXCEEDED;
        goto CleanUpandReturn;
    }
    bufferHeapElement->pBuffer      = buf;
    bufferHeapElement->pCtx         = (void*)m_ddiDecodeCtx;
    bufferHeapElement->uiCtxType    = DDI_MEDIA_CONTEXT_TYPE_DECODER;
    *bufId                          = bufferHeapElement->uiVaBufferID;

    // Keep record the VaBufferID of JPEG slice data buffer we allocated, in order to do buffer mapping when render this buffer. otherwise we
    // can not get correct buffer address when application create them disordered.
    if (type == VASliceDataBufferType && m_ddiDecodeCtx->wMode == CODECHAL_DECODE_MODE_JPEG)
    {
        // since the dwNumSliceData already +1 when allocate buffer, but here we need to track the VaBufferID before dwSliceData increased.
        m_ddiDecodeCtx->BufMgr.pSliceData[m_ddiDecodeCtx->BufMgr.dwNumSliceData - 1].vaBufferId = *bufId;
    }
    m_ddiDecodeCtx->pMediaCtx->uiNumBufs++;

    if(data == nullptr)
    {
        return va;
    }

    if( true == buf->bCFlushReq )
    {
        mos_bo_wait_rendering(buf->bo);
    }
    status = MOS_SecureMemcpy((void *)(buf->pData + buf->uiOffset), size * numElements, data, size * numElements);
    DDI_CHK_CONDITION((status != MOS_STATUS_SUCCESS), "DDI:Failed to copy buffer data!", VA_STATUS_ERROR_OPERATION_FAILED);
    return va;

CleanUpandReturn:
    if(buf)
    {
        MOS_FreeMemory(buf->pData);
        MOS_FreeMemory(buf);
    }
    return va;

}

void DdiMediaDecode::ContextInit(
    int32_t picWidth,
    int32_t picHeight)
{
    m_width           = picWidth;
    m_height          = picHeight;
    m_picWidthInMB     = (int16_t)(DDI_CODEC_NUM_MACROBLOCKS_WIDTH(picWidth));
    m_picHeightInMB    = (int16_t)(DDI_CODEC_NUM_MACROBLOCKS_HEIGHT(picHeight));
    m_ddiDecodeCtx->wMode             = CODECHAL_DECODE_MODE_AVCVLD;
    m_ddiDecodeCtx->bShortFormatInUse = false;
#ifdef _DECODE_PROCESSING_SUPPORTED
    if (m_ddiDecodeAttr->uiDecProcessingType == VA_DEC_PROCESSING)
    {
        DDI_NORMALMESSAGE("Decoding context has scaling/format conversion capabilities");
        m_decProcessingType = VA_DEC_PROCESSING;
    }
    else
#endif
    {
        DDI_NORMALMESSAGE("Decoding context DOESN'T have scaling/format conversion capabilities");
        m_decProcessingType = VA_DEC_PROCESSING_NONE;
    }
    m_streamOutEnabled                  = false;
    m_ddiDecodeCtx->DecodeParams.m_picIdRemappingInUse = true;
}

VAStatus DdiMediaDecode::CreateCodecHal(
    DDI_MEDIA_CONTEXT       *mediaCtx,
    void                    *ptr,
    _CODECHAL_STANDARD_INFO *standardInfo)
{
    if ((mediaCtx == nullptr) ||
        (ptr == nullptr) ||
        (m_codechalSettings == nullptr) ||
        (standardInfo == nullptr))
    {
        DDI_ASSERTMESSAGE("NULL pointer is passed for CreateCodecHal.\n");
        return VA_STATUS_ERROR_INVALID_PARAMETER;

    }
    MOS_CONTEXT    *mosCtx   = (MOS_CONTEXT *)ptr;
    VAStatus        vaStatus = VA_STATUS_SUCCESS;

    Codechal *codecHal = CodechalDevice::CreateFactory(
        nullptr,
        mosCtx,
        standardInfo,
        m_codechalSettings);

    if (nullptr == codecHal)
    {
        DDI_ASSERTMESSAGE("Failure in CodecHal create.\n");
        vaStatus = VA_STATUS_ERROR_ALLOCATION_FAILED;
        return vaStatus;
    }

    if (codecHal->IsApogeiosEnabled())
    {
        DecodePipelineAdapter *decoder = dynamic_cast<DecodePipelineAdapter *>(codecHal);
        if (nullptr == decoder)
        {
            DDI_ASSERTMESSAGE("Failure in CodecHal create.\n");
            vaStatus = VA_STATUS_ERROR_ALLOCATION_FAILED;
            return vaStatus;
        }
    }
    else
    {
        CodechalDecode *decoder = dynamic_cast<CodechalDecode *>(codecHal);
        if (nullptr == decoder)
        {
            DDI_ASSERTMESSAGE("Failure in CodecHal create.\n");
            vaStatus = VA_STATUS_ERROR_ALLOCATION_FAILED;
            return vaStatus;
        }
    }

    m_ddiDecodeCtx->pCodecHal = codecHal;

    m_codechalSettings->sfcInUseHinted = true;

    if (m_ddiDecodeAttr && m_ddiDecodeAttr->uiEncryptionType)
    {
        m_codechalSettings->secureMode = true;
    }

    if (codecHal->Allocate(m_codechalSettings) != MOS_STATUS_SUCCESS)
    {
        DDI_ASSERTMESSAGE("Failure in decode allocate.\n");
        vaStatus = VA_STATUS_ERROR_ALLOCATION_FAILED;
        return vaStatus;
    }

    PMOS_INTERFACE osInterface = codecHal->GetOsInterface();
    if (osInterface == nullptr)
    {
        DDI_ASSERTMESSAGE("Failure in decode allocate.\n");
        vaStatus = VA_STATUS_ERROR_ALLOCATION_FAILED;
        return vaStatus;
    }

#ifdef _MMC_SUPPORTED
    if (!osInterface->apoMosEnabled                                                  &&
        MEDIA_IS_SKU(osInterface->pfnGetSkuTable(osInterface), FtrMemoryCompression) &&
        !mediaCtx->pMediaMemDecompState)
    {
        mediaCtx->pMediaMemDecompState =
            static_cast<MediaMemDecompState *>(MmdDevice::CreateFactory(mosCtx));
    }
#endif

    m_ddiDecodeCtx->pCpDdiInterface->CreateCencDecode(codecHal->GetDebugInterface(), mosCtx, m_codechalSettings);

    return vaStatus;
}

void DdiMediaDecode::GetDummyReferenceFromDPB(
    DDI_DECODE_CONTEXT      *decodeCtx)
{
    MOS_SURFACE     *destSurface = decodeCtx->DecodeParams.m_destSurface;
    MOS_SURFACE     dummyReference;
    MOS_STATUS      eStatus;
    uint32_t        i;

    if (destSurface == nullptr)
    {
        DDI_ASSERTMESSAGE("Decode output surface is NULL.\n");
        return;
    }

    for (i = 0; i < DDI_MEDIA_MAX_SURFACE_NUMBER_CONTEXT; i++)
    {
        if (decodeCtx->RTtbl.pRT[i] != nullptr && 
            decodeCtx->RTtbl.pRT[i] != decodeCtx->RTtbl.pCurrentRT)
        {
            MOS_ZeroMemory(&dummyReference, sizeof(MOS_SURFACE));
            DdiMedia_MediaSurfaceToMosResource(decodeCtx->RTtbl.pRT[i], &(dummyReference.OsResource));

            if (!Mos_ResourceIsNull(&dummyReference.OsResource))
            {
                eStatus = MOS_STATUS_SUCCESS;
                dummyReference.Format = Format_Invalid;
                eStatus = Mos_Specific_GetResourceInfo(decodeCtx->pCodecHal->GetOsInterface(), &dummyReference.OsResource, &dummyReference);
                if (eStatus != MOS_STATUS_SUCCESS)
                {
                    continue;
                }

                if (dummyReference.Type == destSurface->Type && 
                    dummyReference.Format == destSurface->Format && 
                    dummyReference.bIsCompressed == destSurface->bIsCompressed && 
                    dummyReference.CompressionMode == destSurface->CompressionMode && 
                    dummyReference.TileType == destSurface->TileType && 
                    dummyReference.dwPitch >= destSurface->dwPitch && 
                    dummyReference.dwWidth >= destSurface->dwWidth && 
                    dummyReference.dwHeight >= destSurface->dwHeight)
                {
                    break;
                }
            }
        }
    }

    if (i < DDI_MEDIA_MAX_SURFACE_NUMBER_CONTEXT)
    {
        if (decodeCtx->pCodecHal->IsApogeiosEnabled())
        {
            DecodePipelineAdapter *decoder = dynamic_cast<DecodePipelineAdapter *>(decodeCtx->pCodecHal);
            if (decoder == nullptr)
            {
                DDI_ASSERTMESSAGE("Codechal decode context is NULL.\n");
                return;
            }
            decoder->GetDummyReference()->OsResource = dummyReference.OsResource;
        }
        else
        {
            CodechalDecode *decoder = dynamic_cast<CodechalDecode *>(decodeCtx->pCodecHal);
            if (decoder == nullptr)
            {
                DDI_ASSERTMESSAGE("Codechal decode context is NULL.\n");
                return;
            }
            decoder->GetDummyReference()->OsResource = dummyReference.OsResource;
        }
    }
}

void DdiMediaDecode::ReportDecodeMode(
    uint16_t      wMode)
 {
    PMOS_INTERFACE      osInterface = m_ddiDecodeCtx->pCodecHal ? m_ddiDecodeCtx->pCodecHal->GetOsInterface() : nullptr;
    MOS_CONTEXT_HANDLE  ctxHandle   = osInterface ? (MOS_CONTEXT_HANDLE)osInterface->pOsContext : nullptr;

    MOS_USER_FEATURE_VALUE_WRITE_DATA userFeatureWriteData;
    MOS_ZeroMemory(&userFeatureWriteData, sizeof(userFeatureWriteData));
    userFeatureWriteData.Value.i32Data = wMode;
    switch (wMode)
    {
        case CODECHAL_DECODE_MODE_MPEG2IDCT:
        case CODECHAL_DECODE_MODE_MPEG2VLD:
            userFeatureWriteData.ValueID = __MEDIA_USER_FEATURE_VALUE_DECODE_MPEG2_MODE_ID;
            MOS_UserFeature_WriteValues_ID(nullptr, &userFeatureWriteData, 1, ctxHandle);
            break;
        case CODECHAL_DECODE_MODE_VC1IT:
        case CODECHAL_DECODE_MODE_VC1VLD:
            userFeatureWriteData.ValueID = __MEDIA_USER_FEATURE_VALUE_DECODE_VC1_MODE_ID;
            MOS_UserFeature_WriteValues_ID(nullptr, &userFeatureWriteData, 1, ctxHandle);
            break;
        case CODECHAL_DECODE_MODE_AVCVLD:
            userFeatureWriteData.ValueID = __MEDIA_USER_FEATURE_VALUE_DECODE_AVC_MODE_ID;
            MOS_UserFeature_WriteValues_ID(nullptr, &userFeatureWriteData, 1, ctxHandle);
            break;
        case CODECHAL_DECODE_MODE_JPEG:
            userFeatureWriteData.ValueID = __MEDIA_USER_FEATURE_VALUE_DECODE_JPEG_MODE_ID;
            MOS_UserFeature_WriteValues_ID(nullptr, &userFeatureWriteData, 1, ctxHandle);
            break;
        case CODECHAL_DECODE_MODE_VP8VLD:
            userFeatureWriteData.ValueID = __MEDIA_USER_FEATURE_VALUE_DECODE_VP8_MODE_ID;
            MOS_UserFeature_WriteValues_ID(nullptr, &userFeatureWriteData, 1, ctxHandle);
            break;
        case CODECHAL_DECODE_MODE_HEVCVLD:
            userFeatureWriteData.ValueID = __MEDIA_USER_FEATURE_VALUE_DECODE_HEVC_MODE_ID;
            MOS_UserFeature_WriteValues_ID(nullptr, &userFeatureWriteData, 1, ctxHandle);
            break;
        case CODECHAL_DECODE_MODE_VP9VLD:
            userFeatureWriteData.ValueID = __MEDIA_USER_FEATURE_VALUE_DECODE_VP9_MODE_ID;
            MOS_UserFeature_WriteValues_ID(nullptr, &userFeatureWriteData, 1, ctxHandle);
            break;
        case CODECHAL_DECODE_MODE_AV1VLD:
            userFeatureWriteData.ValueID = __MEDIA_USER_FEATURE_VALUE_DECODE_AV1_MODE_ID;
            MOS_UserFeature_WriteValues_ID(nullptr, &userFeatureWriteData, 1, ctxHandle);
            break;
        default:
            break;
    }
#if MOS_EVENT_TRACE_DUMP_SUPPORTED
    {
        DECODE_EVENTDATA_VA_FEATURE_REPORTMODE eventData;
        eventData.wMode = (uint32_t)wMode;
        eventData.ValueID = userFeatureWriteData.ValueID;
        MOS_TraceEvent(EVENT_DECODE_FEATURE_DECODEMODE_REPORTVA, EVENT_TYPE_INFO, &eventData, sizeof(eventData), NULL, 0);
    }
#endif
 }
