/*
* Copyright (c) 2009-2018, 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_libva.cpp
//! \brief    libva(and its extension) interface implementaion.
//!

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/ioctl.h>
#include <unistd.h>

#if !defined(ANDROID) && defined(X11_FOUND)
#include <X11/Xutil.h>
#endif

#include <linux/fb.h>

#include "media_libva.h"

#include "media_libva_util.h"
#include "media_libva_decoder.h"
#include "media_libva_encoder.h"
#if !defined(ANDROID) && defined(X11_FOUND)
#include "media_libva_putsurface_linux.h"
#endif
#include "media_libva_vp.h"
#include "mos_os.h"

#include "hwinfo_linux.h"
#include "mediamemdecomp.h"
#include "mos_solo_generic.h"
#include "media_libva_caps.h"
#include "media_interfaces_mmd.h"
#include "mos_util_user_interface.h"
#include "cplib_utils.h"
#include "media_interfaces.h"

#ifdef __cplusplus
extern "C" {
#endif
extern VAStatus DdiDestroyContextCM (VADriverContextP   vaDrvCtx, VAContextID         vaCtxID);
#ifdef __cplusplus
}
#endif

extern template class MediaInterfacesFactory<MhwInterfaces>;

VAProcFilterType vp_supported_filters[DDI_VP_MAX_NUM_FILTERS] = {
    VAProcFilterNoiseReduction,
    VAProcFilterDeinterlacing,
    VAProcFilterSharpening,
    VAProcFilterColorBalance,
    VAProcFilterSkinToneEnhancement,
    VAProcFilterTotalColorCorrection,
    VAProcFilterHVSNoiseReduction,
    VAProcFilterHighDynamicRangeToneMapping
};

VAProcColorStandardType vp_input_color_std[DDI_VP_NUM_INPUT_COLOR_STD] = {
    VAProcColorStandardBT601,
    VAProcColorStandardBT709,
    VAProcColorStandardSRGB,
    VAProcColorStandardSTRGB,
    VAProcColorStandardBT2020
};

VAProcColorStandardType vp_output_color_std[DDI_VP_NUM_OUT_COLOR_STD] = {
    VAProcColorStandardBT601,
    VAProcColorStandardBT709,
    VAProcColorStandardSRGB,
    VAProcColorStandardSTRGB,
    VAProcColorStandardBT2020
};

static VAStatus DdiMedia_DestroyContext (
    VADriverContextP    ctx,
    VAContextID         context);

// Making this API public since media_libva_vp.c calls this
VAStatus DdiMedia_MapBuffer (
    VADriverContextP    ctx,
    VABufferID          buf_id,    /* in */
    void                **pbuf     /* out */
);

VAStatus DdiMedia_UnmapBuffer (
    VADriverContextP    ctx,
    VABufferID          buf_id    /* in */
);

//!
//! \brief  Destroy buffer 
//! 
//! \param  [in] ctx
//!         Pointer to VA driver context
//! \param  [in] buffer_id
//!         VA buffer ID
//!
//! \return     VAStatus
//!     VA_STATUS_SUCCESS if success, else fail reason
//!
VAStatus DdiMedia_DestroyBuffer (
    VADriverContextP    ctx,
    VABufferID          buffer_id
);

VAStatus DdiMedia_DestroyImage (
    VADriverContextP ctx,
    VAImageID        image
);

static PDDI_MEDIA_CONTEXT DdiMedia_CreateMediaDriverContext()
{
    PDDI_MEDIA_CONTEXT   mediaCtx;

    mediaCtx = (PDDI_MEDIA_CONTEXT)MOS_AllocAndZeroMemory(sizeof(DDI_MEDIA_CONTEXT));

    return mediaCtx;
}

// refine this for decoder later
static bool DdiMedia_ReleaseSliceControlBuffer(
    uint32_t          ctxType,
    void             *ctx,
    DDI_MEDIA_BUFFER *buf)
{
    DDI_UNUSED(buf);

    switch (ctxType)
    {
        case DDI_MEDIA_CONTEXT_TYPE_DECODER:
        case DDI_MEDIA_CONTEXT_TYPE_CENC_DECODER:
        {
            PDDI_DECODE_CONTEXT  decCtx;

            decCtx = DdiDecode_GetDecContextFromPVOID(ctx);
            DDI_CODEC_COM_BUFFER_MGR *bufMgr = &(decCtx->BufMgr);

            switch (decCtx->wMode)
            {
                case CODECHAL_DECODE_MODE_AVCVLD:
                    if(decCtx->bShortFormatInUse)
                    {
                        if(bufMgr->Codec_Param.Codec_Param_H264.pVASliceParaBufH264Base == nullptr)
                        {
                            return false;
                        }
                    }
                    else
                    {
                        if(bufMgr->Codec_Param.Codec_Param_H264.pVASliceParaBufH264 == nullptr)
                        {
                            return false;
                        }
                    }
                    break;
                case CODECHAL_DECODE_MODE_MPEG2VLD:
                    if(bufMgr->Codec_Param.Codec_Param_MPEG2.pVASliceParaBufMPEG2 == nullptr)
                    {
                        return false;
                    }
                    break;
                case CODECHAL_DECODE_MODE_VC1VLD:
                    if(bufMgr->Codec_Param.Codec_Param_VC1.pVASliceParaBufVC1 == nullptr)
                    {
                        return false;
                    }
                    break;
                case CODECHAL_DECODE_MODE_JPEG:
                    if(bufMgr->Codec_Param.Codec_Param_JPEG.pVASliceParaBufJPEG == nullptr)
                    {
                        return false;
                    }
                    break;
                case CODECHAL_DECODE_MODE_VP8VLD:
                    if(bufMgr->Codec_Param.Codec_Param_VP8.pVASliceParaBufVP8 == nullptr)
                    {
                        return false;
                    }
                    break;
                case CODECHAL_DECODE_MODE_HEVCVLD:
                    if(decCtx->bShortFormatInUse)
                    {
                        if(bufMgr->Codec_Param.Codec_Param_HEVC.pVASliceParaBufBaseHEVC == nullptr)
                        {
                            return false;
                        }
                    }
                    else
                    {
                        if(bufMgr->Codec_Param.Codec_Param_HEVC.pVASliceParaBufHEVC == nullptr &&
                            bufMgr->Codec_Param.Codec_Param_HEVC.pVASliceParaBufHEVCRext == nullptr)
                        {
                            return false;
                        }
                    }
                    break;
                case CODECHAL_DECODE_MODE_VP9VLD:
                    if(bufMgr->Codec_Param.Codec_Param_VP9.pVASliceParaBufVP9 == nullptr)
                    {
                        return false;
                    }
                    break;
                default:
                    return false;
            }
            break;
        }
        case DDI_MEDIA_CONTEXT_TYPE_ENCODER:
            break;
        default:
            break;
    }

    return true;
}

static bool DdiMedia_ReleaseBpBuffer(
    DDI_CODEC_COM_BUFFER_MGR   *bufMgr,
    DDI_MEDIA_BUFFER           *buf)
{
    DDI_UNUSED(bufMgr);
    DDI_UNUSED(buf);
    return true;
}

static bool DdiMedia_ReleaseBsBuffer(
    DDI_CODEC_COM_BUFFER_MGR   *bufMgr,
    DDI_MEDIA_BUFFER           *buf)
{
    if ((bufMgr == nullptr) || (buf == nullptr))
    {
        return true;
    }

    if (buf->format == Media_Format_CPU)
    {
        for(uint32_t i = 0; i < bufMgr->dwNumSliceData; i++)
        {
            if(bufMgr->pSliceData[i].pBaseAddress == buf->pData)
            {
                DdiMediaUtil_FreeBuffer(buf);
                bufMgr->pSliceData[i].pBaseAddress = nullptr;
                if (bufMgr->pSliceData[i].pMappedGPUBuffer != nullptr)
                {
                    DdiMediaUtil_UnlockBuffer(bufMgr->pSliceData[i].pMappedGPUBuffer);
                    if (bufMgr->pSliceData[i].pMappedGPUBuffer->bMapped == false)
                    {
                        DdiMediaUtil_FreeBuffer(bufMgr->pSliceData[i].pMappedGPUBuffer);
                        MOS_FreeMemory(bufMgr->pSliceData[i].pMappedGPUBuffer);
                    }
                }
                MOS_ZeroMemory((void*)(&(bufMgr->pSliceData[i])), sizeof(bufMgr->pSliceData[0]));
                bufMgr->dwNumSliceData --;
                return true;
            }
        }
        return false;
    }
    return true;
}

static uint32_t DdiMedia_CreateRenderTarget(
    PDDI_MEDIA_CONTEXT            mediaDrvCtx,
    DDI_MEDIA_FORMAT              mediaFormat,
    uint32_t                      width,
    uint32_t                      height,
    DDI_MEDIA_SURFACE_DESCRIPTOR *surfDesc,
    uint32_t                      surfaceUsageHint
)
{
    DdiMediaUtil_LockMutex(&mediaDrvCtx->SurfaceMutex);

    PDDI_MEDIA_SURFACE_HEAP_ELEMENT surfaceElement = DdiMediaUtil_AllocPMediaSurfaceFromHeap(mediaDrvCtx->pSurfaceHeap);
    if (nullptr == surfaceElement)
    {
        DdiMediaUtil_UnLockMutex(&mediaDrvCtx->SurfaceMutex);
        return VA_INVALID_ID;
    }

    surfaceElement->pSurface = (DDI_MEDIA_SURFACE *)MOS_AllocAndZeroMemory(sizeof(DDI_MEDIA_SURFACE));
    if (nullptr == surfaceElement->pSurface)
    {
        DdiMediaUtil_ReleasePMediaSurfaceFromHeap(mediaDrvCtx->pSurfaceHeap, surfaceElement->uiVaSurfaceID);
        DdiMediaUtil_UnLockMutex(&mediaDrvCtx->SurfaceMutex);
        return VA_INVALID_ID;
    }

    surfaceElement->pSurface->pMediaCtx       = mediaDrvCtx;
    surfaceElement->pSurface->iWidth          = width;
    surfaceElement->pSurface->iHeight         = height;
    surfaceElement->pSurface->pSurfDesc       = surfDesc;
    surfaceElement->pSurface->format          = mediaFormat;
    surfaceElement->pSurface->uiLockedBufID   = VA_INVALID_ID;
    surfaceElement->pSurface->uiLockedImageID = VA_INVALID_ID;
    surfaceElement->pSurface->surfaceUsageHint= surfaceUsageHint;

    if(DdiMediaUtil_CreateSurface(surfaceElement->pSurface, mediaDrvCtx)!= VA_STATUS_SUCCESS)
    {
        MOS_FreeMemory(surfaceElement->pSurface);
        DdiMediaUtil_ReleasePMediaSurfaceFromHeap(mediaDrvCtx->pSurfaceHeap, surfaceElement->uiVaSurfaceID);
        DdiMediaUtil_UnLockMutex(&mediaDrvCtx->SurfaceMutex);
        return VA_INVALID_ID;
    }

    mediaDrvCtx->uiNumSurfaces++;
    uint32_t surfaceID = surfaceElement->uiVaSurfaceID;
    DdiMediaUtil_UnLockMutex(&mediaDrvCtx->SurfaceMutex);
    return surfaceID;
}

VAStatus
DdiMedia_HybridQueryBufferAttributes (
    VADisplay    dpy,
    VAContextID  context,
    VABufferType bufferType,
    void        *outputData,
    uint32_t    *outputDataLen
)
{
    return VA_STATUS_ERROR_UNIMPLEMENTED;
}

//!
//! \brief  Set Frame ID 
//! 
//! \param  [in] dpy
//!         VA display
//! \param  [in] surface
//!         VA surface ID
//! \param  [in] frame_id
//!         Frame ID
//!
//! \return VAStatus
//!     VA_STATUS_SUCCESS if success, else fail reason
//!
VAStatus DdiMedia_SetFrameID(
    VADisplay    dpy,
    VASurfaceID  surface,
    uint32_t     frame_id
)
{
    VADriverContextP ctx            = (((VADisplayContextP)dpy)->pDriverContext);
    DDI_CHK_NULL(ctx, "nullptr ctx", VA_STATUS_ERROR_INVALID_CONTEXT);

    PDDI_MEDIA_CONTEXT mediaCtx     = DdiMedia_GetMediaContext(ctx);
    DDI_CHK_NULL(mediaCtx, "nullptr mediaCtx.", VA_STATUS_ERROR_INVALID_CONTEXT);

    DDI_MEDIA_SURFACE *mediaSurface = DdiMedia_GetSurfaceFromVASurfaceID(mediaCtx, surface);
    DDI_CHK_NULL(mediaSurface, "nullptr mediaSurface.", VA_STATUS_ERROR_INVALID_PARAMETER);

    mediaSurface->frame_idx = frame_id;

    return VA_STATUS_SUCCESS;
}

//!
//! \brief  Convert media format to OS format 
//! 
//! \param  [in] format
//!         Ddi media format
//!
//! \return Os format if call sucesss,else
//!     VA_STATUS_ERROR_UNSUPPORTED_RT_FORMAT if fail
//!
int32_t DdiMedia_MediaFormatToOsFormat(DDI_MEDIA_FORMAT format)
{
    switch (format)
    {
        case Media_Format_X8R8G8B8:
            return VA_FOURCC_XRGB;
        case Media_Format_X8B8G8R8:
            return VA_FOURCC_XBGR;
        case Media_Format_A8B8G8R8:
        case Media_Format_R10G10B10A2:
            return VA_FOURCC_ABGR;
        case Media_Format_R8G8B8A8:
            return VA_FOURCC_RGBA;
        case Media_Format_A8R8G8B8:
        case Media_Format_B10G10R10A2:
            return VA_FOURCC_ARGB;
        case Media_Format_R5G6B5:
            return VA_FOURCC_R5G6B5;
        case Media_Format_R8G8B8:
            return VA_FOURCC_R8G8B8;
        case Media_Format_NV12:
            return VA_FOURCC_NV12;
        case Media_Format_NV21:
            return VA_FOURCC_NV21;
        case  Media_Format_YUY2:
            return VA_FOURCC_YUY2;
        case  Media_Format_UYVY:
            return VA_FOURCC_UYVY;
        case Media_Format_YV12:
            return VA_FOURCC_YV12;
        case Media_Format_IYUV:
            return VA_FOURCC_IYUV;
        case Media_Format_I420:
            return VA_FOURCC_I420;
        case Media_Format_400P:
            return VA_FOURCC('4','0','0','P');
        case Media_Format_IMC3:
            return VA_FOURCC_IMC3;
        case Media_Format_422H:
            return VA_FOURCC_422H;
        case Media_Format_422V:
            return VA_FOURCC_422V;
        case Media_Format_411P:
            return VA_FOURCC_411P;
        case Media_Format_444P:
            return VA_FOURCC_444P;
        case Media_Format_RGBP:
            return VA_FOURCC_RGBP;
        case Media_Format_Buffer:
            return VA_FOURCC_P208;
        case Media_Format_P010:
            return VA_FOURCC_P010;
        case Media_Format_P016:
            return VA_FOURCC_P016;
        case Media_Format_Y210:
            return VA_FOURCC_Y210;
        case Media_Format_Y216:
            return VA_FOURCC_Y216;
        case Media_Format_AYUV:
            return VA_FOURCC_AYUV;
        case Media_Format_Y410:
            return VA_FOURCC_Y410;
        case Media_Format_Y416:
            return VA_FOURCC_Y416;
        default:
            return VA_STATUS_ERROR_UNSUPPORTED_RT_FORMAT;
    }
}

//!
//! \brief  Convert Os format to media format 
//! 
//! \param  [in] fourcc
//!         FourCC
//! \param  [in] rtformatType
//!         Rt format type
//!
//! \return DDI_MEDIA_FORMAT
//!     Ddi media format
//!
DDI_MEDIA_FORMAT DdiMedia_OsFormatToMediaFormat(int32_t fourcc, int32_t rtformatType)
{
    switch (fourcc)
    {
        case VA_FOURCC_BGRA:
        case VA_FOURCC_ARGB:
#ifdef VA_RT_FORMAT_RGB32_10BPP
            if(VA_RT_FORMAT_RGB32_10BPP == rtformatType)
            {
                return Media_Format_B10G10R10A2;
            }
#endif
            return Media_Format_A8R8G8B8;
        case VA_FOURCC_RGBA:
#ifdef VA_RT_FORMAT_RGB32_10BPP
            if(VA_RT_FORMAT_RGB32_10BPP == rtformatType)
            {
                return Media_Format_R10G10B10A2;
            }
#endif
            return Media_Format_R8G8B8A8;
        case VA_FOURCC_ABGR:
#ifdef VA_RT_FORMAT_RGB32_10BPP
            if(VA_RT_FORMAT_RGB32_10BPP == rtformatType)
            {
                return Media_Format_R10G10B10A2;
            }
#endif
            return Media_Format_A8B8G8R8;
        case VA_FOURCC_BGRX:
        case VA_FOURCC_XRGB:
            return Media_Format_X8R8G8B8;
        case VA_FOURCC_XBGR:
        case VA_FOURCC_RGBX:
            return Media_Format_X8B8G8R8;
        case VA_FOURCC_R5G6B5:
            return Media_Format_R5G6B5;
        case VA_FOURCC_R8G8B8:
            return Media_Format_R8G8B8;
        case VA_FOURCC_NV12:
            return Media_Format_NV12;
        case VA_FOURCC_NV21:
            return Media_Format_NV21;
        case VA_FOURCC_YUY2:
            return Media_Format_YUY2;
        case VA_FOURCC_UYVY:
            return Media_Format_UYVY;
        case VA_FOURCC_YV12:
            return Media_Format_YV12;
        case VA_FOURCC_IYUV:
            return Media_Format_IYUV;
        case VA_FOURCC_I420:
            return Media_Format_I420;
        case VA_FOURCC_422H:
            return Media_Format_422H;
        case VA_FOURCC_422V:
            return Media_Format_422V;
        case VA_FOURCC('4','0','0','P'):
        case VA_FOURCC_Y800:
            return Media_Format_400P;
        case VA_FOURCC_411P:
            return Media_Format_411P;
        case VA_FOURCC_IMC3:
            return Media_Format_IMC3;
        case VA_FOURCC_444P:
        case VA_FOURCC_BGRP:
            return Media_Format_444P;
        case VA_FOURCC_RGBP:
            return Media_Format_RGBP;
        case VA_FOURCC_P208:
            return Media_Format_Buffer;
        case VA_FOURCC_P010:
            return Media_Format_P010;
        case VA_FOURCC_P016:
            return Media_Format_P016;
        case VA_FOURCC_Y210:
            return Media_Format_Y210;
        case VA_FOURCC_Y216:
            return Media_Format_Y216;
        case VA_FOURCC_AYUV:
            return Media_Format_AYUV;
        case VA_FOURCC_Y410:
            return Media_Format_Y410;
        case VA_FOURCC_Y416:
            return Media_Format_Y416;
        default:
            return Media_Format_Count;
    }
}

//!
//! \brief  Apply Os format alpha mask to media format 
//! 
//! \param  [in] fourcc
//!         FourCC
//! \param  [in] alphaMask
//!         Alpha mask
//!
//! \return DDI_MEDIA_FORMAT
//!     Ddi media format
//!
DDI_MEDIA_FORMAT DdiMedia_OsFormatAlphaMaskToMediaFormat(int32_t fourcc, int32_t alphaMask)
{
    switch (fourcc)
    {
        case VA_FOURCC_BGRA:
        case VA_FOURCC_ARGB:
            if(RGB_10BIT_ALPHAMASK == alphaMask)
            {
                return Media_Format_B10G10R10A2;
            }
            else
            {
                return Media_Format_A8R8G8B8;
            }
        case VA_FOURCC_RGBA:
            if(RGB_10BIT_ALPHAMASK == alphaMask)
            {
                return Media_Format_R10G10B10A2;
            }
            else
            {
                return Media_Format_R8G8B8A8;
            }
        case VA_FOURCC_ABGR:
            if(RGB_10BIT_ALPHAMASK == alphaMask)
            {
                return Media_Format_R10G10B10A2;
            }
            else
            {
                return Media_Format_A8B8G8R8;
            }
        case VA_FOURCC_BGRX:
        case VA_FOURCC_XRGB:
            return Media_Format_X8R8G8B8;
        case VA_FOURCC_XBGR:
        case VA_FOURCC_RGBX:
            return Media_Format_X8B8G8R8;
        case VA_FOURCC_R5G6B5:
            return Media_Format_R5G6B5;
        case VA_FOURCC_R8G8B8:
            return Media_Format_R8G8B8;
        case VA_FOURCC_NV12:
            return Media_Format_NV12;
        case VA_FOURCC_NV21:
            return Media_Format_NV21;
        case VA_FOURCC_YUY2:
            return Media_Format_YUY2;
        case VA_FOURCC_YV12:
            return Media_Format_YV12;
        case VA_FOURCC_IYUV:
            return Media_Format_IYUV;
        case VA_FOURCC_I420:
            return Media_Format_I420;
        case VA_FOURCC_422H:
            return Media_Format_422H;
        case VA_FOURCC_422V:
            return Media_Format_422V;
        case VA_FOURCC('4','0','0','P'):
        case VA_FOURCC_Y800:
            return Media_Format_400P;
        case VA_FOURCC_411P:
            return Media_Format_411P;
        case VA_FOURCC_IMC3:
            return Media_Format_IMC3;
        case VA_FOURCC_444P:
        case VA_FOURCC_BGRP:
            return Media_Format_444P;
        case VA_FOURCC_RGBP:
            return Media_Format_RGBP;
        case VA_FOURCC_P208:
            return Media_Format_Buffer;
        case VA_FOURCC('P','0','1','0'):
            return Media_Format_P010;
        case VA_FOURCC_AYUV:
            return Media_Format_AYUV;
        default:
            return Media_Format_Count;
    }
}

#if !defined(ANDROID) && defined(X11_FOUND)

#define X11_LIB_NAME "libX11.so.6"

/*
 * Close opened libX11.so lib, free related function table.
 */
static void DdiMedia_DestroyX11Connection(
    PDDI_MEDIA_CONTEXT mediaCtx
)
{
    if (nullptr == mediaCtx || nullptr == mediaCtx->X11FuncTable)
    {
        return;
    }

    MOS_FreeLibrary(mediaCtx->X11FuncTable->pX11LibHandle);
    MOS_FreeMemory(mediaCtx->X11FuncTable);
    mediaCtx->X11FuncTable = nullptr;

    return;
}

/*
 * dlopen libX11.so, setup the function table, which is used by
 * DdiCodec_PutSurface (Linux) so far.
 */
static VAStatus DdiMedia_ConnectX11(
    PDDI_MEDIA_CONTEXT mediaCtx
)
{
    DDI_CHK_NULL(mediaCtx, "nullptr mediaCtx", VA_STATUS_ERROR_INVALID_CONTEXT);

    mediaCtx->X11FuncTable = (PDDI_X11_FUNC_TABLE)MOS_AllocAndZeroMemory(sizeof(DDI_X11_FUNC_TABLE));
    DDI_CHK_NULL(mediaCtx->X11FuncTable, "Allocation Failed for X11FuncTable", VA_STATUS_ERROR_ALLOCATION_FAILED);

    HMODULE    h_module   = nullptr;
    MOS_STATUS mos_status = MOS_LoadLibrary(X11_LIB_NAME, &h_module);
    if (MOS_STATUS_SUCCESS != mos_status || nullptr == h_module)
    {
        DdiMedia_DestroyX11Connection(mediaCtx);
        return VA_STATUS_ERROR_OPERATION_FAILED;
    }

    mediaCtx->X11FuncTable->pX11LibHandle = h_module;

    mediaCtx->X11FuncTable->pfnXCreateGC =
        MOS_GetProcAddress(h_module, "XCreateGC");
    mediaCtx->X11FuncTable->pfnXFreeGC =
        MOS_GetProcAddress(h_module, "XFreeGC");
    mediaCtx->X11FuncTable->pfnXCreateImage =
        MOS_GetProcAddress(h_module, "XCreateImage");
    mediaCtx->X11FuncTable->pfnXDestroyImage =
        MOS_GetProcAddress(h_module, "XDestroyImage");
    mediaCtx->X11FuncTable->pfnXPutImage =
        MOS_GetProcAddress(h_module, "XPutImage");

    if (nullptr == mediaCtx->X11FuncTable->pfnXCreateGC     ||
        nullptr == mediaCtx->X11FuncTable->pfnXFreeGC       ||
        nullptr == mediaCtx->X11FuncTable->pfnXCreateImage  ||
        nullptr == mediaCtx->X11FuncTable->pfnXDestroyImage ||
        nullptr == mediaCtx->X11FuncTable->pfnXPutImage)
    {
        DdiMedia_DestroyX11Connection(mediaCtx);
        return VA_STATUS_ERROR_OPERATION_FAILED;
    }

    return VA_STATUS_SUCCESS;
}
#endif

/////////////////////////////////////////////////////////////////////////////
//! \Free allocated surfaceheap elements
//! \params
//! [in] PDDI_MEDIA_CONTEXT
//! [out] none
//! \returns
/////////////////////////////////////////////////////////////////////////////
static void DdiMedia_FreeSurfaceHeapElements(PDDI_MEDIA_CONTEXT mediaCtx)
{
    if (nullptr == mediaCtx)
        return;
    PDDI_MEDIA_HEAP surfaceHeap = mediaCtx->pSurfaceHeap;

    if (nullptr == surfaceHeap)
        return;

    PDDI_MEDIA_SURFACE_HEAP_ELEMENT mediaSurfaceHeapBase = (PDDI_MEDIA_SURFACE_HEAP_ELEMENT)surfaceHeap->pHeapBase;
    if (nullptr == mediaSurfaceHeapBase)
        return;

    int32_t surfaceNums = mediaCtx->uiNumSurfaces;
    for (int32_t elementId = 0; elementId < surfaceNums; elementId++)
    {
        PDDI_MEDIA_SURFACE_HEAP_ELEMENT mediaSurfaceHeapElmt = &mediaSurfaceHeapBase[elementId];
        if (nullptr == mediaSurfaceHeapElmt->pSurface)
            continue;

        DdiMediaUtil_FreeSurface(mediaSurfaceHeapElmt->pSurface);
        MOS_FreeMemory(mediaSurfaceHeapElmt->pSurface);
        DdiMediaUtil_ReleasePMediaSurfaceFromHeap(surfaceHeap,mediaSurfaceHeapElmt->uiVaSurfaceID);
        mediaCtx->uiNumSurfaces--;
    }
}

/////////////////////////////////////////////////////////////////////////////
//! \Free allocated bufferheap elements
//! \params
//! [in] VADriverContextP
//! [out] none
//! \returns
/////////////////////////////////////////////////////////////////////////////
static void DdiMedia_FreeBufferHeapElements(VADriverContextP    ctx)
{
    PDDI_MEDIA_CONTEXT mediaCtx = DdiMedia_GetMediaContext(ctx);
    if (nullptr == mediaCtx)
        return;

    PDDI_MEDIA_HEAP  bufferHeap = mediaCtx->pBufferHeap;
    if (nullptr == bufferHeap)
        return;

    PDDI_MEDIA_BUFFER_HEAP_ELEMENT mediaBufferHeapBase = (PDDI_MEDIA_BUFFER_HEAP_ELEMENT)bufferHeap->pHeapBase;
    if (nullptr == mediaBufferHeapBase)
        return;

    int32_t bufNums = mediaCtx->uiNumBufs;
    for (int32_t elementId = 0; elementId < bufNums; ++elementId)
    {
        PDDI_MEDIA_BUFFER_HEAP_ELEMENT mediaBufferHeapElmt = &mediaBufferHeapBase[elementId];
        if (nullptr == mediaBufferHeapElmt->pBuffer)
            continue;
        DdiMedia_DestroyBuffer(ctx,mediaBufferHeapElmt->uiVaBufferID);
    }
}

/////////////////////////////////////////////////////////////////////////////
//! \Free allocated Imageheap elements
//! \params
//! [in] VADriverContextP
//! [out] none
//! \returns
/////////////////////////////////////////////////////////////////////////////
static void DdiMedia_FreeImageHeapElements(VADriverContextP    ctx)
{
    PDDI_MEDIA_CONTEXT mediaCtx = DdiMedia_GetMediaContext(ctx);
    if (nullptr == mediaCtx)
        return;

    PDDI_MEDIA_HEAP imageHeap = mediaCtx->pImageHeap;
    if (nullptr == imageHeap)
        return;

    PDDI_MEDIA_IMAGE_HEAP_ELEMENT mediaImageHeapBase = (PDDI_MEDIA_IMAGE_HEAP_ELEMENT)imageHeap->pHeapBase;
    if (nullptr == mediaImageHeapBase)
        return;

    int32_t imageNums = mediaCtx->uiNumImages;
    for (int32_t elementId = 0; elementId < imageNums; ++elementId)
    {
        PDDI_MEDIA_IMAGE_HEAP_ELEMENT mediaImageHeapElmt = &mediaImageHeapBase[elementId];
        if (nullptr == mediaImageHeapElmt->pImage)
            continue;
        DdiMedia_DestroyImage(ctx,mediaImageHeapElmt->uiVaImageID);
    }
}

/////////////////////////////////////////////////////////////////////////////
//! \Execute free allocated bufferheap elements for FreeContextHeapElements function
//! \params
//! [in] VADriverContextP
//! [in] PDDI_MEDIA_HEAP
//! [out] none
//! \returns
/////////////////////////////////////////////////////////////////////////////
static void DdiMedia_FreeContextHeap(VADriverContextP ctx, PDDI_MEDIA_HEAP contextHeap,int32_t vaContextOffset, int32_t ctxNums)
{
    PDDI_MEDIA_VACONTEXT_HEAP_ELEMENT mediaContextHeapBase = (PDDI_MEDIA_VACONTEXT_HEAP_ELEMENT)contextHeap->pHeapBase;
    if (nullptr == mediaContextHeapBase)
        return;

    for (int32_t elementId = 0; elementId < ctxNums; ++elementId)
    {
        PDDI_MEDIA_VACONTEXT_HEAP_ELEMENT mediaContextHeapElmt = &mediaContextHeapBase[elementId];
        if (nullptr == mediaContextHeapElmt->pVaContext)
            continue;
        VAContextID vaCtxID = (VAContextID)(mediaContextHeapElmt->uiVaContextID + vaContextOffset);
        DdiMedia_DestroyContext(ctx,vaCtxID);
    }

}

/////////////////////////////////////////////////////////////////////////////
//! \Free allocated contextheap elements
//! \params
//! [in] VADriverContextP
//! [out] none
//! \returns
/////////////////////////////////////////////////////////////////////////////
static void DdiMedia_FreeContextHeapElements(VADriverContextP    ctx)
{
    PDDI_MEDIA_CONTEXT mediaCtx = DdiMedia_GetMediaContext(ctx);
    if (nullptr == mediaCtx)
        return;

    //Free EncoderContext
    PDDI_MEDIA_HEAP encoderContextHeap = mediaCtx->pEncoderCtxHeap;
    int32_t encCtxNums        = mediaCtx->uiNumEncoders;
    if (nullptr != encoderContextHeap)
        DdiMedia_FreeContextHeap(ctx,encoderContextHeap,DDI_MEDIA_VACONTEXTID_OFFSET_ENCODER,encCtxNums);

    //Free DecoderContext
    PDDI_MEDIA_HEAP decoderContextHeap = mediaCtx->pDecoderCtxHeap;
    int32_t decCtxNums        = mediaCtx->uiNumDecoders;
    if (nullptr != decoderContextHeap)
        DdiMedia_FreeContextHeap(ctx,decoderContextHeap,DDI_MEDIA_VACONTEXTID_OFFSET_DECODER,decCtxNums);

    //Free VpContext
    PDDI_MEDIA_HEAP vpContextHeap      = mediaCtx->pVpCtxHeap;
    int32_t vpctxNums         = mediaCtx->uiNumVPs;
    if (nullptr != vpContextHeap)
        DdiMedia_FreeContextHeap(ctx,vpContextHeap,DDI_MEDIA_VACONTEXTID_OFFSET_VP,vpctxNums);

    //Free MfeContext
    PDDI_MEDIA_HEAP mfeContextHeap     = mediaCtx->pMfeCtxHeap;
    int32_t mfeCtxNums        = mediaCtx->uiNumMfes;
    if (nullptr != mfeContextHeap)
        DdiMedia_FreeContextHeap(ctx, mfeContextHeap, DDI_MEDIA_VACONTEXTID_OFFSET_MFE, mfeCtxNums);

    // Free media memory decompression data structure
    if (mediaCtx->pMediaMemDecompState)
    {
        MediaMemDecompBaseState *mediaMemCompState =
            static_cast<MediaMemDecompBaseState*>(mediaCtx->pMediaMemDecompState);
        MOS_Delete(mediaMemCompState);
        mediaCtx->pMediaMemDecompState = nullptr;
    }
}

/////////////////////////////////////////////////////////////////////////////
//! \Free allocated ContextCM elements
//! \params
//! [in] VADriverContextP
//! [out] none
//! \returns
/////////////////////////////////////////////////////////////////////////////
static void DdiMedia_FreeContextCMElements(VADriverContextP ctx)
{
    PDDI_MEDIA_CONTEXT mediaCtx = DdiMedia_GetMediaContext(ctx);
    if (nullptr == mediaCtx)
        return;

    int32_t cmnums = mediaCtx->uiNumCMs;
    for (int32_t elementId = 0; elementId < cmnums; elementId++)
    {
        VAContextID vaCtxID = elementId + DDI_MEDIA_VACONTEXTID_OFFSET_CM;
        DdiDestroyContextCM(ctx,vaCtxID);
    }
}

//!
//! \brief  Get VA image from VA image ID
//! 
//! \param  [in] mediaCtx
//!         Pointer to ddi media context
//! \param  [in] imageID
//!         VA image ID
//!
//! \return VAImage*
//!     Pointer to VAImage
//!
VAImage* DdiMedia_GetVAImageFromVAImageID (PDDI_MEDIA_CONTEXT mediaCtx, VAImageID imageID)
{
    DDI_CHK_NULL(mediaCtx, "nullptr mediaCtx", nullptr);

    uint32_t i       = (uint32_t)imageID;
    DDI_CHK_LESS(i, mediaCtx->pImageHeap->uiAllocatedHeapElements, "invalid image id", nullptr);
    DdiMediaUtil_LockMutex(&mediaCtx->ImageMutex);
    PDDI_MEDIA_IMAGE_HEAP_ELEMENT imageElement = (PDDI_MEDIA_IMAGE_HEAP_ELEMENT)mediaCtx->pImageHeap->pHeapBase;
    imageElement    += i;
    VAImage *vaImage = imageElement->pImage;
    DdiMediaUtil_UnLockMutex(&mediaCtx->ImageMutex);

    return vaImage;
}

//!
//! \brief  Get ctx from VA buffer ID
//! 
//! \param  [in] mediaCtx
//!         pddi media context
//! \param  [in] bufferID
//!         VA Buffer ID
//!
//! \return void*
//!     Pointer to buffer heap element context
//!
void* DdiMedia_GetCtxFromVABufferID (PDDI_MEDIA_CONTEXT mediaCtx, VABufferID bufferID)
{
    DDI_CHK_NULL(mediaCtx, "nullptr mediaCtx", nullptr);

    uint32_t i      = (uint32_t)bufferID;
    DDI_CHK_LESS(i, mediaCtx->pBufferHeap->uiAllocatedHeapElements, "invalid buffer id", nullptr);
    DdiMediaUtil_LockMutex(&mediaCtx->BufferMutex);
    PDDI_MEDIA_BUFFER_HEAP_ELEMENT bufHeapElement  = (PDDI_MEDIA_BUFFER_HEAP_ELEMENT)mediaCtx->pBufferHeap->pHeapBase;
    bufHeapElement += i;
    void *temp      = bufHeapElement->pCtx;
    DdiMediaUtil_UnLockMutex(&mediaCtx->BufferMutex);

    return temp;
}

//!
//! \brief  Get ctx type from VA buffer ID
//! 
//! \param  [in] mediaCtx
//!         Pointer to ddi media context
//! \param  [in] bufferID
//!         VA buffer ID
//!
//! \return uint32_t
//1     Context type
//!
uint32_t DdiMedia_GetCtxTypeFromVABufferID (PDDI_MEDIA_CONTEXT mediaCtx, VABufferID bufferID)
{
    DDI_CHK_NULL(mediaCtx, "nullptr mediaCtx", DDI_MEDIA_CONTEXT_TYPE_NONE);

    uint32_t i       = (uint32_t)bufferID;
    DDI_CHK_LESS(i, mediaCtx->pBufferHeap->uiAllocatedHeapElements, "invalid buffer id", DDI_MEDIA_CONTEXT_TYPE_NONE);
    DdiMediaUtil_LockMutex(&mediaCtx->BufferMutex);
    PDDI_MEDIA_BUFFER_HEAP_ELEMENT bufHeapElement  = (PDDI_MEDIA_BUFFER_HEAP_ELEMENT)mediaCtx->pBufferHeap->pHeapBase;
    bufHeapElement  += i;
    uint32_t ctxType = bufHeapElement->uiCtxType;
    DdiMediaUtil_UnLockMutex(&mediaCtx->BufferMutex);

    return ctxType;

}

//!
//! \brief  Destroy image from VA image ID 
//! 
//! \param  [in] mediaCtx
//!         Pointer to ddi media context
//! \param  [in] imageID
//!     VA image ID
//!
//! \return bool
//!     True if destroy image from VA image ID, else fail
//!
bool DdiMedia_DestroyImageFromVAImageID (PDDI_MEDIA_CONTEXT mediaCtx, VAImageID imageID)
{
    DDI_CHK_NULL(mediaCtx, "nullptr mediaCtx", false);

    DdiMediaUtil_LockMutex(&mediaCtx->ImageMutex);
    DdiMediaUtil_ReleasePVAImageFromHeap(mediaCtx->pImageHeap, (uint32_t)imageID);
    mediaCtx->uiNumImages--;
    DdiMediaUtil_UnLockMutex(&mediaCtx->ImageMutex);
    return true;
}
#ifdef _MMC_SUPPORTED
//!
//! \brief  Decompress internal media memory 
//! 
//! \param  [in] mosCtx
//!         Pointer to mos context
//! \param  [in] osResource
//!         Pointer mos resource
//!
void DdiMedia_MediaMemoryDecompressInternal(PMOS_CONTEXT mosCtx, PMOS_RESOURCE osResource)
{
    DDI_CHK_NULL(mosCtx, "nullptr mosCtx",);
    DDI_CHK_NULL(osResource, "nullptr osResource",);
    DDI_ASSERT(osResource);

    MediaMemDecompBaseState *mediaMemDecompState = static_cast<MediaMemDecompBaseState*>(*mosCtx->ppMediaMemDecompState);

    if (!mediaMemDecompState)
    {
        mediaMemDecompState =
            static_cast<MediaMemDecompBaseState*>(MmdDevice::CreateFactory(mosCtx));
    }

    if (mediaMemDecompState)
    {
        mediaMemDecompState->MemoryDecompress(osResource);
    }
    else
    {
        DDI_ASSERTMESSAGE("Invalid memory decompression state.");
    }
}
#endif

//!
//! \brief  Decompress a compressed surface.
//! 
//! \param  [in]     mediaCtx
//!     Pointer to ddi media context
//! \param  [in]     mediaSurface
//!     Ddi media surface 
//!
//! \return     VAStatus
//!     VA_STATUS_SUCCESS if success, else fail reason
//!
VAStatus DdiMedia_MediaMemoryDecompress(PDDI_MEDIA_CONTEXT mediaCtx, DDI_MEDIA_SURFACE *mediaSurface)
{
    DDI_CHK_NULL(mediaSurface, "nullptr mediaSurface", VA_STATUS_ERROR_INVALID_PARAMETER);
    DDI_CHK_NULL(mediaSurface->pGmmResourceInfo, "nullptr mediaSurface->pGmmResourceInfo", VA_STATUS_ERROR_INVALID_PARAMETER);

    VAStatus vaStatus = VA_STATUS_SUCCESS;
    GMM_RESOURCE_FLAG GmmFlags;

    MOS_ZeroMemory(&GmmFlags, sizeof(GmmFlags));
    GmmFlags = mediaSurface->pGmmResourceInfo->GetResFlags();

    if (((GmmFlags.Gpu.MMC                                                        ||
          GmmFlags.Gpu.CCS)                                                       &&
          GmmFlags.Gpu.UnifiedAuxSurface)                                         ||
          mediaSurface->pGmmResourceInfo->IsMediaMemoryCompressed(0))
    {
#ifdef _MMC_SUPPORTED
        MOS_CONTEXT  mosCtx;
        MOS_RESOURCE surface;
        DdiCpInterface *pCpDdiInterface;
        
        MOS_ZeroMemory(&mosCtx, sizeof(mosCtx));
        MOS_ZeroMemory(&surface, sizeof(surface));

        DDI_CHK_NULL(mediaCtx, "Null mediaCtx.", VA_STATUS_ERROR_INVALID_CONTEXT);

        mosCtx.bufmgr          = mediaCtx->pDrmBufMgr;
        mosCtx.m_gpuContextMgr = mediaCtx->m_gpuContextMgr;
        mosCtx.m_cmdBufMgr     = mediaCtx->m_cmdBufMgr;
        mosCtx.fd              = mediaCtx->fd;
        mosCtx.iDeviceId       = mediaCtx->iDeviceId;
        mosCtx.SkuTable        = mediaCtx->SkuTable;
        mosCtx.WaTable         = mediaCtx->WaTable;
        mosCtx.gtSystemInfo    = *mediaCtx->pGtSystemInfo;
        mosCtx.platform        = mediaCtx->platform;

        mosCtx.ppMediaMemDecompState = &mediaCtx->pMediaMemDecompState;
        mosCtx.pfnMemoryDecompress   = mediaCtx->pfnMemoryDecompress;
        mosCtx.pPerfData             = (PERF_DATA *)MOS_AllocAndZeroMemory(sizeof(PERF_DATA));
        mosCtx.gtSystemInfo          = *mediaCtx->pGtSystemInfo;
        mosCtx.m_auxTableMgr         = mediaCtx->m_auxTableMgr;

        pCpDdiInterface = Create_DdiCpInterface(mosCtx);

        if (nullptr == pCpDdiInterface)
        {
            return VA_STATUS_ERROR_ALLOCATION_FAILED;
        }
        
        mosCtx.ppMediaMemDecompState = &mediaCtx->pMediaMemDecompState;
        DdiMedia_MediaSurfaceToMosResource(mediaSurface, &surface);
        DdiMedia_MediaMemoryDecompressInternal(&mosCtx, &surface);

        if (pCpDdiInterface)
        {
            Delete_DdiCpInterface(pCpDdiInterface);
            pCpDdiInterface = NULL;
        }
#else
        vaStatus = VA_STATUS_ERROR_INVALID_SURFACE;
#endif
    }

    return vaStatus;
}

/*
 * Initialize the library
 */

// Global mutex
MEDIA_MUTEX_T  GlobalMutex = MEDIA_MUTEX_INITIALIZER;

//!
//! \brief  Free for media context
//!
//! \param  [in] mediaCtx
//!         Pointer to ddi media context
//!
void FreeForMediaContext(PDDI_MEDIA_CONTEXT mediaCtx)
{
    DdiMediaUtil_UnLockMutex(&GlobalMutex);

    if (mediaCtx)
    {
        mediaCtx->SkuTable.reset();
        mediaCtx->WaTable.reset();
        MOS_FreeMemory(mediaCtx->pSurfaceHeap);
        MOS_FreeMemory(mediaCtx->pBufferHeap);
        MOS_FreeMemory(mediaCtx->pImageHeap);
        MOS_FreeMemory(mediaCtx->pDecoderCtxHeap);
        MOS_FreeMemory(mediaCtx->pEncoderCtxHeap);
        MOS_FreeMemory(mediaCtx->pVpCtxHeap);
        MOS_FreeMemory(mediaCtx->pMfeCtxHeap);
        MOS_FreeMemory(mediaCtx);
    }

    return;
}

//!
//! \brief  Initialize
//! 
//! \param  [in] ctx
//!         Pointer to VA driver context
//! \param  [out] major_version
//!         Major version
//! \param  [out] minor_version
//!         Minor version
//!
//! \return VAStatus
//!     VA_STATUS_SUCCESS if success, else fail reason
//!
VAStatus DdiMedia__Initialize (
    VADriverContextP ctx,
    int32_t         *major_version,     /* out */
    int32_t         *minor_version      /* out */
)
{
#if !defined(ANDROID) && defined(X11_FOUND)
    // ATRACE code in <cutils/trace.h> started from KitKat, version = 440
    // ENABLE_TRACE is defined only for eng build so release build won't leak perf data
    // thus trace code enabled only on KitKat (and newer) && eng build
#if ANDROID_VERSION > 439 && defined(ENABLE_ATRACE)
    char switch_value[PROPERTY_VALUE_MAX];

    property_get("debug.DdiCodec_.umd", switch_value, "0");
    atrace_switch = atoi(switch_value);
#endif
#endif

    DDI_CHK_NULL(ctx,          "nullptr ctx",       VA_STATUS_ERROR_INVALID_CONTEXT);

    struct drm_state *pDRMState = (struct drm_state *)ctx->drm_state;
    DDI_CHK_NULL(pDRMState,    "nullptr pDRMState", VA_STATUS_ERROR_INVALID_CONTEXT);

    if(CPLibUtils::LoadCPLib(ctx))
    {
        DDI_NORMALMESSAGE("CPLIB is not loaded.");
    }

    // If libva failes to open the graphics card, try to open it again within Media Driver
    if(pDRMState->fd < 0 || pDRMState->fd == 0 )
    {
        DDI_ASSERTMESSAGE("DDI:LIBVA Wrapper doesn't pass file descriptor for graphics adaptor, trying to open the graphics... ");
        pDRMState->fd = DdiMediaUtil_OpenGraphicsAdaptor((char *)DEVICE_NAME);
        if (pDRMState->fd < 0) {
            DDI_ASSERTMESSAGE("DDI: Still failed to open the graphic adaptor, return failure");
            return VA_STATUS_ERROR_INVALID_PARAMETER;
        }
    }
    int32_t devicefd = pDRMState->fd;

    if(major_version)
    {
        *major_version = VA_MAJOR_VERSION;
    }

    if(minor_version)
    {
        *minor_version = VA_MINOR_VERSION;
    }

    DdiMediaUtil_LockMutex(&GlobalMutex);
    // media context is already created, return directly to support multiple entry
    PDDI_MEDIA_CONTEXT mediaCtx = DdiMedia_GetMediaContext(ctx);
    if(mediaCtx)
    {
        mediaCtx->uiRef++;
        FreeForMediaContext(mediaCtx);
        return VA_STATUS_SUCCESS;
    }

    MOS_utilities_init();

    mediaCtx = DdiMedia_CreateMediaDriverContext();
    if (nullptr == mediaCtx)
    {
        FreeForMediaContext(mediaCtx);
        return VA_STATUS_ERROR_ALLOCATION_FAILED;
    }

    mediaCtx->uiRef++;

    // Heap initialization here
    mediaCtx->pSurfaceHeap                         = (DDI_MEDIA_HEAP *)MOS_AllocAndZeroMemory(sizeof(DDI_MEDIA_HEAP));
    if (nullptr == mediaCtx->pSurfaceHeap)
    {
        FreeForMediaContext(mediaCtx);
        return VA_STATUS_ERROR_ALLOCATION_FAILED;
    }
    mediaCtx->pSurfaceHeap->uiHeapElementSize      = sizeof(DDI_MEDIA_SURFACE_HEAP_ELEMENT);

    mediaCtx->pBufferHeap                          = (DDI_MEDIA_HEAP *)MOS_AllocAndZeroMemory(sizeof(DDI_MEDIA_HEAP));
    if (nullptr == mediaCtx->pBufferHeap)
    {
        FreeForMediaContext(mediaCtx);
        return VA_STATUS_ERROR_ALLOCATION_FAILED;
    }
    mediaCtx->pBufferHeap->uiHeapElementSize       = sizeof(DDI_MEDIA_BUFFER_HEAP_ELEMENT);

    mediaCtx->pImageHeap                           = (DDI_MEDIA_HEAP *)MOS_AllocAndZeroMemory(sizeof(DDI_MEDIA_HEAP));
    if (nullptr == mediaCtx->pImageHeap)
    {
        FreeForMediaContext(mediaCtx);
        return VA_STATUS_ERROR_ALLOCATION_FAILED;
    }
    mediaCtx->pImageHeap->uiHeapElementSize        = sizeof(DDI_MEDIA_IMAGE_HEAP_ELEMENT);

    mediaCtx->pDecoderCtxHeap                      = (DDI_MEDIA_HEAP *)MOS_AllocAndZeroMemory(sizeof(DDI_MEDIA_HEAP));
    if (nullptr == mediaCtx->pDecoderCtxHeap)
    {
        FreeForMediaContext(mediaCtx);
        return VA_STATUS_ERROR_ALLOCATION_FAILED;
    }
    mediaCtx->pDecoderCtxHeap->uiHeapElementSize   = sizeof(DDI_MEDIA_VACONTEXT_HEAP_ELEMENT);

    mediaCtx->pEncoderCtxHeap                      = (DDI_MEDIA_HEAP *)MOS_AllocAndZeroMemory(sizeof(DDI_MEDIA_HEAP));
    if (nullptr == mediaCtx->pEncoderCtxHeap)
    {
        FreeForMediaContext(mediaCtx);
        return VA_STATUS_ERROR_ALLOCATION_FAILED;
    }
    mediaCtx->pEncoderCtxHeap->uiHeapElementSize   = sizeof(DDI_MEDIA_VACONTEXT_HEAP_ELEMENT);

    mediaCtx->pVpCtxHeap                           = (DDI_MEDIA_HEAP *)MOS_AllocAndZeroMemory(sizeof(DDI_MEDIA_HEAP));
    if (nullptr == mediaCtx->pVpCtxHeap)
    {
        FreeForMediaContext(mediaCtx);
        return VA_STATUS_ERROR_ALLOCATION_FAILED;
    }
    mediaCtx->pVpCtxHeap->uiHeapElementSize        = sizeof(DDI_MEDIA_VACONTEXT_HEAP_ELEMENT);

    mediaCtx->pCmCtxHeap                          = (DDI_MEDIA_HEAP *)MOS_AllocAndZeroMemory(sizeof(DDI_MEDIA_HEAP));
    if (nullptr == mediaCtx->pCmCtxHeap)
    {
        FreeForMediaContext(mediaCtx);
        return VA_STATUS_ERROR_ALLOCATION_FAILED;
    }
    mediaCtx->pCmCtxHeap->uiHeapElementSize        = sizeof(DDI_MEDIA_VACONTEXT_HEAP_ELEMENT);

    mediaCtx->pMfeCtxHeap                           = (DDI_MEDIA_HEAP *)MOS_AllocAndZeroMemory(sizeof(DDI_MEDIA_HEAP));
    if (nullptr == mediaCtx->pMfeCtxHeap)
    {
        FreeForMediaContext(mediaCtx);
        return VA_STATUS_ERROR_ALLOCATION_FAILED;
    }
    mediaCtx->pMfeCtxHeap->uiHeapElementSize        = sizeof(DDI_MEDIA_VACONTEXT_HEAP_ELEMENT);

    // Allocate memory for Media System Info
    mediaCtx->pGtSystemInfo                        = (MEDIA_SYSTEM_INFO *)MOS_AllocAndZeroMemory(sizeof(MEDIA_SYSTEM_INFO));
    if(nullptr == mediaCtx->pGtSystemInfo)
    {
        FreeForMediaContext(mediaCtx);
        return VA_STATUS_ERROR_ALLOCATION_FAILED;
    }

    mediaCtx->fd         = devicefd;
    mediaCtx->pDrmBufMgr = mos_bufmgr_gem_init(mediaCtx->fd, DDI_CODEC_BATCH_BUFFER_SIZE);
    if( nullptr == mediaCtx->pDrmBufMgr)
    {
        DDI_ASSERTMESSAGE("DDI:No able to allocate buffer manager, fd=0x%d", mediaCtx->fd);
        FreeForMediaContext(mediaCtx);
        return VA_STATUS_ERROR_INVALID_PARAMETER;
    }
    mos_bufmgr_gem_enable_reuse(mediaCtx->pDrmBufMgr);

    //Latency reducation:replace HWGetDeviceID to get device using ioctl from drm.
    mediaCtx->iDeviceId = mos_bufmgr_gem_get_devid(mediaCtx->pDrmBufMgr);

    MEDIA_FEATURE_TABLE *skuTable = &mediaCtx->SkuTable;
    MEDIA_WA_TABLE      *waTable  = &mediaCtx->WaTable;
    skuTable->reset();
    waTable->reset();

    // get Sku/Wa tables and platform information
    PLATFORM platform;
    MOS_STATUS eStatus = HWInfo_GetGfxInfo(mediaCtx->fd, &platform, skuTable, waTable, mediaCtx->pGtSystemInfo);
    if( MOS_STATUS_SUCCESS != eStatus)
    {
        DDI_ASSERTMESSAGE("Fatal error - unsuccesfull Sku/Wa/GtSystemInfo initialization");
        FreeForMediaContext(mediaCtx);
        return VA_STATUS_ERROR_OPERATION_FAILED;
    }

    GMM_SKU_FEATURE_TABLE        gmmSkuTable;
    memset(&gmmSkuTable, 0, sizeof(gmmSkuTable));

    GMM_WA_TABLE                 gmmWaTable;
    memset(&gmmWaTable, 0, sizeof(gmmWaTable));

    GMM_GT_SYSTEM_INFO           gmmGtInfo;
    memset(&gmmGtInfo, 0, sizeof(gmmGtInfo));

    eStatus = HWInfo_GetGmmInfo(mediaCtx->fd, &gmmSkuTable, &gmmWaTable, &gmmGtInfo);
    if( MOS_STATUS_SUCCESS != eStatus)
    {
        DDI_ASSERTMESSAGE("Fatal error - unsuccesfull Gmm Sku/Wa/GtSystemInfo initialization");
        FreeForMediaContext(mediaCtx);
        return VA_STATUS_ERROR_OPERATION_FAILED;
    }

    eStatus = Mos_Solo_DdiInitializeDeviceId(
                 (void*)mediaCtx->pDrmBufMgr,
                 &mediaCtx->SkuTable,
                 &mediaCtx->WaTable,
                 &gmmSkuTable,
                 &gmmWaTable,
                 &gmmGtInfo,
                 &mediaCtx->iDeviceId,
                 &mediaCtx->fd,
                 &platform);
    if (eStatus != MOS_STATUS_SUCCESS)
    {
        FreeForMediaContext(mediaCtx);
        return VA_STATUS_ERROR_OPERATION_FAILED;
    }

    MosUtilUserInterfaceInit(platform.eProductFamily);

    mediaCtx->platform = platform;

    if (MEDIA_IS_SKU(skuTable, FtrEnableMediaKernels) == 0)
    {
        MEDIA_WR_WA(waTable, WaHucStreamoutOnlyDisable, 0);
    }

    mediaCtx->m_caps = MediaLibvaCaps::CreateMediaLibvaCaps(mediaCtx);
    if (!mediaCtx->m_caps)
    {
        DDI_ASSERTMESSAGE("Caps create failed. Not supported GFX device.");
        FreeForMediaContext(mediaCtx);
        return VA_STATUS_ERROR_ALLOCATION_FAILED;
    }

    if(mediaCtx->m_caps->Init() != VA_STATUS_SUCCESS)
    {
        DDI_ASSERTMESSAGE("Caps init failed. Not supported GFX device.");
        MOS_Delete(mediaCtx->m_caps);
        mediaCtx->m_caps = nullptr;
        FreeForMediaContext(mediaCtx);
        return VA_STATUS_ERROR_ALLOCATION_FAILED;
    }
    ctx->max_image_formats = mediaCtx->m_caps->GetImageFormatsMaxNum();
#ifdef _MMC_SUPPORTED
    mediaCtx->pfnMemoryDecompress = DdiMedia_MediaMemoryDecompressInternal;
#endif
    // init the mutexs
    DdiMediaUtil_InitMutex(&mediaCtx->SurfaceMutex);
    DdiMediaUtil_InitMutex(&mediaCtx->BufferMutex);
    DdiMediaUtil_InitMutex(&mediaCtx->ImageMutex);
    DdiMediaUtil_InitMutex(&mediaCtx->DecoderMutex);
    DdiMediaUtil_InitMutex(&mediaCtx->EncoderMutex);
    DdiMediaUtil_InitMutex(&mediaCtx->VpMutex);
    DdiMediaUtil_InitMutex(&mediaCtx->CmMutex);
    DdiMediaUtil_InitMutex(&mediaCtx->MfeMutex);
#if !defined(ANDROID) && defined(X11_FOUND)
    DdiMediaUtil_InitMutex(&mediaCtx->PutSurfaceRenderMutex);
    DdiMediaUtil_InitMutex(&mediaCtx->PutSurfaceSwapBufferMutex);

    // try to open X11 lib, if fail, assume no X11 environment
    if (VA_STATUS_SUCCESS != DdiMedia_ConnectX11(mediaCtx))
    {
        // assume no X11 environment. In current implementation,
        // PutSurface (Linux) needs X11 support, so just replace
        // it with a dummy version. DdiCodec_PutSurfaceDummy() will
        // return VA_STATUS_ERROR_UNIMPLEMENTED directly.
        ctx->vtable->vaPutSurface = NULL;
    }
#endif

    ctx->pDriverData  = (void*)mediaCtx;
    mediaCtx->bIsAtomSOC = IS_ATOMSOC(mediaCtx->iDeviceId);

#if !defined(ANDROID) && defined(X11_FOUND)
    output_dri_init(ctx);
#endif

    GMM_STATUS gmmStatus = OpenGmm(&mediaCtx->GmmFuncs);
    if(gmmStatus != GMM_SUCCESS)
    {
        DDI_ASSERTMESSAGE("gmm init failed.");
        FreeForMediaContext(mediaCtx);
        return VA_STATUS_ERROR_OPERATION_FAILED;
    }

    // init GMM context
    gmmStatus = mediaCtx->GmmFuncs.pfnCreateSingletonContext(mediaCtx->platform,
                                     &gmmSkuTable,
                                     &gmmWaTable,
                                     &gmmGtInfo);

    if(gmmStatus != GMM_SUCCESS)
    {
        DDI_ASSERTMESSAGE("gmm init failed.");
        FreeForMediaContext(mediaCtx);
        return VA_STATUS_ERROR_OPERATION_FAILED;
    }

    // Create GMM Client Context
    mediaCtx->pGmmClientContext = mediaCtx->GmmFuncs.pfnCreateClientContext((GMM_CLIENT)GMM_LIBVA_LINUX);

    // Create GMM page table manager 
    mediaCtx->m_auxTableMgr = AuxTableMgr::CreateAuxTableMgr(mediaCtx->pDrmBufMgr,
        &mediaCtx->SkuTable, &mediaCtx->WaTable);

    mediaCtx->m_useSwSwizzling = MEDIA_IS_SKU(&mediaCtx->SkuTable, FtrSimulationMode);
    mediaCtx->m_tileYFlag      = MEDIA_IS_SKU(&mediaCtx->SkuTable, FtrTileY);
    mediaCtx->modularizedGpuCtxEnabled = true;

    if (mediaCtx->modularizedGpuCtxEnabled)
    {
        // prepare m_osContext
        mediaCtx->m_osContext = OsContext::GetOsContextObject();
        if (mediaCtx->m_osContext == nullptr)
        {
            MOS_OS_ASSERTMESSAGE("Unable to get the active OS context.");
            return VA_STATUS_ERROR_OPERATION_FAILED;
        }

        // fill in the mos context struct as input to initialize m_osContext
        MOS_CONTEXT mosCtx           = {};
        mosCtx.bufmgr                = mediaCtx->pDrmBufMgr;
        mosCtx.fd                    = mediaCtx->fd;
        mosCtx.iDeviceId             = mediaCtx->iDeviceId;
        mosCtx.SkuTable              = mediaCtx->SkuTable;
        mosCtx.WaTable               = mediaCtx->WaTable;
        mosCtx.gtSystemInfo          = *mediaCtx->pGtSystemInfo;
        mosCtx.platform              = mediaCtx->platform;
        mosCtx.ppMediaMemDecompState = &mediaCtx->pMediaMemDecompState;
        mosCtx.pfnMemoryDecompress   = mediaCtx->pfnMemoryDecompress;
        mosCtx.m_auxTableMgr         = mediaCtx->m_auxTableMgr;

        eStatus = mediaCtx->m_osContext->Init(&mosCtx);
        if (MOS_STATUS_SUCCESS != eStatus)
        {
            MOS_OS_ASSERTMESSAGE("Unable to initialize OS context.");
            return VA_STATUS_ERROR_OPERATION_FAILED;
        }

        // Prepare the command buffer manager
        mediaCtx->m_cmdBufMgr = CmdBufMgr::GetObject();
        if (mediaCtx->m_cmdBufMgr == nullptr)
        {
            MOS_OS_ASSERTMESSAGE(" nullptr returned by CmdBufMgr::GetObject");
            return VA_STATUS_ERROR_OPERATION_FAILED;
        }

        MOS_STATUS ret = mediaCtx->m_cmdBufMgr->Initialize(mediaCtx->m_osContext, COMMAND_BUFFER_SIZE/2);
        if (ret != MOS_STATUS_SUCCESS)
        {
            MOS_OS_ASSERTMESSAGE(" cmdBufMgr Initialization failed");
            return VA_STATUS_ERROR_OPERATION_FAILED;
        }

        // Prepare the gpu Context manager
        mediaCtx->m_gpuContextMgr = GpuContextMgr::GetObject(mediaCtx->pGtSystemInfo, mediaCtx->m_osContext);
        if (mediaCtx->m_gpuContextMgr == nullptr)
        {
            MOS_OS_ASSERTMESSAGE(" nullptr returned by GpuContextMgr::GetObject");
            return VA_STATUS_ERROR_OPERATION_FAILED;
        }
    }

    DdiMediaUtil_UnLockMutex(&GlobalMutex);

    return VA_STATUS_SUCCESS;
}

/*
 * After this call, all library internal resources will be cleaned up
 */
static VAStatus DdiMedia_Terminate (
    VADriverContextP ctx
)
{
    DDI_FUNCTION_ENTER();

    DDI_CHK_NULL(ctx,       "nullptr ctx",       VA_STATUS_ERROR_INVALID_CONTEXT);

    PDDI_MEDIA_CONTEXT mediaCtx   = DdiMedia_GetMediaContext(ctx);
    DDI_CHK_NULL(mediaCtx, "nullptr mediaCtx", VA_STATUS_ERROR_INVALID_CONTEXT);

    DdiMediaUtil_LockMutex(&GlobalMutex);

    if (mediaCtx->m_auxTableMgr != nullptr)
    {
        MOS_Delete(mediaCtx->m_auxTableMgr);
        mediaCtx->m_auxTableMgr = nullptr;
    }

#if !defined(ANDROID) && defined(X11_FOUND)
    DdiMedia_DestroyX11Connection(mediaCtx);

    if (mediaCtx->m_caps)
    {
        if (mediaCtx->dri_output != nullptr) {
            if (mediaCtx->dri_output->handle)
                dso_close(mediaCtx->dri_output->handle);

            free(mediaCtx->dri_output);
            mediaCtx->dri_output = nullptr;
        }
    }
#endif

    //destory resources
    DdiMedia_FreeSurfaceHeapElements(mediaCtx);
    DdiMedia_FreeBufferHeapElements(ctx);
    DdiMedia_FreeImageHeapElements(ctx);
    DdiMedia_FreeContextHeapElements(ctx);
    DdiMedia_FreeContextCMElements(ctx);

    if (mediaCtx->modularizedGpuCtxEnabled)
    {
        if (mediaCtx->m_gpuContextMgr)
        {
            mediaCtx->m_gpuContextMgr->CleanUp();
            MOS_Delete(mediaCtx->m_gpuContextMgr);
        }

        if (mediaCtx->m_cmdBufMgr)
        {
            mediaCtx->m_cmdBufMgr->CleanUp();
            MOS_Delete(mediaCtx->m_cmdBufMgr);
        }

        if (mediaCtx->m_osContext)
        {
            mediaCtx->m_osContext->CleanUp();
            MOS_Delete(mediaCtx->m_osContext);
        }
    }

    if (mediaCtx->uiRef > 1)
    {
        mediaCtx->uiRef--;
        DdiMediaUtil_UnLockMutex(&GlobalMutex);

        return VA_STATUS_SUCCESS;
    }

    mediaCtx->SkuTable.reset();
    mediaCtx->WaTable.reset();
    // destroy libdrm buffer manager
    mos_bufmgr_destroy(mediaCtx->pDrmBufMgr);

    // destroy heaps
    MOS_FreeMemory(mediaCtx->pSurfaceHeap->pHeapBase);
    MOS_FreeMemory(mediaCtx->pSurfaceHeap);

    MOS_FreeMemory(mediaCtx->pBufferHeap->pHeapBase);
    MOS_FreeMemory(mediaCtx->pBufferHeap);

    MOS_FreeMemory(mediaCtx->pImageHeap->pHeapBase);
    MOS_FreeMemory(mediaCtx->pImageHeap);

    MOS_FreeMemory(mediaCtx->pDecoderCtxHeap->pHeapBase);
    MOS_FreeMemory(mediaCtx->pDecoderCtxHeap);

    MOS_FreeMemory(mediaCtx->pEncoderCtxHeap->pHeapBase);
    MOS_FreeMemory(mediaCtx->pEncoderCtxHeap);

    MOS_FreeMemory(mediaCtx->pVpCtxHeap->pHeapBase);
    MOS_FreeMemory(mediaCtx->pVpCtxHeap);

    MOS_FreeMemory(mediaCtx->pCmCtxHeap->pHeapBase);
    MOS_FreeMemory(mediaCtx->pCmCtxHeap);

    MOS_FreeMemory(mediaCtx->pMfeCtxHeap->pHeapBase);
    MOS_FreeMemory(mediaCtx->pMfeCtxHeap);

    // Destroy memory allocated to store Media System Info
    MOS_FreeMemory(mediaCtx->pGtSystemInfo);

    // destroy the mutexs
    DdiMediaUtil_DestroyMutex(&mediaCtx->SurfaceMutex);
    DdiMediaUtil_DestroyMutex(&mediaCtx->BufferMutex);
    DdiMediaUtil_DestroyMutex(&mediaCtx->ImageMutex);
    DdiMediaUtil_DestroyMutex(&mediaCtx->DecoderMutex);
    DdiMediaUtil_DestroyMutex(&mediaCtx->EncoderMutex);
    DdiMediaUtil_DestroyMutex(&mediaCtx->VpMutex);
    DdiMediaUtil_DestroyMutex(&mediaCtx->CmMutex);
    DdiMediaUtil_DestroyMutex(&mediaCtx->MfeMutex);

    //resource checking
    if (mediaCtx->uiNumSurfaces != 0)
    {
        DDI_ASSERTMESSAGE("APP does not destroy all the surfaces.");
    }
    if (mediaCtx->uiNumBufs != 0)
    {
        DDI_ASSERTMESSAGE("APP does not destroy all the buffers.");
    }
    if (mediaCtx->uiNumImages != 0)
    {
        DDI_ASSERTMESSAGE("APP does not destroy all the images.");
    }
    if (mediaCtx->uiNumDecoders != 0)
    {
        DDI_ASSERTMESSAGE("APP does not destroy all the decoders.");
    }
    if (mediaCtx->uiNumEncoders != 0)
    {
        DDI_ASSERTMESSAGE("APP does not destroy all the encoders.");
    }
    if (mediaCtx->uiNumVPs != 0)
    {
        DDI_ASSERTMESSAGE("APP does not destroy all the VPs.");
    }
    if (mediaCtx->uiNumCMs != 0)
    {
        DDI_ASSERTMESSAGE("APP does not destroy all the CMs.");
    }

    if (mediaCtx->m_caps)
    {
        MOS_Delete(mediaCtx->m_caps);
        mediaCtx->m_caps = nullptr;
    }

    // Free GMM memory.
    mediaCtx->GmmFuncs.pfnDeleteClientContext(mediaCtx->pGmmClientContext);
    mediaCtx->GmmFuncs.pfnDestroySingletonContext();

    // release media driver context
    MOS_FreeMemory(mediaCtx);

    ctx->pDriverData = nullptr;
    CPLibUtils::UnloadCPLib(ctx);

    MOS_utilities_close();

    DdiMediaUtil_UnLockMutex(&GlobalMutex);

    return VA_STATUS_SUCCESS;
}

/*
 * Query supported entrypoints for a given profile
 * The caller must provide an "entrypoint_list" array that can hold at
 * least vaMaxNumEntrypoints() entries. The actual number of entrypoints
 * returned in "entrypoint_list" is returned in "num_entrypoints".
 */
static VAStatus DdiMedia_QueryConfigEntrypoints(
    VADriverContextP    ctx,
    VAProfile           profile,
    VAEntrypoint       *entrypoint_list,
    int32_t            *num_entrypoints
)
{
    DDI_FUNCTION_ENTER();

    DDI_CHK_NULL(ctx, "nullptr Ctx", VA_STATUS_ERROR_INVALID_CONTEXT);
    PDDI_MEDIA_CONTEXT mediaCtx = DdiMedia_GetMediaContext(ctx);
    DDI_CHK_NULL(mediaCtx, "nullptr mediaCtx", VA_STATUS_ERROR_INVALID_CONTEXT);
    DDI_CHK_NULL(mediaCtx->m_caps, "nullptr m_caps", VA_STATUS_ERROR_INVALID_CONTEXT);

    DDI_CHK_NULL(entrypoint_list, "nullptr entrypoint_list", VA_STATUS_ERROR_INVALID_PARAMETER);
    DDI_CHK_NULL(num_entrypoints, "nullptr num_entrypoints", VA_STATUS_ERROR_INVALID_PARAMETER);

    return mediaCtx->m_caps->QueryConfigEntrypoints(profile,
            entrypoint_list, num_entrypoints);
}

/*
 * Query supported profiles
 * The caller must provide a "profile_list" array that can hold at
 * least vaMaxNumProfile() entries. The actual number of profiles
 * returned in "profile_list" is returned in "num_profile".
 */
static VAStatus DdiMedia_QueryConfigProfiles (
    VADriverContextP    ctx,
    VAProfile          *profile_list,
    int32_t            *num_profiles
)
{
    DDI_FUNCTION_ENTER();

    DDI_CHK_NULL(ctx, "nullptr Ctx", VA_STATUS_ERROR_INVALID_CONTEXT);
    PDDI_MEDIA_CONTEXT mediaCtx = DdiMedia_GetMediaContext(ctx);

    DDI_CHK_NULL(mediaCtx, "nullptr mediaCtx", VA_STATUS_ERROR_INVALID_CONTEXT);
    DDI_CHK_NULL(mediaCtx->m_caps, "nullptr m_caps", VA_STATUS_ERROR_INVALID_CONTEXT);
    DDI_CHK_NULL(profile_list, "nullptr profile_list", VA_STATUS_ERROR_INVALID_PARAMETER);
    DDI_CHK_NULL(num_profiles, "nullptr num_profiles", VA_STATUS_ERROR_INVALID_PARAMETER);

    return mediaCtx->m_caps->QueryConfigProfiles(profile_list, num_profiles);
}

/*
 * Query all attributes for a given configuration
 * The profile of the configuration is returned in "profile"
 * The entrypoint of the configuration is returned in "entrypoint"
 * The caller must provide an "attrib_list" array that can hold at least
 * vaMaxNumConfigAttributes() entries. The actual number of attributes
 * returned in "attrib_list" is returned in "num_attribs"
 */
static VAStatus DdiMedia_QueryConfigAttributes (
    VADriverContextP    ctx,
    VAConfigID          config_id,
    VAProfile          *profile,
    VAEntrypoint       *entrypoint,
    VAConfigAttrib     *attrib_list,
    int32_t            *num_attribs
)
{
    DDI_FUNCTION_ENTER();

    DDI_CHK_NULL(profile,     "nullptr profile", VA_STATUS_ERROR_INVALID_PARAMETER);
    DDI_CHK_NULL(entrypoint,  "nullptr entrypoint", VA_STATUS_ERROR_INVALID_PARAMETER);
    DDI_CHK_NULL(ctx,         "nullptr Ctx", VA_STATUS_ERROR_INVALID_CONTEXT);
    DDI_CHK_NULL(num_attribs, "nullptr num_attribs", VA_STATUS_ERROR_INVALID_PARAMETER);

    PDDI_MEDIA_CONTEXT mediaCtx = DdiMedia_GetMediaContext(ctx);
    DDI_CHK_NULL(mediaCtx,   "nullptr mediaCtx", VA_STATUS_ERROR_INVALID_CONTEXT);
    DDI_CHK_NULL(mediaCtx->m_caps, "nullptr m_caps", VA_STATUS_ERROR_INVALID_CONTEXT);

    return mediaCtx->m_caps->QueryConfigAttributes(
                config_id, profile, entrypoint, attrib_list, num_attribs);
}

/*
 * Create a configuration for the encode/decode/vp pipeline
 * it passes in the attribute list that specifies the attributes it cares
 * about, with the rest taking default values.
 */
static VAStatus DdiMedia_CreateConfig (
    VADriverContextP    ctx,
    VAProfile           profile,
    VAEntrypoint        entrypoint,
    VAConfigAttrib     *attrib_list,
    int32_t             num_attribs,
    VAConfigID         *config_id
)
{
    DDI_FUNCTION_ENTER();

    DDI_CHK_NULL(ctx,       "nullptr ctx",       VA_STATUS_ERROR_INVALID_CONTEXT);
    DDI_CHK_NULL(config_id, "nullptr config_id", VA_STATUS_ERROR_INVALID_PARAMETER);

    PDDI_MEDIA_CONTEXT mediaCtx = DdiMedia_GetMediaContext(ctx);
    DDI_CHK_NULL(mediaCtx, "nullptr mediaCtx", VA_STATUS_ERROR_INVALID_CONTEXT);
    DDI_CHK_NULL(mediaCtx->m_caps, "nullptr m_caps", VA_STATUS_ERROR_INVALID_CONTEXT);

    return mediaCtx->m_caps->CreateConfig(
            profile, entrypoint, attrib_list, num_attribs, config_id);
}

/*
 * Free resources associated with a given config
 */
static VAStatus DdiMedia_DestroyConfig (
    VADriverContextP    ctx,
    VAConfigID          config_id
)
{
    DDI_FUNCTION_ENTER();

    DDI_CHK_NULL(ctx,       "nullptr ctx",       VA_STATUS_ERROR_INVALID_CONTEXT);

    PDDI_MEDIA_CONTEXT mediaCtx = DdiMedia_GetMediaContext(ctx);
    DDI_CHK_NULL(mediaCtx, "nullptr mediaCtx", VA_STATUS_ERROR_INVALID_CONTEXT);
    DDI_CHK_NULL(mediaCtx->m_caps, "nullptr m_caps", VA_STATUS_ERROR_INVALID_CONTEXT);

    return mediaCtx->m_caps->DestroyConfig(config_id);
}

/*
 * Get attributes for a given profile/entrypoint pair
 * The caller must provide an "attrib_list" with all attributes to be
 * retrieved.  Upon return, the attributes in "attrib_list" have been
 * updated with their value.  Unknown attributes or attributes that are
 * not supported for the given profile/entrypoint pair will have their
 * value set to VA_ATTRIB_NOT_SUPPORTED
 */
static VAStatus DdiMedia_GetConfigAttributes(
    VADriverContextP    ctx,
    VAProfile           profile,
    VAEntrypoint        entrypoint,
    VAConfigAttrib     *attrib_list,
    int32_t             num_attribs
)
{
    DDI_FUNCTION_ENTER();

    DDI_CHK_NULL(ctx,       "nullptr ctx",       VA_STATUS_ERROR_INVALID_CONTEXT);

    PDDI_MEDIA_CONTEXT mediaCtx = DdiMedia_GetMediaContext(ctx);
    DDI_CHK_NULL(mediaCtx, "nullptr mediaCtx", VA_STATUS_ERROR_INVALID_CONTEXT);
    DDI_CHK_NULL(mediaCtx->m_caps, "nullptr m_caps", VA_STATUS_ERROR_INVALID_CONTEXT);

    return mediaCtx->m_caps->GetConfigAttributes(
            profile, entrypoint, attrib_list, num_attribs);
}

static VAStatus DdiMedia_CreateSurfaces (
    VADriverContextP    ctx,
    int32_t             width,
    int32_t             height,
    int32_t             format,
    int32_t             num_surfaces,
    VASurfaceID        *surfaces
)
{
    DDI_FUNCTION_ENTER();

    DDI_CHK_NULL(ctx,               "nullptr ctx",             VA_STATUS_ERROR_INVALID_CONTEXT);
    DDI_CHK_LARGER(num_surfaces, 0, "Invalid num_surfaces", VA_STATUS_ERROR_INVALID_PARAMETER);
    DDI_CHK_NULL(surfaces,          "nullptr surfaces",        VA_STATUS_ERROR_INVALID_PARAMETER);
    DDI_CHK_LARGER(width,        0, "Invalid width",        VA_STATUS_ERROR_INVALID_PARAMETER);
    DDI_CHK_LARGER(height,       0, "Invalid height",       VA_STATUS_ERROR_INVALID_PARAMETER);

    PDDI_MEDIA_CONTEXT mediaDrvCtx = DdiMedia_GetMediaContext(ctx);
    DDI_CHK_NULL(mediaDrvCtx,       "nullptr mediaDrvCtx", VA_STATUS_ERROR_INVALID_CONTEXT);

    if( format != VA_RT_FORMAT_YUV420 ||
        format != VA_RT_FORMAT_YUV422 ||
        format != VA_RT_FORMAT_YUV444 ||
        format != VA_RT_FORMAT_YUV400 ||
        format != VA_RT_FORMAT_YUV411)
    {
        return VA_STATUS_ERROR_UNSUPPORTED_RT_FORMAT;
    }

    DDI_MEDIA_FORMAT mediaFmt = DdiMedia_OsFormatToMediaFormat(VA_FOURCC_NV12,format);

    height = MOS_ALIGN_CEIL(height, 16);
    for(int32_t i = 0; i < num_surfaces; i++)
    {
        VASurfaceID vaSurfaceID = (VASurfaceID)DdiMedia_CreateRenderTarget(mediaDrvCtx, mediaFmt, width, height, nullptr, VA_SURFACE_ATTRIB_USAGE_HINT_GENERIC);
        if (VA_INVALID_ID != vaSurfaceID)
            surfaces[i] = vaSurfaceID;
        else
        {
            // here to release the successful allocated surfaces?
            return VA_STATUS_ERROR_ALLOCATION_FAILED;
        }
    }

    return VA_STATUS_SUCCESS;
}

/*
 * vaDestroySurfaces - Destroy resources associated with surfaces.
 *  Surfaces can only be destroyed after the context associated has been
 *  destroyed.
 *  dpy: display
 *  surfaces: array of surfaces to destroy
 *  num_surfaces: number of surfaces in the array to be destroyed.
 */
static VAStatus DdiMedia_DestroySurfaces (
    VADriverContextP    ctx,
    VASurfaceID        *surfaces,
    int32_t             num_surfaces
)
{
    DDI_FUNCTION_ENTER();

    DDI_CHK_NULL  (ctx,             "nullptr ctx",             VA_STATUS_ERROR_INVALID_CONTEXT);
    DDI_CHK_LARGER(num_surfaces, 0, "Invalid num_surfaces", VA_STATUS_ERROR_INVALID_PARAMETER);
    DDI_CHK_NULL  (surfaces,        "nullptr surfaces",        VA_STATUS_ERROR_INVALID_PARAMETER);

    PDDI_MEDIA_CONTEXT mediaCtx = DdiMedia_GetMediaContext(ctx);
    DDI_CHK_NULL  (mediaCtx,                  "nullptr mediaCtx",               VA_STATUS_ERROR_INVALID_CONTEXT);
    DDI_CHK_NULL  (mediaCtx->pSurfaceHeap,    "nullptr mediaCtx->pSurfaceHeap", VA_STATUS_ERROR_INVALID_CONTEXT);

    PDDI_MEDIA_SURFACE surface = nullptr;
    for(int32_t i = 0; i < num_surfaces; i++)
    {
        DDI_CHK_LESS((uint32_t)surfaces[i], mediaCtx->pSurfaceHeap->uiAllocatedHeapElements, "Invalid surfaces", VA_STATUS_ERROR_INVALID_SURFACE);
        surface = DdiMedia_GetSurfaceFromVASurfaceID(mediaCtx, surfaces[i]);
        DDI_CHK_NULL(surface, "nullptr surface", VA_STATUS_ERROR_INVALID_SURFACE);
        if(surface->pCurrentFrameSemaphore)
        {
            DdiMediaUtil_WaitSemaphore(surface->pCurrentFrameSemaphore);
            DdiMediaUtil_PostSemaphore(surface->pCurrentFrameSemaphore);
        }
        if(surface->pReferenceFrameSemaphore)
        {
            DdiMediaUtil_WaitSemaphore(surface->pReferenceFrameSemaphore);
            DdiMediaUtil_PostSemaphore(surface->pReferenceFrameSemaphore);
        }
    }

    for(int32_t i = 0; i < num_surfaces; i++)
    {
        DDI_CHK_LESS((uint32_t)surfaces[i], mediaCtx->pSurfaceHeap->uiAllocatedHeapElements, "Invalid surfaces", VA_STATUS_ERROR_INVALID_SURFACE);
        surface = DdiMedia_GetSurfaceFromVASurfaceID(mediaCtx, surfaces[i]);
        DDI_CHK_NULL(surface, "nullptr surface", VA_STATUS_ERROR_INVALID_SURFACE);
        if(surface->pCurrentFrameSemaphore)
        {
            DdiMediaUtil_DestroySemaphore(surface->pCurrentFrameSemaphore);
            surface->pCurrentFrameSemaphore = nullptr;
        }

        if(surface->pReferenceFrameSemaphore)
        {
            DdiMediaUtil_DestroySemaphore(surface->pReferenceFrameSemaphore);
            surface->pReferenceFrameSemaphore = nullptr;
        }

        DdiMediaUtil_UnRegisterRTSurfaces(ctx, surface);

        DdiMediaUtil_FreeSurface(surface);
        MOS_FreeMemory(surface);
        DdiMediaUtil_LockMutex(&mediaCtx->SurfaceMutex);
        DdiMediaUtil_ReleasePMediaSurfaceFromHeap(mediaCtx->pSurfaceHeap, (uint32_t)surfaces[i]);
        mediaCtx->uiNumSurfaces--;
        DdiMediaUtil_UnLockMutex(&mediaCtx->SurfaceMutex);
    }

    return VA_STATUS_SUCCESS;
}

static VAStatus
DdiMedia_CreateSurfaces2(
    VADriverContextP    ctx,
    uint32_t            format,
    uint32_t            width,
    uint32_t            height,
    VASurfaceID        *surfaces,
    uint32_t            num_surfaces,
    VASurfaceAttrib    *attrib_list,
    uint32_t            num_attribs
    )
{
    DDI_FUNCTION_ENTER();

    DDI_CHK_NULL  (ctx,             "nullptr ctx",             VA_STATUS_ERROR_INVALID_CONTEXT);
    DDI_CHK_LARGER(num_surfaces, 0, "Invalid num_surfaces", VA_STATUS_ERROR_INVALID_PARAMETER);
    DDI_CHK_NULL  (surfaces,        "nullptr surfaces",        VA_STATUS_ERROR_INVALID_PARAMETER);
    DDI_CHK_LARGER(width,        0, "Invalid width",        VA_STATUS_ERROR_INVALID_PARAMETER);
    DDI_CHK_LARGER(height,       0, "Invalid height",       VA_STATUS_ERROR_INVALID_PARAMETER);

    if(num_attribs > 0)
    {
        DDI_CHK_NULL(attrib_list, "nullptr attrib_list", VA_STATUS_ERROR_INVALID_PARAMETER);
    }

    PDDI_MEDIA_CONTEXT mediaCtx    = DdiMedia_GetMediaContext(ctx);
    DDI_CHK_NULL(mediaCtx,       "nullptr mediaCtx",   VA_STATUS_ERROR_INVALID_CONTEXT);

    int32_t expected_fourcc = VA_FOURCC_NV12;
    switch(format)
    {
        case VA_RT_FORMAT_YUV420:
            expected_fourcc = VA_FOURCC_NV12;
            break;
        case VA_RT_FORMAT_YUV420_12:
            expected_fourcc = VA_FOURCC_P016;
            break;
        case VA_RT_FORMAT_YUV422:
            expected_fourcc = VA_FOURCC_YUY2;
            break;
        case VA_RT_FORMAT_YUV422_10:
            expected_fourcc = VA_FOURCC_Y210;
            break;
        case VA_RT_FORMAT_YUV422_12:
            expected_fourcc = VA_FOURCC_Y216;
            break;
        case VA_RT_FORMAT_YUV444:
            expected_fourcc = VA_FOURCC_444P;
            break;
        case VA_RT_FORMAT_YUV444_10:
            expected_fourcc = VA_FOURCC_Y410;
            break;
        case VA_RT_FORMAT_YUV411:
            expected_fourcc = VA_FOURCC_411P;
            break;
        case VA_RT_FORMAT_YUV400:
            expected_fourcc = VA_FOURCC('4','0','0','P');
            break;
        case VA_RT_FORMAT_YUV420_10BPP:
            expected_fourcc = VA_FOURCC_P010;
            break;
        case VA_RT_FORMAT_RGB16:
            expected_fourcc = VA_FOURCC_R5G6B5;
            break;
        case VA_RT_FORMAT_RGB32:
            expected_fourcc = VA_FOURCC_BGRA;
            break;
        case VA_RT_FORMAT_RGBP:
            expected_fourcc = VA_FOURCC_RGBP;
            break;
#ifdef VA_RT_FORMAT_RGB32_10BPP
        case VA_RT_FORMAT_RGB32_10BPP:
            expected_fourcc = VA_FOURCC_BGRA;
            break;
#endif
#if 1 //added for having MDF sanity test pass, will be removed after MDF formal patch checked in
        case VA_FOURCC_NV12:
            expected_fourcc = VA_FOURCC_NV12;
            break;
        case VA_FOURCC_NV21:
            expected_fourcc = VA_FOURCC_NV21;
            break;
        case VA_FOURCC_ABGR:
            expected_fourcc = VA_FOURCC_ABGR;
            break;
        case VA_FOURCC_ARGB:
            expected_fourcc = VA_FOURCC_ARGB;
            break;
        case VA_FOURCC_XBGR:
            expected_fourcc = VA_FOURCC_XBGR;
            break;
        case VA_FOURCC_XRGB:
            expected_fourcc = VA_FOURCC_XRGB;
            break;
        case VA_FOURCC_R5G6B5:
            expected_fourcc = VA_FOURCC_R5G6B5;
            break;
        case VA_FOURCC_R8G8B8:
            expected_fourcc = VA_FOURCC_R8G8B8;
            break;
        case VA_FOURCC_YUY2:
            expected_fourcc = VA_FOURCC_YUY2;
            break;
        case VA_FOURCC_YV12:
            expected_fourcc = VA_FOURCC_YV12;
            break;
        case VA_FOURCC_422H:
            expected_fourcc = VA_FOURCC_422H;
            break;
        case VA_FOURCC_422V:
            expected_fourcc = VA_FOURCC_422V;
            break;
        case VA_FOURCC_P208:
            expected_fourcc = VA_FOURCC_P208;
            break;
        case VA_FOURCC_P010:
            expected_fourcc = VA_FOURCC_P010;
            break;
        case VA_FOURCC_P016:
            expected_fourcc = VA_FOURCC_P016;
            break;
        case VA_FOURCC_Y210:
            expected_fourcc = VA_FOURCC_Y210;
            break;
        case VA_FOURCC_Y216:
            expected_fourcc = VA_FOURCC_Y216;
            break;
        case VA_FOURCC_AYUV:
            expected_fourcc = VA_FOURCC_AYUV;
            break;
        case VA_FOURCC_Y410:
            expected_fourcc = VA_FOURCC_Y410;
            break;
        case VA_FOURCC_Y416:
            expected_fourcc = VA_FOURCC_Y416;
            break;
#endif
        default:
            DDI_ASSERTMESSAGE("Invalid VAConfigAttribRTFormat: 0x%x. Please uses the format defined in libva/va.h", format);
            return VA_STATUS_ERROR_UNSUPPORTED_RT_FORMAT;
    }

    VASurfaceAttribExternalBuffers externalBufDescripor;
    VASurfaceAttribExternalBuffers *externalBufDesc = &externalBufDescripor;
    MOS_ZeroMemory(&externalBufDescripor, sizeof(externalBufDescripor));

    int32_t  memTypeFlag      = 0;
    uint32_t surfaceUsageHint = VA_SURFACE_ATTRIB_USAGE_HINT_GENERIC;
    bool     surfDescProvided = false;
    bool     surfIsUserPtr    = false;

    for (uint32_t i = 0; i < num_attribs && attrib_list; i++)
    {
        if (attrib_list[i].flags & VA_SURFACE_ATTRIB_SETTABLE)
        {
             switch (attrib_list[i].type)
             {
                  case VASurfaceAttribUsageHint:
                      DDI_ASSERT(attrib_list[i].value.type == VAGenericValueTypeInteger);
                      surfaceUsageHint = attrib_list[i].value.value.i;
                      break;
                  case VASurfaceAttribPixelFormat:
                      DDI_ASSERT(attrib_list[i].value.type == VAGenericValueTypeInteger);
                      expected_fourcc = attrib_list[i].value.value.i;
                      break;
                  case VASurfaceAttribMemoryType:
                      DDI_ASSERT(attrib_list[i].value.type == VAGenericValueTypeInteger);
                      if (attrib_list[i].value.value.i == VA_SURFACE_ATTRIB_MEM_TYPE_VA)
                      {
                          // Default memory type - no effect.
                      }
                      else if ( (attrib_list[i].value.value.i == VA_SURFACE_ATTRIB_MEM_TYPE_KERNEL_DRM)
                                ||(attrib_list[i].value.value.i == VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME)
                                ||(attrib_list[i].value.value.i == VA_SURFACE_ATTRIB_MEM_TYPE_USER_PTR)
                          )
                      {
                           memTypeFlag = attrib_list[i].value.value.i;
                           surfIsUserPtr = (attrib_list[i].value.value.i == VA_SURFACE_ATTRIB_MEM_TYPE_USER_PTR);
                      }
                      else
                      {
                           DDI_ASSERTMESSAGE("Not supported external buffer type.");
                           return VA_STATUS_ERROR_INVALID_PARAMETER;
                      }
                      break;
                  case (VASurfaceAttribType)VASurfaceAttribExternalBufferDescriptor:
                      DDI_ASSERT(attrib_list[i].value.type == VAGenericValueTypePointer);
                      if( nullptr == attrib_list[i].value.value.p )
                      {
                          DDI_ASSERTMESSAGE("Invalid VASurfaceAttribExternalBuffers used.");
                          //remove the check for libva-utils conformance test, need libva-utils change cases
                          //after libva-utils fix the case, return VA_STATUS_ERROR_INVALID_PARAMETER;
                          break;
                      }
                      MOS_SecureMemcpy(externalBufDesc, sizeof(VASurfaceAttribExternalBuffers),  attrib_list[i].value.value.p, sizeof(VASurfaceAttribExternalBuffers));

                      expected_fourcc  = externalBufDesc->pixel_format;
                      width            = externalBufDesc->width;
                      height           = externalBufDesc->height;
                      surfDescProvided = true;
                      // the following code is for backward compatible and it will be removed in the future
                     // new implemention should use VASurfaceAttribMemoryType attrib and set its value to VA_SURFACE_ATTRIB_MEM_TYPE_KERNEL_DRM
                     if( (externalBufDesc->flags & VA_SURFACE_ATTRIB_MEM_TYPE_KERNEL_DRM )
                         || (externalBufDesc->flags & VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME)
                         || (externalBufDesc->flags & VA_SURFACE_EXTBUF_DESC_PROTECTED)
                         )
                      {
                          memTypeFlag       = externalBufDesc->flags;
                          surfIsUserPtr = false;
                      }

                      break;
                  default:
                      DDI_ASSERTMESSAGE("Unsupported type.");
                      break;
              }
        }
    }

    DDI_MEDIA_FORMAT mediaFmt = DdiMedia_OsFormatToMediaFormat(expected_fourcc,format);
    if (mediaFmt == Media_Format_Count)
    {
        DDI_ASSERTMESSAGE("DDI: unsupported surface type in DdiMedia_CreateSurfaces2.");
        return VA_STATUS_ERROR_UNSUPPORTED_RT_FORMAT;
    }

    if ( surfDescProvided == true && memTypeFlag == 0) {
        DDI_ASSERTMESSAGE("Not supported external buffer type.");
        return VA_STATUS_ERROR_INVALID_PARAMETER;
    }

    for(uint32_t i = 0; i < num_surfaces; i++)
    {
        PDDI_MEDIA_SURFACE_DESCRIPTOR surfDesc = nullptr;
        MOS_STATUS                    eStatus = MOS_STATUS_SUCCESS;

        if( surfDescProvided == true )
        {
            surfDesc = (PDDI_MEDIA_SURFACE_DESCRIPTOR)MOS_AllocAndZeroMemory(sizeof(DDI_MEDIA_SURFACE_DESCRIPTOR));
            if( surfDesc == nullptr )
            {
                return VA_STATUS_ERROR_ALLOCATION_FAILED;
            }
            memset(surfDesc,0,sizeof(DDI_MEDIA_SURFACE_DESCRIPTOR));

            surfDesc->uiPlanes       = externalBufDesc->num_planes;
            surfDesc->ulBuffer       = externalBufDesc->buffers[i];
            surfDesc->uiFlags        = memTypeFlag;
            surfDesc->uiSize         = externalBufDesc->data_size;
            surfDesc->uiBuffserSize  = externalBufDesc->data_size;

            eStatus = MOS_SecureMemcpy(surfDesc->uiPitches, sizeof(surfDesc->uiPitches), externalBufDesc->pitches, sizeof(externalBufDesc->pitches));
            if (eStatus != MOS_STATUS_SUCCESS)
            {
                DDI_VERBOSEMESSAGE("DDI:Failed to copy surface buffer data!");
                return VA_STATUS_ERROR_OPERATION_FAILED;
            }
            eStatus = MOS_SecureMemcpy(surfDesc->uiOffsets, sizeof(surfDesc->uiOffsets), externalBufDesc->offsets, sizeof(externalBufDesc->offsets));
            if (eStatus != MOS_STATUS_SUCCESS)
            {
                DDI_VERBOSEMESSAGE("DDI:Failed to copy surface buffer data!");
                return VA_STATUS_ERROR_OPERATION_FAILED;
            }

            if( surfIsUserPtr )
            {
                surfDesc->uiTile = I915_TILING_NONE;
                if (surfDesc->ulBuffer % 4096 != 0)
                {
                    DDI_VERBOSEMESSAGE("Buffer Address is invalid");
                    return VA_STATUS_ERROR_INVALID_PARAMETER;
                }
            }
        }
        VASurfaceID vaSurfaceID = (VASurfaceID)DdiMedia_CreateRenderTarget(mediaCtx, mediaFmt, width, height, (surfDescProvided ? surfDesc : nullptr), surfaceUsageHint );
        if (VA_INVALID_ID != vaSurfaceID)
        {
            surfaces[i] = vaSurfaceID;
        }
        else
        {
            // here to release the successful allocated surfaces?
            if( nullptr != surfDesc )
            {
                MOS_FreeMemory(surfDesc);
            }
            return VA_STATUS_ERROR_ALLOCATION_FAILED;
        }
    }

    return VA_STATUS_SUCCESS;
}

static VAStatus DdiMedia_CreateMfeContextInternal(
    VADriverContextP    ctx,
    VAMFContextID      *mfe_context
)
{
    PDDI_MEDIA_CONTEXT mediaDrvCtx   = DdiMedia_GetMediaContext(ctx);
    DDI_CHK_NULL(mediaDrvCtx, "nullptr pMediaCtx", VA_STATUS_ERROR_INVALID_CONTEXT);

    DDI_CHK_NULL(mfe_context, "nullptr mfe_context", VA_STATUS_ERROR_INVALID_PARAMETER);
    *mfe_context        = DDI_MEDIA_INVALID_VACONTEXTID;

    if (!GFX_IS_PRODUCT(mediaDrvCtx->platform, IGFX_SKYLAKE))
    {
        DDI_VERBOSEMESSAGE("MFE is not supported on the platform!");
        return VA_STATUS_ERROR_UNIMPLEMENTED;
    }

    PDDI_ENCODE_MFE_CONTEXT encodeMfeContext = (PDDI_ENCODE_MFE_CONTEXT)MOS_AllocAndZeroMemory(sizeof(DDI_ENCODE_MFE_CONTEXT));
    if (nullptr == encodeMfeContext)
    {
        MOS_FreeMemory(encodeMfeContext);
        return VA_STATUS_ERROR_ALLOCATION_FAILED;
    }

    DdiMediaUtil_LockMutex(&mediaDrvCtx->MfeMutex);
    PDDI_MEDIA_VACONTEXT_HEAP_ELEMENT vaContextHeapElmt = DdiMediaUtil_AllocPVAContextFromHeap(mediaDrvCtx->pMfeCtxHeap);
    if (nullptr == vaContextHeapElmt)
    {
        DdiMediaUtil_UnLockMutex(&mediaDrvCtx->MfeMutex);
        MOS_FreeMemory(encodeMfeContext);
        return VA_STATUS_ERROR_MAX_NUM_EXCEEDED;
    }

    vaContextHeapElmt->pVaContext    = (void*)encodeMfeContext;
    mediaDrvCtx->uiNumMfes++;
    *mfe_context                     = (VAMFContextID)(vaContextHeapElmt->uiVaContextID + DDI_MEDIA_VACONTEXTID_OFFSET_MFE);
    DdiMediaUtil_UnLockMutex(&mediaDrvCtx->MfeMutex);

    // Create shared state, which is used by all the sub contexts
    MfeSharedState *mfeEncodeSharedState   = (MfeSharedState*)MOS_AllocAndZeroMemory(sizeof(MfeSharedState));
    if (nullptr == mfeEncodeSharedState)
    {
        MOS_FreeMemory(encodeMfeContext);
        return VA_STATUS_ERROR_ALLOCATION_FAILED;
    }

    encodeMfeContext->mfeEncodeSharedState = mfeEncodeSharedState;

    DdiMediaUtil_InitMutex(&encodeMfeContext->encodeMfeMutex);

    return VA_STATUS_SUCCESS;
}

static VAStatus DdiMedia_DestoryMfeContext (
    VADriverContextP    ctx,
    VAMFContextID      mfe_context
)
{
    PDDI_MEDIA_CONTEXT mediaCtx              = DdiMedia_GetMediaContext(ctx);
    DDI_CHK_NULL(mediaCtx, "nullptr mediaCtx", VA_STATUS_ERROR_INVALID_CONTEXT);

    uint32_t ctxType = DDI_MEDIA_CONTEXT_TYPE_NONE;
    PDDI_ENCODE_MFE_CONTEXT encodeMfeContext = (PDDI_ENCODE_MFE_CONTEXT)DdiMedia_GetContextFromContextID(ctx, mfe_context, &ctxType);
    DDI_CHK_NULL(encodeMfeContext, "nullptr encodeMfeContext", VA_STATUS_ERROR_INVALID_CONTEXT);

    // Release std::vector memory
    encodeMfeContext->pDdiEncodeContexts.clear();
    encodeMfeContext->pDdiEncodeContexts.shrink_to_fit();

    encodeMfeContext->mfeEncodeSharedState->encoders.clear();
    encodeMfeContext->mfeEncodeSharedState->encoders.shrink_to_fit();

    DdiMediaUtil_DestroyMutex(&encodeMfeContext->encodeMfeMutex);
    MOS_FreeMemory(encodeMfeContext->mfeEncodeSharedState);
    MOS_FreeMemory(encodeMfeContext);

    DdiMediaUtil_LockMutex(&mediaCtx->MfeMutex);
    DdiMediaUtil_ReleasePVAContextFromHeap(mediaCtx->pMfeCtxHeap, (mfe_context & DDI_MEDIA_MASK_VACONTEXTID));
    mediaCtx->uiNumMfes--;
    DdiMediaUtil_UnLockMutex(&mediaCtx->MfeMutex);
    return VA_STATUS_SUCCESS;
}

static VAStatus DdiMedia_AddContextInternal(
    VADriverContextP    ctx,
    VAContextID         context,
    VAMFContextID      mfe_context
)
{
    PDDI_MEDIA_CONTEXT      mediaCtx         = DdiMedia_GetMediaContext(ctx);
    DDI_CHK_NULL(mediaCtx, "nullptr mediaCtx", VA_STATUS_ERROR_INVALID_CONTEXT);

    uint32_t                ctxType          = DDI_MEDIA_CONTEXT_TYPE_NONE;
    PDDI_ENCODE_MFE_CONTEXT encodeMfeContext = (PDDI_ENCODE_MFE_CONTEXT)DdiMedia_GetContextFromContextID(ctx, mfe_context, &ctxType);
    DDI_CHK_NULL(encodeMfeContext, "nullptr encodeMfeContext", VA_STATUS_ERROR_INVALID_CONTEXT);

    if (ctxType != DDI_MEDIA_CONTEXT_TYPE_MFE)
    {
        return VA_STATUS_ERROR_OPERATION_FAILED;
    }

    PDDI_ENCODE_CONTEXT     encodeContext    = DdiEncode_GetEncContextFromContextID(ctx, context);
    DDI_CHK_NULL(encodeContext, "nullptr encodeContext", VA_STATUS_ERROR_INVALID_CONTEXT);

    CodechalEncoderState    *encoder         = dynamic_cast<CodechalEncoderState *>(encodeContext->pCodecHal);
    DDI_CHK_NULL(encoder, "nullptr codechal encoder", VA_STATUS_ERROR_INVALID_CONTEXT);

    if (!mediaCtx->m_caps->IsMfeSupportedEntrypoint(encodeContext->vaEntrypoint))
    {
        return VA_STATUS_ERROR_UNSUPPORTED_ENTRYPOINT;
    }

    if (!mediaCtx->m_caps->IsMfeSupportedProfile(encodeContext->vaProfile))
    {
        return VA_STATUS_ERROR_UNSUPPORTED_PROFILE;
    }

    DdiMediaUtil_LockMutex(&encodeMfeContext->encodeMfeMutex);
    encodeMfeContext->pDdiEncodeContexts.push_back(encodeContext);

    if (encodeMfeContext->currentStreamId == 0)
    {
        encodeMfeContext->isFEI = (encodeContext->vaEntrypoint == VAEntrypointFEI) ? true : false;
    }

    //MFE cannot support legacy and FEI together
    if ((encodeContext->vaEntrypoint != VAEntrypointFEI && encodeMfeContext->isFEI) ||
        (encodeContext->vaEntrypoint == VAEntrypointFEI && !encodeMfeContext->isFEI))
    {
        DdiMediaUtil_UnLockMutex(&encodeMfeContext->encodeMfeMutex);
        return VA_STATUS_ERROR_INVALID_CONTEXT;
    }

    encoder->m_mfeEnabled = true;
    // Assign one unique id to this sub context/stream
    encoder->m_mfeEncodeParams.streamId = encodeMfeContext->currentStreamId;
    encoder->m_mfeEncodeSharedState     = encodeMfeContext->mfeEncodeSharedState;

    encodeMfeContext->currentStreamId++;
    DdiMediaUtil_UnLockMutex(&encodeMfeContext->encodeMfeMutex);
    return VA_STATUS_SUCCESS;
}

static VAStatus DdiMedia_ReleaseContextInternal(
    VADriverContextP    ctx,
    VAContextID         context,
    VAMFContextID      mfe_context
)
{
    PDDI_MEDIA_CONTEXT mediaCtx   = DdiMedia_GetMediaContext(ctx);
    DDI_CHK_NULL(mediaCtx, "nullptr mediaCtx", VA_STATUS_ERROR_INVALID_CONTEXT);

    uint32_t  ctxType = DDI_MEDIA_CONTEXT_TYPE_NONE;
    PDDI_ENCODE_MFE_CONTEXT encodeMfeContext  = (PDDI_ENCODE_MFE_CONTEXT)DdiMedia_GetContextFromContextID(ctx, mfe_context, &ctxType);
    DDI_CHK_NULL(encodeMfeContext, "nullptr encodeMfeContext", VA_STATUS_ERROR_INVALID_CONTEXT);

    if (ctxType != DDI_MEDIA_CONTEXT_TYPE_MFE ||
        encodeMfeContext->pDdiEncodeContexts.size() == 0)
    {
        return VA_STATUS_ERROR_OPERATION_FAILED;
    }

    PDDI_ENCODE_CONTEXT encodeContext  = DdiEncode_GetEncContextFromContextID(ctx, context);
    DDI_CHK_NULL(encodeMfeContext, "nullptr encodeContext", VA_STATUS_ERROR_INVALID_CONTEXT);

    bool contextErased = false;
    DdiMediaUtil_LockMutex(&encodeMfeContext->encodeMfeMutex);
    for (uint32_t i = 0; i < encodeMfeContext->pDdiEncodeContexts.size(); i++)
    {
        if (encodeMfeContext->pDdiEncodeContexts[i] == encodeContext)
        {
            encodeMfeContext->pDdiEncodeContexts.erase(encodeMfeContext->pDdiEncodeContexts.begin() + i);
            contextErased = true;
            break;
        }
    }

    if (!contextErased)
    {
        DdiMediaUtil_UnLockMutex(&encodeMfeContext->encodeMfeMutex);
        return VA_STATUS_ERROR_OPERATION_FAILED;
    }

    DdiMediaUtil_UnLockMutex(&encodeMfeContext->encodeMfeMutex);

    return VA_STATUS_SUCCESS;
}

static VAStatus DdiMedia_CreateContext (
    VADriverContextP    ctx,
    VAConfigID          config_id,
    int32_t             picture_width,
    int32_t             picture_height,
    int32_t             flag,
    VASurfaceID        *render_targets,
    int32_t             num_render_targets,
    VAContextID        *context
)
{
    DDI_FUNCTION_ENTER();

    DDI_CHK_NULL(ctx,     "nullptr ctx",          VA_STATUS_ERROR_INVALID_CONTEXT);
    DDI_CHK_NULL(context, "nullptr context",      VA_STATUS_ERROR_INVALID_PARAMETER);

    PDDI_MEDIA_CONTEXT mediaDrvCtx = DdiMedia_GetMediaContext(ctx);
    DDI_CHK_NULL(mediaDrvCtx,     "nullptr mediaDrvCtx", VA_STATUS_ERROR_INVALID_CONTEXT);

    if(num_render_targets > 0)
    {
        DDI_CHK_NULL(render_targets,             "nullptr render_targets",             VA_STATUS_ERROR_INVALID_PARAMETER);
        DDI_CHK_NULL(mediaDrvCtx->pSurfaceHeap, "nullptr mediaDrvCtx->pSurfaceHeap", VA_STATUS_ERROR_INVALID_CONTEXT);
        for(int32_t i = 0; i < num_render_targets; i++)
        {
            uint32_t surfaceId = (uint32_t)render_targets[i];
            DDI_CHK_LESS(surfaceId, mediaDrvCtx->pSurfaceHeap->uiAllocatedHeapElements, "Invalid Surface", VA_STATUS_ERROR_INVALID_SURFACE);
        }
    }

    VAStatus vaStatus = VA_STATUS_SUCCESS;
    if(mediaDrvCtx->m_caps->IsDecConfigId(config_id))
    {
        vaStatus = DdiDecode_CreateContext(ctx, config_id - DDI_CODEC_GEN_CONFIG_ATTRIBUTES_DEC_BASE, picture_width, picture_height, flag, render_targets, num_render_targets, context);
    }
    else if(mediaDrvCtx->m_caps->IsEncConfigId(config_id))
    {
        vaStatus = DdiEncode_CreateContext(ctx, config_id - DDI_CODEC_GEN_CONFIG_ATTRIBUTES_ENC_BASE, picture_width, picture_height, flag, render_targets, num_render_targets, context);
    }
    else if(mediaDrvCtx->m_caps->IsVpConfigId(config_id))
    {
        vaStatus = DdiVp_CreateContext(ctx, config_id - DDI_VP_GEN_CONFIG_ATTRIBUTES_BASE, picture_width, picture_height, flag, render_targets, num_render_targets, context);
    }
    else
    {
        DDI_ASSERTMESSAGE("DDI: Invalid config_id");
        vaStatus = VA_STATUS_ERROR_INVALID_CONFIG;
    }

    return vaStatus;
}

static VAStatus DdiMedia_DestroyContext (
    VADriverContextP    ctx,
    VAContextID         context
)
{
    DDI_FUNCTION_ENTER();

    DDI_CHK_NULL(ctx, "nullptr ctx", VA_STATUS_ERROR_INVALID_CONTEXT);

    uint32_t            ctxType = DDI_MEDIA_CONTEXT_TYPE_NONE;
    void *ctxPtr = DdiMedia_GetContextFromContextID(ctx, context, &ctxType);

    switch (ctxType)
    {
        case DDI_MEDIA_CONTEXT_TYPE_DECODER:
        case DDI_MEDIA_CONTEXT_TYPE_CENC_DECODER:
            return DdiDecode_DestroyContext(ctx, context);
        case DDI_MEDIA_CONTEXT_TYPE_ENCODER:
            return DdiEncode_DestroyContext(ctx, context);
        case DDI_MEDIA_CONTEXT_TYPE_VP:
            return DdiVp_DestroyContext(ctx, context);
        case DDI_MEDIA_CONTEXT_TYPE_MFE:
            return DdiMedia_DestoryMfeContext(ctx, context);
        default:
            DDI_ASSERTMESSAGE("DDI: unsupported context in DdiCodec_DestroyContext.");
            return VA_STATUS_ERROR_INVALID_CONTEXT;
    }
}

static VAStatus DdiMedia_CreateBuffer (
    VADriverContextP    ctx,
    VAContextID         context,
    VABufferType        type,
    uint32_t            size,
    uint32_t            num_elements,
    void                *data,
    VABufferID          *bufId
)
{
    DDI_FUNCTION_ENTER();

    DDI_CHK_NULL(ctx,        "nullptr ctx",     VA_STATUS_ERROR_INVALID_CONTEXT);
    DDI_CHK_NULL(bufId,     "nullptr buf_id",  VA_STATUS_ERROR_INVALID_PARAMETER);
    DDI_CHK_LARGER(size, 0,  "Invalid size", VA_STATUS_ERROR_INVALID_PARAMETER);

    PDDI_MEDIA_CONTEXT mediaCtx = DdiMedia_GetMediaContext(ctx);
    DDI_CHK_NULL(mediaCtx, "nullptr mediaCtx", VA_STATUS_ERROR_INVALID_CONTEXT);

    uint32_t ctxType = DDI_MEDIA_CONTEXT_TYPE_NONE;
    void     *ctxPtr = DdiMedia_GetContextFromContextID(ctx, context, &ctxType);
    DDI_CHK_NULL(ctxPtr,      "nullptr ctxPtr",      VA_STATUS_ERROR_INVALID_CONTEXT);

    *bufId     = VA_INVALID_ID;

    DdiMediaUtil_LockMutex(&mediaCtx->BufferMutex);
    VAStatus va = VA_STATUS_SUCCESS;
    switch (ctxType)
    {
        case DDI_MEDIA_CONTEXT_TYPE_DECODER:
        case DDI_MEDIA_CONTEXT_TYPE_CENC_DECODER:
            va = DdiDecode_CreateBuffer(ctx, DdiDecode_GetDecContextFromPVOID(ctxPtr), type, size, num_elements, data, bufId);
            break;
        case DDI_MEDIA_CONTEXT_TYPE_ENCODER:
            va = DdiEncode_CreateBuffer(ctx, context, type, size, num_elements, data, bufId);
            break;
        case DDI_MEDIA_CONTEXT_TYPE_VP:
            va = DdiVp_CreateBuffer(ctx, ctxPtr, type, size, num_elements, data, bufId);
            break;
        default:
            va = VA_STATUS_ERROR_INVALID_CONTEXT;
    }

    DdiMediaUtil_UnLockMutex(&mediaCtx->BufferMutex);
    return va;
}

/*
 * Convey to the server how many valid elements are in the buffer.
 * e.g. if multiple slice parameters are being held in a single buffer,
 * this will communicate to the server the number of slice parameters
 * that are valid in the buffer.
 */
static VAStatus DdiMedia_BufferSetNumElements (
    VADriverContextP    ctx,
    VABufferID          buf_id,
    uint32_t            num_elements
)
{
    DDI_FUNCTION_ENTER();

    DDI_CHK_NULL(ctx, "nullptr ctx", VA_STATUS_ERROR_INVALID_CONTEXT);

    PDDI_MEDIA_CONTEXT mediaCtx = DdiMedia_GetMediaContext(ctx);
    DDI_CHK_NULL(mediaCtx,              "nullptr mediaCtx",              VA_STATUS_ERROR_INVALID_CONTEXT);

    DDI_CHK_NULL(mediaCtx->pBufferHeap, "nullptr mediaCtx->pBufferHeap", VA_STATUS_ERROR_INVALID_CONTEXT);
    DDI_CHK_LESS((uint32_t)buf_id, mediaCtx->pBufferHeap->uiAllocatedHeapElements, "Invalid buf_id", VA_STATUS_ERROR_INVALID_BUFFER);

    DDI_MEDIA_BUFFER *buf       = DdiMedia_GetBufferFromVABufferID(mediaCtx, buf_id);
    DDI_CHK_NULL(buf, "Invalid buffer.", VA_STATUS_ERROR_INVALID_BUFFER);

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

    if(buf->uiType == VASliceParameterBufferType &&
       buf->uiNumElements < num_elements)
    {
        MOS_FreeMemory(buf->pData);
        buf->iSize = buf->iSize / buf->uiNumElements;
        buf->pData = (uint8_t*)MOS_AllocAndZeroMemory(buf->iSize * num_elements);
        buf->iSize = buf->iSize * num_elements;
    }

    return VA_STATUS_SUCCESS;
}

//!
//! \brief  Map data store of the buffer into the client's address space
//!         vaCreateBuffer() needs to be called with "data" set to nullptr before
//!         calling vaMapBuffer()
//! 
//! \param  [in] ctx
//!         Pointer to VA driver context
//! \param  [in] buf_id
//!         VA buffer ID
//! \param  [out] pbuf
//!         Pointer to buffer
//! \param  [in] flag
//!         Flag
//!
//! \return VAStatus
//!     VA_STATUS_SUCCESS if success, else fail reason
//!
VAStatus DdiMedia_MapBufferInternal (
    VADriverContextP    ctx,
    VABufferID          buf_id,
    void              **pbuf,
    uint32_t            flag
)
{
    DDI_FUNCTION_ENTER();

    DDI_CHK_NULL(ctx,   "nullptr ctx",     VA_STATUS_ERROR_INVALID_CONTEXT);
    DDI_CHK_NULL(pbuf,  "nullptr pbuf",    VA_STATUS_ERROR_INVALID_PARAMETER);

    PDDI_MEDIA_CONTEXT mediaCtx = DdiMedia_GetMediaContext(ctx);
    DDI_CHK_NULL(mediaCtx,              "nullptr mediaCtx",              VA_STATUS_ERROR_INVALID_CONTEXT);

    DDI_CHK_NULL(mediaCtx->pBufferHeap, "nullptr mediaCtx->pBufferHeap", VA_STATUS_ERROR_INVALID_CONTEXT);
    DDI_CHK_LESS((uint32_t)buf_id, mediaCtx->pBufferHeap->uiAllocatedHeapElements, "Invalid bufferId", VA_STATUS_ERROR_INVALID_CONTEXT);

    DDI_MEDIA_BUFFER   *buf     = DdiMedia_GetBufferFromVABufferID(mediaCtx, buf_id);
    DDI_CHK_NULL(buf, "nullptr buf", VA_STATUS_ERROR_INVALID_BUFFER);

    // The context is nullptr when the buffer is created from DdiMedia_DeriveImage
    // So doesn't need to check the context for all cases
    // Only check the context in dec/enc mode
    uint32_t                 ctxType = DdiMedia_GetCtxTypeFromVABufferID(mediaCtx, buf_id);
    void                     *ctxPtr = nullptr;
    DDI_CODEC_COM_BUFFER_MGR *bufMgr = nullptr;
    PDDI_ENCODE_CONTEXT      encCtx = nullptr;
    PDDI_DECODE_CONTEXT      decCtx = nullptr;
    switch (ctxType)
    {
        case DDI_MEDIA_CONTEXT_TYPE_VP:
            break;
        case DDI_MEDIA_CONTEXT_TYPE_DECODER:
        case DDI_MEDIA_CONTEXT_TYPE_CENC_DECODER:
            ctxPtr = DdiMedia_GetCtxFromVABufferID(mediaCtx, buf_id);
            DDI_CHK_NULL(ctxPtr, "nullptr ctxPtr", VA_STATUS_ERROR_INVALID_CONTEXT);

            decCtx = DdiDecode_GetDecContextFromPVOID(ctxPtr);
            bufMgr = &(decCtx->BufMgr);
            break;
        case DDI_MEDIA_CONTEXT_TYPE_ENCODER:
            ctxPtr = DdiMedia_GetCtxFromVABufferID(mediaCtx, buf_id);
            DDI_CHK_NULL(ctxPtr, "nullptr ctxPtr", VA_STATUS_ERROR_INVALID_CONTEXT);

            encCtx = DdiEncode_GetEncContextFromPVOID(ctxPtr);
            DDI_CHK_NULL(encCtx, "nullptr encCtx", VA_STATUS_ERROR_INVALID_CONTEXT);
            bufMgr = &(encCtx->BufMgr);
            break;
        case DDI_MEDIA_CONTEXT_TYPE_MEDIA:
            break;
        default:
            return VA_STATUS_ERROR_INVALID_BUFFER;
    }

    switch ((int32_t)buf->uiType)
    {
        case VASliceDataBufferType:
        case VAProtectedSliceDataBufferType:
        case VABitPlaneBufferType:
            *pbuf = (void *)(buf->pData + buf->uiOffset);
            break;

        case VASliceParameterBufferType:
            ctxPtr = DdiMedia_GetCtxFromVABufferID(mediaCtx, buf_id);
            DDI_CHK_NULL(ctxPtr, "nullptr ctxPtr", VA_STATUS_ERROR_INVALID_CONTEXT);

            decCtx = DdiDecode_GetDecContextFromPVOID(ctxPtr);
            bufMgr = &(decCtx->BufMgr);
            switch (decCtx->wMode)
            {
                case CODECHAL_DECODE_MODE_AVCVLD:
                    if(decCtx->bShortFormatInUse)
                        *pbuf = (void *)((uint8_t*)(bufMgr->Codec_Param.Codec_Param_H264.pVASliceParaBufH264Base) + buf->uiOffset);
                    else
                        *pbuf = (void *)((uint8_t*)(bufMgr->Codec_Param.Codec_Param_H264.pVASliceParaBufH264) + buf->uiOffset);
                    break;
                case CODECHAL_DECODE_MODE_MPEG2VLD:
                    *pbuf = (void *)((uint8_t*)(bufMgr->Codec_Param.Codec_Param_MPEG2.pVASliceParaBufMPEG2) + buf->uiOffset);
                    break;
                case CODECHAL_DECODE_MODE_VC1VLD:
                    *pbuf = (void *)((uint8_t*)(bufMgr->Codec_Param.Codec_Param_VC1.pVASliceParaBufVC1) + buf->uiOffset);
                    break;
                case CODECHAL_DECODE_MODE_JPEG:
                    *pbuf = (void *)((uint8_t*)(bufMgr->Codec_Param.Codec_Param_JPEG.pVASliceParaBufJPEG) + buf->uiOffset);
                    break;
                case CODECHAL_DECODE_MODE_VP8VLD:
                    *pbuf = (void *)((uint8_t*)(bufMgr->Codec_Param.Codec_Param_VP8.pVASliceParaBufVP8) + buf->uiOffset);
                    break;
                case CODECHAL_DECODE_MODE_HEVCVLD:
                    if(decCtx->bShortFormatInUse)
                        *pbuf = (void *)((uint8_t*)(bufMgr->Codec_Param.Codec_Param_HEVC.pVASliceParaBufBaseHEVC) + buf->uiOffset);
                    else
                    {
                        if(!decCtx->m_ddiDecode->IsRextProfile())
                           *pbuf = (void *)((uint8_t*)(bufMgr->Codec_Param.Codec_Param_HEVC.pVASliceParaBufHEVC) + buf->uiOffset);
                        else
                           *pbuf = (void *)((uint8_t*)(bufMgr->Codec_Param.Codec_Param_HEVC.pVASliceParaBufHEVCRext) + buf->uiOffset);
                     }
                    break;
                case CODECHAL_DECODE_MODE_VP9VLD:
                    *pbuf = (void *)((uint8_t*)(bufMgr->Codec_Param.Codec_Param_VP9.pVASliceParaBufVP9) + buf->uiOffset);
                    break;
                case CODECHAL_DECODE_RESERVED_0:
                    *pbuf = (void *)((uint8_t*)(bufMgr->pCodecSlcParamReserved) + buf->uiOffset);
                    break;
                default:
                    break;
            }
            break;

        case VAEncCodedBufferType:
            DDI_CHK_NULL(encCtx, "nullptr encCtx", VA_STATUS_ERROR_INVALID_CONTEXT);

            if( DdiEncode_CodedBufferExistInStatusReport( encCtx, buf ) )
            {
                return DdiEncode_StatusReport(encCtx, buf, pbuf);
            }
            // so far a coded buffer that has NOT been added into status report is skipped frame in non-CP case
            // but this can change in future if new usage models come up
            encCtx->BufMgr.pCodedBufferSegment->buf  = DdiMediaUtil_LockBuffer(buf, flag);
            encCtx->BufMgr.pCodedBufferSegment->size = buf->iSize;
            *pbuf =  encCtx->BufMgr.pCodedBufferSegment;

            break;

        case VAStatsStatisticsBufferType:
        case VAStatsStatisticsBottomFieldBufferType:
        case VAStatsMVBufferType:
            {
                DDI_CHK_NULL(encCtx, "nullptr encCtx", VA_STATUS_ERROR_INVALID_CONTEXT)
                DDI_ENCODE_PRE_ENC_BUFFER_TYPE idx = (buf->uiType == VAStatsMVBufferType) ? PRE_ENC_BUFFER_TYPE_MVDATA :
                                                    ((buf->uiType == VAStatsStatisticsBufferType)   ? PRE_ENC_BUFFER_TYPE_STATS
                                                                                                          : PRE_ENC_BUFFER_TYPE_STATS_BOT);
                if((encCtx->codecFunction == CODECHAL_FUNCTION_FEI_PRE_ENC) && DdiEncode_PreEncBufferExistInStatusReport( encCtx, buf, idx))
                {
                    return  DdiEncode_PreEncStatusReport(encCtx, buf, pbuf);
                }
                if(buf->bo)
                {
                    *pbuf = DdiMediaUtil_LockBuffer(buf, flag);
                }
                break;
            }
        case VAStatsMVPredictorBufferType:
        case VAEncFEIMBControlBufferType:
        case VAEncFEIMVPredictorBufferType:
        case VAEncQPBufferType:
            if(buf->bo)
            {
                *pbuf = DdiMediaUtil_LockBuffer(buf, flag);
            }
            break;
        case VADecodeStreamoutBufferType:
            if(buf->bo)
            {
                 uint32_t timeout_NS = 100000000;
                 while (0 != mos_gem_bo_wait(buf->bo, timeout_NS))
                 {
                     // Just loop while gem_bo_wait times-out.
                 }
                 *pbuf = DdiMediaUtil_LockBuffer(buf, flag);
            }
            break;
        case VAEncFEIMVBufferType:
        case VAEncFEIMBCodeBufferType:
        case VAEncFEICURecordBufferType:
        case VAEncFEICTBCmdBufferType:
        case VAEncFEIDistortionBufferType:
            {
                DDI_CHK_NULL(encCtx, "nullptr encCtx", VA_STATUS_ERROR_INVALID_CONTEXT)
                if(encCtx->wModeType == CODECHAL_ENCODE_MODE_AVC)
                {
                    CodecEncodeAvcFeiPicParams *feiPicParams = (CodecEncodeAvcFeiPicParams *)encCtx->pFeiPicParams;

                    DDI_ENCODE_FEI_ENC_BUFFER_TYPE idx = (buf->uiType == VAEncFEIMVBufferType) ? FEI_ENC_BUFFER_TYPE_MVDATA :
                                       ((buf->uiType == VAEncFEIMBCodeBufferType) ? FEI_ENC_BUFFER_TYPE_MBCODE :
                                                                                        FEI_ENC_BUFFER_TYPE_DISTORTION);
                    if((feiPicParams != nullptr) && (encCtx->codecFunction == CODECHAL_FUNCTION_FEI_ENC) && DdiEncode_EncBufferExistInStatusReport( encCtx, buf, idx))
                    {
                        return  DdiEncode_EncStatusReport(encCtx, buf, pbuf);
                    }
                }
                else if(encCtx->wModeType == CODECHAL_ENCODE_MODE_HEVC)

                {
                    CodecEncodeHevcFeiPicParams *feiPicParams = (CodecEncodeHevcFeiPicParams *)encCtx->pFeiPicParams;
                    DDI_ENCODE_FEI_ENC_BUFFER_TYPE idx = (buf->uiType == VAEncFEICTBCmdBufferType) ? FEI_ENC_BUFFER_TYPE_MVDATA   :
                                                      ((buf->uiType == VAEncFEICURecordBufferType) ? FEI_ENC_BUFFER_TYPE_MBCODE :
                                                                                                      FEI_ENC_BUFFER_TYPE_DISTORTION);
                    if((feiPicParams != nullptr) && (encCtx->codecFunction == CODECHAL_FUNCTION_FEI_ENC) && DdiEncode_EncBufferExistInStatusReport( encCtx, buf, idx))
                    {
                        return  DdiEncode_EncStatusReport(encCtx, buf, pbuf);
                    }
                }
                if(buf->bo)
                {
                    *pbuf = DdiMediaUtil_LockBuffer(buf, flag);
                }
            }
            break;
        case VAStatsStatisticsParameterBufferType:
            *pbuf = (void *)(buf->pData + buf->uiOffset);
            break;
        case VAEncMacroblockMapBufferType:
            DdiMediaUtil_LockMutex(&mediaCtx->BufferMutex);
            *pbuf = DdiMediaUtil_LockBuffer(buf, flag);
            DdiMediaUtil_UnLockMutex(&mediaCtx->BufferMutex);
            if (nullptr == (*pbuf))
            {
                return VA_STATUS_ERROR_OPERATION_FAILED;
            }
            else
            {
                return VA_STATUS_SUCCESS;
            }
            break;

        case VABufferTypeMax:
            if (DdiMedia_MediaFormatToOsFormat(buf->format) != VA_STATUS_ERROR_UNSUPPORTED_RT_FORMAT)
            {
                DdiMediaUtil_LockMutex(&mediaCtx->BufferMutex);

                if ((nullptr != buf->pSurface) && (Media_Format_CPU != buf->format))
                {
                    DDI_CHK_RET(DdiMedia_MediaMemoryDecompress(mediaCtx, buf->pSurface),"MMD unsupported!");
                }

                *pbuf = DdiMediaUtil_LockBuffer(buf, flag);
                DdiMediaUtil_UnLockMutex(&mediaCtx->BufferMutex);
                if (nullptr == (*pbuf))
                {
                    return VA_STATUS_ERROR_OPERATION_FAILED;
                }
                else
                {
                    return VA_STATUS_SUCCESS;
                }
            }
            return VA_STATUS_ERROR_INVALID_BUFFER;

        case VAProbabilityBufferType:
            *pbuf = (void *)(buf->pData + buf->uiOffset);

            break;

        case VAEncMacroblockDisableSkipMapBufferType:
            if(buf->bo)
            {
                *pbuf = DdiMediaUtil_LockBuffer(buf, flag);
            }
            break;

        case VAImageBufferType:
        default:
            *pbuf = (void *)(buf->pData + buf->uiOffset);
            break;
    }

    return VA_STATUS_SUCCESS;
}

VAStatus DdiMedia_MapBuffer (
    VADriverContextP    ctx,
    VABufferID          buf_id,
    void                **pbuf
)
{
    return DdiMedia_MapBufferInternal(ctx, buf_id, pbuf, MOS_LOCKFLAG_READONLY | MOS_LOCKFLAG_WRITEONLY);
}

/*
 * After client making changes to a mapped data store, it needs to
 * "Unmap" it to let the server know that the data is ready to be
 * consumed by the server
 */
VAStatus DdiMedia_UnmapBuffer (
    VADriverContextP    ctx,
    VABufferID          buf_id
)
{
    DDI_FUNCTION_ENTER();

    DDI_CHK_NULL(ctx, "nullptr ctx", VA_STATUS_ERROR_INVALID_CONTEXT);

    PDDI_MEDIA_CONTEXT mediaCtx = DdiMedia_GetMediaContext(ctx);
    DDI_CHK_NULL(mediaCtx,               "nullptr mediaCtx",               VA_STATUS_ERROR_INVALID_CONTEXT);

    DDI_CHK_NULL( mediaCtx->pBufferHeap, "nullptr  mediaCtx->pBufferHeap", VA_STATUS_ERROR_INVALID_CONTEXT);
    DDI_CHK_LESS((uint32_t)buf_id, mediaCtx->pBufferHeap->uiAllocatedHeapElements, "Invalid buf_id", VA_STATUS_ERROR_INVALID_BUFFER);

    DDI_MEDIA_BUFFER   *buf     = DdiMedia_GetBufferFromVABufferID(mediaCtx,  buf_id);
    DDI_CHK_NULL(buf, "nullptr buf", VA_STATUS_ERROR_INVALID_BUFFER);

    // The context is nullptr when the buffer is created from DdiMedia_DeriveImage
    // So doesn't need to check the context for all cases
    // Only check the context in dec/enc mode
    void     *ctxPtr = nullptr;
    uint32_t ctxType = DdiMedia_GetCtxTypeFromVABufferID(mediaCtx, buf_id);
    DDI_CODEC_COM_BUFFER_MGR *bufMgr = nullptr;
    PDDI_DECODE_CONTEXT decCtx = nullptr;
    PDDI_ENCODE_CONTEXT encCtx = nullptr;
    switch (ctxType)
    {
        case DDI_MEDIA_CONTEXT_TYPE_VP:
            break;
        case DDI_MEDIA_CONTEXT_TYPE_DECODER:
        case DDI_MEDIA_CONTEXT_TYPE_CENC_DECODER:
            ctxPtr = DdiMedia_GetCtxFromVABufferID(mediaCtx, buf_id);
            DDI_CHK_NULL(ctxPtr, "nullptr ctxPtr", VA_STATUS_ERROR_INVALID_CONTEXT);

            decCtx = DdiDecode_GetDecContextFromPVOID(ctxPtr);
            bufMgr = &(decCtx->BufMgr);
            break;
        case DDI_MEDIA_CONTEXT_TYPE_ENCODER:
            ctxPtr = DdiMedia_GetCtxFromVABufferID(mediaCtx, buf_id);
            DDI_CHK_NULL(ctxPtr, "nullptr ctxPtr", VA_STATUS_ERROR_INVALID_CONTEXT);

            encCtx = DdiEncode_GetEncContextFromPVOID(ctxPtr);
            bufMgr = &(encCtx->BufMgr);
            break;
        case DDI_MEDIA_CONTEXT_TYPE_MEDIA:
            break;
        default:
            return VA_STATUS_ERROR_INVALID_BUFFER;
    }

    switch ((int32_t)buf->uiType)
    {
        case VASliceDataBufferType:
        case VAProtectedSliceDataBufferType:
        case VABitPlaneBufferType:
            break;
        case VAEncCodedBufferType:
        case VAStatsStatisticsBufferType:
        case VAStatsStatisticsBottomFieldBufferType:
        case VAStatsMVBufferType:
        case VAStatsMVPredictorBufferType:
        case VAEncFEIMBControlBufferType:
        case VAEncFEIMVPredictorBufferType:
        case VAEncFEIMVBufferType:
        case VAEncFEIMBCodeBufferType:
        case VAEncFEICURecordBufferType:
        case VAEncFEICTBCmdBufferType:
        case VAEncFEIDistortionBufferType:
        case VAEncQPBufferType:
        case VADecodeStreamoutBufferType:
            if(buf->bo)
            {
                DdiMediaUtil_UnlockBuffer(buf);
            }
            break;

        case VABufferTypeMax:
            if (DdiMedia_MediaFormatToOsFormat(buf->format) != VA_STATUS_ERROR_UNSUPPORTED_RT_FORMAT)
            {
                DdiMediaUtil_LockMutex(&mediaCtx->BufferMutex);
                DdiMediaUtil_UnlockBuffer(buf);
                DdiMediaUtil_UnLockMutex(&mediaCtx->BufferMutex);
                return VA_STATUS_SUCCESS;
            }
            return VA_STATUS_ERROR_INVALID_BUFFER;
        case VAEncMacroblockDisableSkipMapBufferType:
            if(buf->bo)
            {
                DdiMediaUtil_UnlockBuffer(buf);
            }
            break;

        case VAImageBufferType:
         default:
            break;
    }

    return VA_STATUS_SUCCESS;
}

/*
 * After this call, the buffer is deleted and this buffer_id is no longer valid
 * Only call this if the buffer is not going to be passed to vaRenderBuffer
 */
VAStatus DdiMedia_DestroyBuffer (
    VADriverContextP    ctx,
    VABufferID          buffer_id
)
{
    DDI_FUNCTION_ENTER();

    DDI_CHK_NULL(ctx,                    "nullptr ctx",                    VA_STATUS_ERROR_INVALID_CONTEXT);

    PDDI_MEDIA_CONTEXT mediaCtx = DdiMedia_GetMediaContext(ctx);
    DDI_CHK_NULL(mediaCtx,              "nullptr mediaCtx",              VA_STATUS_ERROR_INVALID_CONTEXT);

    DDI_CHK_NULL(mediaCtx->pBufferHeap, "nullptr mediaCtx->pBufferHeap", VA_STATUS_ERROR_INVALID_CONTEXT);
    DDI_CHK_LESS((uint32_t)buffer_id, mediaCtx->pBufferHeap->uiAllocatedHeapElements, "Invalid bufferId", VA_STATUS_ERROR_INVALID_CONTEXT);

    DDI_MEDIA_BUFFER   *buf     = DdiMedia_GetBufferFromVABufferID(mediaCtx,  buffer_id);
    DDI_CHK_NULL(buf, "nullptr buf", VA_STATUS_ERROR_INVALID_BUFFER);

    void     *ctxPtr = DdiMedia_GetCtxFromVABufferID(mediaCtx,     buffer_id);
    uint32_t ctxType = DdiMedia_GetCtxTypeFromVABufferID(mediaCtx, buffer_id);

    DDI_CODEC_COM_BUFFER_MGR     *bufMgr  = nullptr;
    PDDI_ENCODE_CONTEXT           encCtx  = nullptr;
    PDDI_DECODE_CONTEXT           decCtx  = nullptr;
    switch (ctxType)
    {
        case DDI_MEDIA_CONTEXT_TYPE_DECODER:
        case DDI_MEDIA_CONTEXT_TYPE_CENC_DECODER:
            DDI_CHK_NULL(ctxPtr, "nullptr ctxPtr", VA_STATUS_ERROR_INVALID_CONTEXT);
            decCtx = DdiDecode_GetDecContextFromPVOID(ctxPtr);
            bufMgr = &(decCtx->BufMgr);
            break;
        case DDI_MEDIA_CONTEXT_TYPE_ENCODER:
            DDI_CHK_NULL(ctxPtr, "nullptr ctxPtr", VA_STATUS_ERROR_INVALID_CONTEXT);
            encCtx = DdiEncode_GetEncContextFromPVOID(ctxPtr);
            bufMgr = &(encCtx->BufMgr);
            break;
        case DDI_MEDIA_CONTEXT_TYPE_VP:
            break;
        case DDI_MEDIA_CONTEXT_TYPE_MEDIA:
            break;
        default:
            return VA_STATUS_ERROR_INVALID_BUFFER;
    }
    switch ((int32_t)buf->uiType)
    {
        case VASliceDataBufferType:
        case VAProtectedSliceDataBufferType:
            DdiMedia_ReleaseBsBuffer(bufMgr, buf);
            break;
        case VABitPlaneBufferType:
            DdiMedia_ReleaseBpBuffer(bufMgr, buf);
            break;
        case VAProbabilityBufferType:
            DdiMedia_ReleaseBpBuffer(bufMgr, buf);
            break;

        case VASliceParameterBufferType:
            DdiMedia_ReleaseSliceControlBuffer(ctxType, ctxPtr, buf);
            break;
        case VAPictureParameterBufferType:
            break;
        case VAImageBufferType:
            MOS_FreeMemory(buf->pData);
            break;
        case VAProcPipelineParameterBufferType:
        case VAProcFilterParameterBufferType:
            MOS_FreeMemory(buf->pData);
            break;
        case VASubsetsParameterBufferType:
        case VAIQMatrixBufferType:
        case VAHuffmanTableBufferType:
        case VAEncSliceParameterBufferType:
        case VAEncPictureParameterBufferType:
        case VAEncSequenceParameterBufferType:
        case VAEncPackedHeaderDataBufferType:
        case VAEncPackedHeaderParameterBufferType:
            MOS_FreeMemory(buf->pData);
            break;
        case VABufferTypeMax:
            DdiMediaUtil_UnRefBufObjInMediaBuffer(buf);
            break;
        case VAEncMacroblockMapBufferType:
            DdiMediaUtil_FreeBuffer(buf);
            break;
#ifdef ENABLE_ENC_UNLIMITED_OUTPUT
        case VAEncCodedBufferType:
            if(nullptr == encCtx)
            {
                encCtx = DdiEncode_GetEncContextFromPVOID(ctxPtr);
                if(nullptr == encCtx)
                    return VA_STATUS_ERROR_INVALID_CONTEXT;
            }
            DdiEncode_RemoveFromStatusReportQueue(encCtx,buf);
            DdiMediaUtil_FreeBuffer(buf);
            break;
#endif
        case VAStatsStatisticsParameterBufferType:
            MOS_FreeMemory(buf->pData);
            break;
        case VAStatsStatisticsBufferType:
        case VAStatsStatisticsBottomFieldBufferType:
        case VAStatsMVBufferType:
            {
                if(nullptr == encCtx)
                {
                    encCtx = DdiEncode_GetEncContextFromPVOID(ctxPtr);
                    if(nullptr == encCtx)
                        return VA_STATUS_ERROR_INVALID_CONTEXT;
                }
                if(encCtx->codecFunction == CODECHAL_FUNCTION_FEI_PRE_ENC)
                {
                    DDI_ENCODE_PRE_ENC_BUFFER_TYPE idx = (buf->uiType == VAStatsMVBufferType) ? PRE_ENC_BUFFER_TYPE_MVDATA :
                                                        ((buf->uiType == VAStatsStatisticsBufferType)   ? PRE_ENC_BUFFER_TYPE_STATS
                                                                                                              : PRE_ENC_BUFFER_TYPE_STATS_BOT);
                    DdiEncode_RemoveFromPreEncStatusReportQueue(encCtx, buf, idx);
                }
            }
            DdiMediaUtil_FreeBuffer(buf);
            break;
        case VAStatsMVPredictorBufferType:
        case VAEncFEIMBControlBufferType:
        case VAEncFEIMVPredictorBufferType:
        case VAEncQPBufferType:
        case VADecodeStreamoutBufferType:
            DdiMediaUtil_FreeBuffer(buf);
            break;
        case VAEncFEIMVBufferType:
        case VAEncFEIMBCodeBufferType:
        case VAEncFEICURecordBufferType:
        case VAEncFEICTBCmdBufferType:
        case VAEncFEIDistortionBufferType:
            {
                if(nullptr == encCtx)
                {
                    encCtx = DdiEncode_GetEncContextFromPVOID(ctxPtr);
                    if(nullptr == encCtx)
                        return VA_STATUS_ERROR_INVALID_CONTEXT;
                }
                if(encCtx->wModeType == CODECHAL_ENCODE_MODE_AVC)
                {
                    CodecEncodeAvcFeiPicParams *feiPicParams;
                    feiPicParams = (CodecEncodeAvcFeiPicParams *)(encCtx->pFeiPicParams);
                    if((feiPicParams != nullptr) && (encCtx->codecFunction == CODECHAL_FUNCTION_FEI_ENC))
                    {
                        DDI_ENCODE_FEI_ENC_BUFFER_TYPE idx = (buf->uiType == VAEncFEIMVBufferType) ? FEI_ENC_BUFFER_TYPE_MVDATA :
                                                        ((buf->uiType == VAEncFEIMBCodeBufferType) ? FEI_ENC_BUFFER_TYPE_MBCODE :
                                                                                                      FEI_ENC_BUFFER_TYPE_DISTORTION);
                        DdiEncode_RemoveFromEncStatusReportQueue(encCtx, buf, idx);
                    }

                }
                else if(encCtx->wModeType == CODECHAL_ENCODE_MODE_HEVC)
                {
                    CodecEncodeHevcFeiPicParams *feiPicParams;
                    feiPicParams = (CodecEncodeHevcFeiPicParams *)(encCtx->pFeiPicParams);
                    if((feiPicParams != nullptr) && (encCtx->codecFunction == CODECHAL_FUNCTION_FEI_ENC))
                    {
                        DDI_ENCODE_FEI_ENC_BUFFER_TYPE idx = (buf->uiType == VAEncFEICTBCmdBufferType) ? FEI_ENC_BUFFER_TYPE_MVDATA   :
                                                          ((buf->uiType == VAEncFEICURecordBufferType) ? FEI_ENC_BUFFER_TYPE_MBCODE :
                                                                                                          FEI_ENC_BUFFER_TYPE_DISTORTION);
                        DdiEncode_RemoveFromEncStatusReportQueue(encCtx, buf, idx);
                    }
                }
            }
            DdiMediaUtil_FreeBuffer(buf);
            break;
        default: // do not handle any un-listed buffer type
            MOS_FreeMemory(buf->pData);
            break;
            //return va_STATUS_SUCCESS;
    }
    MOS_FreeMemory(buf);

    DdiMedia_DestroyBufFromVABufferID(mediaCtx, buffer_id);

    return VA_STATUS_SUCCESS;
}

/*
 * Get ready to decode a picture to a target surface
 */
static VAStatus DdiMedia_BeginPicture (
    VADriverContextP    ctx,
    VAContextID         context,
    VASurfaceID         render_target
)
{
    DDI_FUNCTION_ENTER();

    DDI_CHK_NULL(ctx, "nullptr ctx", VA_STATUS_ERROR_INVALID_CONTEXT);

    PDDI_MEDIA_CONTEXT mediaCtx   = DdiMedia_GetMediaContext(ctx);

    DDI_CHK_NULL(mediaCtx,               "nullptr mediaCtx",               VA_STATUS_ERROR_INVALID_CONTEXT);
    DDI_CHK_NULL(mediaCtx->pSurfaceHeap, "nullptr mediaCtx->pSurfaceHeap", VA_STATUS_ERROR_INVALID_CONTEXT);
    DDI_CHK_LESS((uint32_t)render_target, mediaCtx->pSurfaceHeap->uiAllocatedHeapElements, "render_target", VA_STATUS_ERROR_INVALID_SURFACE);

    uint32_t ctxType = DDI_MEDIA_CONTEXT_TYPE_NONE;
    void     *ctxPtr = DdiMedia_GetContextFromContextID(ctx, context, &ctxType);

    PDDI_MEDIA_SURFACE surface = DdiMedia_GetSurfaceFromVASurfaceID(mediaCtx, render_target);
    DDI_CHK_NULL(surface, "nullptr surface", VA_STATUS_ERROR_INVALID_SURFACE);

    DdiMediaUtil_LockMutex(&mediaCtx->SurfaceMutex);
    surface->curCtxType = ctxType;
    surface->curStatusReportQueryState = DDI_MEDIA_STATUS_REPORT_QUREY_STATE_PENDING;
    if(ctxType == DDI_MEDIA_CONTEXT_TYPE_VP)
    {
        surface->curStatusReport.vpp.status = VPREP_NOTAVAILABLE;
    }
    DdiMediaUtil_UnLockMutex(&mediaCtx->SurfaceMutex);

    switch (ctxType)
    {
        case DDI_MEDIA_CONTEXT_TYPE_DECODER:
        case DDI_MEDIA_CONTEXT_TYPE_CENC_DECODER:
            return DdiDecode_BeginPicture(ctx, context, render_target);
        case DDI_MEDIA_CONTEXT_TYPE_ENCODER:
            return DdiEncode_BeginPicture(ctx, context, render_target);
        case DDI_MEDIA_CONTEXT_TYPE_VP:
            return DdiVp_BeginPicture(ctx, context, render_target);
        default:
            DDI_ASSERTMESSAGE("DDI: unsupported context in DdiCodec_BeginPicture.");
            return VA_STATUS_ERROR_INVALID_CONTEXT;
    }
}

/*
 * Send decode buffers to the server.
 * Buffers are automatically destroyed afterwards
 */
static VAStatus DdiMedia_RenderPicture (
    VADriverContextP    ctx,
    VAContextID         context,
    VABufferID         *buffers,
    int32_t             num_buffers
)
{

    DDI_FUNCTION_ENTER();

    DDI_CHK_NULL(  ctx,            "nullptr ctx",                   VA_STATUS_ERROR_INVALID_CONTEXT);
    DDI_CHK_NULL(  buffers,        "nullptr buffers",               VA_STATUS_ERROR_INVALID_PARAMETER);
    DDI_CHK_LARGER(num_buffers, 0, "Invalid number buffers",     VA_STATUS_ERROR_INVALID_PARAMETER);

    PDDI_MEDIA_CONTEXT mediaCtx   = DdiMedia_GetMediaContext(ctx);
    DDI_CHK_NULL(mediaCtx,              "nullptr mediaCtx",              VA_STATUS_ERROR_INVALID_CONTEXT);
    DDI_CHK_NULL(mediaCtx->pBufferHeap, "nullptr mediaCtx->pBufferHeap", VA_STATUS_ERROR_INVALID_CONTEXT);

    for(int32_t i = 0; i < num_buffers; i++)
    {
       DDI_CHK_LESS((uint32_t)buffers[i], mediaCtx->pBufferHeap->uiAllocatedHeapElements, "Invalid Buffer", VA_STATUS_ERROR_INVALID_BUFFER);
    }

    uint32_t ctxType = DDI_MEDIA_CONTEXT_TYPE_NONE;
    void     *ctxPtr = DdiMedia_GetContextFromContextID(ctx, context, &ctxType);

    switch (ctxType)
    {
        case DDI_MEDIA_CONTEXT_TYPE_DECODER:
        case DDI_MEDIA_CONTEXT_TYPE_CENC_DECODER:
            return DdiDecode_RenderPicture(ctx, context, buffers, num_buffers);
        case DDI_MEDIA_CONTEXT_TYPE_ENCODER:
            return DdiEncode_RenderPicture(ctx, context, buffers, num_buffers);
        case DDI_MEDIA_CONTEXT_TYPE_VP:
            return DdiVp_RenderPicture(ctx, context, buffers, num_buffers);
        default:
            DDI_ASSERTMESSAGE("DDI: unsupported context in DdiCodec_RenderPicture.");
            return VA_STATUS_ERROR_INVALID_CONTEXT;
    }

}

/*
 * Make the end of rendering for a picture.
 * The server should start processing all pending operations for this
 * surface. This call is non-blocking. The client can start another
 * Begin/Render/End sequence on a different render target.
 */
static VAStatus DdiMedia_EndPicture (
    VADriverContextP    ctx,
    VAContextID         context
)
{
    DDI_FUNCTION_ENTER();

    DDI_CHK_NULL(ctx, "nullptr ctx", VA_STATUS_ERROR_INVALID_CONTEXT);

    uint32_t ctxType = DDI_MEDIA_CONTEXT_TYPE_NONE;
    void     *ctxPtr = DdiMedia_GetContextFromContextID(ctx, context, &ctxType);

    switch (ctxType)
    {
        case DDI_MEDIA_CONTEXT_TYPE_DECODER:
        case DDI_MEDIA_CONTEXT_TYPE_CENC_DECODER:
            return DdiDecode_EndPicture(ctx, context);
        case DDI_MEDIA_CONTEXT_TYPE_ENCODER:
            return DdiEncode_EndPicture(ctx, context);
        case DDI_MEDIA_CONTEXT_TYPE_VP:
            return DdiVp_EndPicture(ctx, context);
        default:
            DDI_ASSERTMESSAGE("DDI: unsupported context in DdiCodec_EndPicture.");
            return VA_STATUS_ERROR_INVALID_CONTEXT;
    }
}

/*
 * This function blocks until all pending operations on the render target
 * have been completed.  Upon return it is safe to use the render target for a
 * different picture.
 */
static VAStatus DdiMedia_SyncSurface (
    VADriverContextP    ctx,
    VASurfaceID         render_target
)
{
    DDI_FUNCTION_ENTER();

    DDI_CHK_NULL(ctx,    "nullptr ctx",    VA_STATUS_ERROR_INVALID_CONTEXT);

    PDDI_MEDIA_CONTEXT mediaCtx = DdiMedia_GetMediaContext(ctx);
    DDI_CHK_NULL(mediaCtx,               "nullptr mediaCtx",               VA_STATUS_ERROR_INVALID_CONTEXT);
    DDI_CHK_NULL(mediaCtx->pSurfaceHeap, "nullptr mediaCtx->pSurfaceHeap", VA_STATUS_ERROR_INVALID_CONTEXT);

    DDI_CHK_LESS((uint32_t)render_target, mediaCtx->pSurfaceHeap->uiAllocatedHeapElements, "Invalid render_target", VA_STATUS_ERROR_INVALID_SURFACE);

    DDI_MEDIA_SURFACE  *surface = DdiMedia_GetSurfaceFromVASurfaceID(mediaCtx, render_target);
    DDI_CHK_NULL(surface,    "nullptr surface",      VA_STATUS_ERROR_INVALID_CONTEXT);
    if (surface->pCurrentFrameSemaphore)
    {
        DdiMediaUtil_WaitSemaphore(surface->pCurrentFrameSemaphore);
        DdiMediaUtil_PostSemaphore(surface->pCurrentFrameSemaphore);
    }

    // check the bo here?
    // zero is a expected return value
    uint32_t timeout_NS = 100000000;
    while (0 != mos_gem_bo_wait(surface->bo, timeout_NS))
    {
        // Just loop while gem_bo_wait times-out.
    }

    uint32_t i = 0;
    PDDI_DECODE_CONTEXT decCtx = (PDDI_DECODE_CONTEXT)surface->pDecCtx;
    if (decCtx && surface->curCtxType == DDI_MEDIA_CONTEXT_TYPE_DECODER)
    {
        Codechal *codecHal = decCtx->pCodecHal;
        DDI_CHK_NULL(codecHal, "nullptr decCtx->pCodecHal", VA_STATUS_ERROR_INVALID_CONTEXT);

        CodechalDecode *decoder = dynamic_cast<CodechalDecode *>(codecHal);
        DDI_CHK_NULL(decoder, "nullptr codecHal->pDecoder", VA_STATUS_ERROR_INVALID_CONTEXT);

        if (decoder->IsStatusQueryReportingEnabled())
        {
            if (surface->curStatusReportQueryState == DDI_MEDIA_STATUS_REPORT_QUREY_STATE_PENDING)
            {
                CodechalDecodeStatusBuffer *decodeStatusBuf = decoder->GetDecodeStatusBuf();
                uint32_t uNumAvailableReport = (decodeStatusBuf->m_currIndex - decodeStatusBuf->m_firstIndex) & (CODECHAL_DECODE_STATUS_NUM - 1);
                DDI_CHK_CONDITION((uNumAvailableReport == 0),
                    "No report available at all", VA_STATUS_ERROR_OPERATION_FAILED);

                for (i = 0; i < uNumAvailableReport; i++)
                {
                    int32_t index = (decodeStatusBuf->m_firstIndex + i) & (CODECHAL_DECODE_STATUS_NUM - 1);
                    if ((decodeStatusBuf->m_decodeStatus[index].m_decodeStatusReport.m_currDecodedPicRes.bo == surface->bo) ||
                        (decoder->GetStandard() == CODECHAL_VC1 && decodeStatusBuf->m_decodeStatus[index].m_decodeStatusReport.m_deblockedPicResOlp.bo == surface->bo))
                    {
                        break;
                    }
                }

                DDI_CHK_CONDITION((i == uNumAvailableReport),
                    "No report available for this surface", VA_STATUS_ERROR_OPERATION_FAILED);

                uint32_t uNumCompletedReport = i+1;

                for (i = 0; i < uNumCompletedReport; i++)
                {
                    CodechalDecodeStatusReport tempNewReport;
                    MOS_ZeroMemory(&tempNewReport, sizeof(CodechalDecodeStatusReport));
                    MOS_STATUS eStatus = decoder->GetStatusReport(&tempNewReport, 1);
                    DDI_CHK_CONDITION(MOS_STATUS_SUCCESS != eStatus, "Get status report fail", VA_STATUS_ERROR_OPERATION_FAILED);

                    MOS_LINUX_BO *bo = tempNewReport.m_currDecodedPicRes.bo;

                    if (decoder->GetStandard() == CODECHAL_VC1)
                    {
                        bo = (tempNewReport.m_deblockedPicResOlp.bo) ? tempNewReport.m_deblockedPicResOlp.bo : bo;
                    }

                    if ((tempNewReport.m_codecStatus == CODECHAL_STATUS_SUCCESSFUL) || (tempNewReport.m_codecStatus == CODECHAL_STATUS_ERROR) || (tempNewReport.m_codecStatus == CODECHAL_STATUS_INCOMPLETE))
                    {
                        DdiMediaUtil_LockMutex(&mediaCtx->SurfaceMutex);
                        PDDI_MEDIA_SURFACE_HEAP_ELEMENT mediaSurfaceHeapElmt = (PDDI_MEDIA_SURFACE_HEAP_ELEMENT)mediaCtx->pSurfaceHeap->pHeapBase;

                        uint32_t j = 0;
                        for (j = 0; j < mediaCtx->pSurfaceHeap->uiAllocatedHeapElements; j++, mediaSurfaceHeapElmt++)
                        {
                            if (mediaSurfaceHeapElmt != nullptr &&
                                    mediaSurfaceHeapElmt->pSurface != nullptr &&
                                    bo == mediaSurfaceHeapElmt->pSurface->bo)
                            {
                                mediaSurfaceHeapElmt->pSurface->curStatusReport.decode.status = (uint32_t)tempNewReport.m_codecStatus;
                                mediaSurfaceHeapElmt->pSurface->curStatusReport.decode.errMbNum = (uint32_t)tempNewReport.m_numMbsAffected;
                                mediaSurfaceHeapElmt->pSurface->curStatusReport.decode.crcValue = (decoder->GetStandard() == CODECHAL_AVC)?(uint32_t)tempNewReport.m_frameCrc:0;
                                mediaSurfaceHeapElmt->pSurface->curStatusReportQueryState = DDI_MEDIA_STATUS_REPORT_QUREY_STATE_COMPLETED;
                                break;
                            }
                        }

                        if (j == mediaCtx->pSurfaceHeap->uiAllocatedHeapElements)
                        {
                            DdiMediaUtil_UnLockMutex(&mediaCtx->SurfaceMutex);
                            return VA_STATUS_ERROR_OPERATION_FAILED;
                        }
                        DdiMediaUtil_UnLockMutex(&mediaCtx->SurfaceMutex);
                    }
                    else
                    {
                        // return failed if queried INCOMPLETE or UNAVAILABLE report.
                        return VA_STATUS_ERROR_OPERATION_FAILED;
                    }
                }
            }

            // check the report ptr of current surface.
            if (surface->curStatusReportQueryState == DDI_MEDIA_STATUS_REPORT_QUREY_STATE_COMPLETED)
            {
                if (surface->curStatusReport.decode.status == CODECHAL_STATUS_SUCCESSFUL)
                {
                    return VA_STATUS_SUCCESS;
                }            
                else if (surface->curStatusReport.decode.status == CODECHAL_STATUS_ERROR)
                {
                    return VA_STATUS_ERROR_DECODING_ERROR;
                }
                else if (surface->curStatusReport.decode.status == CODECHAL_STATUS_INCOMPLETE || surface->curStatusReport.decode.status == CODECHAL_STATUS_UNAVAILABLE)
                {
                    return VA_STATUS_ERROR_HW_BUSY;
                }
            }
            else
            {
                return VA_STATUS_ERROR_OPERATION_FAILED;
            }
        }
    }

    if (surface->curCtxType == DDI_MEDIA_CONTEXT_TYPE_VP)
    {
        PDDI_VP_CONTEXT vpCtx = (PDDI_VP_CONTEXT)surface->pVpCtx;
        DDI_CHK_NULL(vpCtx ,        "nullptr vpCtx",         VA_STATUS_ERROR_INVALID_CONTEXT);
        DDI_CHK_NULL(vpCtx->pVpHal ,"nullptr vpCtx->pVpHal", VA_STATUS_ERROR_INVALID_CONTEXT);

        QUERY_STATUS_REPORT_APP tempVpReport;
        MOS_ZeroMemory(&tempVpReport, sizeof(QUERY_STATUS_REPORT_APP));

        // Get reported surfaces' count
        uint32_t tableLen = 0;
        vpCtx->pVpHal->GetStatusReportEntryLength(&tableLen);

        if (tableLen > 0 && surface->curStatusReportQueryState == DDI_MEDIA_STATUS_REPORT_QUREY_STATE_PENDING)
        {
            // Query the status for all of surfaces which have finished
            for(i = 0; i < tableLen; i++)
            {
                MOS_ZeroMemory(&tempVpReport, sizeof(QUERY_STATUS_REPORT_APP));
                vpCtx->pVpHal->GetStatusReport(&tempVpReport, 1);

                // StatusFeedBackID is last time submitted Target Surface ID which is set in BeginPicture,
                // So we can know the report is for which surface here.
                DDI_MEDIA_SURFACE *tempSurface = DdiMedia_GetSurfaceFromVASurfaceID(mediaCtx, tempVpReport.StatusFeedBackID);
                if(tempSurface == nullptr)
                {
                    return VA_STATUS_ERROR_OPERATION_FAILED;
                }

                // Update the status of the surface which is reported.
                tempSurface->curStatusReport.vpp.status = (uint32_t)tempVpReport.dwStatus;
                tempSurface->curStatusReportQueryState  = DDI_MEDIA_STATUS_REPORT_QUREY_STATE_COMPLETED;

                if(tempVpReport.StatusFeedBackID == render_target)
                {
                    break;
                }
            }
        }

        if (surface->curStatusReportQueryState == DDI_MEDIA_STATUS_REPORT_QUREY_STATE_COMPLETED)
        {
            if(surface->curStatusReport.vpp.status == VPREP_OK)
            {
                return VA_STATUS_SUCCESS;
            }
            else if(surface->curStatusReport.vpp.status == VPREP_NOTREADY)
            {
                return VA_STATUS_ERROR_HW_BUSY;
            }
            else
            {
                return VA_STATUS_ERROR_OPERATION_FAILED;
            }
        }
        else
        {
            return VA_STATUS_ERROR_OPERATION_FAILED;
        }
    }

    return VA_STATUS_SUCCESS;
}

/*
 * Find out any pending ops on the render target
 */
static VAStatus DdiMedia_QuerySurfaceStatus (
    VADriverContextP    ctx,
    VASurfaceID         render_target,
    VASurfaceStatus    *status
)
{
    DDI_FUNCTION_ENTER();

    DDI_CHK_NULL(ctx,    "nullptr ctx",    VA_STATUS_ERROR_INVALID_CONTEXT);
    DDI_CHK_NULL(status, "nullptr status", VA_STATUS_ERROR_INVALID_PARAMETER);

    PDDI_MEDIA_CONTEXT mediaCtx = DdiMedia_GetMediaContext(ctx);
    DDI_CHK_NULL(mediaCtx,                  "nullptr mediaCtx",               VA_STATUS_ERROR_INVALID_CONTEXT);
    DDI_CHK_NULL(mediaCtx->pSurfaceHeap,    "nullptr mediaCtx->pSurfaceHeap", VA_STATUS_ERROR_INVALID_CONTEXT);

    DDI_CHK_LESS((uint32_t)render_target, mediaCtx->pSurfaceHeap->uiAllocatedHeapElements, "Invalid render_target", VA_STATUS_ERROR_INVALID_SURFACE);
    DDI_MEDIA_SURFACE *surface   = DdiMedia_GetSurfaceFromVASurfaceID(mediaCtx, render_target);
    DDI_CHK_NULL(surface,    "nullptr surface",    VA_STATUS_ERROR_INVALID_SURFACE);

    if (surface->pCurrentFrameSemaphore)
    {
        if(DdiMediaUtil_TryWaitSemaphore(surface->pCurrentFrameSemaphore) == 0)
        {
            DdiMediaUtil_PostSemaphore(surface->pCurrentFrameSemaphore);
        }
        else
        {
            // Return busy state if the surface is not submitted
            *status = VASurfaceRendering;
            return VA_STATUS_SUCCESS;
        }
    }

    // Query the busy state of bo.
    // check the bo here?
    if(mos_bo_busy(surface->bo))
    {
        // busy
        *status = VASurfaceRendering;
    }
    else
    {
        // idle
        *status = VASurfaceReady;
    }

    return VA_STATUS_SUCCESS;
}

//!
//! \brief  Report MB error info
//! 
//! \param  [in] ctx
//!         Pointer to VA driver context 
//! \param  [in] render_target
//!         VA surface ID
//! \param  [in] error_status
//!         Error status
//! \param  [out] error_info
//!         Information on error
//!
//! \return VAStatus
//!     VA_STATUS_SUCCESS if success, else fail reason
//!
VAStatus DdiMedia_QuerySurfaceError(
    VADriverContextP ctx,
    VASurfaceID      render_target,
    VAStatus         error_status,
    void             **error_info /*out*/
)
{
    DDI_UNUSED(error_status);

    DDI_FUNCTION_ENTER();

    DDI_CHK_NULL( ctx, "nullptr ctx", VA_STATUS_ERROR_INVALID_CONTEXT );

    PDDI_MEDIA_CONTEXT mediaCtx = DdiMedia_GetMediaContext(ctx);
    DDI_CHK_NULL( mediaCtx, "nullptr mediaCtx", VA_STATUS_ERROR_INVALID_CONTEXT);

    DDI_MEDIA_SURFACE *surface = DdiMedia_GetSurfaceFromVASurfaceID(mediaCtx, render_target);
    DDI_CHK_NULL(surface, "nullptr surface", VA_STATUS_ERROR_INVALID_SURFACE);

    PDDI_DECODE_CONTEXT decCtx = (PDDI_DECODE_CONTEXT)surface->pDecCtx;
    DDI_CHK_NULL( decCtx, "nullptr surface->pDecCtx", VA_STATUS_ERROR_INVALID_CONTEXT );

    VASurfaceDecodeMBErrors *surfaceErrors   = decCtx->vaSurfDecErrOutput;
    DDI_CHK_NULL(surfaceErrors , "nullptr surfaceErrors", VA_STATUS_ERROR_INVALID_CONTEXT );

    DdiMediaUtil_LockMutex(&mediaCtx->SurfaceMutex);
    if (surface->curStatusReportQueryState == DDI_MEDIA_STATUS_REPORT_QUREY_STATE_COMPLETED)
    {
        if (error_status == -1 && surface->curCtxType == DDI_MEDIA_CONTEXT_TYPE_DECODER)
            //&& surface->curStatusReport.decode.status == CODECHAL_STATUS_SUCCESSFUL)  // get the crc value whatever the status is
        {
            CodechalDecode *decoder = dynamic_cast<CodechalDecode *>(decCtx->pCodecHal);
            DDI_CHK_NULL(decoder, "nullptr codechal decoder", VA_STATUS_ERROR_INVALID_CONTEXT);
            if (decoder->GetStandard() != CODECHAL_AVC)
            {
                DdiMediaUtil_UnLockMutex(&mediaCtx->SurfaceMutex);
                return VA_STATUS_ERROR_UNIMPLEMENTED;
            }
            *error_info = (void *)&surface->curStatusReport.decode.crcValue;
            DdiMediaUtil_UnLockMutex(&mediaCtx->SurfaceMutex);
            return VA_STATUS_SUCCESS;
        }

        if (error_status != -1 && surface->curCtxType == DDI_MEDIA_CONTEXT_TYPE_DECODER &&
            surface->curStatusReport.decode.status == CODECHAL_STATUS_ERROR)
        {
            surfaceErrors[1].status            = -1;
            surfaceErrors[0].status            = 2;
            surfaceErrors[0].start_mb          = 0;
            surfaceErrors[0].end_mb            = 0;
            surfaceErrors[0].num_mb            = surface->curStatusReport.decode.errMbNum;
            surfaceErrors[0].decode_error_type = VADecodeMBError;
            *error_info = surfaceErrors;
            DdiMediaUtil_UnLockMutex(&mediaCtx->SurfaceMutex);
            return VA_STATUS_SUCCESS;
        }

        if (surface->curCtxType == DDI_MEDIA_CONTEXT_TYPE_VP &&
            surface->curStatusReport.vpp.status == CODECHAL_STATUS_ERROR)
        {
            DdiMediaUtil_UnLockMutex(&mediaCtx->SurfaceMutex);
            return VA_STATUS_SUCCESS;
        }
    }

    surfaceErrors[0].status = -1;
    DdiMediaUtil_UnLockMutex(&mediaCtx->SurfaceMutex);
    return VA_STATUS_SUCCESS;
}

//!
//! \brief  End picture process for cenc query
//! 
//! \param  [in] ctx
//!         Pointer to VA driver context 
//! \param  [in] context
//!         VA context ID
//!
//! \return VAStatus
//!     VA_STATUS_SUCCESS if success, else fail reason
//!

/*
 * Query surface attributes for the supplied config
 */
static VAStatus
DdiMedia_QuerySurfaceAttributes(
    VADriverContextP ctx,
    VAConfigID config_id,
    VASurfaceAttrib *attrib_list,
    uint32_t *num_attribs
)
{
    DDI_FUNCTION_ENTER();

    DDI_CHK_NULL(ctx,         "nullptr ctx",         VA_STATUS_ERROR_INVALID_CONTEXT);
    DDI_CHK_NULL(num_attribs, "nullptr num_attribs", VA_STATUS_ERROR_INVALID_PARAMETER);

    PDDI_MEDIA_CONTEXT mediaCtx = DdiMedia_GetMediaContext(ctx);
    DDI_CHK_NULL(mediaCtx,   "nullptr mediaCtx",   VA_STATUS_ERROR_INVALID_CONTEXT);
    DDI_CHK_NULL(mediaCtx->m_caps, "nullptr m_caps", VA_STATUS_ERROR_INVALID_CONTEXT);

    return mediaCtx->m_caps->QuerySurfaceAttributes(config_id,
            attrib_list, num_attribs);
}

static VAStatus DdiMedia_PutSurface(
    VADriverContextP ctx,
    VASurfaceID      surface,
    void*            draw,             /* Drawable of window system */
    int16_t          srcx,
    int16_t          srcy,
    uint16_t         srcw,
    uint16_t         srch,
    int16_t          destx,
    int16_t          desty,
    uint16_t         destw,
    uint16_t         desth,
    VARectangle     *cliprects,        /* client supplied clip list */
    uint32_t         number_cliprects, /* number of clip rects in the clip list */
    uint32_t         flags             /* de-interlacing flags */
)
{
    DDI_FUNCTION_ENTER();

    DDI_CHK_NULL(ctx, "nullptr ctx", VA_STATUS_ERROR_INVALID_PARAMETER);
    if(number_cliprects > 0)
    {
        DDI_CHK_NULL(cliprects, "nullptr cliprects", VA_STATUS_ERROR_INVALID_PARAMETER);
    }

    void               *vpCtx        = nullptr;
    PDDI_MEDIA_CONTEXT mediaDrvCtx   = DdiMedia_GetMediaContext(ctx);

    DDI_CHK_NULL(mediaDrvCtx,               "nullptr mediaDrvCtx",               VA_STATUS_ERROR_INVALID_CONTEXT);
    DDI_CHK_NULL(mediaDrvCtx->pSurfaceHeap, "nullptr mediaDrvCtx->pSurfaceHeap", VA_STATUS_ERROR_INVALID_CONTEXT);

    DDI_CHK_LESS((uint32_t)surface, mediaDrvCtx->pSurfaceHeap->uiAllocatedHeapElements, "Invalid surface", VA_STATUS_ERROR_INVALID_SURFACE);

    if (nullptr != mediaDrvCtx->pVpCtxHeap->pHeapBase)
    {
        uint32_t ctxType = DDI_MEDIA_CONTEXT_TYPE_NONE;
        vpCtx = DdiMedia_GetContextFromContextID(ctx, (VAContextID)(0 + DDI_MEDIA_VACONTEXTID_OFFSET_VP), &ctxType);
    }

#if defined(ANDROID) || !defined(X11_FOUND)
       return VA_STATUS_ERROR_UNIMPLEMENTED;
#else
    if(nullptr == vpCtx)
    {
        VAContextID context = VA_INVALID_ID;
        VAStatus vaStatus = DdiVp_CreateContext(ctx, 0, 0, 0, 0, 0, 0, &context);
        DDI_CHK_RET(vaStatus, "Create VP Context failed");
    }
    return DdiCodec_PutSurfaceLinuxHW(ctx, surface, draw, srcx, srcy, srcw, srch, destx, desty, destw, desth, cliprects, number_cliprects, flags);
#endif

}

/* List all the VAImageFormats supported during vaCreateSurfaces
 *  It can be used by vaQueryImageFormats and other functions
 */
/*
 * Query supported image formats
 * The caller must provide a "format_list" array that can hold at
 * least vaMaxNumImageFormats() entries. The actual number of formats
 * returned in "format_list" is returned in "num_formats".
 */
static VAStatus DdiMedia_QueryImageFormats (
    VADriverContextP    ctx,
    VAImageFormat      *format_list,
    int32_t            *num_formats
)
{
    DDI_FUNCTION_ENTER();

    PDDI_MEDIA_CONTEXT mediaCtx = DdiMedia_GetMediaContext(ctx);
    DDI_CHK_NULL(mediaCtx,   "nullptr mediaCtx.",   VA_STATUS_ERROR_INVALID_PARAMETER);
    DDI_CHK_NULL(mediaCtx->m_caps,   "nullptr pointer.",   VA_STATUS_ERROR_INVALID_PARAMETER);
    return mediaCtx->m_caps->QueryImageFormats(format_list, num_formats);
}

//!
//! \brief  Create an image
//! 
//! \param  [in] ctx
//!     Driver context
//! \param  [in] format
//!     The format of image
//! \param  [in] width
//!     The width of the image
//! \param  [in] height
//!     The height of the image
//! \param  [out] image
//!     The generated image
//!
//! \return VAStatus
//!     VA_STATUS_SUCCESS if success, else fail reason
//!
VAStatus DdiMedia_CreateImage(
    VADriverContextP ctx,
    VAImageFormat   *format,
    int32_t          width,
    int32_t          height,
    VAImage         *image     /* out */
)
{
    DDI_FUNCTION_ENTER();

    DDI_CHK_NULL(ctx,         "Invalid context!",    VA_STATUS_ERROR_INVALID_CONTEXT);
    DDI_CHK_NULL(format,      "Invalid format!",     VA_STATUS_ERROR_INVALID_PARAMETER);
    DDI_CHK_NULL(image,       "Invalid image!",      VA_STATUS_ERROR_INVALID_PARAMETER);
    DDI_CHK_LARGER(width,  0, "Invalid width!",      VA_STATUS_ERROR_INVALID_PARAMETER);
    DDI_CHK_LARGER(height, 0, "Invalid height!",     VA_STATUS_ERROR_INVALID_PARAMETER);

    PDDI_MEDIA_CONTEXT mediaCtx        = DdiMedia_GetMediaContext(ctx);
    DDI_CHK_NULL(mediaCtx,   "nullptr mediaCtx.",   VA_STATUS_ERROR_INVALID_PARAMETER);
    DDI_CHK_NULL(mediaCtx->pGmmClientContext, "nullptr mediaCtx->pGmmClientContext.", VA_STATUS_ERROR_INVALID_PARAMETER);

    VAImage *vaimg           = (VAImage*)MOS_AllocAndZeroMemory(sizeof(VAImage));
    DDI_CHK_NULL(vaimg,  "Insufficient to allocate an VAImage.",  VA_STATUS_ERROR_ALLOCATION_FAILED);
    
    GMM_RESCREATE_PARAMS        gmmParams;
    GMM_RESOURCE_INFO          *gmmResourceInfo;
    MOS_ZeroMemory(&gmmParams, sizeof(gmmParams));

    gmmParams.BaseWidth             = width;
    gmmParams.BaseHeight            = height;
    gmmParams.ArraySize             = 1;
    gmmParams.Type                  = RESOURCE_2D;
    gmmParams.Flags.Gpu.Video       = true;

    switch(format->fourcc)
    {
        case VA_FOURCC_RGBA:
            gmmParams.Format = GMM_FORMAT_R8G8B8A8_UNORM_TYPE;
            gmmParams.Flags.Info.Linear = true;
            break;
        case VA_FOURCC_BGRA:
            gmmParams.Format = GMM_FORMAT_B8G8R8A8_UNORM_TYPE;
            gmmParams.Flags.Info.Linear = true;
            break;
        case VA_FOURCC_ARGB:
            gmmParams.Format = GMM_FORMAT_B8G8R8A8_UNORM_TYPE;
            gmmParams.Flags.Info.Linear = true;
            break;
        case VA_FOURCC_ABGR:
            gmmParams.Format = GMM_FORMAT_R8G8B8A8_UNORM_TYPE;
            gmmParams.Flags.Info.Linear = true;
            break;
        case VA_FOURCC_RGBX:
            gmmParams.Format = GMM_FORMAT_R8G8B8X8_UNORM_TYPE;
            gmmParams.Flags.Info.Linear = true;
            break;
        case VA_FOURCC_BGRX:
            gmmParams.Format = GMM_FORMAT_B8G8R8X8_UNORM_TYPE;
            gmmParams.Flags.Info.Linear = true;
            break;
        case VA_FOURCC_I420:
            gmmParams.Format = GMM_FORMAT_I420_TYPE;
            gmmParams.Flags.Info.Linear = true;
            break;
        case VA_FOURCC_YV12:
            gmmParams.Format = GMM_FORMAT_YV12_TYPE;
            gmmParams.Flags.Info.Linear = true;
            break;
        case VA_FOURCC_NV21:
            gmmParams.Format = GMM_FORMAT_NV21_TYPE;
            gmmParams.Flags.Info.Linear = true;
            break;
        case VA_FOURCC_RGBP:
            gmmParams.Format = GMM_FORMAT_RGBP;
            gmmParams.Flags.Info.Linear = true;
            break;
        case VA_FOURCC_YUY2:
            gmmParams.Format = GMM_FORMAT_YUY2;
#if UFO_GRALLOC_NEW_FORMAT
            //Planar type surface align 64 to improve performance.
            gmmParams.BaseHeight = MOS_ALIGN_CEIL(height, 64);
#else
            //Planar type surface align 32 to improve performance.
            gmmParams.BaseHeight = MOS_ALIGN_CEIL(height, 32);
#endif
            break;
        case VA_FOURCC_NV12:
            gmmParams.Format = GMM_FORMAT_NV12_TYPE;
#if UFO_GRALLOC_NEW_FORMAT
            //Planar type surface align 64 to improve performance.
            gmmParams.BaseHeight = MOS_ALIGN_CEIL(height, 64);
#else
            //Planar type surface align 32 to improve performance.
            gmmParams.BaseHeight = MOS_ALIGN_CEIL(height, 32);
#endif
            break;
        case VA_FOURCC_P010:
            gmmParams.Format = GMM_FORMAT_P010_TYPE;
#if UFO_GRALLOC_NEW_FORMAT
            //Planar type surface align 64 to improve performance.
            gmmParams.BaseHeight = MOS_ALIGN_CEIL(height, 64);
#else
            //Planar type surface align 32 to improve performance.
            gmmParams.BaseHeight = MOS_ALIGN_CEIL(height, 32);
#endif
            break;
        case VA_FOURCC_444P:
            gmmParams.Format = GMM_FORMAT_MFX_JPEG_YUV444_TYPE;
            gmmParams.BaseHeight = MOS_ALIGN_CEIL(height, 32);
            break;
        case VA_FOURCC_422H:
            gmmParams.Format = GMM_FORMAT_MFX_JPEG_YUV422H_TYPE;
            gmmParams.BaseHeight = MOS_ALIGN_CEIL(height, 32);
            break;
        case VA_FOURCC_422V:
            gmmParams.Format = GMM_FORMAT_MFX_JPEG_YUV422V_TYPE;
            gmmParams.BaseHeight = MOS_ALIGN_CEIL(height, 32);
            break;
        case VA_FOURCC_UYVY:
            gmmParams.Format = GMM_FORMAT_UYVY;
            gmmParams.Flags.Info.TiledY = true;
            break;
        default:
            MOS_FreeMemory(vaimg);
            return VA_STATUS_ERROR_UNIMPLEMENTED;
    }

    gmmResourceInfo = mediaCtx->pGmmClientContext->CreateResInfoObject(&gmmParams);
    if(nullptr == gmmResourceInfo)
    {
        DDI_ASSERTMESSAGE("Gmm Create Resource Failed.");
        MOS_FreeMemory(vaimg);
        return VA_STATUS_ERROR_ALLOCATION_FAILED;
    }

    uint32_t    gmmPitch;
    uint32_t    gmmSize;
    uint32_t    gmmHeight;
    gmmPitch    = (uint32_t)gmmResourceInfo->GetRenderPitch();
    gmmSize     = (uint32_t)gmmResourceInfo->GetSizeSurface();
    gmmHeight   = (uint32_t)gmmResourceInfo->GetBaseHeight();

    vaimg->format                   = *format;
    vaimg->format.byte_order        = VA_LSB_FIRST;
    vaimg->width                    = width;
    vaimg->height                   = height;
    vaimg->data_size                = gmmSize;
    vaimg->format.bits_per_pixel    = format->bits_per_pixel;

    switch(format->fourcc)
    {
        case VA_FOURCC_RGBA:
        case VA_FOURCC_BGRA:
        case VA_FOURCC_BGRX:
        case VA_FOURCC_RGBX:
        case VA_FOURCC_ARGB:
        case VA_FOURCC_ABGR:
            vaimg->format.bits_per_pixel = 32;
            vaimg->num_planes = 1;
            vaimg->pitches[0] = gmmPitch;
            break;
        case VA_FOURCC_YV12:
        case VA_FOURCC_I420:
            vaimg->num_planes = 3;
            vaimg->pitches[0] = gmmPitch;
            vaimg->pitches[1] = gmmPitch / 2;
            vaimg->pitches[2] = gmmPitch / 2;
            vaimg->offsets[1] = gmmPitch * gmmHeight;
            vaimg->offsets[2] = vaimg->offsets[1] + gmmPitch * gmmHeight / 4;
            break;
        case VA_FOURCC_UYVY:
        case VA_FOURCC_YUY2:
            vaimg->num_planes = 1;
            vaimg->pitches[0] = gmmPitch;
            break;
        case VA_FOURCC_NV12:
        case VA_FOURCC_NV21:
            vaimg->num_planes = 2;
            vaimg->pitches[0] = gmmPitch;
            vaimg->pitches[1] = gmmPitch;
            vaimg->pitches[2] = gmmPitch;
            vaimg->offsets[1] = gmmPitch * gmmHeight;
            vaimg->offsets[2] = vaimg->offsets[1] + 1;
            break;
        case VA_FOURCC_P010:
            vaimg->format.bits_per_pixel = 24;
            vaimg->num_planes = 2;
            vaimg->pitches[0] = gmmPitch;
            vaimg->pitches[1] = gmmPitch;
            vaimg->pitches[2] = gmmPitch;
            vaimg->offsets[1] = gmmPitch * gmmHeight;
            vaimg->offsets[2] = vaimg->offsets[1] + 2;
            break;
        case VA_FOURCC_444P:
            vaimg->format.bits_per_pixel = 24;
            vaimg->num_planes = 3;
            vaimg->pitches[0] = vaimg->pitches[1] =  vaimg->pitches[2] = gmmPitch;
            vaimg->offsets[1] = gmmPitch * gmmHeight;
            vaimg->offsets[2] = vaimg->offsets[1] + gmmPitch * gmmHeight;
            break;
        case VA_FOURCC_422H:
            vaimg->format.bits_per_pixel = 16;
            vaimg->num_planes = 3;
            vaimg->pitches[0] = gmmPitch;
            vaimg->pitches[1] = vaimg->pitches[2] = gmmPitch / 2;
            vaimg->offsets[1] = gmmPitch * gmmHeight;
            vaimg->offsets[2] = vaimg->offsets[1] + gmmPitch * gmmHeight / 2;
            break;
        case VA_FOURCC_422V:
            vaimg->format.bits_per_pixel = 16;
            vaimg->num_planes = 3;
            vaimg->pitches[0] = vaimg->pitches[1] = vaimg->pitches[2] = gmmPitch;
            vaimg->offsets[1] = gmmPitch * gmmHeight;
            vaimg->offsets[2] = vaimg->offsets[1] + gmmPitch * gmmHeight / 2;
        case VA_FOURCC_RGBP:
            vaimg->format.bits_per_pixel = 24;
            vaimg->num_planes = 3;
            vaimg->pitches[0] = gmmPitch;
            vaimg->pitches[1] = gmmPitch;
            vaimg->pitches[2] = gmmPitch;
            vaimg->offsets[1] = gmmPitch * gmmHeight;
            vaimg->offsets[2] = gmmPitch * gmmHeight * 2;
            break;
    }

    mediaCtx->pGmmClientContext->DestroyResInfoObject(gmmResourceInfo);

    DDI_MEDIA_BUFFER *buf  = (DDI_MEDIA_BUFFER *)MOS_AllocAndZeroMemory(sizeof(DDI_MEDIA_BUFFER));
    if (nullptr == buf)
    {
        MOS_FreeMemory(vaimg);
        return VA_STATUS_ERROR_ALLOCATION_FAILED;
    }
    buf->uiNumElements     = 1;
    buf->iSize             = vaimg->data_size;
    buf->uiType            = VAImageBufferType;
    buf->format            = Media_Format_CPU;//DdiCodec_OsFormatToMediaFormat(vaimg->format.fourcc); //Media_Format_Buffer;
    buf->uiOffset          = 0;
    buf->pMediaCtx         = mediaCtx;

    //Put Image in untiled buffer for better CPU access?
    VAStatus status= DdiMediaUtil_CreateBuffer(buf,  mediaCtx->pDrmBufMgr);
    if((status != VA_STATUS_SUCCESS))
    {
        MOS_FreeMemory(vaimg);
        MOS_FreeMemory(buf);
        return status;
    }
    buf->TileType     = I915_TILING_NONE;

    DdiMediaUtil_LockMutex(&mediaCtx->BufferMutex);
    PDDI_MEDIA_BUFFER_HEAP_ELEMENT bufferHeapElement  = DdiMediaUtil_AllocPMediaBufferFromHeap(mediaCtx->pBufferHeap);

    if (nullptr == bufferHeapElement)
    {
        DdiMediaUtil_UnLockMutex(&mediaCtx->BufferMutex);
        MOS_FreeMemory(vaimg);
        DdiMediaUtil_FreeBuffer(buf);
        MOS_FreeMemory(buf);
        return VA_STATUS_ERROR_MAX_NUM_EXCEEDED;
    }

    bufferHeapElement->pBuffer   = buf;
    bufferHeapElement->pCtx      = nullptr;
    bufferHeapElement->uiCtxType = DDI_MEDIA_CONTEXT_TYPE_MEDIA;

    vaimg->buf                   = bufferHeapElement->uiVaBufferID;
    mediaCtx->uiNumBufs++;
    DdiMediaUtil_UnLockMutex(&mediaCtx->BufferMutex);

    DdiMediaUtil_LockMutex(&mediaCtx->ImageMutex);
    PDDI_MEDIA_IMAGE_HEAP_ELEMENT imageHeapElement = DdiMediaUtil_AllocPVAImageFromHeap(mediaCtx->pImageHeap);
    if (nullptr == imageHeapElement)
    {
        DdiMediaUtil_UnLockMutex(&mediaCtx->ImageMutex);
        MOS_FreeMemory(vaimg);
        return VA_STATUS_ERROR_MAX_NUM_EXCEEDED;
    }
    imageHeapElement->pImage     = vaimg;
    mediaCtx->uiNumImages++;
    vaimg->image_id              = imageHeapElement->uiVaImageID;
    DdiMediaUtil_UnLockMutex(&mediaCtx->ImageMutex);

   *image = *vaimg;
    return VA_STATUS_SUCCESS;
}

//!
//! \brief  Derive image
//! 
//! \param  [in] ctx
//!         Pointer to VA driver context
//! \param  [in] surface
//!         VA surface ID
//! \param  [in] image
//!         VA image
//!
//! \return VAStatus
//!     VA_STATUS_SUCCESS if success, else fail reason
//!
VAStatus DdiMedia_DeriveImage (
    VADriverContextP  ctx,
    VASurfaceID       surface,
    VAImage           *image
)
{
    DDI_FUNCTION_ENTER();

    DDI_CHK_NULL(ctx,   "nullptr ctx",   VA_STATUS_ERROR_INVALID_CONTEXT);
    DDI_CHK_NULL(image, "nullptr image", VA_STATUS_ERROR_INVALID_PARAMETER);

    PDDI_MEDIA_CONTEXT mediaCtx     = DdiMedia_GetMediaContext(ctx);
    DDI_CHK_NULL(mediaCtx, "nullptr mediaCtx", VA_STATUS_ERROR_INVALID_CONTEXT);

    DDI_CHK_NULL(mediaCtx->pSurfaceHeap, "nullptr mediaCtx->pSurfaceHeap", VA_STATUS_ERROR_INVALID_CONTEXT);
    DDI_CHK_LESS((uint32_t)surface, mediaCtx->pSurfaceHeap->uiAllocatedHeapElements, "Invalid surface", VA_STATUS_ERROR_INVALID_SURFACE);

    DDI_MEDIA_SURFACE *mediaSurface = DdiMedia_GetSurfaceFromVASurfaceID(mediaCtx, surface);
    DDI_CHK_NULL(mediaSurface, "nullptr mediaSurface", VA_STATUS_ERROR_INVALID_SURFACE);

    VAImage *vaimg                  = (VAImage*)MOS_AllocAndZeroMemory(sizeof(VAImage));
    DDI_CHK_NULL(vaimg, "nullptr vaimg", VA_STATUS_ERROR_ALLOCATION_FAILED);

    if (mediaSurface->pCurrentFrameSemaphore)
    {
        DdiMediaUtil_WaitSemaphore(mediaSurface->pCurrentFrameSemaphore);
        DdiMediaUtil_PostSemaphore(mediaSurface->pCurrentFrameSemaphore);
    }
    DdiMediaUtil_LockMutex(&mediaCtx->ImageMutex);
    PDDI_MEDIA_IMAGE_HEAP_ELEMENT imageHeapElement = DdiMediaUtil_AllocPVAImageFromHeap(mediaCtx->pImageHeap);
    if (nullptr == imageHeapElement)
    {
        DdiMediaUtil_UnLockMutex(&mediaCtx->ImageMutex);
        MOS_FreeMemory(vaimg);
        return VA_STATUS_ERROR_MAX_NUM_EXCEEDED;
    }
    imageHeapElement->pImage        = vaimg;
    mediaCtx->uiNumImages++;
    vaimg->image_id                 = imageHeapElement->uiVaImageID;
    DdiMediaUtil_UnLockMutex(&mediaCtx->ImageMutex);

    vaimg->format.fourcc            = DdiMedia_MediaFormatToOsFormat(mediaSurface->format);
    vaimg->width                    = mediaSurface->iWidth;
    vaimg->height                   = mediaSurface->iRealHeight;
    vaimg->format.byte_order        = VA_LSB_FIRST;

    switch( mediaSurface->format )
    {
    case Media_Format_YV12:
        vaimg->format.bits_per_pixel    = 12;
        vaimg->data_size                = mediaSurface->iPitch * mediaSurface->iHeight * 3 / 2;
        vaimg->num_planes               = 3;
        vaimg->pitches[0]               = mediaSurface->iPitch;
        vaimg->pitches[1]               =
        vaimg->pitches[2]               = mediaSurface->iPitch / 2;
        vaimg->offsets[1]               = mediaSurface->iHeight * mediaSurface->iPitch;
        vaimg->offsets[2]               = mediaSurface->iPitch * mediaSurface->iHeight * 5 / 4;
        break;
    case Media_Format_I420:
        vaimg->format.bits_per_pixel    = 12;
        vaimg->data_size                = mediaSurface->iPitch * mediaSurface->iHeight * 3 / 2;
        vaimg->num_planes               = 3;
        vaimg->pitches[0]               = mediaSurface->iPitch;
        vaimg->pitches[1]               =
        vaimg->pitches[2]               = mediaSurface->iPitch / 2;
        vaimg->offsets[1]               = mediaSurface->iPitch * mediaSurface->iHeight * 5 / 4;
        vaimg->offsets[2]               = mediaSurface->iHeight * mediaSurface->iPitch;
        break;
    case Media_Format_A8B8G8R8:
    case Media_Format_R8G8B8A8:
    case Media_Format_A8R8G8B8:
        vaimg->format.bits_per_pixel    = 32;
        vaimg->format.alpha_mask        = RGB_8BIT_ALPHAMASK;
        vaimg->data_size                = mediaSurface->iPitch * mediaSurface->iHeight;
        vaimg->num_planes               = 1;
        vaimg->pitches[0]               = mediaSurface->iPitch;
        break;
    case Media_Format_X8R8G8B8:
    case Media_Format_X8B8G8R8:
        vaimg->format.bits_per_pixel    = 32;
        vaimg->data_size                = mediaSurface->iPitch * mediaSurface->iHeight;
        vaimg->num_planes               = 1;
        vaimg->pitches[0]               = mediaSurface->iPitch;
        break;
    case Media_Format_R10G10B10A2:
    case Media_Format_B10G10R10A2:
        vaimg->format.bits_per_pixel    = 32;
        vaimg->format.alpha_mask        = RGB_10BIT_ALPHAMASK;
        vaimg->data_size                = mediaSurface->iPitch * mediaSurface->iHeight;
        vaimg->num_planes               = 1;
        vaimg->pitches[0]               = mediaSurface->iPitch;
        break;
   case Media_Format_R5G6B5:
        vaimg->format.bits_per_pixel    = 16;
        vaimg->data_size                = mediaSurface->iPitch * mediaSurface->iHeight;
        vaimg->num_planes               = 1;
        vaimg->pitches[0]               = mediaSurface->iPitch;
        break;
   case Media_Format_R8G8B8:
        vaimg->format.bits_per_pixel    = 24;
        vaimg->data_size                = mediaSurface->iPitch * mediaSurface->iHeight;
        vaimg->num_planes               = 1;
        vaimg->pitches[0]               = mediaSurface->iPitch;
        break;
     case Media_Format_YUY2:
        vaimg->format.bits_per_pixel    = 16;
        vaimg->data_size                = mediaSurface->iPitch * mediaSurface->iHeight;
        vaimg->num_planes               = 1;
        vaimg->pitches[0]               = mediaSurface->iPitch;
        break;
     case Media_Format_400P:
        vaimg->format.bits_per_pixel    = 8;
        vaimg->data_size                = mediaSurface->iPitch * mediaSurface->iHeight;
        vaimg->num_planes               = 1;
        vaimg->pitches[0]               = mediaSurface->iPitch;
        break;
    case Media_Format_444P:
    case Media_Format_RGBP:
        vaimg->format.bits_per_pixel    = 24;
        vaimg->data_size                = mediaSurface->iPitch * mediaSurface->iHeight * 3;
        vaimg->num_planes               = 3;
        vaimg->pitches[0]               =
        vaimg->pitches[1]               =
        vaimg->pitches[2]               = mediaSurface->iPitch;
        vaimg->offsets[1]               = mediaSurface->iHeight * mediaSurface->iPitch;
        vaimg->offsets[2]               = mediaSurface->iHeight * mediaSurface->iPitch * 2;
        break;
    case Media_Format_IMC3:
        vaimg->format.bits_per_pixel    = 12;
        vaimg->data_size                = mediaSurface->iPitch * mediaSurface->iHeight * 2;
        vaimg->num_planes               = 3;
        vaimg->pitches[0]               =
        vaimg->pitches[1]               =
        vaimg->pitches[2]               = mediaSurface->iPitch;
        vaimg->offsets[1]               = mediaSurface->iHeight * mediaSurface->iPitch;
        vaimg->offsets[2]               = mediaSurface->iHeight * mediaSurface->iPitch * 3 / 2;
        break;
    case Media_Format_411P:
        vaimg->format.bits_per_pixel    = 12;
        vaimg->data_size                = mediaSurface->iPitch * mediaSurface->iHeight * 3;
        vaimg->num_planes               = 3;
        vaimg->pitches[0]               =
        vaimg->pitches[1]               =
        vaimg->pitches[2]               = mediaSurface->iPitch;
        vaimg->offsets[1]               = mediaSurface->iHeight * mediaSurface->iPitch;
        vaimg->offsets[2]               = mediaSurface->iHeight * mediaSurface->iPitch * 2;
        break;
    case Media_Format_422V:
        vaimg->format.bits_per_pixel    = 16;
        vaimg->data_size                = mediaSurface->iPitch * mediaSurface->iHeight * 2;
        vaimg->num_planes               = 3;
        vaimg->pitches[0]               =
        vaimg->pitches[1]               =
        vaimg->pitches[2]               = mediaSurface->iPitch;
        vaimg->offsets[1]               = mediaSurface->iHeight * mediaSurface->iPitch;
        vaimg->offsets[2]               = mediaSurface->iHeight * mediaSurface->iPitch * 3 / 2;
        break;
    case Media_Format_422H:
        vaimg->format.bits_per_pixel    = 16;
        vaimg->data_size                = mediaSurface->iPitch * mediaSurface->iHeight * 3;
        vaimg->num_planes               = 3;
        vaimg->pitches[0]               =
        vaimg->pitches[1]               =
        vaimg->pitches[2]               = mediaSurface->iPitch;
        vaimg->offsets[1]               = mediaSurface->iHeight * mediaSurface->iPitch;
        vaimg->offsets[2]               = mediaSurface->iHeight * mediaSurface->iPitch * 2;
        break;
     case Media_Format_P010:
         vaimg->format.bits_per_pixel    = 24;
         vaimg->data_size                = mediaSurface->iPitch * mediaSurface->iHeight * 3 / 2;
         vaimg->num_planes               = 2;
         vaimg->pitches[0]               = mediaSurface->iPitch;
         vaimg->pitches[1]               =
         vaimg->pitches[2]               = mediaSurface->iPitch;
         vaimg->offsets[1]               = mediaSurface->iHeight * mediaSurface->iPitch;
         vaimg->offsets[2]               = vaimg->offsets[1] + 2;
        break;
     default:
        vaimg->format.bits_per_pixel    = 12;
        vaimg->data_size                = mediaSurface->iPitch * mediaSurface->iHeight * 3 / 2;
        vaimg->num_planes               = 2;
        vaimg->pitches[0]               = mediaSurface->iPitch;
        vaimg->pitches[1]               =
        vaimg->pitches[2]               = mediaSurface->iPitch;
        vaimg->offsets[1]               = mediaSurface->iHeight * mediaSurface->iPitch;
        vaimg->offsets[2]               = vaimg->offsets[1] + 1;
        break;
    }
    
    mediaCtx->m_caps->PopulateColorMaskInfo(&vaimg->format);

    DDI_MEDIA_BUFFER *buf               = (DDI_MEDIA_BUFFER *)MOS_AllocAndZeroMemory(sizeof(DDI_MEDIA_BUFFER));
    if (buf == nullptr)
    {
        MOS_FreeMemory(vaimg);
        MOS_FreeMemory(buf);
        return VA_STATUS_ERROR_ALLOCATION_FAILED;
    }
    buf->uiNumElements = 1;
    buf->iSize         = vaimg->data_size;
    buf->uiType        = VABufferTypeMax;
    buf->format        = mediaSurface->format;
    buf->uiOffset      = 0;

    buf->bo            = mediaSurface->bo;
    buf->format        = mediaSurface->format;
    buf->TileType      = mediaSurface->TileType;
    buf->pSurface      = mediaSurface;
    mos_bo_reference(mediaSurface->bo);

    DdiMediaUtil_LockMutex(&mediaCtx->BufferMutex);
    PDDI_MEDIA_BUFFER_HEAP_ELEMENT bufferHeapElement = DdiMediaUtil_AllocPMediaBufferFromHeap(mediaCtx->pBufferHeap);

    if (nullptr == bufferHeapElement)
    {
        DdiMediaUtil_UnLockMutex(&mediaCtx->BufferMutex);
        MOS_FreeMemory(vaimg);
        MOS_FreeMemory(buf);
        return VA_STATUS_ERROR_MAX_NUM_EXCEEDED;
    }
    bufferHeapElement->pBuffer    = buf;
    bufferHeapElement->pCtx       = nullptr;
    bufferHeapElement->uiCtxType  = DDI_MEDIA_CONTEXT_TYPE_MEDIA;

    vaimg->buf             = bufferHeapElement->uiVaBufferID;
    mediaCtx->uiNumBufs++;
    DdiMediaUtil_UnLockMutex(&mediaCtx->BufferMutex);

    *image = *vaimg;

    return VA_STATUS_SUCCESS;
}

//!
//! \brief  Free allocated surfaceheap elements
//! 
//! \param  [in] ctx
//!         Pointer to VA driver context
//! \param  [in] image
//!         VA image ID
//!
//! \return VAStatus
//!     VA_STATUS_SUCCESS if success, else fail reason
//!
VAStatus DdiMedia_DestroyImage (
    VADriverContextP ctx,
    VAImageID        image)
{
    DDI_FUNCTION_ENTER();

    DDI_CHK_NULL(ctx, "nullptr ctx", VA_STATUS_ERROR_INVALID_CONTEXT);
    PDDI_MEDIA_CONTEXT mediaCtx = DdiMedia_GetMediaContext(ctx);

    DDI_CHK_NULL(mediaCtx,             "nullptr Media",                        VA_STATUS_ERROR_INVALID_CONTEXT);
    DDI_CHK_NULL(mediaCtx->pImageHeap, "nullptr mediaCtx->pImageHeap",        VA_STATUS_ERROR_INVALID_CONTEXT);
    DDI_CHK_LESS((uint32_t)image, mediaCtx->pImageHeap->uiAllocatedHeapElements, "Invalid image", VA_STATUS_ERROR_INVALID_IMAGE);

    VAImage *vaImage = DdiMedia_GetVAImageFromVAImageID(mediaCtx, image);
    if (vaImage == nullptr)
    {
        return VA_STATUS_ERROR_INVALID_PARAMETER;
    }
    DdiMedia_DestroyBuffer(ctx, vaImage->buf);
    MOS_FreeMemory(vaImage);

    DdiMedia_DestroyImageFromVAImageID(mediaCtx, image);
    return VA_STATUS_SUCCESS;
}

//!
//! \brief  Set image palette
//! 
//! \param  [in] ctx
//!         Pointer to VA driver context
//! \param  [in] image
//!         VA image ID
//! \param  [in] palette
//!         Palette
//!
//! \return VAStatus
//!     VA_STATUS_ERROR_UNIMPLEMENTED if call success, else fail reason
//!
VAStatus DdiMedia_SetImagePalette(
    VADriverContextP ctx,
    VAImageID        image,
    unsigned char    *palette
)
{
    DDI_UNUSED(ctx);
    DDI_UNUSED(image);
    DDI_UNUSED(palette);
    DDI_FUNCTION_ENTER();

    return VA_STATUS_ERROR_UNIMPLEMENTED;
}

VAStatus SwizzleSurface(PDDI_MEDIA_CONTEXT mediaCtx, PGMM_RESOURCE_INFO pGmmResInfo, void *pLockedAddr, uint32_t TileType, uint8_t* pResourceBase, bool bUpload)
{
    uint32_t            uiSize, uiPitch;
    GMM_RES_COPY_BLT    gmmResCopyBlt;
    uint32_t               uiPicHeight;
    uint32_t               ulSwizzledSize;
    VAStatus            vaStatus = VA_STATUS_SUCCESS;

    DDI_CHK_NULL(pGmmResInfo, "pGmmResInfo is NULL", VA_STATUS_ERROR_OPERATION_FAILED);
    DDI_CHK_NULL(pLockedAddr, "pLockedAddr is NULL", VA_STATUS_ERROR_OPERATION_FAILED);
    DDI_CHK_NULL(pResourceBase, "pResourceBase is NULL", VA_STATUS_ERROR_ALLOCATION_FAILED);

    memset(&gmmResCopyBlt, 0x0, sizeof(GMM_RES_COPY_BLT));
    uiPicHeight = pGmmResInfo->GetBaseHeight();
    uiSize = pGmmResInfo->GetSizeSurface();
    uiPitch = pGmmResInfo->GetRenderPitch();
    gmmResCopyBlt.Gpu.pData = pLockedAddr;
    gmmResCopyBlt.Sys.pData = pResourceBase;
    gmmResCopyBlt.Sys.RowPitch = uiPitch;
    gmmResCopyBlt.Sys.BufferSize = uiSize;
    gmmResCopyBlt.Sys.SlicePitch = uiSize;
    gmmResCopyBlt.Blt.Slices = 1;
    gmmResCopyBlt.Blt.Upload = bUpload;

    if(mediaCtx->pGmmClientContext->IsPlanar(pGmmResInfo->GetResourceFormat()) == true)
    {
        gmmResCopyBlt.Blt.Width = pGmmResInfo->GetBaseWidth();
        gmmResCopyBlt.Blt.Height = uiSize/uiPitch;
    }

    pGmmResInfo->CpuBlt(&gmmResCopyBlt);

    return vaStatus;
}

//!
//! \brief  Retrive surface data into a VAImage
//! \details    Image must be in a format supported by the implementation
//!
//! \param  [in] ctx
//!         Input driver context
//! \param  [in] surface
//!         Input surface ID of source
//! \param  [in] x
//!         X offset of the wanted region
//! \param  [in] y
//!         Y offset of the wanted region
//! \param  [in] width
//!         Width of the wanted region
//! \param  [in] height
//!         Height of the wanted region
//! \param  [in] image
//!     The image ID of the source image
//!
//! \return VAStatus
//!     VA_STATUS_SUCCESS if success, else fail reason
//!
VAStatus DdiMedia_GetImage(
    VADriverContextP ctx,
    VASurfaceID      surface,
    int32_t          x,     /* coordinates of the upper left source pixel */
    int32_t          y,
    uint32_t         width, /* width and height of the region */
    uint32_t         height,
    VAImageID        image
)
{
    DDI_FUNCTION_ENTER();

    DDI_CHK_NULL(ctx,       "nullptr ctx.",         VA_STATUS_ERROR_INVALID_CONTEXT);

    PDDI_MEDIA_CONTEXT mediaCtx = DdiMedia_GetMediaContext(ctx);
    DDI_CHK_NULL(mediaCtx,  "nullptr mediaCtx.",    VA_STATUS_ERROR_INVALID_PARAMETER);

    DDI_CHK_NULL(mediaCtx->pSurfaceHeap,    "nullptr mediaCtx->pSurfaceHeap",   VA_STATUS_ERROR_INVALID_CONTEXT);
    DDI_CHK_NULL(mediaCtx->pImageHeap,      "nullptr mediaCtx->pImageHeap",     VA_STATUS_ERROR_INVALID_CONTEXT);
    DDI_CHK_LESS((uint32_t)surface, mediaCtx->pSurfaceHeap->uiAllocatedHeapElements, "Invalid surface", VA_STATUS_ERROR_INVALID_SURFACE);
    DDI_CHK_LESS((uint32_t)image,   mediaCtx->pImageHeap->uiAllocatedHeapElements,   "Invalid image",   VA_STATUS_ERROR_INVALID_IMAGE);

    VAImage *vaimg = DdiMedia_GetVAImageFromVAImageID(mediaCtx, image);
    DDI_CHK_NULL(vaimg,     "nullptr vaimg.",       VA_STATUS_ERROR_INVALID_PARAMETER);

    DDI_MEDIA_BUFFER *buf = DdiMedia_GetBufferFromVABufferID(mediaCtx, vaimg->buf);
    DDI_CHK_NULL(buf,       "nullptr buf.",         VA_STATUS_ERROR_INVALID_PARAMETER);

    DDI_MEDIA_SURFACE *inputSurface = DdiMedia_GetSurfaceFromVASurfaceID(mediaCtx, surface);
    DDI_CHK_NULL(inputSurface,     "nullptr inputSurface.",      VA_STATUS_ERROR_INVALID_PARAMETER);
    DDI_CHK_NULL(inputSurface->bo, "nullptr inputSurface->bo.",  VA_STATUS_ERROR_INVALID_PARAMETER);

    VAStatus        vaStatus = VA_STATUS_SUCCESS;
    VASurfaceID     target_surface = VA_INVALID_SURFACE;
    VASurfaceID     output_surface = surface;

    //VP Pipeline will be called for CSC/Scaling if the surface format or data size is not consistent with image.
    if (inputSurface->format != DdiMedia_OsFormatAlphaMaskToMediaFormat(vaimg->format.fourcc, vaimg->format.alpha_mask) ||
        width != vaimg->width || height != vaimg->height)
    {
        VAContextID context = VA_INVALID_ID;
        
        if (mediaCtx->pVpCtxHeap->pHeapBase != nullptr)
        {
            //Get VP Context from heap.
            context = (VAContextID)(0 + DDI_MEDIA_VACONTEXTID_OFFSET_VP);
        }else
        {
            //Create VP Context.
            vaStatus = DdiVp_CreateContext(ctx, 0, 0, 0, 0, 0, 0, &context);
            DDI_CHK_RET(vaStatus, "Create VP Context failed");
        }

        //Create target surface for VP pipeline.
        vaStatus = DdiMedia_CreateSurfaces2(ctx, vaimg->format.fourcc, vaimg->width, vaimg->height, &target_surface, 1, NULL, 0);
        DDI_CHK_RET(vaStatus, "Create temp surface failed.");

        //Execute VP pipeline.
        vaStatus = DdiVp_VideoProcessPipeline(ctx, context, surface, x, y, width, height, target_surface);
        if (vaStatus != VA_STATUS_SUCCESS)
        {
            DDI_ASSERTMESSAGE("VP Pipeline failed.");
            DdiMedia_DestroySurfaces(ctx, &target_surface, 1);
            return vaStatus;
        }

        output_surface = target_surface;
    }

    //Get Media Surface from output surface ID
    DDI_MEDIA_SURFACE *mediaSurface = DdiMedia_GetSurfaceFromVASurfaceID(mediaCtx, output_surface);
    DDI_CHK_NULL(mediaSurface,     "nullptr mediaSurface.",      VA_STATUS_ERROR_INVALID_PARAMETER);
    DDI_CHK_NULL(mediaSurface->bo, "nullptr mediaSurface->bo.",  VA_STATUS_ERROR_INVALID_PARAMETER);

    //Lock Surface
    void *surfData = DdiMediaUtil_LockSurface(mediaSurface, (MOS_LOCKFLAG_READONLY | MOS_LOCKFLAG_NO_SWIZZLE));
    if (surfData == nullptr)
    {
        DDI_ASSERTMESSAGE("nullptr surfData.");
        if(target_surface != VA_INVALID_SURFACE)
        {
            DdiMedia_DestroySurfaces(ctx, &target_surface, 1);
        }
        return vaStatus;
    }

    void *imageData = nullptr;
    vaStatus = DdiMedia_MapBuffer(ctx, vaimg->buf, &imageData);
    if (vaStatus != VA_STATUS_SUCCESS)
    {
        DdiMediaUtil_UnlockSurface(mediaSurface);
        if(target_surface != VA_INVALID_SURFACE)
        {
            DdiMedia_DestroySurfaces(ctx, &target_surface, 1);
        }
        return vaStatus;
    }

    //Copy data from surface to image
    if(mediaSurface->TileType == I915_TILING_NONE)
    {
        vaStatus = MOS_SecureMemcpy(imageData, vaimg->data_size, surfData, vaimg->data_size);
    }
    else
    {
        //Mos_SwizzleData((uint8_t*)surfData, (uint8_t *)imageData, (MOS_TILE_TYPE)mediaSurface->TileType, MOS_TILE_LINEAR, vaimg->data_size / mediaSurface->iPitch, mediaSurface->iPitch, mediaSurface->uiMapFlag);
        vaStatus = SwizzleSurface(mediaSurface->pMediaCtx,mediaSurface->pGmmResourceInfo, surfData, (MOS_TILE_TYPE)mediaSurface->TileType, (uint8_t *)imageData, false);
    }
    if (vaStatus != MOS_STATUS_SUCCESS)
    {
        DDI_ASSERTMESSAGE("DDI:Failed to copy surface to image buffer data!");
        DdiMediaUtil_UnlockSurface(mediaSurface);
        if(target_surface != VA_INVALID_SURFACE)
        {
            DdiMedia_DestroySurfaces(ctx, &target_surface, 1);
        }
        return vaStatus;
    }

    vaStatus = DdiMedia_UnmapBuffer(ctx, vaimg->buf);
    if (vaStatus != VA_STATUS_SUCCESS)
    {
        DdiMediaUtil_UnlockSurface(mediaSurface);
        if(target_surface != VA_INVALID_SURFACE)
        {
            DdiMedia_DestroySurfaces(ctx, &target_surface, 1);
        }
        return vaStatus;
    }

    DdiMediaUtil_UnlockSurface(mediaSurface);

    //Destroy temp surface if created
    if(target_surface != VA_INVALID_SURFACE)
    {
        DdiMedia_DestroySurfaces(ctx, &target_surface, 1);
    }

    return VA_STATUS_SUCCESS;
}

//!
//! \brief  Copy data from a VAImage to a surface
//! \details    Image must be in a format supported by the implementation
//! 
//! \param  [in] ctx
//!         Input driver context
//! \param  [in] surface
//!         Surface ID of destination
//! \param  [in] image
//!         The image ID of the destination image
//! \param  [in] src_x
//!         Source x offset of the surface region
//! \param  [in] src_y
//!         Source y offset of the surface region
//! \param  [in] src_width
//!         Source width offset of the surface region
//! \param  [in] src_height
//!         Source height offset of the surface region
//! \param  [in] dest_x
//!         Destination x offset of the image region
//! \param  [in] dest_y
//!         Destination y offset of the image region
//! \param  [in] dest_width
//!         Destination width offset of the image region
//! \param  [in] dest_height
//!         Destination height offset of the image region
//!
//! \return VAStatus
//!     VA_STATUS_SUCCESS if success, else fail reason
//!
VAStatus DdiMedia_PutImage(
    VADriverContextP ctx,
    VASurfaceID      surface,
    VAImageID        image,
    int32_t          src_x,
    int32_t          src_y,
    uint32_t         src_width,
    uint32_t         src_height,
    int32_t          dest_x,
    int32_t          dest_y,
    uint32_t         dest_width,
    uint32_t         dest_height
)
{
    DDI_UNUSED(src_x);
    DDI_UNUSED(src_y);
    DDI_UNUSED(src_width);
    DDI_UNUSED(src_height);
    DDI_UNUSED(dest_x);
    DDI_UNUSED(dest_y);
    DDI_UNUSED(dest_width);
    DDI_UNUSED(dest_height);

    DDI_FUNCTION_ENTER();

    DDI_CHK_NULL(ctx,                     "nullptr ctx.",                    VA_STATUS_ERROR_INVALID_CONTEXT);

    PDDI_MEDIA_CONTEXT mediaCtx     = DdiMedia_GetMediaContext(ctx);
    DDI_CHK_NULL(mediaCtx,               "nullptr mediaCtx.",              VA_STATUS_ERROR_INVALID_PARAMETER);
    DDI_CHK_NULL(mediaCtx->pSurfaceHeap, "nullptr mediaCtx->pSurfaceHeap",   VA_STATUS_ERROR_INVALID_CONTEXT);
    DDI_CHK_LESS((uint32_t)surface, mediaCtx->pSurfaceHeap->uiAllocatedHeapElements, "Invalid surface", VA_STATUS_ERROR_INVALID_SURFACE);
    DDI_CHK_NULL(mediaCtx->pImageHeap,   "nullptr mediaCtx->pImageHeap",     VA_STATUS_ERROR_INVALID_CONTEXT);
    DDI_CHK_LESS((uint32_t)image, mediaCtx->pImageHeap->uiAllocatedHeapElements,     "Invalid image",   VA_STATUS_ERROR_INVALID_IMAGE);

    DDI_MEDIA_SURFACE *mediaSurface = DdiMedia_GetSurfaceFromVASurfaceID(mediaCtx, surface);
    DDI_CHK_NULL(mediaSurface, "nullptr mediaSurface.", VA_STATUS_ERROR_INVALID_PARAMETER);

    if (mediaSurface->pCurrentFrameSemaphore)
    {
        DdiMediaUtil_WaitSemaphore(mediaSurface->pCurrentFrameSemaphore);
        DdiMediaUtil_PostSemaphore(mediaSurface->pCurrentFrameSemaphore);
    }

    VAImage          *vaimg = DdiMedia_GetVAImageFromVAImageID(mediaCtx, image);
    DDI_CHK_NULL(vaimg,      "Invalid image.",      VA_STATUS_ERROR_INVALID_PARAMETER);

    DDI_MEDIA_BUFFER *buf   = DdiMedia_GetBufferFromVABufferID(mediaCtx, vaimg->buf);
    DDI_CHK_NULL(buf,       "Invalid buffer.",      VA_STATUS_ERROR_INVALID_PARAMETER);

    if (mediaSurface->format != DdiMedia_OsFormatAlphaMaskToMediaFormat(vaimg->format.fourcc,vaimg->format.alpha_mask))
    {
        return VA_STATUS_ERROR_UNIMPLEMENTED;
    }

    DDI_CHK_NULL(mediaSurface->bo, "Invalid buffer.", VA_STATUS_ERROR_INVALID_PARAMETER);

    //Lock Surface
    void *surfData = DdiMediaUtil_LockSurface(mediaSurface, (MOS_LOCKFLAG_READONLY | MOS_LOCKFLAG_WRITEONLY));
    if (nullptr == surfData)
    {
        return VA_STATUS_ERROR_SURFACE_BUSY;
    }

    void *imageData = nullptr;
    VAStatus status = DdiMedia_MapBuffer(ctx, vaimg->buf, &imageData);
    if (status != VA_STATUS_SUCCESS)
    {
        DdiMediaUtil_UnlockSurface(mediaSurface);
        return VA_STATUS_ERROR_UNKNOWN;
    }

    //copy data from image to surferce
    //this is temp solution, will copy by difference size and difference format in further
    MOS_STATUS eStatus = MOS_SecureMemcpy(surfData, mediaSurface->data_size, imageData, vaimg->data_size);
    DDI_CHK_CONDITION((eStatus != MOS_STATUS_SUCCESS), "DDI:Failed to copy image to surface buffer data!", VA_STATUS_ERROR_OPERATION_FAILED);

    status = DdiMedia_UnmapBuffer(ctx, vaimg->buf);
    if (status != VA_STATUS_SUCCESS)
    {
        DdiMediaUtil_UnlockSurface(mediaSurface);
        return VA_STATUS_ERROR_UNKNOWN;
    }

    DdiMediaUtil_UnlockSurface(mediaSurface);

    return VA_STATUS_SUCCESS;

}

//!
//! \brief  Query subpicture formats
//! 
//! \param  [in] ctx
//!         Pointer to VA driver context
//! \param  [in] format_list
//!         VA image format
//! \param  [in] flags
//!         Flags
//! \param  [in] num_formats
//!         Number of formats
//!
//! \return VAStatus
//!     VA_STATUS_SUCCESS if success, else fail reason
//!
VAStatus DdiMedia_QuerySubpictureFormats(
    VADriverContextP ctx,
    VAImageFormat   *format_list,
    uint32_t        *flags,
    uint32_t        *num_formats)
{
    DDI_UNUSED(ctx);
    DDI_UNUSED(format_list);
    DDI_UNUSED(flags);
    DDI_UNUSED(num_formats);

    DDI_FUNCTION_ENTER();

    return VA_STATUS_SUCCESS;
}

//!
//! \brief  Create subpicture
//! 
//! \param  [in] ctx
//!         Pointer to VA driver context
//! \param  [in] image
//!         VA image ID
//! \param  [out] subpicture
//!         VA subpicture ID
//!
//! \return VAStatus
//!     VA_STATUS_ERROR_UNIMPLEMENTED
//!
VAStatus DdiMedia_CreateSubpicture(
    VADriverContextP ctx,
    VAImageID        image,
    VASubpictureID  *subpicture   /* out */
)
{
    DDI_UNUSED(ctx);
    DDI_UNUSED(image);
    DDI_UNUSED(subpicture);

    DDI_FUNCTION_ENTER();

    return VA_STATUS_ERROR_UNIMPLEMENTED;
}

//!
//! \brief  Destroy subpicture
//! 
//! \param  [in] ctx
//!         Pointer to VA driver context
//! \param  [in] subpicture
//!         VA subpicture ID
//!
//! \return VAStatus
//!     VA_STATUS_ERROR_UNIMPLEMENTED
//!
VAStatus DdiMedia_DestroySubpicture(
    VADriverContextP ctx,
    VASubpictureID   subpicture
)
{
    DDI_UNUSED(ctx);
    DDI_UNUSED(subpicture);

    DDI_FUNCTION_ENTER();

    return VA_STATUS_ERROR_UNIMPLEMENTED;
}

//!
//! \brief  Set subpicture image
//! 
//! \param  [in] ctx
//!         Pointer to VA driver context
//! \param  [in] subpicture
//!         VA subpicture ID
//! \param  [in] image
//!         VA image ID
//!
//! \return VAStatus
//!     VA_STATUS_ERROR_UNIMPLEMENTED
//!
VAStatus DdiMedia_SetSubpictureImage(
    VADriverContextP ctx,
    VASubpictureID   subpicture,
    VAImageID        image
)
{
    DDI_UNUSED(ctx);
    DDI_UNUSED(subpicture);
    DDI_UNUSED(image);

    DDI_FUNCTION_ENTER();

    return VA_STATUS_ERROR_UNIMPLEMENTED;
}

//!
//! \brief  Set subpicture chrome key
//! 
//! \param  [in] ctx
//!         Pointer to VA driver context
//! \param  [in] subpicture
//!         VA subpicture ID
//! \param  [in] chromakey_min
//!         Minimum chroma key
//! \param  [in] chromakey_max
//!         Maximum chroma key
//! \param  [in] chromakey_mask
//!         Chromakey mask
//!
//! \return VAStatus
//!     VA_STATUS_ERROR_UNIMPLEMENTED
//!
VAStatus DdiMedia_SetSubpictureChromakey(
    VADriverContextP ctx,
    VASubpictureID   subpicture,
    uint32_t         chromakey_min,
    uint32_t         chromakey_max,
    uint32_t         chromakey_mask
)
{
    DDI_UNUSED(ctx);
    DDI_UNUSED(subpicture);
    DDI_UNUSED(chromakey_min);
    DDI_UNUSED(chromakey_max);
    DDI_UNUSED(chromakey_mask);

    DDI_FUNCTION_ENTER();

    return VA_STATUS_ERROR_UNIMPLEMENTED;
}

//!
//! \brief  set subpicture global alpha
//! 
//! \param  [in] ctx
//!         Pointer to VA driver context
//! \param  [in] subpicture
//!         VA subpicture ID
//! \param  [in] global_alpha
//!         Global alpha
//!
//! \return VAStatus
//!     VA_STATUS_ERROR_UNIMPLEMENTED
VAStatus DdiMedia_SetSubpictureGlobalAlpha(
    VADriverContextP ctx,
    VASubpictureID   subpicture,
    float            global_alpha
)
{
    DDI_UNUSED(ctx);
    DDI_UNUSED(subpicture);
    DDI_UNUSED(global_alpha);

    DDI_FUNCTION_ENTER();

    return VA_STATUS_ERROR_UNIMPLEMENTED;
}

//!
//! \brief  Associate subpicture
//! 
//! \param  [in] ctx
//!         Pointer to VA driver context
//! \param  [in] subpicture
//!         VA subpicture ID
//! \param  [in] target_surfaces
//!         VA surface ID
//! \param  [in] num_surfaces
//!         Number of surfaces
//! \param  [in] src_x
//!         Source x of the region
//! \param  [in] src_y
//!         Source y of the region
//! \param  [in] src_width
//!         Source width of the region
//! \param  [in] src_height
//!         Source height of the region
//! \param  [in] dest_x
//!         Destination x
//! \param  [in] dest_y
//!         Destination y
//! \param  [in] dest_width
//!         Destination width
//! \param  [in] dest_height
//!         Destination height
//! \param  [in] flags
//!         Flags
//!
//! \return VAStatus
//!     VA_STATUS_ERROR_UNIMPLEMENTED
//!
VAStatus DdiMedia_AssociateSubpicture(
    VADriverContextP ctx,
    VASubpictureID   subpicture,
    VASurfaceID     *target_surfaces,
    int32_t          num_surfaces,
    int16_t          src_x,  /* upper left offset in subpicture */
    int16_t          src_y,
    uint16_t         src_width,
    uint16_t         src_height,
    int16_t          dest_x, /* upper left offset in surface */
    int16_t          dest_y,
    uint16_t         dest_width,
    uint16_t         dest_height,
    /*
     * whether to enable chroma-keying or global-alpha
     * see VA_SUBPICTURE_XXX values
     */
    uint32_t     flags
)
{
    DDI_UNUSED(ctx);
    DDI_UNUSED(subpicture);
    DDI_UNUSED(target_surfaces);
    DDI_UNUSED(num_surfaces);
    DDI_UNUSED(src_x);
    DDI_UNUSED(src_y);
    DDI_UNUSED(src_width);
    DDI_UNUSED(src_height);
    DDI_UNUSED(dest_x);
    DDI_UNUSED(dest_y);
    DDI_UNUSED(dest_width);
    DDI_UNUSED(dest_height);
    DDI_UNUSED(flags);

    DDI_FUNCTION_ENTER();

    return VA_STATUS_ERROR_UNIMPLEMENTED;
}

//!
//! \brief  Deassociate subpicture
//! 
//! \param  [in] ctx
//!         Pointer to VA driver context
//! \param  [in] subpicture
//!         VA subpicture ID
//! \param  [in] target_surfaces
//!         VA surface ID
//! \param  [in] num_surfaces
//!         Number of surfaces
//!
//! \return VAStatus
//!     VA_STATUS_ERROR_UNIMPLEMENTED
//!
VAStatus DdiMedia_DeassociateSubpicture(
    VADriverContextP ctx,
    VASubpictureID   subpicture,
    VASurfaceID     *target_surfaces,
    int32_t          num_surfaces
)
{
    DDI_UNUSED(ctx);
    DDI_UNUSED(subpicture);
    DDI_UNUSED(target_surfaces);
    DDI_UNUSED(num_surfaces);

    DDI_FUNCTION_ENTER();

    return VA_STATUS_ERROR_UNIMPLEMENTED;
}

//!
//! \brief  Query display attributes
//! 
//! \param  [in] ctx
//!         Pointer to VA driver context
//! \param  [in] attr_list
//!         VA display attribute
//! \param  [in] num_attributes
//!         Number of attributes
//!
//! \return VAStatus
//!     VA_STATUS_SUCCESS if success, else fail reason
//!
VAStatus DdiMedia_QueryDisplayAttributes(
    VADriverContextP    ctx,
    VADisplayAttribute *attr_list,
    int32_t            *num_attributes)
{
    DDI_UNUSED(ctx);
    DDI_UNUSED(attr_list);

    DDI_FUNCTION_ENTER();

    if (num_attributes)
        *num_attributes = 0;

    return VA_STATUS_SUCCESS;
}

//!
//! \brief  Get display attributes
//! \details    This function returns the current attribute values in "attr_list".
//!         Only attributes returned with VA_DISPLAY_ATTRIB_GETTABLE set in the "flags" field
//!         from vaQueryDisplayAttributes() can have their values retrieved.
//! 
//! \param  [in] ctx
//!         Pointer to VA driver context
//! \param  [in] attr_list
//!         VA display attribute
//! \param  [in] num_attributes
//!         Number of attributes
//!
//! \return VAStatus
//!     VA_STATUS_ERROR_UNIMPLEMENTED
//!
VAStatus DdiMedia_GetDisplayAttributes(
    VADriverContextP    ctx,
    VADisplayAttribute *attr_list,
    int32_t             num_attributes)
{
    DDI_UNUSED(ctx);
    DDI_UNUSED(attr_list);
    DDI_UNUSED(num_attributes);

    DDI_FUNCTION_ENTER();

    return VA_STATUS_ERROR_UNIMPLEMENTED;
}

//!
//! \brief  Set display attributes
//! \details    Only attributes returned with VA_DISPLAY_ATTRIB_SETTABLE set in the "flags" field
//!         from vaQueryDisplayAttributes() can be set.  If the attribute is not settable or
//!         the value is out of range, the function returns VA_STATUS_ERROR_ATTR_NOT_SUPPORTED
//! 
//! \param  [in] ctx
//!         Pointer to VA driver context
//! \param  [in] attr_list
//!         VA display attribute
//! \param  [in] num_attributes
//!         Number of attributes
//!
//! \return VAStatus
//!     VA_STATUS_ERROR_UNIMPLEMENTED
//!
VAStatus DdiMedia_SetDisplayAttributes(
    VADriverContextP    ctx,
    VADisplayAttribute *attr_list,
    int32_t             num_attributes)
{
    DDI_UNUSED(ctx);
    DDI_UNUSED(attr_list);
    DDI_UNUSED(num_attributes);

    DDI_FUNCTION_ENTER();

    return VA_STATUS_ERROR_UNIMPLEMENTED;
}

//!
//! \brief  Query processing rate
//! 
//! \param  [in] ctx
//!         Pointer to VA driver context
//! \param  [in] config_id
//!         VA configuration ID
//! \param  [in] proc_buf
//!         VA processing rate parameter
//! \param  [out] processing_rate
//!         Processing rate
//!
//! \return VAStatus
//!     VA_STATUS_SUCCESS if success, else fail reason
//!
VAStatus
DdiMedia_QueryProcessingRate(
      VADriverContextP          ctx,
      VAConfigID                config_id,
      VAProcessingRateParameter *proc_buf,
      uint32_t                  *processing_rate /* output parameter */)
{
    DDI_CHK_NULL(ctx,             "nullptr ctx",             VA_STATUS_ERROR_INVALID_CONTEXT);
    DDI_CHK_NULL(proc_buf,        "nullptr proc_buf",        VA_STATUS_ERROR_INVALID_PARAMETER);
    DDI_CHK_NULL(processing_rate, "nullptr processing_rate", VA_STATUS_ERROR_INVALID_PARAMETER);

    PDDI_MEDIA_CONTEXT mediaCtx   = DdiMedia_GetMediaContext(ctx);
    DDI_CHK_NULL(mediaCtx, "nullptr mediaCtx", VA_STATUS_ERROR_INVALID_CONTEXT);
    DDI_CHK_NULL(mediaCtx->m_caps, "nullptr m_caps", VA_STATUS_ERROR_INVALID_CONTEXT);

    return mediaCtx->m_caps->QueryProcessingRate(config_id,
            proc_buf, processing_rate);
}

//!
//! \brief  Check for buffer info
//! 
//! \param  [in] ctx
//!         Pointer to VA driver context
//! \param  [in] buf_id
//!         VA buffer ID
//! \param  [out] type
//!         VA buffer type
//! \param  [out] size
//!         Size
//! \param  [out] num_elements
//!         Number of elements
//!
//! \return VAStatus
//!     VA_STATUS_SUCCESS if success, else fail reason
//!
VAStatus DdiMedia_BufferInfo (
    VADriverContextP ctx,
    VABufferID       buf_id,
    VABufferType    *type,
    uint32_t        *size,
    uint32_t        *num_elements)
{
    DDI_FUNCTION_ENTER();

    DDI_CHK_NULL(ctx,          "nullptr ctx",          VA_STATUS_ERROR_INVALID_CONTEXT);
    DDI_CHK_NULL(type,         "nullptr type",         VA_STATUS_ERROR_INVALID_PARAMETER);
    DDI_CHK_NULL(size,         "nullptr size",         VA_STATUS_ERROR_INVALID_PARAMETER);
    DDI_CHK_NULL(num_elements, "nullptr num_elements", VA_STATUS_ERROR_INVALID_PARAMETER);

    PDDI_MEDIA_CONTEXT mediaCtx = DdiMedia_GetMediaContext(ctx);
    if (nullptr == mediaCtx)
        return VA_STATUS_ERROR_INVALID_CONTEXT;

    DDI_CHK_NULL(mediaCtx->pBufferHeap, "nullptr mediaCtx->pBufferHeap", VA_STATUS_ERROR_INVALID_CONTEXT);
    DDI_CHK_LESS((uint32_t)buf_id, mediaCtx->pBufferHeap->uiAllocatedHeapElements, "Invalid buf_id", VA_STATUS_ERROR_INVALID_BUFFER);

    DDI_MEDIA_BUFFER *buf  = DdiMedia_GetBufferFromVABufferID(mediaCtx, buf_id);
    if (nullptr == buf)
    {
        return VA_STATUS_ERROR_INVALID_BUFFER;
    }

    *type         = (VABufferType)buf->uiType;
    *size         = buf->iSize / buf->uiNumElements;
    *num_elements = buf->uiNumElements;

    return VA_STATUS_SUCCESS;
}

//!
//! \brief  Lock surface
//! 
//! \param  [in] ctx
//!         Pointer to VA driver context
//! \param  [in] surface
//!         VA surface ID
//! \param  [out] fourcc
//!         FourCC
//! \param  [out] luma_stride
//!         Luma stride
//! \param  [out] chroma_u_stride
//!         Chroma U stride
//! \param  [out] chroma_v_stride
//!         Chroma V stride
//! \param  [out] luma_offset
//!         Luma offset
//! \param  [out] chroma_u_offset
//!         Chroma U offset
//! \param  [out] chroma_v_offset
//!         Chroma V offset
//! \param  [out] buffer_name
//!         Buffer name
//! \param  [out] buffer
//!         Buffer
//!
//! \return VAStatus
//!     VA_STATUS_SUCCESS if success, else fail reason
//!
VAStatus DdiMedia_LockSurface (
    VADriverContextP ctx,
    VASurfaceID      surface,
    uint32_t        *fourcc,
    uint32_t        *luma_stride,
    uint32_t        *chroma_u_stride,
    uint32_t        *chroma_v_stride,
    uint32_t        *luma_offset,
    uint32_t        *chroma_u_offset,
    uint32_t        *chroma_v_offset,
    uint32_t        *buffer_name,
    void           **buffer )
{
    DDI_FUNCTION_ENTER();

    DDI_CHK_NULL(ctx,             "nullptr context",         VA_STATUS_ERROR_INVALID_CONTEXT);
    DDI_CHK_NULL(fourcc,          "nullptr fourcc",          VA_STATUS_ERROR_INVALID_PARAMETER);
    DDI_CHK_NULL(luma_stride,     "nullptr luma_stride",     VA_STATUS_ERROR_INVALID_PARAMETER);
    DDI_CHK_NULL(chroma_u_stride, "nullptr chroma_u_stride", VA_STATUS_ERROR_INVALID_PARAMETER);
    DDI_CHK_NULL(chroma_v_stride, "nullptr chroma_v_stride", VA_STATUS_ERROR_INVALID_PARAMETER);
    DDI_CHK_NULL(luma_offset,     "nullptr luma_offset",     VA_STATUS_ERROR_INVALID_PARAMETER);
    DDI_CHK_NULL(chroma_u_offset, "nullptr chroma_u_offset", VA_STATUS_ERROR_INVALID_PARAMETER);
    DDI_CHK_NULL(chroma_v_offset, "nullptr chroma_v_offset", VA_STATUS_ERROR_INVALID_PARAMETER);
    DDI_CHK_NULL(buffer_name,     "nullptr buffer_name",     VA_STATUS_ERROR_INVALID_PARAMETER);
    DDI_CHK_NULL(buffer,          "nullptr buffer",          VA_STATUS_ERROR_INVALID_PARAMETER);

    PDDI_MEDIA_CONTEXT mediaCtx          = DdiMedia_GetMediaContext(ctx);
    DDI_CHK_NULL(mediaCtx,               "nullptr Media",                   VA_STATUS_ERROR_INVALID_CONTEXT);
    DDI_CHK_NULL(mediaCtx->pSurfaceHeap, "nullptr mediaCtx->pSurfaceHeap", VA_STATUS_ERROR_INVALID_CONTEXT);
    DDI_CHK_LESS((uint32_t)surface, mediaCtx->pSurfaceHeap->uiAllocatedHeapElements, "Invalid surface", VA_STATUS_ERROR_INVALID_SURFACE);

    DDI_MEDIA_SURFACE *mediaSurface = DdiMedia_GetSurfaceFromVASurfaceID(mediaCtx, surface);
    
#ifdef _MMC_SUPPORTED
    // Decompress surface is needed
    DdiMedia_MediaMemoryDecompress(mediaCtx, mediaSurface);
#endif

    if (nullptr == mediaSurface)
    {
        // Surface is absent.
        buffer = nullptr;
        return VA_STATUS_ERROR_INVALID_SURFACE;
    }

    if (mediaSurface->uiLockedImageID != VA_INVALID_ID)
    {
        // Surface is locked already.
        buffer = nullptr;
        return VA_STATUS_ERROR_INVALID_PARAMETER;
    }

    VAImage tmpImage;
    tmpImage.image_id = VA_INVALID_ID;
    VAStatus vaStatus = DdiMedia_DeriveImage(ctx,surface,&tmpImage);
    if (vaStatus != VA_STATUS_SUCCESS)
    {
        buffer = nullptr;
        return vaStatus;
    }

    mediaSurface->uiLockedImageID = tmpImage.image_id;

    vaStatus = DdiMedia_MapBuffer(ctx,tmpImage.buf,buffer);
    if (vaStatus != VA_STATUS_SUCCESS)
    {
        buffer = nullptr;
        return vaStatus;
    }

    mediaSurface->uiLockedBufID = tmpImage.buf;

    *fourcc                 = tmpImage.format.fourcc;
    *luma_offset            = tmpImage.offsets[0];
    *luma_stride            = tmpImage.pitches[0];
    *chroma_u_offset        = tmpImage.offsets[1];
    *chroma_u_stride        = tmpImage.pitches[1];
    *chroma_v_offset        = tmpImage.offsets[2];
    *chroma_v_stride        = tmpImage.pitches[2];
    *buffer_name            = tmpImage.buf;

    return VA_STATUS_SUCCESS;
}

//!
//! \brief  Unlock surface
//! 
//! \param  [in] ctx
//!         Pointer to VA driver context
//! \param  [in] surface
//!         VA surface ID
//!
//! \return VAStatus
//!     VA_STATUS_SUCCESS if success, else fail reason
//!
VAStatus DdiMedia_UnlockSurface (
    VADriverContextP   ctx,
    VASurfaceID        surface)
{
    DDI_FUNCTION_ENTER();

    DDI_CHK_NULL(ctx, "nullptr ctx", VA_STATUS_ERROR_INVALID_CONTEXT);

    PDDI_MEDIA_CONTEXT mediaCtx = DdiMedia_GetMediaContext(ctx);
    DDI_CHK_NULL(mediaCtx,               "nullptr mediaCtx",                 VA_STATUS_ERROR_INVALID_CONTEXT);
    DDI_CHK_NULL(mediaCtx->pSurfaceHeap, "nullptr mediaCtx->pSurfaceHeap",   VA_STATUS_ERROR_INVALID_CONTEXT);
    DDI_CHK_LESS((uint32_t)surface, mediaCtx->pSurfaceHeap->uiAllocatedHeapElements, "Invalid surface", VA_STATUS_ERROR_INVALID_SURFACE);

    DDI_MEDIA_SURFACE *mediaSurface = DdiMedia_GetSurfaceFromVASurfaceID(mediaCtx, surface);
    DDI_CHK_NULL(mediaSurface, "nullptr mediaSurface", VA_STATUS_ERROR_INVALID_SURFACE);

    if (mediaSurface->uiLockedImageID == VA_INVALID_ID)
    {
        return VA_STATUS_ERROR_INVALID_PARAMETER;
    }

    VABufferID bufID    = (VABufferID)(mediaSurface->uiLockedBufID);
    VAStatus   vaStatus = DdiMedia_UnmapBuffer(ctx, bufID);
    if (vaStatus != VA_STATUS_SUCCESS)
    {
        return vaStatus;
    }
    mediaSurface->uiLockedBufID = VA_INVALID_ID;

    VAImageID imageID  = (VAImageID)(mediaSurface->uiLockedImageID);
    vaStatus = DdiMedia_DestroyImage(ctx,imageID);
    if (vaStatus != VA_STATUS_SUCCESS)
    {
        return vaStatus;
    }
    mediaSurface->uiLockedImageID = VA_INVALID_ID;

    return VA_STATUS_SUCCESS;
}

//!
//! \brief  Query video proc filters
//! 
//! \param  [in] ctx
//!         Pointer to VA driver context
//! \param  [in] context
//!         VA context ID
//! \param  [in] filters
//!         VA proc filter type
//! \param  [in] num_filters
//!         Number of filters
//!
//! \return VAStatus
//!     VA_STATUS_SUCCESS if success, else fail reason
//!
VAStatus
DdiMedia_QueryVideoProcFilters(
    VADriverContextP    ctx,
    VAContextID         context,
    VAProcFilterType   *filters,
    uint32_t           *num_filters)
{
    DDI_UNUSED(ctx);
    DDI_UNUSED(context);

    DDI_FUNCTION_ENTER();

    DDI_CHK_NULL(filters,     "nullptr filters",     VA_STATUS_ERROR_INVALID_PARAMETER);
    DDI_CHK_NULL(num_filters, "nullptr num_filters", VA_STATUS_ERROR_INVALID_PARAMETER);

    uint32_t  max_num_filters = DDI_VP_MAX_NUM_FILTERS;
    // check if array size is less than VP_MAX_NUM_FILTERS
    if(*num_filters < max_num_filters)
    {
        DDI_NORMALMESSAGE("num_filters %d < max_num_filters %d. Probably caused by Libva version upgrade!", *num_filters, max_num_filters);
    }

    // Set the filters
    uint32_t i = 0;
    while(i < *num_filters && i < DDI_VP_MAX_NUM_FILTERS)
    {
        filters[i] = vp_supported_filters[i];
        i++;
    }

    // Tell the app how many valid filters are filled in the array
    *num_filters = DDI_VP_MAX_NUM_FILTERS;

    return VA_STATUS_SUCCESS;
}

//!
//! \brief  Query video processing filter capabilities.
//!         The real implementation is in media_libva_vp.c, since it needs to use some definitions in vphal.h.
//! 
//! \param  [in] ctx
//!         Pointer to VA driver context
//! \param  [in] context
//!         VA context ID
//! \param  [in] type
//!         VA proc filter type
//! \param  [inout] filter_caps
//!         FIlter caps
//! \param  [inout] num_filter_caps
//!         Number of filter caps
//!
//! \return VAStatus
//!     VA_STATUS_SUCCESS if success, else fail reason
//!
VAStatus
DdiMedia_QueryVideoProcFilterCaps(
    VADriverContextP    ctx,
    VAContextID         context,
    VAProcFilterType    type,
    void               *filter_caps,
    uint32_t           *num_filter_caps
)
{
    DDI_FUNCTION_ENTER();

    return DdiVp_QueryVideoProcFilterCaps(ctx, context, type, filter_caps, num_filter_caps);
}

//!
//! \brief  Query video proc pipeline caps
//! 
//! \param  [in] ctx
//!         Pointer to VA driver context 
//! \param  [in] context
//!         VA context ID
//! \param  [in] filters
//!         VA buffer ID
//! \param  [in] num_filters
//!         Number of filters
//! \param  [in] pipeline_caps
//!         VA proc pipeline caps
//!
//! \return VAStatus
//!     VA_STATUS_SUCCESS if success, else fail reason
//!
VAStatus
DdiMedia_QueryVideoProcPipelineCaps(
    VADriverContextP    ctx,
    VAContextID         context,
    VABufferID         *filters,
    uint32_t            num_filters,
    VAProcPipelineCaps *pipeline_caps
)
{
    DDI_FUNCTION_ENTER();

    PDDI_MEDIA_CONTEXT mediaCtx   = DdiMedia_GetMediaContext(ctx);

    DDI_CHK_NULL(ctx,           "nullptr ctx",           VA_STATUS_ERROR_INVALID_CONTEXT);
    DDI_CHK_NULL(pipeline_caps, "nullptr pipeline_caps", VA_STATUS_ERROR_INVALID_PARAMETER);
    if (num_filters > 0)
        DDI_CHK_NULL(filters,   "nullptr filters",       VA_STATUS_ERROR_INVALID_PARAMETER);

    pipeline_caps->pipeline_flags             = VA_PROC_PIPELINE_FAST;
    pipeline_caps->filter_flags               = 0;
    pipeline_caps->rotation_flags             = (1 << VA_ROTATION_NONE) | (1 << VA_ROTATION_90) | (1 << VA_ROTATION_180) | (1 << VA_ROTATION_270);
    pipeline_caps->mirror_flags               = VA_MIRROR_HORIZONTAL  | VA_MIRROR_VERTICAL;
    pipeline_caps->blend_flags                = VA_BLEND_GLOBAL_ALPHA | VA_BLEND_PREMULTIPLIED_ALPHA | VA_BLEND_LUMA_KEY;
    pipeline_caps->num_forward_references     = DDI_CODEC_NUM_FWD_REF;
    pipeline_caps->num_backward_references    = DDI_CODEC_NUM_BK_REF;
    pipeline_caps->input_color_standards      = vp_input_color_std;
    pipeline_caps->num_input_color_standards  = DDI_VP_NUM_INPUT_COLOR_STD;
    pipeline_caps->output_color_standards     = vp_output_color_std;
    pipeline_caps->num_output_color_standards = DDI_VP_NUM_OUT_COLOR_STD;

    if ((context & DDI_MEDIA_MASK_VACONTEXT_TYPE) == DDI_MEDIA_VACONTEXTID_OFFSET_DECODER)
    {
        //Decode+SFC, go SFC path, the restriction here is the capability of SFC
        pipeline_caps->num_input_pixel_formats    = 1;
        pipeline_caps->input_pixel_format[0]      = VA_FOURCC_NV12;
        pipeline_caps->num_output_pixel_formats   = 1;
        pipeline_caps->output_pixel_format[0]     = VA_FOURCC_NV12;
        if((MEDIA_IS_SKU(&(mediaCtx->SkuTable), FtrHCP2SFCPipe)))
        {
            pipeline_caps->max_input_width            = DDI_DECODE_HCP_SFC_MAX_WIDTH;
            pipeline_caps->max_input_height           = DDI_DECODE_HCP_SFC_MAX_HEIGHT;
        }
        else
        {
            pipeline_caps->max_input_width            = DDI_DECODE_SFC_MAX_WIDTH;
            pipeline_caps->max_input_height           = DDI_DECODE_SFC_MAX_HEIGHT;
        }
        pipeline_caps->min_input_width            = DDI_DECODE_SFC_MIN_WIDTH;
        pipeline_caps->min_input_height           = DDI_DECODE_SFC_MIN_HEIGHT;
        pipeline_caps->max_output_width           = DDI_DECODE_SFC_MAX_WIDTH;
        pipeline_caps->max_output_height          = DDI_DECODE_SFC_MAX_HEIGHT;
        pipeline_caps->min_output_width           = DDI_DECODE_SFC_MIN_WIDTH;
        pipeline_caps->min_output_height          = DDI_DECODE_SFC_MIN_HEIGHT;
    }
    else if ((context & DDI_MEDIA_MASK_VACONTEXT_TYPE) == DDI_MEDIA_VACONTEXTID_OFFSET_VP)
    {
        if(mediaCtx->platform.eRenderCoreFamily <= IGFX_GEN8_CORE)
        {
            //Capability of Gen8- platform
            pipeline_caps->max_input_width            = VP_MAX_PIC_WIDTH_Gen8;
            pipeline_caps->max_input_height           = VP_MAX_PIC_HEIGHT_Gen8;
            pipeline_caps->max_output_width           = VP_MAX_PIC_WIDTH_Gen8;
            pipeline_caps->max_output_height          = VP_MAX_PIC_HEIGHT_Gen8;
        }else
        {
            //Capability of Gen9+ platform
            pipeline_caps->max_input_width            = VP_MAX_PIC_WIDTH;
            pipeline_caps->max_input_height           = VP_MAX_PIC_HEIGHT;
            pipeline_caps->max_output_width           = VP_MAX_PIC_WIDTH;
            pipeline_caps->max_output_height          = VP_MAX_PIC_HEIGHT;
        }
        pipeline_caps->min_input_width            = VP_MIN_PIC_WIDTH;
        pipeline_caps->min_input_height           = VP_MIN_PIC_HEIGHT;
        pipeline_caps->min_output_width           = VP_MIN_PIC_WIDTH;
        pipeline_caps->min_output_height          = VP_MIN_PIC_WIDTH;
    }
    return VA_STATUS_SUCCESS;
}

/**
 * \brief Get surface attributes for the supplied config.
 *
 * This function retrieves the surface attributes matching the supplied
 * config. The caller shall provide an \c attrib_list with all attributes
 * to be retrieved. Upon successful return, the attributes in \c attrib_list
 * are updated with the requested value. Unknown attributes or attributes
 * that are not supported for the given config will have their \c flags
 * field set to \c VA_SURFACE_ATTRIB_NOT_SUPPORTED.
 *
 * param[in] ctx               the VA display
 * param[in] config            the config identifying a codec or a video
 *     processing pipeline
 * param[out] attrib_list        the list of attributes on output, with at
 *     least \c type fields filled in, and possibly \c value fields whenever
 *     necessary.The updated list of attributes and flags on output
 * param[in] num_attribs       the number of attributes supplied in the
 *     \c attrib_list array
 */
VAStatus DdiMedia_GetSurfaceAttributes(
    VADriverContextP    ctx,
    VAConfigID          config,
    VASurfaceAttrib    *attrib_list,
    uint32_t            num_attribs
)
{
    DDI_UNUSED(ctx);
    DDI_UNUSED(config);
    DDI_UNUSED(attrib_list);
    DDI_UNUSED(num_attribs);

    DDI_FUNCTION_ENTER();

    VAStatus vaStatus = VA_STATUS_ERROR_UNIMPLEMENTED;

    return vaStatus;
}

//!
//! \brief  Aquire buffer handle
//! 
//! \param  [in] ctx
//!         Pointer to VA driver context
//! \param  [in] buf_id
//!         VA buffer ID
//! \param  [in] buf_info
//!         VA buffer Info
//!
//! \return VAStatus
//!     VA_STATUS_SUCCESS if success, else fail reason
//!
VAStatus DdiMedia_AcquireBufferHandle(
    VADriverContextP ctx,
    VABufferID buf_id,
    VABufferInfo *buf_info)
{
    DDI_FUNCTION_ENTER();

    DDI_CHK_NULL(ctx,          "nullptr ctx",          VA_STATUS_ERROR_INVALID_CONTEXT);
    DDI_CHK_NULL(buf_info,     "nullptr buf_info",     VA_STATUS_ERROR_INVALID_PARAMETER);

    PDDI_MEDIA_CONTEXT mediaCtx = DdiMedia_GetMediaContext(ctx);
    DDI_CHK_NULL(mediaCtx,          "Invalid Media ctx", VA_STATUS_ERROR_INVALID_CONTEXT);

    DDI_MEDIA_BUFFER   *buf     = DdiMedia_GetBufferFromVABufferID(mediaCtx, buf_id);
    DDI_CHK_NULL(buf,          "Invalid Media Buffer", VA_STATUS_ERROR_INVALID_BUFFER);
    DDI_CHK_NULL(buf->bo,      "Invalid Media Buffer", VA_STATUS_ERROR_INVALID_BUFFER);

    // If user did not specify memtype he want's we use something we prefer, we prefer PRIME
    if (!buf_info->mem_type)
    {
       buf_info->mem_type = VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME;
    }
    // now chekcing memtype whether we support it
    if ((buf_info->mem_type != VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME) &&
        (buf_info->mem_type != VA_SURFACE_ATTRIB_MEM_TYPE_KERNEL_DRM))
    {
        return VA_STATUS_ERROR_UNSUPPORTED_MEMORY_TYPE;
    }

    DdiMediaUtil_LockMutex(&mediaCtx->BufferMutex);
    // already acquired?
    if (buf->uiExportcount)
    {   // yes, already acquired
        // can't provide access thru another memtype
        if (buf->uiMemtype != buf_info->mem_type)
        {
            DdiMediaUtil_UnLockMutex(&mediaCtx->BufferMutex);
            return VA_STATUS_ERROR_INVALID_PARAMETER;
        }
    }
    else
    {   // no, not acquired - doing this now
        switch (buf_info->mem_type) {
        case VA_SURFACE_ATTRIB_MEM_TYPE_KERNEL_DRM: {
            uint32_t flink = 0;
            if (mos_bo_flink(buf->bo, &flink) != 0)
            {
                DdiMediaUtil_UnLockMutex(&mediaCtx->BufferMutex);
                return VA_STATUS_ERROR_INVALID_BUFFER;
            }
            buf->handle = (intptr_t)flink;
            break;
        }
        case VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME: {
            int32_t prime_fd = 0;
            if (mos_bo_gem_export_to_prime(buf->bo, &prime_fd) != 0)
            {
                DdiMediaUtil_UnLockMutex(&mediaCtx->BufferMutex);
                return VA_STATUS_ERROR_INVALID_BUFFER;
            }

            buf->handle = (intptr_t)prime_fd;
            break;
        }
        }
        // saving memtepy which was provided to the user
        buf->uiMemtype = buf_info->mem_type;
    }

    ++buf->uiExportcount;
    mos_bo_reference(buf->bo);

    buf_info->type = buf->uiType;
    buf_info->handle = buf->handle;
    buf_info->mem_size = buf->uiNumElements * buf->iSize;

    DdiMediaUtil_UnLockMutex(&mediaCtx->BufferMutex);
    return VA_STATUS_SUCCESS;
}

//!
//! \brief  Release buffer handle
//! 
//! \param  [in] ctx
//!         Pointer to VA driver context
//! \param  [in] buf_id
//!         VA bufferID
//!
//! \return VAStatus
//!     VA_STATUS_SUCCESS if success, else fail reason
//!
VAStatus DdiMedia_ReleaseBufferHandle(
    VADriverContextP ctx,
    VABufferID buf_id)
{
    DDI_FUNCTION_ENTER();

    DDI_CHK_NULL(ctx, "nullptr ctx", VA_STATUS_ERROR_INVALID_CONTEXT);

    PDDI_MEDIA_CONTEXT mediaCtx = DdiMedia_GetMediaContext(ctx);
    DDI_CHK_NULL(mediaCtx, "Invalid Media ctx", VA_STATUS_ERROR_INVALID_CONTEXT);

    DDI_MEDIA_BUFFER   *buf     = DdiMedia_GetBufferFromVABufferID(mediaCtx, buf_id);
    DDI_CHK_NULL(buf,          "Invalid Media Buffer", VA_STATUS_ERROR_INVALID_BUFFER);
    DDI_CHK_NULL(buf->bo,      "Invalid Media Buffer", VA_STATUS_ERROR_INVALID_BUFFER);

    DdiMediaUtil_LockMutex(&mediaCtx->BufferMutex);
    if (!buf->uiMemtype || !buf->uiExportcount)
    {
        DdiMediaUtil_UnLockMutex(&mediaCtx->BufferMutex);
        return VA_STATUS_SUCCESS;
    }
    mos_bo_unreference(buf->bo);
    --buf->uiExportcount;

    if (!buf->uiExportcount) {
        switch (buf->uiMemtype) {
        case VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME: {
            close((intptr_t)buf->handle);
            break;
        }
        }
        buf->uiMemtype = 0;
    }
    DdiMediaUtil_UnLockMutex(&mediaCtx->BufferMutex);
    return VA_STATUS_SUCCESS;
}

#include "drm_fourcc.h"
// Locally define DRM_FORMAT values not available in older but still
// supported versions of libdrm.
#ifndef DRM_FORMAT_R8
#define DRM_FORMAT_R8        fourcc_code('R', '8', ' ', ' ')
#endif
#ifndef DRM_FORMAT_R16
#define DRM_FORMAT_R16       fourcc_code('R', '1', '6', ' ')
#endif
#ifndef DRM_FORMAT_GR88
#define DRM_FORMAT_GR88      fourcc_code('G', 'R', '8', '8')
#endif
#ifndef DRM_FORMAT_GR1616
#define DRM_FORMAT_GR1616    fourcc_code('G', 'R', '3', '2')
#endif


static uint32_t DdiMedia_GetChromaPitchHeight(PDDI_MEDIA_SURFACE mediaSurface, uint32_t *chromaWidth, uint32_t *chromaPitch, uint32_t *chromaHeight)
{
    DDI_CHK_NULL(mediaSurface, "nullptr mediaSurface", VA_STATUS_ERROR_INVALID_PARAMETER);
    DDI_CHK_NULL(chromaWidth, "nullptr chromaWidth", VA_STATUS_ERROR_INVALID_PARAMETER);
    DDI_CHK_NULL(chromaPitch, "nullptr chromaPitch", VA_STATUS_ERROR_INVALID_PARAMETER);
    DDI_CHK_NULL(chromaHeight, "nullptr chromaHeight", VA_STATUS_ERROR_INVALID_PARAMETER);

    uint32_t fourcc = DdiMedia_MediaFormatToOsFormat(mediaSurface->format);
    switch(fourcc)
    {
        case VA_FOURCC_NV12:
            *chromaWidth = mediaSurface->iWidth;
            *chromaHeight = mediaSurface->iHeight/2;
            *chromaPitch = mediaSurface->iPitch;
            return 2;
        case VA_FOURCC_I420:
        case VA_FOURCC_YV12:
            *chromaWidth = mediaSurface->iWidth / 2;
            *chromaHeight = mediaSurface->iHeight/2;
            *chromaPitch = mediaSurface->iPitch /2;
            return 3;
        case VA_FOURCC_YV16:
            *chromaWidth = mediaSurface->iWidth / 2;
            *chromaHeight = mediaSurface->iHeight;
            *chromaPitch = mediaSurface->iPitch / 2;
            return 3;
        case VA_FOURCC_P010:
            *chromaWidth = mediaSurface->iWidth ;
            *chromaHeight = mediaSurface->iHeight/2;
            *chromaPitch = mediaSurface->iPitch;
            return 3;
        case VA_FOURCC_I010:
            *chromaWidth = mediaSurface->iWidth / 2;
            *chromaHeight = mediaSurface->iHeight/2;
            *chromaPitch = mediaSurface->iPitch / 2;
            return 2;
        case VA_FOURCC_YUY2:
        case VA_FOURCC_Y800:
        case VA_FOURCC_UYVY:
        case VA_FOURCC_RGBA:
        case VA_FOURCC_RGBX:
        case VA_FOURCC_BGRA:
        case VA_FOURCC_BGRX:
        case VA_FOURCC_ARGB:
        case VA_FOURCC_ABGR:
        default:
            *chromaWidth = 0;
            *chromaPitch = 0;
            *chromaHeight = 0;
            return 1;
    }
}

static uint32_t DdiMedia_GetDrmFormatOfSeparatePlane(uint32_t fourcc, int plane)
{
    if (plane == 0)
    {
        switch (fourcc)
        {
        case VA_FOURCC_NV12:
        case VA_FOURCC_I420:
        case VA_FOURCC_YV12:
        case VA_FOURCC_YV16:
        case VA_FOURCC_Y800:
            return DRM_FORMAT_R8;
        case VA_FOURCC_P010:
        case VA_FOURCC_I010:
            return DRM_FORMAT_R16;

        case VA_FOURCC_YUY2:
        case VA_FOURCC_UYVY:
            // These are not representable as separate planes.
            return 0;

        case VA_FOURCC_RGBA:
            return DRM_FORMAT_ABGR8888;
        case VA_FOURCC_RGBX:
            return DRM_FORMAT_XBGR8888;
        case VA_FOURCC_BGRA:
            return DRM_FORMAT_ARGB8888;
        case VA_FOURCC_BGRX:
            return DRM_FORMAT_XRGB8888;
        case VA_FOURCC_ARGB:
            return DRM_FORMAT_BGRA8888;
        case VA_FOURCC_ABGR:
            return DRM_FORMAT_RGBA8888;
        }
    }
    else
    {
        switch (fourcc)
        {
        case VA_FOURCC_NV12:
            return DRM_FORMAT_GR88;
        case VA_FOURCC_I420:
        case VA_FOURCC_YV12:
        case VA_FOURCC_YV16:
            return DRM_FORMAT_R8;
        case VA_FOURCC_P010:
            return DRM_FORMAT_GR1616;
        case VA_FOURCC_I010:
            return DRM_FORMAT_R16;
        }
    }
    return 0;
}

static uint32_t DdiMedia_GetDrmFormatOfCompositeObject(uint32_t fourcc)
{
    switch (fourcc)
    {
    case VA_FOURCC_NV12:
        return DRM_FORMAT_NV12;
    case VA_FOURCC_I420:
        return DRM_FORMAT_YUV420;
    case VA_FOURCC_YV12:
        return DRM_FORMAT_YVU420;
    case VA_FOURCC_YV16:
        return DRM_FORMAT_YVU422;
    case VA_FOURCC_YUY2:
        return DRM_FORMAT_YUYV;
    case VA_FOURCC_UYVY:
        return DRM_FORMAT_UYVY;
    case VA_FOURCC_Y800:
        return DRM_FORMAT_R8;
    case VA_FOURCC_P010:
    case VA_FOURCC_I010:
        // These currently have no composite DRM format - they are usable
        // only as separate planes.
        return 0;
    case VA_FOURCC_RGBA:
        return DRM_FORMAT_ABGR8888;
    case VA_FOURCC_RGBX:
        return DRM_FORMAT_XBGR8888;
    case VA_FOURCC_BGRA:
        return DRM_FORMAT_ARGB8888;
    case VA_FOURCC_BGRX:
        return DRM_FORMAT_XRGB8888;
    case VA_FOURCC_ARGB:
        return DRM_FORMAT_BGRA8888;
    case VA_FOURCC_ABGR:
        return DRM_FORMAT_RGBA8888;
    }
    return 0;
}


//!
//! \brief   API for export surface handle to other component
//!
//! \param [in] dpy
//!          VA display.
//! \param [in] surface_id
//!          Surface to export.
//! \param [in] mem_type
//!          Memory type to export to.
//! \param [in] flags
//!          Combination of flags to apply
//!\param [out] descriptor
//!Pointer to the descriptor structure to fill
//!with the handle details.  The type of this structure depends on
//!the value of mem_type.
//! \return VAStatus
//!     VA_STATUS_SUCCESS if success, else fail reason
//!
VAStatus DdiMedia_ExportSurfaceHandle(
    VADriverContextP ctx,
    VASurfaceID surface_id,
    uint32_t mem_type,
    uint32_t flags,
    void * descriptor)
{
    DDI_CHK_NULL(descriptor,    "nullptr descriptor",   VA_STATUS_ERROR_INVALID_PARAMETER);
    DDI_CHK_NULL(ctx,                     "nullptr ctx",                     VA_STATUS_ERROR_INVALID_CONTEXT);

    PDDI_MEDIA_CONTEXT mediaCtx = DdiMedia_GetMediaContext(ctx);
    DDI_CHK_NULL(mediaCtx,               "nullptr mediaCtx",               VA_STATUS_ERROR_INVALID_CONTEXT);
    DDI_CHK_NULL(mediaCtx->pSurfaceHeap, "nullptr mediaCtx->pSurfaceHeap", VA_STATUS_ERROR_INVALID_CONTEXT);
    DDI_CHK_LESS((uint32_t)(surface_id), mediaCtx->pSurfaceHeap->uiAllocatedHeapElements, "Invalid surfaces", VA_STATUS_ERROR_INVALID_SURFACE);

    DDI_MEDIA_SURFACE  *mediaSurface = DdiMedia_GetSurfaceFromVASurfaceID(mediaCtx, surface_id);
    DDI_CHK_NULL(mediaSurface,                   "nullptr mediaSurface",                   VA_STATUS_ERROR_INVALID_SURFACE);
    DDI_CHK_NULL(mediaSurface->bo,               "nullptr mediaSurface->bo",               VA_STATUS_ERROR_INVALID_SURFACE);
    DDI_CHK_NULL(mediaSurface->pGmmResourceInfo, "nullptr mediaSurface->pGmmResourceInfo", VA_STATUS_ERROR_INVALID_SURFACE);

    int32_t ret = mos_bo_gem_export_to_prime(mediaSurface->bo, (int32_t*)&mediaSurface->name);
    if (ret)
    {
        //LOGE("Failed drm_intel_gem_export_to_prime operation!!!\n");
        return VA_STATUS_ERROR_OPERATION_FAILED;
    }
    uint32_t tiling, swizzle;
    if(mos_bo_get_tiling(mediaSurface->bo,&tiling, &swizzle))
    {
        tiling = I915_TILING_NONE;
    }

    VADRMPRIMESurfaceDescriptor *desc = (VADRMPRIMESurfaceDescriptor *)descriptor;
    desc->fourcc = DdiMedia_MediaFormatToOsFormat(mediaSurface->format);
    if(desc->fourcc == VA_STATUS_ERROR_UNSUPPORTED_RT_FORMAT)
    {
        return VA_STATUS_ERROR_UNSUPPORTED_RT_FORMAT;
    }
    desc->width  = mediaSurface->iWidth;
    desc->height = mediaSurface->iHeight;

    desc->num_objects     = 1;
    desc->objects[0].fd   = mediaSurface->name;
    desc->objects[0].size = mediaSurface->pGmmResourceInfo->GetSizeSurface();
    switch (tiling) {
    case I915_TILING_X:
        desc->objects[0].drm_format_modifier = I915_FORMAT_MOD_X_TILED;
        break;
    case I915_TILING_Y:
        desc->objects[0].drm_format_modifier = I915_FORMAT_MOD_Y_TILED;
        break;
    case I915_TILING_NONE:
    default:
        desc->objects[0].drm_format_modifier = DRM_FORMAT_MOD_NONE;
    }
    int composite_object = flags & VA_EXPORT_SURFACE_COMPOSED_LAYERS;

    uint32_t formats[4];
    uint32_t chromaWidth;
    uint32_t chromaPitch;
    uint32_t chromaHeight;
    uint32_t num_planes = DdiMedia_GetChromaPitchHeight(mediaSurface,&chromaWidth, &chromaPitch,&chromaHeight);

    if(composite_object)
    {
        formats[0] = DdiMedia_GetDrmFormatOfCompositeObject(desc->fourcc);

        if(!formats[0])
        {
            DDI_ASSERTMESSAGE("vaExportSurfaceHandle: fourcc %08x is not supported for export as a composite object.\n", desc->fourcc);
            return VA_STATUS_ERROR_INVALID_SURFACE;
        }
    }
    else
    {
        for (int i = 0; i < num_planes; i++)
        {
            formats[i] = DdiMedia_GetDrmFormatOfSeparatePlane(desc->fourcc,i);
            if (!formats[i])
            {
                DDI_ASSERTMESSAGE("vaExportSurfaceHandle: fourcc %08x "
                              "is not supported for export as separate "
                              "planes.\n", desc->fourcc);
                return VA_STATUS_ERROR_INVALID_SURFACE;
            }
        }
    }

    uint32_t offset = 0;
    uint32_t pitch  = 0;
    uint32_t height = 0;

    if (composite_object) {
        desc->num_layers = 1;

        desc->layers[0].drm_format = formats[0];
        desc->layers[0].num_planes = num_planes;

        for (int i = 0; i < num_planes; i++)
        {
            desc->layers[0].object_index[i] = 0;
            if (i == 0)
            {
                pitch  = mediaSurface->iPitch;
                height = mediaSurface->iHeight;
            }
            else
            {
                pitch = chromaPitch;
                height = chromaHeight;
            }

            desc->layers[0].offset[i] = offset;
            desc->layers[0].pitch[i]  = pitch;

            offset += pitch * height;
        }
    }
    else
    {
        desc->num_layers = num_planes;

        offset = 0;
        for (int i = 0; i < num_planes; i++)
        {
            desc->layers[i].drm_format = formats[i];
            desc->layers[i].num_planes = 1;

            desc->layers[i].object_index[0] = 0;

            if (i == 0)
            {
                pitch  = mediaSurface->iPitch;
                height = mediaSurface->iHeight;
            }
            else
            {
                pitch  =  chromaPitch;
                height = chromaHeight;
            }

            desc->layers[i].offset[0] = offset;
            desc->layers[i].pitch[0]  = pitch;

            offset += pitch * height;
        }
    }
    return VA_STATUS_SUCCESS;
}

//!
//! \brief  Init VA driver 0.31
//! 
//! \param  [in] ctx
//!         Pointer to VA driver context
//!
//! \return VAStatus
//!     VA_STATUS_SUCCESS if success, else fail reason
//!
VAStatus __vaDriverInit(VADriverContextP ctx )
{
    DDI_CHK_NULL(ctx,         "nullptr ctx",          VA_STATUS_ERROR_INVALID_CONTEXT);

    struct VADriverVTable    *pVTable     = DDI_CODEC_GET_VTABLE(ctx);
    DDI_CHK_NULL(pVTable,     "nullptr pVTable",      VA_STATUS_ERROR_INVALID_CONTEXT);

    struct VADriverVTableVPP *pVTableVpp  = DDI_CODEC_GET_VTABLE_VPP(ctx);
    DDI_CHK_NULL(pVTableVpp,  "nullptr pVTableVpp",   VA_STATUS_ERROR_INVALID_CONTEXT);

    ctx->pDriverData                         = nullptr;
    ctx->version_major                       = VA_MAJOR_VERSION;
    ctx->version_minor                       = VA_MINOR_VERSION;
    ctx->max_profiles                        = DDI_CODEC_GEN_MAX_PROFILES;
    ctx->max_entrypoints                     = DDI_CODEC_GEN_MAX_ENTRYPOINTS;
    ctx->max_attributes                      = (int32_t)VAConfigAttribTypeMax;
    ctx->max_subpic_formats                  = DDI_CODEC_GEN_MAX_SUBPIC_FORMATS;
    ctx->max_display_attributes              = DDI_CODEC_GEN_MAX_DISPLAY_ATTRIBUTES ;
    ctx->str_vendor                          = DDI_CODEC_GEN_STR_VENDOR;
    ctx->vtable_tpi                          = nullptr;

    pVTable->vaTerminate                     = DdiMedia_Terminate;
    pVTable->vaQueryConfigEntrypoints        = DdiMedia_QueryConfigEntrypoints;
    pVTable->vaQueryConfigProfiles           = DdiMedia_QueryConfigProfiles;
    pVTable->vaQueryConfigAttributes         = DdiMedia_QueryConfigAttributes;
    pVTable->vaCreateConfig                  = DdiMedia_CreateConfig;
    pVTable->vaDestroyConfig                 = DdiMedia_DestroyConfig;
    pVTable->vaGetConfigAttributes           = DdiMedia_GetConfigAttributes;

    pVTable->vaCreateSurfaces                = DdiMedia_CreateSurfaces;
    pVTable->vaDestroySurfaces               = DdiMedia_DestroySurfaces;
    pVTable->vaCreateSurfaces2               = DdiMedia_CreateSurfaces2;

    pVTable->vaCreateContext                 = DdiMedia_CreateContext;
    pVTable->vaDestroyContext                = DdiMedia_DestroyContext;
    pVTable->vaCreateBuffer                  = DdiMedia_CreateBuffer;
    pVTable->vaBufferSetNumElements          = DdiMedia_BufferSetNumElements;
    pVTable->vaMapBuffer                     = DdiMedia_MapBuffer;
    pVTable->vaUnmapBuffer                   = DdiMedia_UnmapBuffer;
    pVTable->vaDestroyBuffer                 = DdiMedia_DestroyBuffer;
    pVTable->vaBeginPicture                  = DdiMedia_BeginPicture;
    pVTable->vaRenderPicture                 = DdiMedia_RenderPicture;
    pVTable->vaEndPicture                    = DdiMedia_EndPicture;
    pVTable->vaSyncSurface                   = DdiMedia_SyncSurface;
    pVTable->vaQuerySurfaceStatus            = DdiMedia_QuerySurfaceStatus;
    pVTable->vaQuerySurfaceError             = DdiMedia_QuerySurfaceError;
    pVTable->vaQuerySurfaceAttributes        = DdiMedia_QuerySurfaceAttributes;
    pVTable->vaPutSurface                    = DdiMedia_PutSurface;
    pVTable->vaQueryImageFormats             = DdiMedia_QueryImageFormats;

    pVTable->vaCreateImage                   = DdiMedia_CreateImage;
    pVTable->vaDeriveImage                   = DdiMedia_DeriveImage;
    pVTable->vaDestroyImage                  = DdiMedia_DestroyImage;
    pVTable->vaSetImagePalette               = DdiMedia_SetImagePalette;
    pVTable->vaGetImage                      = DdiMedia_GetImage;
    pVTable->vaPutImage                      = DdiMedia_PutImage;
    pVTable->vaQuerySubpictureFormats        = DdiMedia_QuerySubpictureFormats;
    pVTable->vaCreateSubpicture              = DdiMedia_CreateSubpicture;
    pVTable->vaDestroySubpicture             = DdiMedia_DestroySubpicture;
    pVTable->vaSetSubpictureImage            = DdiMedia_SetSubpictureImage;
    pVTable->vaSetSubpictureChromakey        = DdiMedia_SetSubpictureChromakey;
    pVTable->vaSetSubpictureGlobalAlpha      = DdiMedia_SetSubpictureGlobalAlpha;
    pVTable->vaAssociateSubpicture           = DdiMedia_AssociateSubpicture;
    pVTable->vaDeassociateSubpicture         = DdiMedia_DeassociateSubpicture;
    pVTable->vaQueryDisplayAttributes        = DdiMedia_QueryDisplayAttributes;
    pVTable->vaGetDisplayAttributes          = DdiMedia_GetDisplayAttributes;
    pVTable->vaSetDisplayAttributes          = DdiMedia_SetDisplayAttributes;
    pVTable->vaQueryProcessingRate           = DdiMedia_QueryProcessingRate;

    // vaTrace
    pVTable->vaBufferInfo                    = DdiMedia_BufferInfo;
    pVTable->vaLockSurface                   = DdiMedia_LockSurface;
    pVTable->vaUnlockSurface                 = DdiMedia_UnlockSurface;

    pVTableVpp->vaQueryVideoProcFilters      = DdiMedia_QueryVideoProcFilters;
    pVTableVpp->vaQueryVideoProcFilterCaps   = DdiMedia_QueryVideoProcFilterCaps;
    pVTableVpp->vaQueryVideoProcPipelineCaps = DdiMedia_QueryVideoProcPipelineCaps;

    //pVTable->vaSetSurfaceAttributes          = DdiMedia_SetSurfaceAttributes;
    pVTable->vaGetSurfaceAttributes          = DdiMedia_GetSurfaceAttributes;
    //Export PRIMEFD/FLINK to application for buffer sharing with OpenCL/GL
    pVTable->vaAcquireBufferHandle           = DdiMedia_AcquireBufferHandle;
    pVTable->vaReleaseBufferHandle           = DdiMedia_ReleaseBufferHandle;
    pVTable->vaExportSurfaceHandle           = DdiMedia_ExportSurfaceHandle;
#ifndef ANDROID
    pVTable->vaCreateMFContext               = DdiMedia_CreateMfeContextInternal;
    pVTable->vaMFAddContext                  = DdiMedia_AddContextInternal;
    pVTable->vaMFReleaseContext              = DdiMedia_ReleaseContextInternal;
    pVTable->vaMFSubmit                      = DdiEncode_MfeSubmit;
#endif
    return DdiMedia__Initialize(ctx, nullptr, nullptr);
}

#ifdef __cplusplus
extern "C" {
#endif

//! 
//! \brief Get VA_MAJOR_VERSION and VA_MINOR_VERSION from libva
//!         To form the function name in the format of _vaDriverInit_[VA_MAJOR_VERSION]_[VA_MINOR_VERSION]
//!
#define VA_DRV_INIT_DEF(_major,_minor) __vaDriverInit_##_major##_##_minor
#define VA_DRV_INIT_FUNC(va_major_version, va_minor_version) VA_DRV_INIT_DEF(va_major_version,va_minor_version)
#define VA_DRV_INIT_FUC_NAME VA_DRV_INIT_FUNC(VA_MAJOR_VERSION,VA_MINOR_VERSION)

//!
//! \brief  VA driver init function name
//! 
//! \param  [in] ctx
//!         Pointer to VA driver context
//!
//! \return VAStatus
//!     VA_STATUS_SUCCESS if success, else fail reason
//!
MEDIAAPI_EXPORT VAStatus VA_DRV_INIT_FUC_NAME(VADriverContextP ctx )
{
    return __vaDriverInit(ctx);
}

//!
//! \brief  Private API for openCL
//! 
//! \param  [in] dpy
//!         VA display
//! \param  [in] surface
//!         VA surface ID
//! \param  [in] prime_fd
//!         Prime fd
//!
//! \return VAStatus
//!     VA_STATUS_SUCCESS if success, else fail reason
//!
MEDIAAPI_EXPORT VAStatus DdiMedia_ExtGetSurfaceHandle(
    VADisplay      dpy,
    VASurfaceID   *surface,
    int32_t       *prime_fd)
{
    DDI_CHK_NULL(dpy,                     "nullptr dpy",                     VA_STATUS_ERROR_INVALID_DISPLAY);
    DDI_CHK_NULL(surface,                 "nullptr surfaces",                VA_STATUS_ERROR_INVALID_PARAMETER);
    DDI_CHK_NULL(prime_fd,                "nullptr id",                      VA_STATUS_ERROR_INVALID_PARAMETER);

    VADriverContextP   ctx      = ((VADisplayContextP)dpy)->pDriverContext;
    DDI_CHK_NULL(ctx,                     "nullptr ctx",                     VA_STATUS_ERROR_INVALID_CONTEXT);

    PDDI_MEDIA_CONTEXT mediaCtx = DdiMedia_GetMediaContext(ctx);
    DDI_CHK_NULL(mediaCtx,               "nullptr mediaCtx",               VA_STATUS_ERROR_INVALID_CONTEXT);
    DDI_CHK_NULL(mediaCtx->pSurfaceHeap, "nullptr mediaCtx->pSurfaceHeap", VA_STATUS_ERROR_INVALID_CONTEXT);
    DDI_CHK_LESS((uint32_t)(*surface), mediaCtx->pSurfaceHeap->uiAllocatedHeapElements, "Invalid surfaces", VA_STATUS_ERROR_INVALID_SURFACE);

    DDI_MEDIA_SURFACE  *mediaSurface = DdiMedia_GetSurfaceFromVASurfaceID(mediaCtx, *surface);
    if (mediaSurface)
    {
        if (mediaSurface->bo)
        {
            int32_t ret = mos_bo_gem_export_to_prime(mediaSurface->bo, (int32_t*)&mediaSurface->name);
            if (ret)
            {
                //LOGE("Failed drm_intel_gem_export_to_prime operation!!!\n");
                return VA_STATUS_ERROR_OPERATION_FAILED;
            }
        }
    }
    else
    {
        return VA_STATUS_ERROR_INVALID_SURFACE;
    }

    *prime_fd = mediaSurface->name;

    return VA_STATUS_SUCCESS;
}

//!
//! \brief  Map buffer 2
//! 
//! \param  [in] dpy
//!         VA display
//! \param  [in] buf_id
//!         VA buffer ID
//! \param  [out] pbuf
//!         Pointer to buffer
//! \param  [in] flag
//!         Flag
//!
//! \return VAStatus
//!     VA_STATUS_SUCCESS if success, else fail reason
//!
MEDIAAPI_EXPORT VAStatus DdiMedia_MapBuffer2(
    VADisplay           dpy,
    VABufferID          buf_id,
    void              **pbuf,
    int32_t             flag
)
{
    DDI_CHK_NULL(dpy,                     "nullptr dpy",                     VA_STATUS_ERROR_INVALID_DISPLAY);

    VADriverContextP ctx = ((VADisplayContextP)dpy)->pDriverContext;

    if ((flag == 0) || (flag & ~(MOS_LOCKFLAG_READONLY | MOS_LOCKFLAG_WRITEONLY)))
        return VA_STATUS_ERROR_INVALID_PARAMETER;

    return DdiMedia_MapBufferInternal(ctx, buf_id, pbuf, flag);
}

#ifdef __cplusplus
}
#endif

