/**
 * @file hv_mw_OsdDraw.c
 * @brief osd MiddleWare draw c file.
 * @details This file provides the following functions: \n
 *          (1) Osd draw functions \n
 *
 * @author HiView SoC Software Team
 * @version 1.0.0
 * @date 2022-09-01
 * @copyright Copyright(c),2022-8, Hiview Software. All rights reserved.
 * @par History:
 * <table>
 * <tr><th>Author       <th>Date            <th>Change Description
 * <tr><td>shanpeng     <td>2022-09-01      <td>create
 * </table>
 */

#include "hv_comm_DataBase.h"
#include "hv_mw_PQ.h"
#include "hv_app_PQ.h"
#include "hv_app_Osd.h"
#include "hv_mw_SystemManager.h"
#include "hv_mw_Channel_Manager.h"
#include "hv_mw_OsdComm.h"
#include "hv_mw_OsdLog.h"
#include "hv_mw_OsdInit.h"
#include "hv_mw_OsdDraw.h"
#include "hv_mw_OsdEvent.h"
#include "hv_mw_OsdOperation.h"
#include "hv_mw_OsdInterrupt.h"
#include "hv_drv_Osd.h"
#include "hv_drv_OsdLogo.h"
#include "hv_drv_OsdRotate.h"
#include "hv_drv_DpuCommon.h"
#include "hv_mw_PanelManager.h"
#if (HV_PROJECT_CONFIG_OSD_ANIMITION_SUPPORT == HV_CONFIG_ON)
#include "hv_mw_OsdAnimation.h"
#endif

#define OSD_CHECK_REG_EN_PERIOD_MS      (1)

typedef struct _OsdDrawManager {
    UINT32 uiWindowEnableFlag;
    UINT32 uiRectEnableFlag;
    UINT32 uiGridEnableFlag;
    UINT32 uiLineEnableFlag;
    BOOL bFrameModify;
    OsdLogoState enLogoState;
    BOOL bBypassLogo;
#if (HV_PROJECT_CONFIG_OSD_DDRPATH == HV_CONFIG_ON)
    BOOL bIsFirstFrame;
    UCHAR8 ucMutiFrameDrawCurrentSceneId;
#if (HV_PROJECT_CONFIG_OSD_ROTATION == HV_CONFIG_ON)
    UCHAR8 ucRotatingStep;
    UCHAR8 ucSceneRotating;
    BOOL bRotateChange;
    BOOL bIsLastScene;
#endif
#endif
} OsdDrawManager;

static OsdDrawManager s_stOsdDrawData;

#define SET_WINDOW_USED_FLAG(x)         (s_stOsdDrawData.uiWindowEnableFlag |= (BIT_0 << (x)))
#define GET_WINDOW_USED_FLAG(x)         ((s_stOsdDrawData.uiWindowEnableFlag >> (x)) & BIT_0)
#define CLEAR_WINDOW_USED_FLAG(x)       (s_stOsdDrawData.uiWindowEnableFlag &= ~((UINT32)BIT_0 << (x)))
#define SET_RECT_USED_FLAG(x)           (s_stOsdDrawData.uiRectEnableFlag |= (BIT_0 << (x)))
#define GET_RECT_USED_FLAG(x)           ((s_stOsdDrawData.uiRectEnableFlag >> (x)) & BIT_0)
#define CLEAR_RECT_USED_FLAG(x)         (s_stOsdDrawData.uiRectEnableFlag &= ~((UINT32)BIT_0 << (x)))
#define SET_GRID_USED_FLAG(x)           (s_stOsdDrawData.uiGridEnableFlag |= (BIT_0 << (x)))
#define GET_GRID_USED_FLAG(x)           ((s_stOsdDrawData.uiGridEnableFlag >> (x)) & BIT_0)
#define CLEAR_GRID_USED_FLAG(x)         (s_stOsdDrawData.uiGridEnableFlag &= ~((UINT32)BIT_0 << (x)))
#define SET_LINE_USED_FLAG(x)           (s_stOsdDrawData.uiLineEnableFlag |= (BIT_0 << (x)))
#define GET_LINE_USED_FLAG(x)           ((s_stOsdDrawData.uiLineEnableFlag >> (x)) & BIT_0)
#define CLEAR_LINE_USED_FLAG(x)         (s_stOsdDrawData.uiLineEnableFlag &= ~((UINT32)BIT_0 << (x)))

#if (HV_PROJECT_CONFIG_OSD_CPU_CANVAS_SUPPORT == HV_CONFIG_ON)
typedef struct _OsdCanvasData
{
    OsdComponent stCp;
    USHORT16 usXStep;
    USHORT16 ucPointW;
    USHORT16 ucPointH;
    USHORT16 bFirstDraw;
    USHORT16 ausYArray[OSD_CANVAS_WAVE_POINT_CNT];
    USHORT16 usTotalCnt;
    USHORT16 usOffset;
} OsdCanvasData;
static OsdCanvasData s_stCanvas;

VOID Hv_Mw_OsdCanvasClear(VOID)
{
    OsdComponentNode *pstNode = Hv_Mw_OsdComponentGetNode(s_stCanvas.stCp);
    HV_ASSERT_VALID_PTR_VOID(pstNode);
    Hv_Drv_OsdFont_ClearCPUCanvas(pstNode);
}

VOID Hv_Mw_OsdCanvasDrawPoint(OsdComponent stCp, USHORT16 usX, USHORT16 usY, UINT32 uiColor)
{
    OsdComponentNode *pstNode = Hv_Mw_OsdComponentGetNode(s_stCanvas.stCp);
    HV_ASSERT_VALID_PTR_VOID(pstNode);
    Hv_Drv_OsdFont_DrawCPUCanvasPoint(pstNode, usX, usY, uiColor, HV_FALSE);
}

VOID Hv_Mw_OsdCanvasErasePoint(OsdComponent stCp, USHORT16 usX, USHORT16 usY)
{
    OsdComponentNode *pstNode = Hv_Mw_OsdComponentGetNode(s_stCanvas.stCp);
    HV_ASSERT_VALID_PTR_VOID(pstNode);
    Hv_Drv_OsdFont_DrawCPUCanvasPoint(pstNode, usX, usY, 0, HV_TRUE);
}

VOID Hv_Mw_OsdCanvasWaveResetPointArray(VOID)
{
    HV_MEMSET(s_stCanvas.ausYArray, 0, sizeof(s_stCanvas.ausYArray));
    s_stCanvas.usTotalCnt = 0;
    s_stCanvas.usOffset = 0;
}

VOID Hv_Mw_OsdCanvasWaveInit(OsdComponent stCp, USHORT16 usXStep, UCHAR8 ucPointW, UCHAR8 ucPointH)
{
    s_stCanvas.stCp = stCp;
    s_stCanvas.usXStep = usXStep;
    s_stCanvas.ucPointW = ucPointW;
    s_stCanvas.ucPointH = ucPointH;
    s_stCanvas.bFirstDraw = HV_TRUE;
    Hv_Mw_OsdOpsForceRedraw(HV_TRUE);
}

VOID Hv_Mw_OsdCanvasWaveAppendPoint(USHORT16 usY)
{
    USHORT16 usX = 0;
    USHORT16 usYId = 0;
    USHORT16 usCnt = 0;

    OsdComponentNode *pstNode = Hv_Mw_OsdComponentGetNode(s_stCanvas.stCp);
    HV_ASSERT_VALID_PTR_VOID(pstNode);

    s_stCanvas.ausYArray[s_stCanvas.usOffset++] = usY;
    if (s_stCanvas.usOffset >= OSD_CANVAS_WAVE_POINT_CNT)
    {
        s_stCanvas.usOffset = 0;
    }
    if (s_stCanvas.usTotalCnt < OSD_CANVAS_WAVE_POINT_CNT)
    {
        s_stCanvas.usTotalCnt++;
    }

    usYId = (s_stCanvas.usOffset > 0) ? (s_stCanvas.usOffset - 1) : (OSD_CANVAS_WAVE_POINT_CNT - 1);
    Hv_Drv_OsdFont_ClearCPUCanvas(pstNode);
    while (usCnt < s_stCanvas.usTotalCnt)
    {
        for (UCHAR8 ucYOffset = 0; ucYOffset < s_stCanvas.ucPointH; ucYOffset++)
        {
            for (UCHAR8 ucXOffset = 0; ucXOffset < s_stCanvas.ucPointW; ucXOffset++)
            {
                if ((usX + ucXOffset < pstNode->stBox.usW) && (s_stCanvas.ausYArray[usYId] + ucYOffset < pstNode->stBox.usH))
                {
                    Hv_Drv_OsdFont_DrawCPUCanvasPoint(pstNode, usX + ucXOffset, s_stCanvas.ausYArray[usYId] + ucYOffset, 0, HV_FALSE);
                }
            }
        }
        usX += s_stCanvas.usXStep;
        if (usYId == 0)
        {
            usYId = OSD_CANVAS_WAVE_POINT_CNT - 1;
        }
        else
        {
            usYId--;
        }
        usCnt++;
    }
}
#endif

BOOL Hv_Mw_OsdCheckIsShowing(VOID)
{
    return (0 != Hv_Drv_OsdDataPath_GetDrawParts());
}

static Status Hv_Mw_OsdSetSync(BOOL bSendSync, UCHAR8 ucFrameDelay, UINT32 uiWaitMs)
{
    UINT32 uiWaitCount = 0;
    UCHAR8 ucDelayCount = ucFrameDelay;

    OSD_LOG_DEBUG("Set sync, bSendSync = %d, ucFrameDelay = %d, uiWaitMs = %d (uiWaitCount = %d)",
                 bSendSync, ucFrameDelay, uiWaitMs, uiWaitCount);

    /* enable osd clock */
    if (!Hv_Drv_OsdFrame_GetOsdClockEnable())
    {
        Hv_Drv_OsdFrame_SetOsdClockEnable(HV_TRUE);
        Hv_Vos_Delayus(50);
    }

    Hv_Mw_OsdInterrupt_SetSyncFlag(bSendSync);
    if (bSendSync)
    {
        Hv_Mw_OsdInterrupt_SetSyncFrameDelay(ucFrameDelay);
    }

    do
    {
        Hv_Drv_OsdFrame_SetSync();

        uiWaitCount = uiWaitMs / OSD_CHECK_REG_EN_PERIOD_MS;
        if (0 == uiWaitMs)
        {
            return HV_SUCCESS;
        }
        else if (0xFFFFFFFF == uiWaitMs)
        {
            while (!Hv_Drv_OsdFrame_CheckSync())
            {
                //Hv_Vos_MSleep(OSD_CHECK_REG_EN_PERIOD_MS);
                Hv_Vos_Delayus(OSD_CHECK_REG_EN_PERIOD_MS * 1000);
            }
        }
        else
        {
            while (!Hv_Drv_OsdFrame_CheckSync())
            {
                if (0 == uiWaitCount)
                {
                    OSD_LOG_ERROR("Wait sync timeout!");
                    return HV_FAILURE;
                }
                uiWaitCount--;
                //Hv_Vos_MSleep(OSD_CHECK_REG_EN_PERIOD_MS);
                Hv_Vos_Delayus(OSD_CHECK_REG_EN_PERIOD_MS * 1000);
            }
        }
    } while (ucDelayCount-- > 0);

    return HV_SUCCESS;
}

static Status Hv_Mw_OsdWindowPrepareDraw(OsdWindow* pstWindow)
{
    USHORT16 usWindowRelativeX = 0;
    HV_ASSERT_VALID_PTR(pstWindow);
    HV_ASSERT_VALID_PTR(pstWindow->pstScene);
    const OsdWindowProp *pstWindowProp = OSD_GET_WINDOW_PROP(pstWindow->ucId);
    HV_ASSERT_VALID_PTR(pstWindowProp);
    OsdWindowProp stWindowProp = {0};

    HV_MEMCPY(&stWindowProp, pstWindowProp, sizeof(OsdWindowProp));
    usWindowRelativeX = pstWindowProp->usX;
#if (HV_CONFIG_ON == HV_PROJECT_CONFIG_OSD_MIRROR)
    if (bRTLShow)
    {
        usWindowRelativeX = pstWindow->pstScene->usWidth - pstWindowProp->usX - pstWindowProp->usWidth;
    }
#endif

    /* window 实际位置 = window相对与scene的位置 + scene的绝对位置 */
    stWindowProp.usX = usWindowRelativeX + pstWindow->pstScene->usX;
    stWindowProp.usY = pstWindowProp->usY + pstWindow->pstScene->usY;
    OSD_LOG_DEBUG("Window-%d(Phy-%d)'s pos set to (%d, %d)", pstWindow->ucId, pstWindow->ucPhyId, stWindowProp.usX, stWindowProp.usY);
    Hv_Drv_OsdWindow_DrawWindow(&stWindowProp);

    SET_WINDOW_USED_FLAG(pstWindowProp->ucWindowID);

    return HV_SUCCESS;
}

static VOID Hv_Mw_OsdWindowUpdateComponent(OsdWindow* pstWindow)
{
    HV_ASSERT_VALID_PTR_VOID(pstWindow);

    OsdNodeHead *pstHead = NULL;
    OsdComponentNode *pstNode = NULL;
    VOID *vpCpPropData = NULL;
    const OsdRectStyle *pstStyle = NULL;
    const OsdRectStyle *pstHighLightStyle = NULL;
    const OsdRectHighlight *pstRectHighLight = NULL;
    const OsdLineHighlight *pstLineHighLight = NULL;

    Hv_Drv_OsdFont_UpdateMenuFontList(pstWindow);

    pstHead = &pstWindow->stCpShowListHead;
    for (pstNode = pstHead->pstNode; pstNode != NULL; pstNode = pstNode->pstNext)
    {
        if (pstHead->usUpdateNum == 0)
        {
            break;
        }
        pstHead->usUpdateNum--;

        if (pstNode->pvDynamicData)
        {
            vpCpPropData = pstNode->pvDynamicData;
        }
        else if (pstNode->pvCpData)
        {
            vpCpPropData = pstNode->pvCpData;
        }
        else
        {
            OSD_LOG_WARN("%s has no prop data!", CP_NAME(pstNode->stCp));
            continue;
        }

        switch (pstNode->stCp.enType)
        {
            case OSD_CP_TYPE_RECT:
            {
                pstStyle = Hv_Mw_OsdGetRectStyle(((OsdRect*)vpCpPropData)->ucStyleIndex);
                Hv_Drv_OsdWindow_UpdateRect((OsdRect*)vpCpPropData, pstStyle);
                SET_RECT_USED_FLAG(PHY_RECT_ID(pstNode->stCp.usIndex));
                break;
            }

            case OSD_CP_TYPE_RECTGRID:
            {
                pstStyle = Hv_Mw_OsdGetRectStyle(((OsdRectGrid*)vpCpPropData)->ucNonHlStyleIndex);
                pstRectHighLight = Hv_Mw_OsdGetRectHl(((OsdRectGrid*)vpCpPropData)->ucHlOptionIndex);
                pstHighLightStyle = (pstRectHighLight == NULL) ? NULL : Hv_Mw_OsdGetRectStyle(pstRectHighLight->ucHlStyleIndex);
                Hv_Drv_OsdWindow_UpdateRectGrid((OsdRectGrid*)vpCpPropData, pstStyle, pstRectHighLight, pstHighLightStyle);
                SET_GRID_USED_FLAG(PHY_RECTGRID_ID(pstNode->stCp.usIndex));
                break;
            }

            case OSD_CP_TYPE_LINEGRID:
            {
                pstLineHighLight = Hv_Mw_OsdGetLineHl(((OsdLineGrid*)vpCpPropData)->ucHlOptionIndex);
                Hv_Drv_OsdWindow_UpdateLineGrid((OsdLineGrid*)vpCpPropData, pstLineHighLight);
                SET_LINE_USED_FLAG(PHY_LINEGRID_ID(pstNode->stCp.usIndex));
                break;
            }

            case OSD_CP_TYPE_LINE:
            {
                Hv_Drv_OsdWindow_UpdateLine((OsdLine*)vpCpPropData);
                SET_LINE_USED_FLAG(PHY_LINE_ID(pstNode->stCp.usIndex));
                break;
            }

            default:
            {
                break;
            }
        }
    }
}

static VOID Hv_Mw_OsdWindowDeleteComponent(OsdWindow* pstWindow)
{
    HV_ASSERT_VALID_PTR_VOID(pstWindow);

    OsdComponentNode *pstNode = NULL;
    VOID *vpCpPropData = NULL;

    Hv_Drv_OsdFont_HideMenuFontList(pstWindow);

    for (pstNode = pstWindow->stDeleteListHead.pstNode; pstNode != NULL; pstNode = pstNode->pstNext)
    {
        if (pstNode->pvDynamicData)
        {
            vpCpPropData = pstNode->pvDynamicData;
        }
        else if (pstNode->pvCpData)
        {
            vpCpPropData = pstNode->pvCpData;
        }
        else
        {
            OSD_LOG_WARN("%s has no prop data!", CP_NAME(pstNode->stCp));
            continue;
        }

        switch (pstNode->stCp.enType)
        {
            case OSD_CP_TYPE_RECT:
            {
                if (!GET_RECT_USED_FLAG(PHY_RECT_ID(pstNode->stCp.usIndex)))
                {
                    Hv_Drv_OsdWindow_EraseRect((OsdRect*)vpCpPropData);
                }
                break;
            }

            case OSD_CP_TYPE_RECTGRID:
            {
                if (!GET_GRID_USED_FLAG(PHY_RECTGRID_ID(pstNode->stCp.usIndex)))
                {
                    Hv_Drv_OsdWindow_EraseRectGrid((OsdRectGrid*)vpCpPropData);
                }
                break;
            }

            case OSD_CP_TYPE_LINEGRID:
            {
                if (!GET_LINE_USED_FLAG(PHY_LINEGRID_ID(pstNode->stCp.usIndex)))
                {
                    Hv_Drv_OsdWindow_EraseLineGrid((OsdLineGrid*)vpCpPropData);
                }
                break;
            }

            case OSD_CP_TYPE_LINE:
            {
                if (!GET_LINE_USED_FLAG(PHY_LINE_ID(pstNode->stCp.usIndex)))
                {
                    Hv_Drv_OsdWindow_EraseLine((OsdLine*)vpCpPropData);
                }
                break;
            }

            default:
            {
                break;
            }
        }
    }

    Hv_Mw_OsdWindowClearDeleteList(pstWindow);
}

static VOID Hv_Mw_OsdUpdateWindow(OsdWindow* pstWindow)
{
    HV_ASSERT_VALID_PTR_VOID(pstWindow);

#if (HV_PROJECT_CONFIG_OSD_GRAPHIC == HV_CONFIG_ON)
    if (pstWindow->ucPhyId == PHY_GRAPHIC)
    {
        if (!pstWindow->bVisable)
        {
            OSD_LOG_DEBUG("Disable Window-%d(Graphic)", pstWindow->ucId);
            Hv_Drv_OsdGraphic_SetEnable(HV_FALSE);
        }
        else
        {
            if (pstWindow->stCpShowListHead.pstNode)
            {
                if (pstWindow->stCpShowListHead.pstNode->stCp.enType == OSD_CP_TYPE_GRAPHIC)
                {
                    HV_ASSERT_VALID_PTR_VOID(pstWindow->stCpShowListHead.pstNode->pvCpData);
                    HV_ASSERT_VALID_PTR_VOID(pstWindow->pstScene);
#ifdef CONFIG_USER_DISPCTRL_OD_ON
                    Hv_Mw_PQ_OsdControlOdOff(HV_TRUE);
#endif
                    OSD_LOG_DEBUG("Update Window-%d(Graphic) start", pstWindow->ucId);
                    OsdGraphic stGraphic = {0};
                    OsdGraphicAddition stGraphicAddition = {0};
                    HV_MEMCPY(&stGraphic, pstWindow->stCpShowListHead.pstNode->pvCpData, sizeof(OsdGraphic));
                    stGraphic.usX = pstWindow->pstScene->usX;
                    stGraphic.usY = pstWindow->pstScene->usY;
                    Hv_Drv_OsdGraphic_DrawGraphic(&stGraphic, &stGraphicAddition);
                    SET_WINDOW_USED_FLAG(PHY_GRAPHIC);
                }
            }
        }
        return;
    }
#endif

    if (Hv_Mw_OsdWindowCheckIsEmpty(pstWindow->ucId))
    {
        OSD_LOG_DEBUG("Window-%d(Phy-%d) is empty!", pstWindow->ucId, pstWindow->ucPhyId);
        Hv_Mw_OsdWindowDeleteComponent(pstWindow);
        pstWindow->bVisable = HV_FALSE;
    }

    if (!pstWindow->bVisable)
    {
        const OsdWindowProp *pstWindowProp = OSD_GET_WINDOW_PROP(pstWindow->ucId);
        OsdWindowProp stWindowProp = {.ucWindowID = pstWindowProp->ucWindowID};
        OSD_LOG_DEBUG("Disable Window-%d(Phy-%d)", pstWindow->ucId, pstWindow->ucPhyId);
        Hv_Drv_OsdWindow_EraseWindow(&stWindowProp);
        return;
    }

    if (!pstWindow->bModify)
    {
        SET_WINDOW_USED_FLAG(pstWindow->ucPhyId);
        return;
    }

    OSD_LOG_DEBUG("Update Window-%d(Phy-%d) start", pstWindow->ucId, pstWindow->ucPhyId);
    //Hv_Mw_OsdPrintAllNodeList(pstWindow);

    HV_ASSERT_SUCCESS_VOID(Hv_Mw_OsdWindowPrepareDraw(pstWindow));

    Hv_Mw_OsdWindowDeleteComponent(pstWindow);

    Hv_Mw_OsdWindowUpdateComponent(pstWindow);

    OSD_LOG_DEBUG("Update Window-%d(Phy-%d) done", pstWindow->ucId, pstWindow->ucPhyId);
}

static VOID Hv_Mw_OsdDrawWindow(OsdWindow* pstWindow)
{
    HV_ASSERT_VALID_PTR_VOID(pstWindow);

    OsdNodeHead *pstHead = NULL;
    OsdComponentNode *pstNode = NULL;
    VOID *vpCpPropData = NULL;
    const OsdRectStyle *pstStyle = NULL;
    const OsdRectStyle *pstHighLightStyle = NULL;
    const OsdRectHighlight *pstRectHighLight = NULL;
    const OsdLineHighlight *pstLineHighLight = NULL;
    USHORT16 usUpdateNum = 0;
    OsdBox stBox = {0};

#if (HV_PROJECT_CONFIG_OSD_GRAPHIC == HV_CONFIG_ON)
    if (pstWindow->ucPhyId == PHY_GRAPHIC)
    {
        if (pstWindow->stCpShowListHead.pstNode)
        {
            if (pstWindow->stCpShowListHead.pstNode->stCp.enType == OSD_CP_TYPE_GRAPHIC)
            {
                HV_ASSERT_VALID_PTR_VOID(pstWindow->stCpShowListHead.pstNode->pvCpData);
                HV_ASSERT_VALID_PTR_VOID(pstWindow->pstScene);
#ifdef CONFIG_USER_DISPCTRL_OD_ON
                Hv_Mw_PQ_OsdControlOdOff(HV_TRUE);
#endif
                OSD_LOG_DEBUG("Draw Window-%d(Graphic) start", pstWindow->ucId);
                OsdGraphic stGraphic = {0};
                OsdGraphicAddition stGraphicAddition = {0};
                HV_MEMCPY(&stGraphic, pstWindow->stCpShowListHead.pstNode->pvCpData, sizeof(OsdGraphic));
                stGraphic.usX = pstWindow->pstScene->usX;
                stGraphic.usY = pstWindow->pstScene->usY;
                Hv_Drv_OsdGraphic_DrawGraphic(&stGraphic, &stGraphicAddition);
                SET_WINDOW_USED_FLAG(PHY_GRAPHIC);
            }
        }
        return;
    }
#endif

    OSD_LOG_DEBUG("Draw Window-%d(Phy-%d) start", pstWindow->ucId, pstWindow->ucPhyId);
    //Hv_Mw_OsdPrintAllNodeList(pstWindow);
    HV_ASSERT_SUCCESS_VOID(Hv_Mw_OsdWindowPrepareDraw(pstWindow));

    OSD_LOG_DEBUG("Start draw Window-%d's font list", pstWindow->ucId);
    Hv_Drv_OsdFont_DrawMenuFontList(pstWindow);

#if (HV_PROJECT_CONFIG_OSD_CPU_CANVAS_SUPPORT == HV_CONFIG_ON)
    if (s_stCanvas.bFirstDraw)
    {
        Hv_Mw_OsdCanvasClear();
        s_stCanvas.bFirstDraw = HV_FALSE;
    }
#endif

    OSD_LOG_DEBUG("Start draw Window-%d's rect/grid/line", pstWindow->ucId);

    pstHead = &pstWindow->stCpShowListHead;
    usUpdateNum = pstHead->usUpdateNum;
    for (pstNode = pstHead->pstNode; pstNode != NULL; pstNode = pstNode->pstNext)
    {
        if (pstNode->pvDynamicData)
        {
            vpCpPropData = pstNode->pvDynamicData;
        }
        else if (pstNode->pvCpData)
        {
            vpCpPropData = pstNode->pvCpData;
        }
        else
        {
            OSD_LOG_WARN("%s has no prop data!", CP_NAME(pstNode->stCp));
            continue;
        }

        switch (pstNode->stCp.enType)
        {
            case OSD_CP_TYPE_RECT:
            {
                pstStyle = Hv_Mw_OsdGetRectStyle(((OsdRect*)vpCpPropData)->ucStyleIndex);
                Hv_Drv_OsdWindow_DrawRect((OsdRect*)vpCpPropData, pstStyle);
#if (HV_PROJECT_CONFIG_OSD_ROTATION == HV_CONFIG_ON)
                if (usUpdateNum > 0)
                {
                    if (((OsdRect*)pstNode->pvCpData)->uiDynamicFlag & DYN_POSITION)
                    {
                        stBox.usW = ((OsdRect*)pstNode->pvDynamicData)->usWidth;
                        stBox.usH = ((OsdRect*)pstNode->pvDynamicData)->usHeight;
                        stBox.usX = ((OsdRect*)pstNode->pvDynamicData)->usX;
                        stBox.usY = ((OsdRect*)pstNode->pvDynamicData)->usY;
                    }
                    else
                    {
                        stBox.usW = ((OsdRect*)pstNode->pvCpData)->usWidth;
                        stBox.usH = ((OsdRect*)pstNode->pvCpData)->usHeight;
                        stBox.usX = ((OsdRect*)pstNode->pvCpData)->usX;
                        stBox.usY = ((OsdRect*)pstNode->pvCpData)->usY;
                    }
                    Hv_Drv_OsdAppendDrawAreaBox(stBox);
                    usUpdateNum--;
                }
#endif
                SET_RECT_USED_FLAG(PHY_RECT_ID(pstNode->stCp.usIndex));
                break;
            }

            case OSD_CP_TYPE_RECTGRID:
            {
                pstStyle = Hv_Mw_OsdGetRectStyle(((OsdRectGrid*)vpCpPropData)->ucNonHlStyleIndex);
                pstRectHighLight = Hv_Mw_OsdGetRectHl(((OsdRectGrid*)vpCpPropData)->ucHlOptionIndex);
                pstHighLightStyle = (pstRectHighLight == NULL) ? NULL : Hv_Mw_OsdGetRectStyle(pstRectHighLight->ucHlStyleIndex);
                Hv_Drv_OsdWindow_DrawRectGrid((OsdRectGrid*)vpCpPropData, pstStyle, pstRectHighLight, pstHighLightStyle);
#if (HV_PROJECT_CONFIG_OSD_ROTATION == HV_CONFIG_ON)
                if (usUpdateNum > 0)
                {
                    stBox.usW = ((OsdRectGrid*)pstNode->pvCpData)->usWidth;
                    stBox.usH = ((OsdRectGrid*)pstNode->pvCpData)->usHeight;
                    stBox.usX = ((OsdRectGrid*)pstNode->pvCpData)->usX;
                    stBox.usY = ((OsdRectGrid*)pstNode->pvCpData)->usY;
                    Hv_Drv_OsdAppendDrawAreaBox(stBox);
                    usUpdateNum--;
                }
#endif
                SET_GRID_USED_FLAG(PHY_RECTGRID_ID(pstNode->stCp.usIndex));
                break;
            }

            case OSD_CP_TYPE_LINEGRID:
            {
                pstLineHighLight = Hv_Mw_OsdGetLineHl(((OsdLineGrid*)vpCpPropData)->ucHlOptionIndex);
                Hv_Drv_OsdWindow_DrawLineGrid((OsdLineGrid*)vpCpPropData, pstLineHighLight);
#if (HV_PROJECT_CONFIG_OSD_ROTATION == HV_CONFIG_ON)
                if (usUpdateNum > 0)
                {
                    stBox.usW = ((OsdLineGrid*)pstNode->pvCpData)->usWidth;
                    stBox.usH = ((OsdLineGrid*)pstNode->pvCpData)->usHeight;
                    stBox.usX = ((OsdLineGrid*)pstNode->pvCpData)->usX;
                    stBox.usY = ((OsdLineGrid*)pstNode->pvCpData)->usY;
                    Hv_Drv_OsdAppendDrawAreaBox(stBox);
                    usUpdateNum--;
                }
#endif
                SET_LINE_USED_FLAG(PHY_LINEGRID_ID(pstNode->stCp.usIndex));
                break;
            }

            case OSD_CP_TYPE_LINE:
            {
                Hv_Drv_OsdWindow_DrawLine((OsdLine*)vpCpPropData);
#if (HV_PROJECT_CONFIG_OSD_ROTATION == HV_CONFIG_ON)
                if (usUpdateNum > 0)
                {
                    stBox.usW = ((OsdLine*)pstNode->pvCpData)->usWidth;
                    stBox.usH = ((OsdLine*)pstNode->pvCpData)->usHeight;
                    stBox.usX = ((OsdLine*)pstNode->pvCpData)->usX;
                    stBox.usY = ((OsdLine*)pstNode->pvCpData)->usY;
                    Hv_Drv_OsdAppendDrawAreaBox(stBox);
                    usUpdateNum--;
                }
#endif
                SET_LINE_USED_FLAG(PHY_LINE_ID(pstNode->stCp.usIndex));
                break;
            }

            default:
            {
                break;
            }
        }
    }
    OSD_LOG_DEBUG("Draw Window-%d(Phy-%d) done", pstWindow->ucId, pstWindow->ucPhyId);
}

static VOID Hv_Mw_OsdDrawFramePart(const OsdFramePartProp *pstFramePart)
{
    HV_ASSERT_VALID_PTR_VOID(pstFramePart);

    UCHAR8 ucWindowStartId = pstFramePart->ucWindowStartId;
    UCHAR8 ucWindowEndId = ucWindowStartId + pstFramePart->ucWindowNum;
    OsdWindow *pstWindow = NULL;

    /* draw each visable window */
    for (UCHAR8 ucWinId = ucWindowStartId; ucWinId < ucWindowEndId; ucWinId++)
    {
        pstWindow = OSD_GET_WINDOW(ucWinId);
        if (NULL == pstWindow)
        {
            OSD_LOG_ERROR("Window-%d ptr == NULL!", ucWinId);
            continue;
        }

        if (pstWindow->bVisable)
        {
            if (Hv_Mw_OsdWindowCheckIsEmpty(ucWinId))
            {
                OSD_LOG_DEBUG("Window-%d phy(%d) is empty!", ucWinId, pstWindow->ucPhyId);
                Hv_Mw_OsdWindowClearDeleteList(pstWindow);
                pstWindow->bVisable = HV_FALSE;
                continue;
            }
            if (GET_WINDOW_USED_FLAG(pstWindow->ucPhyId))
            {
                OSD_LOG_WARN("Window-%d's phy(%d) is used!", ucWinId, pstWindow->ucPhyId);
                continue;
            }
            OSD_LOG_DEBUG("Start draw Window-%d", ucWinId);
            Hv_Mw_OsdDrawWindow(pstWindow);
            Hv_Mw_OsdWindowClearUpdateInfo(pstWindow);
        }
        pstWindow->bModify = HV_FALSE;
    }
}

static VOID Hv_Mw_OsdUpdateFramePart(const OsdFramePartProp *pstFramePart)
{
    HV_ASSERT_VALID_PTR_VOID(pstFramePart);

    UCHAR8 ucWindowStartId = pstFramePart->ucWindowStartId;
    UCHAR8 ucWindowEndId = ucWindowStartId + pstFramePart->ucWindowNum;
    OsdWindow *pstWindow = NULL;

    /* update modified window */
    for (UCHAR8 ucWinId = ucWindowStartId; ucWinId < ucWindowEndId; ucWinId++)
    {
        pstWindow = OSD_GET_WINDOW(ucWinId);
        if (NULL == pstWindow)
        {
            OSD_LOG_ERROR("Window-%d ptr == NULL!", ucWinId);
            continue;
        }

        if (pstWindow->bModify || pstWindow->bVisable)
        {
            if (GET_WINDOW_USED_FLAG(pstWindow->ucPhyId))
            {
                if (pstWindow->bVisable)
                {
                    OSD_LOG_WARN("Window-%d's phy(%d) is used!", ucWinId, pstWindow->ucPhyId);
                }
                continue;
            }
            OSD_LOG_DEBUG("Start update Window-%d", ucWinId);
            Hv_Mw_OsdUpdateWindow(pstWindow);
            Hv_Mw_OsdWindowClearUpdateInfo(pstWindow);
            pstWindow->bModify = HV_FALSE;
        }
    }
}

static VOID Hv_Mw_OsdDrawScene(UCHAR8 ucSceneId)
{
    const OsdSceneProp *pstSceneProp = OSD_GET_SCENE_PROP(ucSceneId);

    /* draw each frame part */
    for (UCHAR8 ucFrame = 0; ucFrame < pstSceneProp->ucFramePartNum; ucFrame++)
    {
        OSD_LOG_DEBUG("Start draw FramePart-%d", ucFrame);
        Hv_Mw_OsdDrawFramePart(&pstSceneProp->astFramePart[ucFrame]);
    }
}

static VOID Hv_Mw_OsdUpdateScene(UCHAR8 ucSceneId)
{
    const OsdSceneProp *pstSceneProp = OSD_GET_SCENE_PROP(ucSceneId);

    /* update each frame part */
    for (UCHAR8 ucFrame = 0; ucFrame < pstSceneProp->ucFramePartNum; ucFrame++)
    {
        OSD_LOG_DEBUG("Start update FramePart-%d", ucFrame);
        Hv_Mw_OsdUpdateFramePart(&pstSceneProp->astFramePart[ucFrame]);
    }
}

static VOID Hv_Mw_OsdDrawAll(VOID)
{
    OSD_LOG_DEBUG("Redraw all");
    OsdScene *pstScene = NULL;

    s_stOsdDrawData.uiWindowEnableFlag = 0;
    Hv_Drv_OsdFrame_DrawPre();

    for (UCHAR8 ucSceneId = 0; ucSceneId < SCENE_ID_MAX; ucSceneId++)
    {
        pstScene = OSD_GET_SCENE(ucSceneId);
        if (pstScene)
        {
            if (pstScene->bVisable)
            {
                OSD_LOG_DEBUG("Start draw scene %s", SCENE_NAME(ucSceneId));
                Hv_Mw_OsdDrawScene(ucSceneId);
            }
            pstScene->bModify = HV_FALSE;
        }
    }
    s_stOsdDrawData.bFrameModify = HV_TRUE;
}

static VOID Hv_Mw_OsdUpdateDraw(VOID)
{
    OSD_LOG_DEBUG("Update draw");
    OsdScene *pstScene = NULL;

    s_stOsdDrawData.uiWindowEnableFlag = 0;
    s_stOsdDrawData.uiRectEnableFlag = 0;
    s_stOsdDrawData.uiGridEnableFlag = 0;
    s_stOsdDrawData.uiLineEnableFlag = 0;

    for (UCHAR8 ucSceneId = 0; ucSceneId < SCENE_ID_MAX; ucSceneId++)
    {
        pstScene = OSD_GET_SCENE(ucSceneId);
        if (pstScene)
        {
            if (pstScene->bModify)
            {
                OSD_LOG_DEBUG("Start update scene %s", SCENE_NAME(ucSceneId));
                Hv_Mw_OsdUpdateScene(ucSceneId);
                pstScene->bModify = HV_FALSE;
                s_stOsdDrawData.bFrameModify = HV_TRUE;
            }
        }
    }
}

#if (HV_PROJECT_CONFIG_OSD_DDRPATH == HV_CONFIG_ON)
static Status Hv_Mw_OsdDrawMutiFrame(VOID)
{
    Status uiRet = HV_FAILURE;
    UCHAR8 ucSceneId = SCENE_ID_MAX;
    OsdScene *pstScene = NULL;
    const OsdSceneProp *pstSceneProp = NULL;

    for (ucSceneId = s_stOsdDrawData.ucMutiFrameDrawCurrentSceneId; ucSceneId < SCENE_ID_MAX; ucSceneId++)
    {
        pstScene = OSD_GET_SCENE(ucSceneId);
        HV_ASSERT_VALID_PTR(pstScene);
        if (pstScene->bVisable)
        {
            pstSceneProp = OSD_GET_SCENE_PROP(ucSceneId);
            s_stOsdDrawData.ucMutiFrameDrawCurrentSceneId = ucSceneId;
            break;
        }
    }
    if (ucSceneId == SCENE_ID_MAX)
    {
        /* No scene visable, close all window */
        s_stOsdDrawData.ucMutiFrameDrawCurrentSceneId = 0;
        s_stOsdDrawData.bIsFirstFrame = HV_TRUE;
        Hv_Drv_OsdFrame_DrawPre();
        uiRet = Hv_Drv_OsdDataPath_DrawDDRWhole();
        if (uiRet == HV_FAILURE)
        {
            s_stOsdDrawData.ucMutiFrameDrawCurrentSceneId = 0;
            s_stOsdDrawData.bIsFirstFrame = HV_TRUE;
            return HV_FAILURE;
        }
        Hv_Mw_OsdSetSync(HV_TRUE, 0, 0);

        return HV_SUCCESS;
    }

    OSD_LOG_DEBUG("Start draw scene %s, framePart-%d", SCENE_NAME(ucSceneId), pstScene->ucCurFrame);
    s_stOsdDrawData.uiWindowEnableFlag = 0;
    Hv_Drv_OsdFrame_DrawPre();
    Hv_Mw_OsdDrawFramePart(&pstSceneProp->astFramePart[pstScene->ucCurFrame]);
    uiRet = Hv_Drv_OsdFrame_DrawPost();
    if (uiRet == HV_FAILURE)
    {
        s_stOsdDrawData.ucMutiFrameDrawCurrentSceneId = 0;
        s_stOsdDrawData.bIsFirstFrame = HV_TRUE;
        return HV_FAILURE;
    }

    if (s_stOsdDrawData.bIsFirstFrame)
    {
        uiRet = Hv_Drv_OsdDataPath_DrawDDRWhole();
        if (uiRet == HV_FAILURE)
        {
            s_stOsdDrawData.ucMutiFrameDrawCurrentSceneId = 0;
            s_stOsdDrawData.bIsFirstFrame = HV_TRUE;
            return HV_FAILURE;
        }
    }
    else
    {
        uiRet = Hv_Drv_OsdDataPath_DrawDDRReal(HV_FALSE);
        if (uiRet == HV_FAILURE)
        {
            s_stOsdDrawData.ucMutiFrameDrawCurrentSceneId = 0;
            return HV_FAILURE;
        }
    }

    /* disable OD before draw to DDR */
    UCHAR8 usFlag = Hv_Drv_OsdDataPath_GetDrawParts();
    if (usFlag != 0)
    {
        OSD_LOG_DEBUG("Osd start draw, disable OD");
#ifdef CONFIG_USER_DISPCTRL_OD_ON
        Hv_Mw_PQ_OsdControlOdOff(HV_TRUE);
#endif
    }

    Hv_Mw_OsdSetSync(HV_TRUE, 0, 0);
    pstScene->ucCurFrame++;
    if (pstScene->ucCurFrame == pstSceneProp->ucFramePartNum)
    {
        pstScene->ucCurFrame = 0;
        pstScene->bModify = HV_FALSE;
        s_stOsdDrawData.ucMutiFrameDrawCurrentSceneId++;
        for (ucSceneId = s_stOsdDrawData.ucMutiFrameDrawCurrentSceneId; ucSceneId < SCENE_ID_MAX; ucSceneId++)
        {
            pstScene = OSD_GET_SCENE(ucSceneId);
            HV_ASSERT_VALID_PTR(pstScene);
            if (pstScene->bVisable)
            {
                break;
            }
        }
        s_stOsdDrawData.ucMutiFrameDrawCurrentSceneId = ucSceneId;
    }

    if (s_stOsdDrawData.ucMutiFrameDrawCurrentSceneId < SCENE_ID_MAX)
    {
        s_stOsdDrawData.bIsFirstFrame = HV_FALSE;
        return HV_CONTINUE;
    }
    else
    {
        s_stOsdDrawData.ucMutiFrameDrawCurrentSceneId = 0;
        s_stOsdDrawData.bIsFirstFrame = HV_TRUE;
        return HV_SUCCESS;
    }
}
#endif

#ifdef HV_SCALER_DEBUG_VERSION
 VOID Hv_Mw_OsdSetLogoState(OsdLogoState enState)
{
    s_stOsdDrawData.enLogoState = enState;
}
#endif

OsdLogoState Hv_Mw_OsdGetLogoState(VOID)
{
    return s_stOsdDrawData.enLogoState;
}

VOID Hv_Mw_OsdSetLogoBypass(VOID)
{
    OSD_LOG_INFO("Set logo bypass");
    s_stOsdDrawData.bBypassLogo = HV_TRUE;
    s_stOsdDrawData.enLogoState = OSD_LOGO_DONE;
}

BOOL Hv_Mw_OsdGetLogoBypass(VOID)
{
    return s_stOsdDrawData.bBypassLogo;
}

static Status Hv_Mw_OsdShowLogo(VOID)
{
    OSD_LOG_DEBUG("Start draw logo");
    Status uiRet = Hv_Drv_OsdLogo_ShowLogo(HV_FALSE);
    if (HV_SUCCESS == uiRet)
    {
        /* setting for show logo */
        Hv_App_Cb_LogoSetting(HV_TRUE);

        Hv_Drv_OsdDataPath_SetDrawMode(OSD_HSBLEND_MODE_OSD_ONLY);
        Hv_Mw_OsdSetSync(HV_TRUE, 0, 0);

        Hv_Mw_OsdSetAllKeyEnable(HV_FALSE);
        s_stOsdDrawData.enLogoState = OSD_LOGO_DRAWING;
    }
    else
    {
        Hv_Mw_OsdSetAllKeyEnable(HV_TRUE);
        s_stOsdDrawData.enLogoState = OSD_LOGO_DONE;
    }

#if (HV_PROJECT_CONFIG_OSD_GRAPHIC == HV_CONFIG_ON)
#ifdef CONFIG_USER_DISPCTRL_OD_ON
    if (Hv_Drv_OsdGraphic_GetEnable())
    {
        Hv_Mw_PQ_OsdControlOdOff(HV_TRUE);
    }
#endif
#endif

    return uiRet;
}

#if (HV_PROJECT_CONFIG_OSD_ROTATION == HV_CONFIG_ON)
#if (HV_PROJECT_CONFIG_OSD_LOGO_ROTATION == HV_CONFIG_ON)
static Status Hv_Mw_OsdShowRotateLogo(VOID)
{
    Status uiRet = HV_FAILURE;

    OSD_LOG_DEBUG("Start draw rotate logo");
    OSD_LOG_DEBUG("disable OD");
#ifdef CONFIG_USER_DISPCTRL_OD_ON
    Hv_Mw_PQ_OsdControlOdOff(HV_TRUE);
#endif
    OSD_LOG_DEBUG("Rotation draw: Clear whole DDR");
    Hv_Drv_OsdDataPath_SetDrawMode(OSD_HSBLEND_MODE_DDR_ONLY);
    Hv_Drv_OsdFrame_DrawPre();

    Hv_Drv_OsdLogo_ShowLogoOnlyBg();

    Hv_Drv_OsdDataPath_SetDDREnable(HV_FALSE);
    uiRet = Hv_Drv_OsdDataPath_DrawDDRWhole();
    if (HV_FAILURE == uiRet)
    {
        goto LOGO_FAIL;
    }

    uiRet = Hv_Mw_OsdSetSync(HV_FALSE, 0, 100);
    if (HV_FAILURE == uiRet)
    {
        goto LOGO_FAIL;
    }

    uiRet = Hv_Drv_OsdLogo_ShowLogo(HV_TRUE);

    if (HV_FAILURE == uiRet)
    {
        goto LOGO_FAIL;
    }

#if (HV_OSD_CONFIG_REAL_DDR_CANVAS == HV_CONFIG_ON)
    Hv_Drv_OsdDataPath_SetSceneDrawPartsStart();

    Hv_Drv_OsdDataPath_SetSceneDrawPartsCurrent();

    Hv_Drv_OsdDataPath_SetSceneDrawPartsEnd();
#endif

    uiRet = Hv_Drv_OsdDataPath_DrawDDRReal(HV_TRUE);
    if (HV_FAILURE == uiRet)
    {
        goto LOGO_FAIL;
    }
    /* one more frame */
    uiRet = Hv_Mw_OsdSetSync(HV_FALSE, 1, 100);
    if (HV_FAILURE == uiRet)
    {
        goto LOGO_FAIL;
    }

    Hv_Drv_OsdRotationWhole();

    Hv_Drv_OsdDataPath_ShowDDR();
    Hv_Mw_OsdSetSync(HV_TRUE, 0, 0);

    /* setting for show logo */
    Hv_App_Cb_LogoSetting(HV_TRUE);

    Hv_Mw_OsdSetAllKeyEnable(HV_FALSE);
    s_stOsdDrawData.enLogoState = OSD_LOGO_DRAWING;
    return uiRet;

LOGO_FAIL:
#ifdef CONFIG_USER_DISPCTRL_OD_ON
    Hv_Mw_PQ_OsdControlOdOff(HV_FALSE);
#endif
    Hv_Mw_OsdSetAllKeyEnable(HV_TRUE);
    s_stOsdDrawData.enLogoState = OSD_LOGO_DONE;
    OSD_LOG_ERROR("Show rotated logo fail!");
    return HV_FAILURE;
}
#endif
#endif

static Status Hv_Mw_OsdHideLogo(VOID)
{
    OSD_LOG_DEBUG("Hide logo");
    Hv_Drv_OsdLogo_HideLogo();

    Hv_Drv_OsdDataPath_SetDrawMode(OSD_HSBLEND_MODE_OSD_ONLY);
    Hv_Mw_OsdSetSync(HV_TRUE, 0, 0);
    Hv_Mw_OsdSetAllKeyEnable(HV_TRUE);
    s_stOsdDrawData.enLogoState = OSD_LOGO_HIDEING;

    return HV_SUCCESS;
}

static BOOL Hv_Mw_OsdLogoCheckNeedDraw(VOID)
{
    const PanelParam stPanelParam = Hv_Mw_Panel_GetCurrentPanelParam();

    //if (!Hv_Drv_DpuScaler_CheckDtcTiming(stPanelParam.uiPanelPixelClockMax, stPanelParam.uiPanelPixelClockMin))
    if (0)
    {
        OSD_LOG_ERROR("Check dtc timing error, skip logo!");
        Hv_Mw_OsdSetAllKeyEnable(HV_TRUE);
        s_stOsdDrawData.enLogoState = OSD_LOGO_DONE;
        return HV_FAILURE;
    }
    else if (HV_FALSE == HV_COMMON_DATABASE_GET(SystemData, bShowLogoFlag))
    {
        OSD_LOG_INFO("Logo is disabled");
        Hv_Mw_OsdSetAllKeyEnable(HV_TRUE);
        s_stOsdDrawData.enLogoState = OSD_LOGO_DONE;
        return HV_FALSE;
    }
    else if (Hv_Mw_OsdGetLogoBypass())
    {
        OSD_LOG_INFO("Skip logo");
        Hv_Mw_OsdSetAllKeyEnable(HV_TRUE);
        s_stOsdDrawData.enLogoState = OSD_LOGO_DONE;
        return HV_FALSE;
    }
    else if (OSD_LOGO_WAITING_SHOW != s_stOsdDrawData.enLogoState)
    {
        OSD_LOG_INFO("Logo has already done");
        return HV_FALSE;
    }
    else
    {
        return HV_TRUE;
    }
}

#if (HV_PROJECT_CONFIG_OSD_LOGO_USE_SCENE == HV_CONFIG_ON)
static Status Hv_Mw_OsdLogoProcessByScene(OsdEvent *pstEvent)
{
    HV_ASSERT_VALID_PTR(pstEvent);

    if (pstEvent->usEventId == OSD_EVENT_SHOW_LOGO)
    {
        if (!Hv_Mw_OsdLogoCheckNeedDraw())
        {
            Hv_Mw_OsdSceneClear(SCENE_LOGO);
            return HV_FAILURE;
        }

        /* setting for show logo */
        Hv_App_Cb_LogoSetting(HV_TRUE);

        OSD_LOG_INFO("Start draw logo by scene...");
        Hv_Drv_OsdLogoPalette_Init();
        s_stOsdDrawData.enLogoState = OSD_LOGO_DRAWING;
        return HV_SUCCESS;
    }
    else if (pstEvent->usEventId == OSD_EVENT_TIMER_LOGO_HIDE)
    {
        /* Recover setting */
        Hv_App_Cb_LogoSetting(HV_FALSE);

        OSD_LOG_DEBUG("Logo hide by scene");
        Hv_Drv_OsdPalette_Init();
        s_stOsdDrawData.enLogoState = OSD_LOGO_HIDEING;
        return HV_SUCCESS;
    }
    else
    {
        return HV_FAILURE;
    }
}
#else
static Status Hv_Mw_OsdLogoProcess(OsdEvent *pstEvent)
{
    HV_ASSERT_VALID_PTR(pstEvent);

    /* Show logo do not need set FrameModify flag */
    s_stOsdDrawData.bFrameModify = HV_FALSE;

    if (pstEvent->usEventId == OSD_EVENT_SHOW_LOGO)
    {
        if (!Hv_Mw_OsdLogoCheckNeedDraw())
        {
            return HV_FAILURE;
        }

        Hv_Mw_OsdSceneClearAll();

        /* setting for show logo */
        Hv_App_Cb_LogoSetting(HV_TRUE);

#if (HV_PROJECT_CONFIG_OSD_ROTATION == HV_CONFIG_ON)
#if (HV_PROJECT_CONFIG_OSD_LOGO_ROTATION == HV_CONFIG_ON)
        if (OSD_ROTATION_NONE != Hv_Drv_OsdGetRotateType())
        {
            return Hv_Mw_OsdShowRotateLogo();
        }
        else
#endif
#endif
        {
            return Hv_Mw_OsdShowLogo();
        }
    }
    else if (pstEvent->usEventId == OSD_EVENT_TIMER_LOGO_HIDE)
    {
        return Hv_Mw_OsdHideLogo();
    }
    else
    {
        return HV_FAILURE;
    }
}
#endif

#ifdef HV_SCALER_DEBUG_VERSION
UINT64 ulStartTick = 0;
UINT64 ulEndTick = 0;
UINT64 ulDiff = 0;
UINT64 ulTotal = 0;
static UINT64 ulMaxTick = 0;
static UINT64 ulMinTick = 0xffffffff;
static USHORT16 usCount = 0;

VOID Hv_Mw_OsdDbgDrawStart(VOID)
{
    ulStartTick = Hv_Vos_GetTick();
}

VOID Hv_Mw_OsdDbgDrawEnd(VOID)
{
    ulEndTick = Hv_Vos_GetTick();
    ulDiff = ulEndTick - ulStartTick;
    if (ulDiff > ulMaxTick)
    {
        ulMaxTick = ulDiff;
    }
    if (ulDiff < ulMinTick)
    {
        ulMinTick = ulDiff;
    }
    ulTotal += ulDiff;
    ++usCount;
}

VOID Hv_Mw_OsdDbgDrawPrint(VOID)
{
    OSD_LOG_INFO("Redraw 20 times: counts %u max %llu min %llu total %llu avg %llu",
            usCount, ulMaxTick, ulMinTick, ulTotal, (usCount != 0) ? (ulTotal / usCount) : 0);
}

VOID Hv_Mw_OsdDbgDrawClear(VOID)
{
    ulTotal = 0;
    usCount = 0;
    ulMaxTick = 0;
    ulMinTick = 0xffffffff;
}
#endif

#if (HV_PROJECT_CONFIG_OSD_ANIMITION_SUPPORT == HV_CONFIG_ON)
VOID Hv_Mw_OsdDrawSetFrameModify(BOOL bIsModify)
{
    s_stOsdDrawData.bFrameModify = bIsModify;
}
#endif

#if (HV_OSD_CONFIG_REAL_DDR_CANVAS == HV_CONFIG_ON)
static VOID Hv_Mw_OsdWindowGetRealPos(OsdWindow* pstWindow, USHORT16 *pusX, USHORT16 *pusY)
{
    HV_ASSERT_VALID_PTR_VOID(pstWindow);
    HV_ASSERT_VALID_PTR_VOID(pstWindow->pstScene);
    const OsdWindowProp *pstWindowProp = OSD_GET_WINDOW_PROP(pstWindow->ucId);
    HV_ASSERT_VALID_PTR_VOID(pstWindowProp);
    USHORT16 usWindowRelativeX = pstWindowProp->usX;

#if (HV_CONFIG_ON == HV_PROJECT_CONFIG_OSD_MIRROR)
    if (bRTLShow)
    {
        usWindowRelativeX = pstWindow->pstScene->usWidth - pstWindowProp->usX - pstWindowProp->usWidth;
    }
#endif

#if (HV_PROJECT_CONFIG_OSD_ROTATION == HV_CONFIG_ON)
    if (pstWindow->pstScene->bAbsolutePostion)
    {
        *pusX = usWindowRelativeX + 0;  //pstWindow->pstScene->usAbsoluteX;
        *pusY = pstWindowProp->usY + 0; //pstWindow->pstScene->usAbsoluteY;
    }
    else
#endif
    {
        *pusX = usWindowRelativeX + pstWindow->pstScene->usX;
        *pusY = pstWindowProp->usY + pstWindow->pstScene->usY;
    }

    return;
}

VOID Hv_Mw_OsdSceneGetDrawParts(UCHAR8 ucSceneId, OsdSceneDrawPart *pstScenePart)
{
    UCHAR8 ucFrame = 0;
    UCHAR8 ucWindowStartId = 0;
    UCHAR8 ucWindowEndId = 0;
    UCHAR8 ucWinId = 0;
    OsdWindow *pstWindow = NULL;
    OsdWindowDrawPart *pstWindowPart = NULL;
    const OsdWindowProp *pstWindowProp = NULL;
    const OsdFramePartProp *pstFramePart = NULL;
    const OsdScene *pstScene = OSD_GET_SCENE(ucSceneId);
    HV_ASSERT_VALID_PTR_VOID(pstScene);
    const OsdSceneProp *pstSceneProp = OSD_GET_SCENE_PROP(ucSceneId);
    HV_ASSERT_VALID_PTR_VOID(pstSceneProp);

    HV_MEMSET(pstScenePart, 0, sizeof(*pstScenePart));

    pstScenePart->ucSceneId = ucSceneId;
#if (HV_PROJECT_CONFIG_OSD_ROTATION == HV_CONFIG_ON)
    pstScenePart->bRotateEnable = !Hv_Mw_OsdSceneGetRotateSkip(ucSceneId);
    pstScenePart->bSceneAbsolutePostion = pstScene->bAbsolutePostion;
    pstScenePart->usSceneAbsoluteX = pstScene->usAbsoluteX;
    pstScenePart->usSceneAbsoluteY = pstScene->usAbsoluteY;
#endif

    /* draw each frame part */
    for (ucFrame = 0; ucFrame < pstSceneProp->ucFramePartNum; ucFrame++)
    {
        pstFramePart = &pstSceneProp->astFramePart[ucFrame];
        ucWindowStartId = pstFramePart->ucWindowStartId;
        ucWindowEndId = ucWindowStartId + pstFramePart->ucWindowNum;

        /* draw each visable window */
        for (ucWinId = ucWindowStartId; ucWinId < ucWindowEndId; ucWinId++)
        {
            pstWindow = OSD_GET_WINDOW(ucWinId);
            if (NULL == pstWindow)
            {
                OSD_LOG_ERROR("Window-%d ptr == NULL!", ucWinId);
                continue;
            }
            pstWindowProp = OSD_GET_WINDOW_PROP(pstWindow->ucId);
            if (NULL == pstWindowProp)
            {
                OSD_LOG_ERROR("WindowProp-%d ptr == NULL!", ucWinId);
                continue;
            }

            if (pstWindow->bVisable)
            {
                if (Hv_Mw_OsdWindowCheckIsEmpty(ucWinId))
                {
                    continue;
                }
                if (GET_WINDOW_USED_FLAG(pstWindow->ucPhyId))
                {
                    continue;
                }

                pstWindowPart = &pstScenePart->astAllWindowDrawParts[pstScenePart->ucPartCount++];
                pstWindowPart->enWinId = pstWindow->ucPhyId;

                Hv_Mw_OsdWindowGetRealPos(pstWindow, &pstWindowPart->stDrawArea.usX, &pstWindowPart->stDrawArea.usY);
                pstWindowPart->stDrawArea.usWidth = pstWindowProp->usWidth;
                pstWindowPart->stDrawArea.usHeight = pstWindowProp->usHeight;
            }
        }
    }

    return;
}
#endif

#if (HV_PROJECT_CONFIG_OSD_ROTATION == HV_CONFIG_ON)
Status Hv_Mw_OsdRotationDraw(BOOL bNeedRedraw)
{
    Status uiRet = HV_FAILURE;
    UCHAR8 ucSceneId = SCENE_ID_MAX;
    OsdScene *pstScene = NULL;
    USHORT16 usXbk = 0;
    USHORT16 usYbk = 0;

    if (0 == s_stOsdDrawData.ucRotatingStep)
    {
        /* disable OD before draw to DDR */
        OSD_LOG_DEBUG("Osd start draw, disable OD");
#ifdef CONFIG_USER_DISPCTRL_OD_ON
        Hv_Mw_PQ_OsdControlOdOff(HV_TRUE);
#endif
        s_stOsdDrawData.ucSceneRotating = SCENE_ID_MAX;
        s_stOsdDrawData.ucMutiFrameDrawCurrentSceneId = 0;
        s_stOsdDrawData.uiWindowEnableFlag = 0;

        if (!bNeedRedraw)
        {
            /* Check visable scene */
            for (ucSceneId = 0; ucSceneId < SCENE_ID_MAX; ucSceneId++)
            {
                pstScene = OSD_GET_SCENE(ucSceneId);
                HV_ASSERT_VALID_PTR(pstScene);
                if (pstScene->bVisable)
                {
                    s_stOsdDrawData.ucRotatingStep = 1;
                    break;
                }
            }

            if (ucSceneId == SCENE_ID_MAX)
            {
                /* No visable scene */
                OSD_LOG_DEBUG("Rotation draw: no scene visable, clear whole DDR");
                Hv_Drv_OsdFrame_DrawPre();
                uiRet = Hv_Drv_OsdDataPath_DrawDDRWhole();
                if (uiRet == HV_FAILURE)
                {
                    s_stOsdDrawData.ucMutiFrameDrawCurrentSceneId = 0;
                    s_stOsdDrawData.ucRotatingStep = 0;
                    s_stOsdDrawData.ucSceneRotating = SCENE_ID_MAX;
                    return HV_FAILURE;
                }
                Hv_Mw_OsdSetSync(HV_TRUE, 0, 0);
                return HV_SUCCESS;
            }
        }
        else
        {
            /* Clear whole ddr */
            OSD_LOG_DEBUG("Rotation draw: Clear whole DDR");

            if (s_stOsdDrawData.bRotateChange)
            {
                // fix first frame when 90->0->270 draw switch to ddr rotation
                Hv_Drv_OsdDataPath_SetDDREnable(HV_FALSE);
                s_stOsdDrawData.bRotateChange = HV_FALSE;
            }
            Hv_Drv_OsdDataPath_SetDrawMode(OSD_HSBLEND_MODE_DDR_ONLY);

            Hv_Drv_OsdFrame_DrawPre();
            uiRet = Hv_Drv_OsdDataPath_DrawDDRWhole();
            if (uiRet == HV_FAILURE)
            {
                s_stOsdDrawData.ucMutiFrameDrawCurrentSceneId = 0;
                s_stOsdDrawData.ucRotatingStep = 0;
                s_stOsdDrawData.ucSceneRotating = SCENE_ID_MAX;
                return HV_FAILURE;
            }
            Hv_Mw_OsdSetSync(HV_TRUE, 0, 0);

#if (HV_OSD_CONFIG_REAL_DDR_CANVAS == HV_CONFIG_ON)
            OsdSceneDrawPart stSceneDrawPart = {0};
            Hv_Drv_OsdDataPath_SetSceneDrawPartsStart();
#endif
            /* Check visable scene */
            for (ucSceneId = 0; ucSceneId < SCENE_ID_MAX; ucSceneId++)
            {
                pstScene = OSD_GET_SCENE(ucSceneId);
                HV_ASSERT_VALID_PTR(pstScene);
                if (pstScene->bVisable)
                {
                    s_stOsdDrawData.ucRotatingStep = 1;
#if (HV_OSD_CONFIG_REAL_DDR_CANVAS == HV_CONFIG_ON)
                    /* set all drawing parts */
                    Hv_Mw_OsdSceneGetDrawParts(ucSceneId, &stSceneDrawPart);
                    Hv_Drv_OsdDataPath_SetSceneDrawParts(&stSceneDrawPart);
#endif
                }
            }
#if (HV_OSD_CONFIG_REAL_DDR_CANVAS == HV_CONFIG_ON)
            Hv_Drv_OsdDataPath_SetSceneDrawPartsEnd();
#endif
            if (1 == s_stOsdDrawData.ucRotatingStep)
            {
                return HV_CONTINUE;
            }
            else
            {
                return HV_SUCCESS;
            }
        }
    }

    if (1 == s_stOsdDrawData.ucRotatingStep)
    {
        /* Rotate rotation-ddr to draw-ddr by software */
        if (s_stOsdDrawData.ucSceneRotating != SCENE_ID_MAX)
        {
            OSD_LOG_DEBUG("Rotation draw: Rotating scene %s", SCENE_NAME(s_stOsdDrawData.ucSceneRotating));
            if (Hv_Mw_OsdSceneGetRotateSkip(s_stOsdDrawData.ucSceneRotating))
            {
                OSD_LOG_DEBUG("Do not rotate scene %s, skip", SCENE_NAME(s_stOsdDrawData.ucSceneRotating));
                Hv_Drv_OsdSetRotateSkip(HV_TRUE);
            }

            pstScene = OSD_GET_SCENE(s_stOsdDrawData.ucSceneRotating);
            HV_ASSERT_VALID_PTR(pstScene);
            if (pstScene->bAbsolutePostion)
            {
                Hv_Drv_OsdRecordAbsolutePostion(pstScene->usAbsoluteX, pstScene->usAbsoluteY);
            }
            else
            {
                Hv_Drv_OsdCancelAbsolutePostion();
            }

            if (bNeedRedraw)
            {
                Hv_Drv_OsdRotationWhole();
            }
            else
            {
                Hv_Drv_OsdRotationArea(s_stOsdDrawData.ucSceneRotating);
            }

            if (Hv_Mw_OsdSceneGetRotateSkip(s_stOsdDrawData.ucSceneRotating))
            {
                Hv_Drv_OsdSetRotateSkip(HV_FALSE);
            }
        }

        if (s_stOsdDrawData.bIsLastScene)
        {
            OSD_LOG_DEBUG("Rotation draw: rotate done, go to show");
            Hv_Drv_OsdClearDrawAreaBox();
            /* No modified scene left, go to show ddr */
            s_stOsdDrawData.ucMutiFrameDrawCurrentSceneId = 0;
            s_stOsdDrawData.ucRotatingStep = 0;
            s_stOsdDrawData.ucSceneRotating = SCENE_ID_MAX;
            s_stOsdDrawData.bIsLastScene = HV_FALSE;
            Hv_Mw_OsdSetSync(HV_TRUE, 0, 0);      // set reg_en to triger osd statemechine run to show
            return HV_SUCCESS;
        }

        /* Draw each scene to rotation buffer */
        for (ucSceneId = s_stOsdDrawData.ucMutiFrameDrawCurrentSceneId; ucSceneId < SCENE_ID_MAX; ucSceneId++)
        {
            pstScene = OSD_GET_SCENE(ucSceneId);
            HV_ASSERT_VALID_PTR(pstScene);
            if (pstScene->bVisable)
            {
                OSD_LOG_DEBUG("Rotation draw: draw scene %s to rotate-ddr, bNeedRedraw = %d", SCENE_NAME(ucSceneId), bNeedRedraw);
                Hv_Drv_OsdFrame_DrawPre();
                if (!bNeedRedraw)
                {
                    Hv_Drv_OsdSetRotationPartFlag(ucSceneId);
                }
                if (pstScene->bAbsolutePostion)
                {
                    usXbk = pstScene->usX;
                    usYbk = pstScene->usY;
                    pstScene->usX = 0;
                    pstScene->usY = 0;
                }
                Hv_Mw_OsdDrawScene(ucSceneId);     //Must redraw
                if (pstScene->bAbsolutePostion)
                {
                    pstScene->usX = usXbk;
                    pstScene->usY = usYbk;
                }
                Hv_Drv_OsdSetRotationPartFlag(SCENE_ID_MAX);
                pstScene->bModify = HV_FALSE;
                uiRet = Hv_Drv_OsdFrame_DrawPost();
                if (uiRet == HV_FAILURE)
                {
                    s_stOsdDrawData.ucMutiFrameDrawCurrentSceneId = 0;
                    s_stOsdDrawData.ucRotatingStep = 0;
                    s_stOsdDrawData.ucSceneRotating = SCENE_ID_MAX;
                    return HV_FAILURE;
                }
                /* Draw to rotation buffer */
                uiRet = Hv_Drv_OsdDataPath_DrawDDRReal(HV_TRUE);
                if (uiRet == HV_FAILURE)
                {
                    s_stOsdDrawData.ucMutiFrameDrawCurrentSceneId = 0;
                    s_stOsdDrawData.ucRotatingStep = 0;
                    s_stOsdDrawData.ucSceneRotating = SCENE_ID_MAX;
                    return HV_FAILURE;
                }
                /* Wait one more frame for drawing done to ddr */
                Hv_Mw_OsdSetSync(HV_TRUE, 1, 0);
                s_stOsdDrawData.ucMutiFrameDrawCurrentSceneId = ucSceneId + 1;
                s_stOsdDrawData.ucSceneRotating = ucSceneId;
                break;
            }
        }

        /* Check is last visable scene */
        for (ucSceneId = s_stOsdDrawData.ucMutiFrameDrawCurrentSceneId; ucSceneId < SCENE_ID_MAX; ucSceneId++)
        {
            pstScene = OSD_GET_SCENE(ucSceneId);
            HV_ASSERT_VALID_PTR(pstScene);
            if (pstScene->bVisable)
            {
                break;
            }
        }

        if (ucSceneId == SCENE_ID_MAX)
        {
            s_stOsdDrawData.bIsLastScene = HV_TRUE;
        }
        return HV_CONTINUE;
    }
    else
    {
        return HV_FAILURE;
    }
}
#endif

Status Hv_Mw_OsdDraw(OsdEvent *pstEvent)
{
    HV_ASSERT_VALID_PTR(pstEvent);
    Status uiRet = HV_FAILURE;

    if ((pstEvent->usEventId == OSD_EVENT_SHOW_LOGO) || (pstEvent->usEventId == OSD_EVENT_TIMER_LOGO_HIDE))
    {
#if (HV_PROJECT_CONFIG_OSD_LOGO_USE_SCENE == HV_CONFIG_ON)
        Hv_Mw_OsdLogoProcessByScene(pstEvent);
#else
        return Hv_Mw_OsdLogoProcess(pstEvent);
#endif
    }
    else if (pstEvent->usEventId == OSD_EVENT_ANIMITION)
    {
#if (HV_PROJECT_CONFIG_OSD_ANIMITION_SUPPORT == HV_CONFIG_ON)
#if (HV_PROJECT_CONFIG_OSD_FORCE_REDRAW_ALL == HV_CONFIG_OFF)
        Hv_Mw_OsdResetFontResList();
#endif
        uiRet = Hv_Mw_OsdDoAnimition();
        if (uiRet == HV_FAILURE)
        {
            return HV_FAILURE;
        }
#else
        OSD_LOG_ERROR("OSD ANIMITION disabled");
        return HV_FAILURE;
#endif
    }

#if (HV_PROJECT_CONFIG_OSD_ROTATION == HV_CONFIG_ON)
    if (OSD_ROTATION_NONE != Hv_Drv_OsdGetRotateType())
    {
#if (HV_PROJECT_CONFIG_OSD_FORCE_REDRAW_ALL == HV_CONFIG_OFF)
        Hv_Mw_OsdResetFontResList();
#endif
        return Hv_Mw_OsdRotationDraw(Hv_Mw_OsdOpsIsRedraw());
    }
#endif

    if (Hv_Mw_OsdOpsIsMultiFrameDraw())
    {
#if (HV_PROJECT_CONFIG_OSD_DDRPATH == HV_CONFIG_ON)
#if (HV_PROJECT_CONFIG_OSD_FORCE_REDRAW_ALL == HV_CONFIG_OFF)
        Hv_Mw_OsdResetFontResList();
#endif
        OSD_LOG_DEBUG("Start multiframe draw OSD");
        return Hv_Mw_OsdDrawMutiFrame();
#else
        OSD_LOG_ERROR("DDRPATH disabled, do not support multiframe draw");
        return HV_FAILURE;
#endif
    }
    else
    {
        OSD_LOG_DEBUG("Start draw OSD");
#if (HV_PROJECT_CONFIG_OSD_FORCE_REDRAW_ALL == HV_CONFIG_OFF)
        Hv_Mw_OsdResetFontResList();
#endif
        if (Hv_Mw_OsdOpsIsRedraw())
        {
#ifdef HV_SCALER_DEBUG_VERSION
            UCHAR8 ucIndex = 0;
            Hv_Mw_OsdDbgDrawStart();

            //for (ucIndex = 0; ucIndex < 20; ++ucIndex)
            {
#endif
                Hv_Mw_OsdDrawAll();
#ifdef HV_SCALER_DEBUG_VERSION
            }
            Hv_Mw_OsdDbgDrawEnd();
#endif
        }
        else
        {
#ifdef HV_SCALER_DEBUG_VERSION
            if (g_usResourceRealTotalSizeMax < g_usResourceRealTotalSize)
            {
                g_usResourceRealTotalSizeMax = g_usResourceRealTotalSize;
            }
            g_usResourceRealTotalSize = 0;
#endif
            Hv_Mw_OsdUpdateDraw();
        }
#if (HV_OSD_CONFIG_TRANSFER_USING_MEMCPY == HV_CONFIG_OFF)
        if (s_stOsdDrawData.bFrameModify)
        {
            uiRet = Hv_Drv_OsdFrame_DrawPost();
        }
        if (uiRet == HV_FAILURE)
        {
            return HV_FAILURE;
        }
#endif

        if (s_stOsdDrawData.bFrameModify)
        {
#if (HV_OSD_CONFIG_TRANSFER_USING_MEMCPY == HV_CONFIG_ON)
            Hv_Cal_OsdDP_SetVideoBlendEnable(HV_FALSE);
#else
            s_stOsdDrawData.bFrameModify = HV_FALSE;
#endif

#if (HV_PROJECT_CONFIG_OSD_ANIMITION_SUPPORT == HV_CONFIG_ON)
#if ((HV_CONFIG_ON == HV_PROJECT_CONFIG_OSD_MARQUEE) && (HV_CONFIG_ON == HV_OSD_CONFIG_MARQUEE_AUTO_CHECK_EXCESS))
            Hv_Mw_OsdCheckAutoMarquee();
#endif
#endif
            OSD_LOG_DEBUG("OSD directly draw");
            Hv_Drv_OsdDataPath_SetDrawMode(OSD_HSBLEND_MODE_OSD_ONLY);
            Hv_Mw_OsdSetSync(HV_TRUE, 0, 0);
            return HV_SUCCESS;
        }
        else
        {
            return HV_FAILURE;
        }
    }
}

#if (HV_PROJECT_CONFIG_OSD_ROTATION == HV_CONFIG_ON)
Status Hv_Mw_OsdRotationShow(VOID)
{
    OSD_LOG_DEBUG("Rotation show: rotate done, show ddr OSD");
    Hv_Drv_OsdDataPath_SetDrawMode(OSD_HSBLEND_MODE_DDR_ONLY);
    Hv_Drv_OsdDataPath_ShowDDR();
    Hv_Mw_OsdSetSync(HV_TRUE, 0, 0);
    Hv_Mw_OsdOpsClearRedrawFlag();
    return HV_CONTINUE;
}
#endif

extern BOOL Hv_Mw_OsdHasEventCached(USHORT16 usEventId);

Status Hv_Mw_OsdShow(OsdEvent *pstEvent)
{
#if (HV_PROJECT_CONFIG_OSD_ANIMITION_SUPPORT == HV_CONFIG_ON)
    if ((HV_TRUE == Hv_Mw_OsdAnimIsDoing()) && (!Hv_Mw_OsdHasEventCached(OSD_EVENT_ANIMITION)))
    {
        HV_VOS_QUEUE_S* pOsdQueue = Hv_Mw_System_GetOsdQueue();
        HV_ASSERT_VALID_PTR(pOsdQueue);
        OsdEvent stOsdEvent = {OSD_EVENT_ANIMITION, 0};
        HV_ASSERT_TRUE(Hv_Vos_QueueSend(pOsdQueue, &stOsdEvent));
    }
#endif

#if (HV_PROJECT_CONFIG_OSD_LOGO_USE_SCENE == HV_CONFIG_ON)
    if (s_stOsdDrawData.enLogoState == OSD_LOGO_DRAWING)
    {
        OSD_LOG_INFO("Logo is showing");
        s_stOsdDrawData.enLogoState = OSD_LOGO_SHOWING;
    }
    else if (s_stOsdDrawData.enLogoState == OSD_LOGO_HIDEING)
    {
        OSD_LOG_DEBUG("Logo hide done");
        s_stOsdDrawData.enLogoState = OSD_LOGO_DONE;
    }
#else
    if (s_stOsdDrawData.enLogoState == OSD_LOGO_DRAWING)
    {
        OSD_LOG_INFO("Logo is showing");
        OSD_LOG_DEBUG("Start logo hiding timer = %ds", HV_PROJECT_CONFIG_OSD_LOGO_SHOW_TIME);
        Hv_Mw_OsdStartLogoTimer(HV_PROJECT_CONFIG_OSD_LOGO_SHOW_TIME);
        s_stOsdDrawData.enLogoState = OSD_LOGO_SHOWING;
        Hv_Mw_OsdOpsClearRedrawFlag();
        return HV_SUCCESS;
    }
    else if (s_stOsdDrawData.enLogoState == OSD_LOGO_HIDEING)
    {
        OSD_LOG_DEBUG("Logo hide done");
        /* Recover setting */
        Hv_App_Cb_LogoSetting(HV_FALSE);


#ifdef CONFIG_USER_DISPCTRL_OD_ON
#if (HV_PROJECT_CONFIG_OSD_GRAPHIC == HV_CONFIG_ON)
        if (!Hv_Drv_OsdGraphic_GetEnable())
        {
            Hv_Mw_PQ_OsdControlOdOff(HV_FALSE);
        }
#else
#if (HV_PROJECT_CONFIG_OSD_ROTATION == HV_CONFIG_ON)
#if (HV_PROJECT_CONFIG_OSD_LOGO_ROTATION == HV_CONFIG_ON)
        if (OSD_ROTATION_NONE != Hv_Drv_OsdGetRotateType())
        {
            OSD_LOG_DEBUG("Logo hide done, enable OD");
#ifdef CONFIG_USER_DISPCTRL_OD_ON
            Hv_Mw_PQ_OsdControlOdOff(HV_FALSE);
#endif
        }
#endif
#endif
#endif
#endif

#ifdef HV_SCALER_DEBUG_VERSION
        /* Logo消失后开始Monkey */
        //Hv_Mw_OsdMonkeyTest(HV_TRUE);
#endif
        s_stOsdDrawData.enLogoState = OSD_LOGO_DONE;

        return HV_SUCCESS;
    }
#endif

#if (HV_PROJECT_CONFIG_OSD_ROTATION == HV_CONFIG_ON)
    if (OSD_ROTATION_NONE != Hv_Drv_OsdGetRotateType())
    {
        return Hv_Mw_OsdRotationShow();
    }
    else
    {
#ifdef CONFIG_USER_DISPCTRL_OD_ON
#if (HV_PROJECT_CONFIG_OSD_GRAPHIC == HV_CONFIG_ON)
        if (!Hv_Drv_OsdGraphic_GetEnable())
#endif
        {
            Hv_Mw_PQ_OsdControlOdOff(HV_FALSE);
        }
#endif
    }
#else
#if (HV_PROJECT_CONFIG_OSD_GRAPHIC == HV_CONFIG_ON)
#ifdef CONFIG_USER_DISPCTRL_OD_ON
    if (!Hv_Drv_OsdGraphic_GetEnable())
    {
        Hv_Mw_PQ_OsdControlOdOff(HV_FALSE);
    }
#endif
#endif
#endif

#if (HV_PROJECT_CONFIG_OSD_DDRPATH == HV_CONFIG_ON)
    if (Hv_Mw_OsdOpsIsMultiFrameDraw())
    {
        OSD_LOG_DEBUG("Show ddr OSD");
        Hv_Drv_OsdDataPath_SetDrawMode(OSD_HSBLEND_MODE_DDR_ONLY);
        Hv_Drv_OsdDataPath_ShowDDR();
        Hv_Mw_OsdSetSync(HV_TRUE, 0, 0);
        Hv_Mw_OsdOpsClearMultiFrameDrawFlag();
        Hv_Mw_OsdOpsClearRedrawFlag();
        return HV_CONTINUE;
    }
#endif

#if (HV_OSD_CONFIG_TRANSFER_USING_MEMCPY == HV_CONFIG_ON)
    /* CPU Copy after set Reg_en */
    if (HV_SUCCESS == Hv_Drv_OsdFrame_DrawPost())
    {
        if (s_stOsdDrawData.bFrameModify)
        {
            Hv_Cal_OsdDP_SetVideoBlendEnable(HV_TRUE);
            Hv_Mw_OsdSetSync(HV_TRUE, 0, 0);
            Hv_Mw_OsdOpsClearRedrawFlag();
            s_stOsdDrawData.bFrameModify = HV_FALSE;
            return HV_CONTINUE;
        }
    }
    else
    {
        return HV_FAILURE;
    }
#endif

    Hv_Mw_OsdOpsClearRedrawFlag();
    return HV_SUCCESS;
}

Status Hv_Mw_OsdShowDone(OsdEvent *pstEvent)
{
    /* Enable OD after DDR show done when no OSD display */
    UCHAR8 usFlag = Hv_Drv_OsdDataPath_GetDrawParts();
    if (usFlag == 0)
    {
        OSD_LOG_DEBUG("No osd display, enable OD");
#ifdef CONFIG_USER_DISPCTRL_OD_ON
        Hv_Mw_PQ_OsdControlOdOff(HV_FALSE);
#endif
    }

#if (HV_PROJECT_CONFIG_OSD_DDRPATH == HV_CONFIG_ON)
    Hv_Drv_OsdDataPath_DoubleBufferCopy();
#endif

    return HV_SUCCESS;
}

OsdBox Hv_Mw_OsdGetFontComponentBox(OsdComponent stCp)
{
    OsdComponentNode *pstNode = Hv_Mw_OsdComponentGetNode(stCp);

    if (NULL == pstNode)
    {
        OsdComponentNode stNode = {0};
        stNode.stCp = stCp;
        stNode.pvCpData = (VOID *)Hv_Mw_OsdGetComponentPropAddr(stCp);
        Hv_Drv_OsdFont_CalculateComponentBox(&stNode, HV_FALSE);
        return stNode.stBox;
    }
    else
    {
        Hv_Drv_OsdFont_CalculateComponentBox(pstNode, HV_FALSE);
        return pstNode->stBox;
    }
}

static VOID Hv_Mw_OsdSceneSetModify(OsdScene *pstScene)
{
    HV_ASSERT_VALID_PTR_VOID(pstScene);
    if (!pstScene->bVisable)
    {
        return;
    }

    const OsdSceneProp *pstSceneProp = OSD_GET_SCENE_PROP(pstScene->ucId);
    HV_ASSERT_VALID_PTR_VOID(pstSceneProp);
    OsdWindow *pstWindow = NULL;
    UCHAR8 ucWindowStartId = 0;
    UCHAR8 ucWindowEndId = 0;
    for (UCHAR8 ucPartId = 0; ucPartId < pstSceneProp->ucFramePartNum; ucPartId++)
    {
        ucWindowStartId = pstSceneProp->astFramePart[ucPartId].ucWindowStartId;
        ucWindowEndId = ucWindowStartId + pstSceneProp->astFramePart[ucPartId].ucWindowNum;
        for (UCHAR8 ucWinId = ucWindowStartId; ucWinId < ucWindowEndId; ucWinId++)
        {
            pstWindow = OSD_GET_WINDOW(ucWinId);
            if (pstWindow)
            {
                pstWindow->bModify = HV_TRUE;
            }
        }
    }

    pstScene->bModify = HV_TRUE;

#if (HV_PROJECT_CONFIG_OSD_ROTATION == HV_CONFIG_ON)
    if (OSD_ROTATION_NONE != Hv_Drv_OsdGetRotateType())
    {
        Hv_Mw_OsdOpsForceRedraw(HV_TRUE);
    }
#endif
}

VOID Hv_Mw_OsdSceneSetPosition(UCHAR8 ucSceneId, USHORT16 usX, USHORT16 usY)
{
    OsdScene *pstScene = OSD_GET_SCENE(ucSceneId);
    HV_ASSERT_VALID_PTR_VOID(pstScene);

    if (usX != INVALID_PARAM_USHORT16)
    {
        pstScene->usX = usX;
    }
    if (usY != INVALID_PARAM_USHORT16)
    {
        pstScene->usY = usY;
    }

#if (HV_CONFIG_ON == HV_PROJECT_CONFIG_OSD_MIRROR)
    if (bRTLShow && (pstScene->bMirror))
    {
        USHORT16 usFullWidth = 0;
        USHORT16 usFullHeight = 0;
        Hv_Mw_OsdGetDisplaySize(&usFullWidth, &usFullHeight);
        pstScene->usX = usFullWidth - pstScene->usX - pstScene->usWidth;
    }
#endif

    OSD_LOG_DEBUG("Set scene %s pos=(%d, %d)", SCENE_NAME(ucSceneId), pstScene->usX, pstScene->usY);
    Hv_Mw_OsdSceneSetModify(pstScene);
}

VOID Hv_Mw_OsdCalculateCollisionBox(OsdBox stBorder, OsdBox *pstBox, USHORT16 usDx, USHORT16 usDy)
{
    HV_ASSERT_VALID_PTR_VOID(pstBox);
    HV_ASSERT_TRUE_VOID(stBorder.usX <= pstBox->usX);
    HV_ASSERT_TRUE_VOID(stBorder.usY <= pstBox->usY);
    HV_ASSERT_TRUE_VOID((stBorder.usX + stBorder.usW) >= (pstBox->usX + pstBox->usW));
    HV_ASSERT_TRUE_VOID((stBorder.usY + stBorder.usH) >= (pstBox->usY + pstBox->usH));

    static BOOL bRevertX = HV_FALSE;
    static BOOL bRevertY = HV_FALSE;
    USHORT16 usSpace = 0;

    if (!bRevertX)
    {
        if (pstBox->usX + usDx + pstBox->usW > stBorder.usX + stBorder.usW)
        {
            usSpace = (stBorder.usX + stBorder.usW) - (pstBox->usX + pstBox->usW);
            pstBox->usX += usSpace;
            pstBox->usX -= (usDx - usSpace);
            bRevertX = HV_TRUE;
        }
        else
        {
            pstBox->usX += usDx;
        }
    }
    else
    {
        if (pstBox->usX < stBorder.usX + usDx)
        {
            usSpace = pstBox->usX - stBorder.usX;
            pstBox->usX -= usSpace;
            pstBox->usX += (usDx - usSpace);
            bRevertX = HV_FALSE;
        }
        else
        {
            pstBox->usX -= usDx;
        }
    }

    if (!bRevertY)
    {
        if (pstBox->usY + usDy + pstBox->usH > stBorder.usY + stBorder.usH)
        {
            usSpace = (stBorder.usY + stBorder.usH) - (pstBox->usY + pstBox->usH);
            pstBox->usY += usSpace;
            pstBox->usY -= (usDy - usSpace);
            bRevertY = HV_TRUE;
        }
        else
        {
            pstBox->usY += usDy;
        }
    }
    else
    {
        if (pstBox->usY < stBorder.usY + usDy)
        {
            usSpace = pstBox->usY - stBorder.usY;
            pstBox->usY -= usSpace;
            pstBox->usY += (usDy - usSpace);
            bRevertY = HV_FALSE;
        }
        else
        {
            pstBox->usY -= usDy;
        }
    }
}

UINT32 Hv_Mw_OsdGetPartColor(VOID)
{
    UINT32 uiRGB = 0;
#if (HV_PROJECT_CONFIG_AMBILIGHT == HV_CONFIG_ON)
    CrosshairRGBY stValue = {0};

    Hv_Mw_PQ_CrosshairGetRGBY(&stValue);
    OSD_LOG_DEBUG("B = %d, G = %d, R = %d, Y = %d", stValue.ucB, stValue.ucG, stValue.ucR, stValue.ucY);
#if 0
    SHORT16 sThreshold = 15;
    SHORT16 sDiffR = (SHORT16)stValue.ucR - 128;
    SHORT16 sDiffG = (SHORT16)stValue.ucG - 128;
    SHORT16 sDiffB = (SHORT16)stValue.ucB - 128;
    SHORT16 sDiffMax = max3(ABS(sDiffR, 0), ABS(sDiffG, 0), ABS(sDiffB, 0));
    if (sDiffMax < sThreshold)
    {
        if (stValue.ucY > 128)
        {
            stValue.ucB = 255;
            stValue.ucG = 255;
            stValue.ucR = 255;
        }
        else
        {
            stValue.ucB = 0;
            stValue.ucG = 0;
            stValue.ucR = 0;
        }
    }
    else
#endif
    {
        stValue.ucB = 255 - stValue.ucB;
        stValue.ucG = 255 - stValue.ucG;
        stValue.ucR = 255 - stValue.ucR;
    }
    uiRGB = (((UINT32)stValue.ucB) << 16) | (((UINT32)stValue.ucG) << 8) | (((UINT32)stValue.ucR) << 0);
    OSD_LOG_DEBUG("Revert: B = %d, G = %d, R = %d", stValue.ucB, stValue.ucG, stValue.ucR);
#endif
    return uiRGB;
}

VOID Hv_Mw_OsdSetComponentColor(OsdComponent stCp, UINT32 uiRGB)
{
    OsdWindow *pstWindow = NULL;
    UCHAR8 ucColorIndex = 0;
    UINT32 uiBGR = ((uiRGB & 0xFF) << 16) | (uiRGB & 0xFF00) | (((uiRGB & 0xFF0000)) >> 16);

    switch (stCp.enType)
    {
        case OSD_CP_TYPE_TEXT:
        {
            OsdText *pstDynamicProp = Hv_Mw_OsdComponentGetDynamicProp(stCp);
            HV_ASSERT_VALID_PTR_VOID(pstDynamicProp);
            pstWindow = OSD_GET_WINDOW(pstDynamicProp->ucWindowIndex);
            ucColorIndex = pstDynamicProp->ucColorIndex;
            break;
        }
        case OSD_CP_TYPE_TEXT_LIST:
        {
            OsdTextList *pstDynamicProp = Hv_Mw_OsdComponentGetDynamicProp(stCp);
            HV_ASSERT_VALID_PTR_VOID(pstDynamicProp);
            pstWindow = OSD_GET_WINDOW(pstDynamicProp->ucWindowIndex);
            ucColorIndex = pstDynamicProp->ucColorIndex;
            break;
        }
        case OSD_CP_TYPE_NUMBER:
        {
            OsdNumber *pstDynamicProp = Hv_Mw_OsdComponentGetDynamicProp(stCp);
            HV_ASSERT_VALID_PTR_VOID(pstDynamicProp);
            pstWindow = OSD_GET_WINDOW(pstDynamicProp->ucWindowIndex);
            ucColorIndex = pstDynamicProp->ucColorIndex;
            break;
        }
        case OSD_CP_TYPE_ASCII_STRING:
        {
            OsdAsciiString *pstDynamicProp = Hv_Mw_OsdComponentGetDynamicProp(stCp);
            HV_ASSERT_VALID_PTR_VOID(pstDynamicProp);
            pstWindow = OSD_GET_WINDOW(pstDynamicProp->ucWindowIndex);
            ucColorIndex = pstDynamicProp->ucColorIndex;
            break;
        }
        case OSD_CP_TYPE_ICON:
        {
            OsdIcon *pstDynamicProp = Hv_Mw_OsdComponentGetDynamicProp(stCp);
            HV_ASSERT_VALID_PTR_VOID(pstDynamicProp);
            pstWindow = OSD_GET_WINDOW(pstDynamicProp->ucWindowIndex);
            ucColorIndex = pstDynamicProp->ucColorIndex;
            break;
        }
        case OSD_CP_TYPE_ICON_LIST:
        {
            OsdIconList *pstDynamicProp = Hv_Mw_OsdComponentGetDynamicProp(stCp);
            HV_ASSERT_VALID_PTR_VOID(pstDynamicProp);
            pstWindow = OSD_GET_WINDOW(pstDynamicProp->ucWindowIndex);
            ucColorIndex = pstDynamicProp->ucColorIndex;
            break;
        }
        default:
        {
            return;
        }
    }

    HV_ASSERT_VALID_PTR_VOID(pstWindow);
    Hv_Drv_OsdPalette_ChangeColor(pstWindow->ucPhyId, ucColorIndex, uiBGR);
}

static VOID Hv_Mw_OsdGetComponentPosition(OsdComponentNode *pstNode, USHORT16 *pusX, USHORT16 *pusY)
{
    HV_ASSERT_VALID_PTR_VOID(pstNode);
    OsdWindow *pstWindow = NULL;
    VOID *pstPropData = pstNode->pvDynamicData ? pstNode->pvDynamicData : pstNode->pvCpData;
    HV_ASSERT_VALID_PTR_VOID(pstPropData);

    switch (pstNode->stCp.enType)
    {
        case OSD_CP_TYPE_TEXT:
        {
            OsdText *pstProp = pstPropData;
            pstWindow = OSD_GET_WINDOW(pstProp->ucWindowIndex);
            HV_ASSERT_VALID_PTR_VOID(pstWindow);
            HV_ASSERT_VALID_PTR_VOID(pstWindow->pstScene);
            *pusX = pstWindow->pstScene->usX + pstProp->usX;
            *pusY = pstWindow->pstScene->usY + pstProp->usY;
            break;
        }
        case OSD_CP_TYPE_TEXT_LIST:
        {
            OsdTextList *pstProp = pstPropData;
            HV_ASSERT_VALID_PTR_VOID(pstProp);
            pstWindow = OSD_GET_WINDOW(pstProp->ucWindowIndex);
            HV_ASSERT_VALID_PTR_VOID(pstWindow);
            HV_ASSERT_VALID_PTR_VOID(pstWindow->pstScene);
            *pusX = pstWindow->pstScene->usX + pstProp->usX;
            *pusY = pstWindow->pstScene->usY + pstProp->usY;
            break;
        }
        case OSD_CP_TYPE_NUMBER:
        {
            OsdNumber *pstProp = pstPropData;
            HV_ASSERT_VALID_PTR_VOID(pstProp);
            pstWindow = OSD_GET_WINDOW(pstProp->ucWindowIndex);
            HV_ASSERT_VALID_PTR_VOID(pstWindow);
            *pusX = pstWindow->pstScene->usX + pstProp->usX;
            *pusY = pstWindow->pstScene->usY + pstProp->usY;
            break;
        }
        case OSD_CP_TYPE_ASCII_STRING:
        {
            OsdAsciiString *pstProp = pstPropData;
            HV_ASSERT_VALID_PTR_VOID(pstProp);
            pstWindow = OSD_GET_WINDOW(pstProp->ucWindowIndex);
            HV_ASSERT_VALID_PTR_VOID(pstWindow);
            *pusX = pstWindow->pstScene->usX + pstProp->usX;
            *pusY = pstWindow->pstScene->usY + pstProp->usY;
            break;
        }
        case OSD_CP_TYPE_ICON:
        {
            OsdIcon *pstProp = pstPropData;
            HV_ASSERT_VALID_PTR_VOID(pstProp);
            pstWindow = OSD_GET_WINDOW(pstProp->ucWindowIndex);
            HV_ASSERT_VALID_PTR_VOID(pstWindow);
            *pusX = pstWindow->pstScene->usX + pstProp->usX;
            *pusY = pstWindow->pstScene->usY + pstProp->usY;
            break;
        }
        case OSD_CP_TYPE_ICON_LIST:
        {
            OsdIconList *pstProp = pstPropData;
            HV_ASSERT_VALID_PTR_VOID(pstProp);
            pstWindow = OSD_GET_WINDOW(pstProp->ucWindowIndex);
            HV_ASSERT_VALID_PTR_VOID(pstWindow);
            *pusX = pstWindow->pstScene->usX + pstProp->usX;
            *pusY = pstWindow->pstScene->usY + pstProp->usY;
            break;
        }
        default:
        {
            return;
        }
    }
}

static VOID GetComponentVisibleArea(OsdComponent stCp, USHORT16 *pusXstart, USHORT16 *pusXend, USHORT16 *pusYstart, USHORT16 *pusYend)
{
    OsdFontResourceInfo stResInfo = {0};
    USHORT16 usStartX = 0;
    USHORT16 usStartY = 0;
    OsdComponentNode *pstNode = Hv_Mw_OsdComponentGetNode(stCp);
    HV_ASSERT_VALID_PTR_VOID(pstNode);
    Hv_Mw_OsdGetComponentPosition(pstNode, &usStartX, &usStartY);
    HV_ASSERT_SUCCESS_VOID(Hv_Drv_OsdFont_GetFontResouceInfo(pstNode, &stResInfo));

    USHORT16 usOffset = 0;
    USHORT16 usPreBytes = 0;
    const UCHAR8 *pucMatrix = NULL;
    UCHAR8 ucShift = 0;

    for (UCHAR8 ucVIndex = 0; ucVIndex < stResInfo.ucRows; ucVIndex++)
    {
        for (UCHAR8 ucLineIndex = 0; ucLineIndex < stResInfo.ucResHeight; ucLineIndex++)
        {
            for (UCHAR8 ucHIndex = 0; ucHIndex < stResInfo.ucColumns; ucHIndex++)
            {
                usOffset = stResInfo.pusMatrixOffset[stResInfo.ucColumns * ucVIndex + ucHIndex];
                usPreBytes = (USHORT16)ucLineIndex * stResInfo.ucResWidth * stResInfo.ucResBits;
                pucMatrix = stResInfo.pucMatrixAddr + (UINT32)usOffset * stResInfo.usMatrixSize + (usPreBytes >> 3);
                ucShift = usPreBytes & 0x07;
                for (UCHAR8 ucPixelIndex = 0; ucPixelIndex < stResInfo.ucResWidth; ucPixelIndex++)
                {
                    if (1 == ((*pucMatrix >> ucShift) & ((1 << stResInfo.ucResBits) - 1)))
                    {
                        if (*pusXstart > ucHIndex * stResInfo.ucResWidth + ucPixelIndex)
                        {
                            *pusXstart = ucHIndex * stResInfo.ucResWidth + ucPixelIndex;
                        }
                        if (*pusXend < ucHIndex * stResInfo.ucResWidth + ucPixelIndex)
                        {
                            *pusXend = ucHIndex * stResInfo.ucResWidth + ucPixelIndex;
                        }
                        if (*pusYstart > ucVIndex * stResInfo.ucResHeight + ucLineIndex)
                        {
                            *pusYstart = ucVIndex * stResInfo.ucResHeight + ucLineIndex;
                        }
                        if (*pusYend < ucVIndex * stResInfo.ucResHeight + ucLineIndex)
                        {
                            *pusYend = ucVIndex * stResInfo.ucResHeight + ucLineIndex;
                        }
                    }
                    ucShift += stResInfo.ucResBits;
                    if (ucShift >= 8)
                    {
                        pucMatrix++;
                        ucShift = 0;
                    }
                }
            }
        }
    }
    *pusXstart += usStartX;
    *pusXend += usStartX + 1;
    *pusYstart += usStartY;
    *pusYend += usStartY + 1;
}

VOID Hv_Mw_OsdColorCaptureSetArea(USHORT16 usXstart, USHORT16 usXend, USHORT16 usYstart, USHORT16 usYend)
{
    USHORT16 usXStep = 0;
    USHORT16 usYStep = 0;
    USHORT16 ausXArray[COLOR_CAPTURE_POINT_CNT] = {0};
    USHORT16 ausYArray[COLOR_CAPTURE_POINT_CNT] = {0};
    USHORT16 usPointCnt = 0;

    if (usXstart > 0)
    {
        usXstart -= 1;
    }
    if (usYstart > 0)
    {
        usYstart -= 1;
    }
    usXend = MAX(usXend, usXstart + SCALER_CURSOR_NUM + 1);
    usYend = MAX(usYend, usYstart + COLOR_CAPTURE_FRAME_CNT + 1);
    usXStep = (usXend - usXstart) / (SCALER_CURSOR_NUM + 1);
    usYStep = (usYend - usYstart) / (COLOR_CAPTURE_FRAME_CNT + 1);
    OSD_LOG_VERBOSE("CapturePostion: Xstart=%d, Xend=%d, Ystart=%d, Yend=%d", usXstart, usXend, usYstart, usYend);

    ausXArray[usPointCnt] = (usXend - usXstart) / 2 + usXstart;
    ausYArray[usPointCnt] = (usYend - usYstart) / 2 + usYstart;
    OSD_LOG_VERBOSE("CapturePostion[0]: X=%d, Y=%d", ausXArray[usPointCnt], ausYArray[usPointCnt]);
    usPointCnt++;
    ausXArray[usPointCnt] = (usXend - usXstart) / 4 + usXstart;
    ausYArray[usPointCnt] = (usYend - usYstart) / 2 + usYstart;
    OSD_LOG_VERBOSE("CapturePostion[0]: X=%d, Y=%d", ausXArray[usPointCnt], ausYArray[usPointCnt]);
    usPointCnt++;
    ausXArray[usPointCnt] = (usXend - usXstart) * 3 / 4 + usXstart;
    ausYArray[usPointCnt] = (usYend - usYstart) / 2 + usYstart;
    OSD_LOG_VERBOSE("CapturePostion[0]: X=%d, Y=%d", ausXArray[usPointCnt], ausYArray[usPointCnt]);
    usPointCnt++;
    ausXArray[usPointCnt] = (usXend - usXstart) / 2 + usXstart;
    ausYArray[usPointCnt] = (usYend - usYstart) / 4 + usYstart;
    OSD_LOG_VERBOSE("CapturePostion[0]: X=%d, Y=%d", ausXArray[usPointCnt], ausYArray[usPointCnt]);
    usPointCnt++;
    ausXArray[usPointCnt] = (usXend - usXstart) / 2 + usXstart;
    ausYArray[usPointCnt] = (usYend - usYstart) * 3 / 4 + usYstart;
    OSD_LOG_VERBOSE("CapturePostion[0]: X=%d, Y=%d", ausXArray[usPointCnt], ausYArray[usPointCnt]);
    usPointCnt++;

    for (USHORT16 usId = 0; usId < COLOR_CAPTURE_POINT_CNT / SCALER_CURSOR_NUM; usId++)
    {
        ausXArray[usPointCnt] = usXstart + usXStep * (usId + 1);
        ausYArray[usPointCnt] = usYstart;
        OSD_LOG_VERBOSE("CapturePostion[1]: X=%d, Y=%d", ausXArray[usPointCnt], ausYArray[usPointCnt]);
        usPointCnt++;
    }
    for (USHORT16 usId = 0; usId < COLOR_CAPTURE_POINT_CNT / SCALER_CURSOR_NUM; usId++)
    {
        ausXArray[usPointCnt] = usXstart;
        ausYArray[usPointCnt] = usYstart + usYStep * (usId + 1);
        OSD_LOG_VERBOSE("CapturePostion[2]: X=%d, Y=%d", ausXArray[usPointCnt], ausYArray[usPointCnt]);
        usPointCnt++;
    }
    for (USHORT16 usId = 0; usId < COLOR_CAPTURE_POINT_CNT / SCALER_CURSOR_NUM; usId++)
    {
        ausXArray[usPointCnt] = usXstart + usXStep * (usId + 1);
        ausYArray[usPointCnt] = usYend;
        OSD_LOG_VERBOSE("CapturePostion[3]: X=%d, Y=%d", ausXArray[usPointCnt], ausYArray[usPointCnt]);
        usPointCnt++;
    }
    for (USHORT16 usId = 0; usId < COLOR_CAPTURE_POINT_CNT / SCALER_CURSOR_NUM; usId++)
    {
        ausXArray[usPointCnt] = usXend;
        ausYArray[usPointCnt] = usYstart + usYStep * (usId + 1);
        OSD_LOG_VERBOSE("CapturePostion[4]: X=%d, Y=%d", ausXArray[usPointCnt], ausYArray[usPointCnt]);
        usPointCnt++;
    }

    Hv_Drv_DpuScaler_ColorCaptureLoadPositionTable(ausXArray, ausYArray);
}

VOID Hv_Mw_OsdColorCapturePositionInit(OsdComponent stCp)
{
    USHORT16 usXstart = 0xffff;
    USHORT16 usXend = 0;
    USHORT16 usYstart = 0xffff;
    USHORT16 usYend = 0;

    GetComponentVisibleArea(stCp, &usXstart, &usXend, &usYstart, &usYend);

    Hv_Mw_OsdColorCaptureSetArea(usXstart, usXend, usYstart, usYend);
}

VOID Hv_Mw_OsdColorCapturePositionInitWithGap(OsdComponent stCp, USHORT16 usGap)
{
    USHORT16 usXstart = 0xffff;
    USHORT16 usXend = 0;
    USHORT16 usYstart = 0xffff;
    USHORT16 usYend = 0;

    GetComponentVisibleArea(stCp, &usXstart, &usXend, &usYstart, &usYend);

    usXstart = usXstart > usGap ? usXstart - usGap : usXstart;
    usXend = usXend + usGap;
    usYstart = usYstart > usGap ? usYstart - usGap : usYstart;
    usYend = usYend + usGap;
    Hv_Mw_OsdColorCaptureSetArea(usXstart, usXend, usYstart, usYend);
}

VOID Hv_Mw_OsdDynCrosshairEnable(BOOL bEnable)
{
    Hv_Drv_DpuScaler_ColorCaptureEn(bEnable);
}

UINT32 Hv_Mw_OsdGetDynCrosshairBgAvgColor(VOID)
{
    return Hv_Drv_DpuScaler_CalculateAvgColor();
}

UINT32 Hv_Mw_OsdCalculateRevertColor(VOID)
{
    const UCHAR8 ucThreshold = 30;
    UCHAR8 ucBackgroundR = 0;
    UCHAR8 ucBackgroundG = 0;
    UCHAR8 ucBackgroundB = 0;
    static UCHAR8 ucFrontR = 0;
    static UCHAR8 ucFrontG = 0;
    static UCHAR8 ucFrontB = 0;
    UINT32 uiRevertRGB888 = 0;

    UINT32 uiAvgRGB888 = Hv_Mw_OsdGetDynCrosshairBgAvgColor();
    ucBackgroundR = (uiAvgRGB888 >> 16) & 0xFF;
    ucBackgroundG = (uiAvgRGB888 >> 8) & 0xFF;
    ucBackgroundB = (uiAvgRGB888 >> 0) & 0xFF;
    OSD_LOG_DEBUG("background avg color: R = %d, G = %d, B = %d", ucBackgroundR, ucBackgroundG, ucBackgroundB);

    if (ucBackgroundR < (128 - ucThreshold) || ucBackgroundR > (128 + ucThreshold))
    {
        ucFrontR = (ucBackgroundR < 128) ? 255 : 0;
    }
    if (ucBackgroundG < (128 - ucThreshold) || ucBackgroundG > (128 + ucThreshold))
    {
        ucFrontG = (ucBackgroundG < 128) ? 255 : 0;
    }
    if (ucBackgroundB < (128 - ucThreshold) || ucBackgroundB > (128 + ucThreshold))
    {
        ucFrontB = (ucBackgroundB < 128) ? 255 : 0;
    }

    uiRevertRGB888 = (((UINT32)ucFrontR) << 16) | (((UINT32)ucFrontG) << 8) | (((UINT32)ucFrontB) << 0);
    OSD_LOG_DEBUG("revert color: R = %d, G = %d, B = %d", ucFrontR, ucFrontG, ucFrontB);

    return uiRevertRGB888;
}

VOID Hv_Mw_OsdGetDisplaySize(USHORT16 *pusWidth, USHORT16 *pusHeight)
{
    *pusWidth = Hv_Drv_OsdDP_GetRealHActive();
    *pusHeight = Hv_Drv_OsdDP_GetRealVActive();
    //Hv_Drv_OsdDP_GetPreScalerSize(pusWidth, pusHeight);
}

#if (HV_PROJECT_CONFIG_OSD_ROTATION == HV_CONFIG_ON)
VOID Hv_Mw_OsdCalculateRotateInplacePostion(USHORT16 *pusX, USHORT16 *pusY, OsdRotationType enPrevRot, OsdRotationType enNewRot)
{
    if (enPrevRot == enNewRot)
    {
        return;
    }

    HV_ASSERT_VALID_PTR_VOID(pusX);
    HV_ASSERT_VALID_PTR_VOID(pusY);
    USHORT16 usOriX = 0;
    USHORT16 usOriY = 0;

    switch(enPrevRot)
    {
        case OSD_ROTATION_90:
        {
            usOriX = *pusY;
            usOriY = 100 - *pusX;
            break;
        }
        case OSD_ROTATION_180:
        {
            usOriX = 100 - *pusX;
            usOriY = 100 - *pusY;
            break;
        }
        case OSD_ROTATION_270:
        {
            usOriX = 100 - *pusY;
            usOriY = *pusX;
            break;
        }
        default:
        {
            usOriX = *pusX;
            usOriY = *pusY;
            break;
        }
    }

    switch(enNewRot)
    {
        case OSD_ROTATION_90:
        {
            *pusX = 100 - usOriY;
            *pusY = usOriX;
            break;
        }
        case OSD_ROTATION_180:
        {
            *pusX = 100 - usOriX;
            *pusY = 100 - usOriY;
            break;
        }
        case OSD_ROTATION_270:
        {
            *pusX = usOriY;
            *pusY = 100 - usOriX;
            break;
        }
        default:
        {
            *pusX = usOriX;
            *pusY = usOriY;
            break;
        }
    }
}
#endif

VOID Hv_Mw_OsdSceneSetAbsolutePosition(UCHAR8 ucSceneId, USHORT16 usX, USHORT16 usY)
{
#if (HV_PROJECT_CONFIG_OSD_ROTATION == HV_CONFIG_ON)
    OsdScene *pstScene = OSD_GET_SCENE(ucSceneId);
    HV_ASSERT_VALID_PTR_VOID(pstScene);

    pstScene->usAbsoluteX = usX;
    pstScene->usAbsoluteY = usY;
    pstScene->bAbsolutePostion = HV_TRUE;

    OSD_LOG_DEBUG("Set scene %s absolute pos=(%d, %d)", SCENE_NAME(ucSceneId), usX, usY);
#endif
    Hv_Mw_OsdSceneSetPosition(ucSceneId, usX, usY);
}

VOID Hv_Mw_OsdSceneCancelAbsolutePosition(UCHAR8 ucSceneId)
{
#if (HV_PROJECT_CONFIG_OSD_ROTATION == HV_CONFIG_ON)
    OsdScene *pstScene = OSD_GET_SCENE(ucSceneId);
    HV_ASSERT_VALID_PTR_VOID(pstScene);
    OSD_LOG_DEBUG("Cancel scene %s absolute pos", SCENE_NAME(ucSceneId));
    pstScene->bAbsolutePostion = HV_FALSE;
#endif
}

USHORT16 Hv_Mw_OsdSceneSetPositionRatio(UCHAR8 ucSceneId, BOOL bIsX, USHORT16 usRatio, USHORT16 usLimitStart, USHORT16 usLimitEnd)
{
    HV_ASSERT_TRUE_RET(usLimitStart < usLimitEnd, 0);
    OsdScene *pstScene = OSD_GET_SCENE(ucSceneId);
    HV_ASSERT_VALID_PTR_RET(pstScene, 0);
    USHORT16 usX = 0;
    USHORT16 usY = 0;
    USHORT16 usWidth = 0;
    USHORT16 usHeight = 0;
    USHORT16 usFullWidth = 0;
    USHORT16 usFullHeight = 0;
    USHORT16 usRatioFix = min(usRatio, (USHORT16)100);

    Hv_Mw_OsdGetDisplaySize(&usFullWidth, &usFullHeight);
    OSD_LOG_DEBUG("FullWidth = %d, FullHeight = %d)", usFullWidth, usFullHeight);
    OSD_LOG_DEBUG("LimitStart = %d, LimitEnd = %d)", usLimitStart, usLimitEnd);

    if (bIsX)
    {
        if (usLimitStart != 0)
        {
            usFullWidth -= usLimitStart;
        }
        if (usLimitEnd != INVALID_PARAM_USHORT16)
        {
            usFullWidth = MIN(usFullWidth, usLimitEnd - usLimitStart);
        }
        OSD_LOG_DEBUG("FullWidth limit to %d)", usFullWidth);
        usWidth = pstScene->usWidth;
        usX = (USHORT16)((INT32)usRatioFix * ((INT32)usFullWidth - (INT32)usWidth) / 100) + usLimitStart;
        usX = MIN(usX, usFullWidth - usWidth + usLimitStart);
        Hv_Mw_OsdSceneSetPosition(ucSceneId, usX, INVALID_PARAM_USHORT16);
    }
    else
    {
        if (usLimitStart != 0)
        {
            usFullHeight -= usLimitStart;
        }
        if (usLimitEnd != INVALID_PARAM_USHORT16)
        {
            usFullHeight = MIN(usFullHeight, usLimitEnd - usLimitStart);
        }
        OSD_LOG_DEBUG("FullHeight limit to %d)", usFullHeight);
        usHeight = pstScene->usHeight;
        usY = (USHORT16)((INT32)(100 - usRatioFix) * ((INT32)usFullHeight - (INT32)usHeight) / 100) + usLimitStart;
        usY = MIN(usY, usFullHeight - usHeight + usLimitStart);
        Hv_Mw_OsdSceneSetPosition(ucSceneId, INVALID_PARAM_USHORT16, usY);
    }
    OSD_LOG_DEBUG("Scene(%d) %s:)", ucSceneId, SCENE_NAME(ucSceneId));
    OSD_LOG_DEBUG("      Width = %d, Height = %d)", pstScene->usWidth, pstScene->usHeight);
    OSD_LOG_DEBUG("      usRatio = %d, Pos = (%d, %d)", usRatioFix, pstScene->usX, pstScene->usY);

    return (bIsX ? pstScene->usX : pstScene->usY);
}

VOID Hv_Mw_OsdSetTransparency(UCHAR8 ucAlpha)
{
    OSD_LOG_DEBUG("osd alpha = %d", ucAlpha);
    Hv_Drv_OsdBlend_SetUniversalAlpha(OSD_UNIVERSAL_ALPHA_TYPE_ALL, ucAlpha);
}

VOID Hv_Mw_OsdSetRotateType(OsdRotationType enRotate)
{
#if (HV_PROJECT_CONFIG_OSD_ROTATION == HV_CONFIG_ON)
    OSD_LOG_DEBUG("Set osd rotate type = %d", enRotate);
    Hv_Drv_OsdSetRotateType(enRotate);
    s_stOsdDrawData.bRotateChange = HV_TRUE;
    if (Hv_Mw_OsdIsShowing())
    {
        Hv_Mw_OsdOpsForceRedraw(HV_TRUE);
    }
#else
    OSD_LOG_WARN("Rotation unsupport");
#endif
}

VOID Hv_Mw_OsdSceneSetRotateSkip(UCHAR8 ucSceneId, BOOL bSkip)
{
#if (HV_PROJECT_CONFIG_OSD_ROTATION == HV_CONFIG_ON)
    OsdScene *pstScene = OSD_GET_SCENE(ucSceneId);
    HV_ASSERT_VALID_PTR_VOID(pstScene);

    pstScene->bSkipRotate = bSkip;

    OSD_LOG_DEBUG("Set scene %s SkipRotate = %d", SCENE_NAME(ucSceneId), bSkip);
#endif
}

BOOL Hv_Mw_OsdSceneGetRotateSkip(UCHAR8 ucSceneId)
{
#if (HV_PROJECT_CONFIG_OSD_ROTATION == HV_CONFIG_ON)
    OsdScene *pstScene = OSD_GET_SCENE(ucSceneId);
    HV_ASSERT_VALID_PTR_RET(pstScene, HV_FALSE);

    return pstScene->bSkipRotate;
#else
    return HV_FALSE;
#endif
}

VOID Hv_Mw_OsdSetLanguage(USHORT16 usLangId)
{
    Hv_Drv_OsdResource_SetLanguage(usLangId);
    if (Hv_Mw_OsdIsShowing())
    {
        Hv_Mw_OsdOpsForceRedraw(HV_TRUE);
    }
}

VOID Hv_Mw_OsdDrawInit(VOID)
{
    s_stOsdDrawData.uiWindowEnableFlag = 0;
    s_stOsdDrawData.uiRectEnableFlag = 0;
    s_stOsdDrawData.uiGridEnableFlag = 0;
    s_stOsdDrawData.uiLineEnableFlag = 0;
#if (HV_PROJECT_CONFIG_OSD_DDRPATH == HV_CONFIG_ON)
    s_stOsdDrawData.bIsFirstFrame = HV_TRUE;
    s_stOsdDrawData.ucMutiFrameDrawCurrentSceneId = 0;
#if (HV_PROJECT_CONFIG_OSD_ROTATION == HV_CONFIG_ON)
    s_stOsdDrawData.ucRotatingStep = 0;
    s_stOsdDrawData.ucSceneRotating = SCENE_ID_MAX;
    s_stOsdDrawData.bRotateChange = HV_FALSE;
    s_stOsdDrawData.bIsLastScene = HV_FALSE;
#endif
#endif

    s_stOsdDrawData.enLogoState = OSD_LOGO_WAITING_SHOW;
    s_stOsdDrawData.bBypassLogo = HV_FALSE;

    s_stOsdDrawData.bFrameModify = HV_FALSE;
#if (HV_PROJECT_CONFIG_OSD_ANIMITION_SUPPORT == HV_CONFIG_ON)
    Hv_Mw_OsdAnimInit();
#endif

#if (HV_PROJECT_CONFIG_OSD_FONT_BLEND == HV_CONFIG_ON)
    Hv_Drv_OsdBlend_SetBlendingType(OSD_BLENDING_STAGE_WINALL, OSD_BLENDING_TYPE_BLENDING, 0);
#endif
}

#ifdef HV_SCALER_DEBUG_VERSION
VOID Hv_Mw_OsdResourceDebugStat(VOID)
{
    UCHAR8 ucWinId = 0;
    UCHAR8 ucId = 0;
    UINT32 uiTotalSize = 0;

    OSD_LOG_INFO("====================================================================");
    OSD_LOG_INFO("OSD DATA STATISTICS");
    OSD_LOG_INFO("====================================================================");
    OSD_LOG_INFO("Osd flash data size:");
    uiTotalSize += SCENE_ID_MAX * sizeof(OsdSceneProp);
    OSD_LOG_INFO("  Total SceneProp num = %d, data size = %d Bytes", SCENE_ID_MAX, SCENE_ID_MAX * sizeof(OsdSceneProp));
    uiTotalSize += WIN_ID_MAX * sizeof(OsdWindowProp);
    OSD_LOG_INFO("  Total WindowProp num = %d, data size = %d Bytes", WIN_ID_MAX, WIN_ID_MAX * sizeof(OsdWindowProp));
    uiTotalSize += ITEM_ID_MAX * sizeof(OsdItemProp);
    OSD_LOG_INFO("  Total ItemProp num = %d, data size = %d Bytes", ITEM_ID_MAX, ITEM_ID_MAX * sizeof(OsdItemProp));
    uiTotalSize += TEXT_ID_MAX * sizeof(OsdText);
    OSD_LOG_INFO("  Total Text num = %d, data size = %d Bytes", TEXT_ID_MAX, TEXT_ID_MAX * sizeof(OsdText));
    uiTotalSize += TEXT_LIST_ID_MAX * sizeof(OsdTextList);
    OSD_LOG_INFO("  Total TextList num = %d, data size = %d Bytes", TEXT_LIST_ID_MAX, TEXT_LIST_ID_MAX * sizeof(OsdTextList));
    uiTotalSize += NUMBER_ID_MAX * sizeof(NUMBER_ID_MAX);
    OSD_LOG_INFO("  Total Number num = %d, data size = %d Bytes", NUMBER_ID_MAX, NUMBER_ID_MAX * sizeof(NUMBER_ID_MAX));
    uiTotalSize += ASCII_STRING_ID_MAX * sizeof(OsdAsciiString);
    OSD_LOG_INFO("  Total AsciiString num = %d, data size = %d Bytes", ASCII_STRING_ID_MAX, ASCII_STRING_ID_MAX * sizeof(OsdAsciiString));
    uiTotalSize += ICON_ID_MAX * sizeof(OsdIcon);
    OSD_LOG_INFO("  Total Icon num = %d, data size = %d Bytes", ICON_ID_MAX, ICON_ID_MAX * sizeof(OsdIcon));
    uiTotalSize += ICON_LIST_ID_MAX * sizeof(OsdIconList);
    OSD_LOG_INFO("  Total IconList num = %d, data size = %d Bytes", ICON_LIST_ID_MAX, ICON_LIST_ID_MAX * sizeof(OsdIconList));
    uiTotalSize += BMP_ID_MAX * sizeof(OsdBmp);
    OSD_LOG_INFO("  Total Bmp num = %d, data size = %d Bytes", BMP_ID_MAX, BMP_ID_MAX * sizeof(OsdBmp));
    uiTotalSize += BMP_LIST_ID_MAX * sizeof(OsdBmpList);
    OSD_LOG_INFO("  Total BmpList num = %d, data size = %d Bytes", BMP_LIST_ID_MAX, BMP_LIST_ID_MAX * sizeof(OsdBmpList));
    uiTotalSize += GRAPHIC_ID_MAX * sizeof(OsdGraphic);
    OSD_LOG_INFO("  Total Graphic num = %d, data size = %d Bytes", GRAPHIC_ID_MAX, GRAPHIC_ID_MAX * sizeof(OsdGraphic));
    uiTotalSize += RECT_ID_MAX * sizeof(OsdRect);
    OSD_LOG_INFO("  Total Rect num = %d, data size = %d Bytes", RECT_ID_MAX, RECT_ID_MAX * sizeof(OsdRect));
    uiTotalSize += RECTGRID_ID_MAX * sizeof(OsdRectGrid);
    OSD_LOG_INFO("  Total RectGrid num = %d, data size = %d Bytes", RECTGRID_ID_MAX, RECTGRID_ID_MAX * sizeof(OsdRectGrid));
    uiTotalSize += LINEGRID_ID_MAX * sizeof(OsdLineGrid);
    OSD_LOG_INFO("  Total LineGrid num = %d, data size = %d Bytes", LINEGRID_ID_MAX, LINEGRID_ID_MAX * sizeof(OsdLineGrid));
    uiTotalSize += LINE_ID_MAX * sizeof(OsdLine);
    OSD_LOG_INFO("  Total Line num = %d, data size = %d Bytes", LINE_ID_MAX, LINE_ID_MAX * sizeof(OsdLine));
    OSD_LOG_INFO("  Total prop data size = %d Bytes", uiTotalSize);
    OSD_LOG_INFO("====================================================================");
    OSD_LOG_INFO("Osd fw data size:");
    OSD_LOG_INFO("  Total Scene num = %d, data size = %d Bytes", SCENE_ID_MAX, SCENE_ID_MAX * sizeof(OsdScene));
    OSD_LOG_INFO("  Total Window num = %d, data size = %d Bytes", WIN_ID_MAX, WIN_ID_MAX * sizeof(OsdWindow));
    OSD_LOG_INFO("  Total Item num = %d, data size = %d Bytes", ITEM_ID_MAX, ITEM_ID_MAX * sizeof(OsdItem));
    OSD_LOG_INFO("====================================================================");
    OSD_LOG_INFO("Osd phy used stat:");
    for (ucWinId = PHY_WIN_0; ucWinId < PHY_WIN_ID_MAX; ucWinId++)
    {
        if (!GET_WINDOW_USED_FLAG(ucWinId))
        {
            continue;
        }

        if (OSD_WINDOW_IS_NORMAL(ucWinId))
        {
            OSD_LOG_INFO("  PhyNormalWindow-%d used", ucWinId);
            for (ucId = ucWinId * 4; ucId < (ucWinId + 1) * 4; ucId++)
            {
                if (!GET_RECT_USED_FLAG(ucId))
                {
                    continue;
                }
                OSD_LOG_INFO("      PhyRect-%d used", ucId);
            }
        }
        else
        {
            OSD_LOG_INFO("  PhyRectWindow-%d used", ucWinId);
            for (ucId = (ucWinId - 2) * 8; ucId < (ucWinId - 1) * 8; ucId++)
            {
                if (!GET_RECT_USED_FLAG(ucId))
                {
                    continue;
                }
                OSD_LOG_INFO("      PhyRect-%d used", ucId);
            }
        }

        for (ucId = ucWinId * 2; ucId < (ucWinId + 1) * 2; ucId++)
        {
            if (!GET_GRID_USED_FLAG(ucId))
            {
                continue;
            }
            OSD_LOG_INFO("      PhyGrid-%d used", ucId);
        }

        for (ucId = ucWinId * 2; ucId < (ucWinId + 1) * 2; ucId++)
        {
            if (!GET_LINE_USED_FLAG(ucId))
            {
                continue;
            }
            OSD_LOG_INFO("      PhyLine-%d used", ucId);
        }
    }
    if (GET_WINDOW_USED_FLAG(PHY_GRAPHIC))
    {
        OSD_LOG_INFO("  Graphic used", ucWinId);
    }
    OSD_LOG_INFO("====================================================================");
    Hv_Drv_OsdFont_DubugInfo();
    OSD_LOG_INFO("====================================================================");
    Hv_Mw_OsdDbgDrawPrint();
    OSD_LOG_INFO("====================================================================");
#if (HV_PROJECT_CONFIG_OSD_FORCE_REDRAW_ALL == HV_CONFIG_OFF)
    Hv_Mw_OsdPrintFontResList();
    OSD_LOG_INFO("====================================================================");
#endif
}

static SHORT16 s_sOsdValueBk[E_USERDATA_MAX];
static SHORT16 s_sRealValueBk[E_USERDATA_MAX];
VOID Hv_Mw_OsdUserdataDebugStat(VOID)
{
    UserdataProp stUsedata = { 0 };

    OSD_LOG_INFO("====================================================================");
    OSD_LOG_INFO("Userdata info:");
    for (USHORT16 usId = 1; usId < E_USERDATA_MAX; usId++)
    {
        Hv_App_GetOsdUserdataProp(usId, &stUsedata);
        if ((s_sOsdValueBk[usId] != stUsedata.sOsdValue) || (s_sRealValueBk[usId] != stUsedata.sRealValue))
        {
            OSD_LOG_INFO("  *Userdata(%d): %s = %d, real_value = %d  [min=%d, max=%d, isCircle=%d, real_default=%d, map_type=%d]",
                            usId, Hv_App_GetUserdataName(usId), stUsedata.sOsdValue, stUsedata.sRealValue, stUsedata.sMinValue,
                            stUsedata.sMaxValue, stUsedata.bCircle, stUsedata.sRealDefaultValue, stUsedata.enMappingType);
            s_sOsdValueBk[usId] = stUsedata.sOsdValue;
            s_sRealValueBk[usId] = stUsedata.sRealValue;
        }
        else
        {
            OSD_LOG_INFO("  Userdata(%d): %s = %d  real_value = %d  [min=%d, max=%d, isCircle=%d, real_default=%d, map_type=%d]",
                            usId, Hv_App_GetUserdataName(usId), stUsedata.sOsdValue, stUsedata.sRealValue, stUsedata.sMinValue,
                            stUsedata.sMaxValue, stUsedata.bCircle, stUsedata.sRealDefaultValue, stUsedata.enMappingType);
        }
    }
    OSD_LOG_INFO("====================================================================");
}

#endif
