/**
 * @file hv_mw_Video.c
 * @brief  dpu middleware source file
 * @details This file provides the following functions: \n
 *          (1) dpu operation function \n
 *          (2) init handle \n
 *          (3) Feed functions \n
 *
 * @author HiView SoC Software Team
 * @version 1.0.0
 * @date 2022-08-25
 * @copyright Copyright(c),2022-8, Hiview Software. All rights reserved.
 * @par History:
 * <table>
 * <tr><th>Author                         <th>Date         <th>Change Description
 * <tr><td>Hiview SoC Software Team       <td>2022-08-25   <td>init
 * </table>
*/

#include <string.h>
#include "hv_comm_MemoryConfig.h"
#include "PanelConfig.h"
#include "hv_drv_EdpTx.h"

#include "hv_comm_Assert.h"
#include "hv_comm_DataBase.h"
#include "hv_comm_PqDef.h"
#include "hv_comm_MemParser.h"

#include "hv_mw_Video.h"
#include "hv_mw_PQ.h"
#include "hv_mw_Channel_Manager.h"
#include "hv_mw_PanelManager.h"
#include "hv_mw_SystemManager.h"
#include "hv_mw_Video_Interrupt.h"

#include "hv_drv_DpuCommon.h"
#include "hv_drv_PLL.h"

#include "hv_drv_DpuMainMute.h"
#include "hv_drv_DpuMainScaler.h"
#include "hv_cal_DpuMainScaler.h"
#include "hv_cal_DpuCprConfig.h"

#ifdef CONFIG_USER_DOUBLE_CHANNEL_ON
#include "hv_drv_DpuSubMute.h"
#include "hv_drv_DpuSubScaler.h"
#include "hv_cal_DpuSubScaler.h"
#include "hv_app_PQ.h"
#endif
#if (HV_CONFIG_ON == HV_PROJECT_CONFIG_DPU_BRIGHT_FRAME)
#include "hv_cal_DynamicColorWin.h"
#endif
#include "hv_drv_Mprt.h"
#include "hv_drv_PQ.h"

#include "hv_drv_Gpio.h"
#include "ProjectConfig.h"

#include "hv_app_PQ.h"

typedef struct _SCALER_INFO{
    USHORT16 usDownOutW;//scaler down W
    USHORT16 usDownOutH;//scaler down H
    USHORT16 usUpOutW;  //scaler up W
    USHORT16 usUpOutH;  //scaler up H
}ScalerInfo;

static PanelParam s_stVideoPanelParam = {0};

static Status SendNotifyMessageToSystemTask(SettingParamId enParamId, UINT32 uiValue)
{
    SystemEvent stSystemEvent = {0};
    HV_VOS_QUEUE_S* xSystembQueue = Hv_Mw_System_GetSystemQueue();
    HV_ASSERT_VALID_PTR(xSystembQueue);
    stSystemEvent.enEventType = SYSTEM_REV_EVENT_TYPE_OSD_SETTING;
    stSystemEvent.usEventId = enParamId;
    stSystemEvent.uiValue = uiValue;
    HV_ASSERT_TRUE(Hv_Vos_QueueSend(xSystembQueue, (void *)&stSystemEvent));
    return HV_SUCCESS;
}

static const DataPathSearchElem s_stDataPathSearchTabkeByEffect[] =
{
    {DATA_PATH_MODE_THROUGH_COLORFORMAT_RX,              ColorFormatType_YCbCr444, COMPRESS_RATIO_1},
    {DATA_PATH_MODE_COMPRESS_COLORFORMAT1_6_RX,          ColorFormatType_YCbCr444, COMPRESS_RATIO_ONE_POINT_SIX},
    {DATA_PATH_MODE_COMPRESS_COLORFORMAT_RX,             ColorFormatType_YCbCr444, COMPRESS_RATIO_TWO_POINT_FIVE},

    {DATA_PATH_MODE_THROUGH_COLORFORMAT_YUV444,          ColorFormatType_YCbCr444, COMPRESS_RATIO_1},
    {DATA_PATH_MODE_THROUGH_COLORFORMAT_YUV422,          ColorFormatType_YCbCr422, COMPRESS_RATIO_1},

    {DATA_PATH_MODE_COMPRESS_COLORFORMAT_YUV444,         ColorFormatType_YCbCr444, COMPRESS_RATIO_TWO_POINT_FIVE},
    {DATA_PATH_MODE_COMPRESS_COLORFORMAT_YUV422,         ColorFormatType_YCbCr422, COMPRESS_RATIO_TWO_POINT_FIVE},

    {DATA_PATH_MODE_COMPRESS_RATIO_3_COLORFORMAT_YUV444, ColorFormatType_YCbCr444, COMPRESS_RATIO_THREE},
    {DATA_PATH_MODE_COMPRESS_RATIO_3_COLORFORMAT_YUV422, ColorFormatType_YCbCr422, COMPRESS_RATIO_THREE},
};


VOID Hv_Mw_Video_GetFakeVideoConfigParams(VideoTimingParam *pstVideoTiming, VideoConfigParams *pstVideoConfigParams)
{
    const PanelParam stPanelParam = Hv_Mw_Panel_GetCurrentPanelParam();
    HV_ASSERT_VALID_PTR_VOID(pstVideoTiming);
    HV_ASSERT_VALID_PTR_VOID(pstVideoConfigParams);
    pstVideoConfigParams->uiInputVideoWidth                    = stPanelParam.usPanelHactive;
    pstVideoConfigParams->uiInputVideoHight                    = stPanelParam.usPanelVactive;
    pstVideoConfigParams->uiInputVideoHtotal                   = stPanelParam.usPanelHtotalType;
    pstVideoConfigParams->uiInputVideoVtotal                   = stPanelParam.usPanelVtotalType;
    pstVideoConfigParams->uiInputFrameRate                     = stPanelParam.usPanelFrameRateType;
    pstVideoConfigParams->uiDdrOrWtrVideoWidth                 = stPanelParam.usPanelHactive;
    pstVideoConfigParams->uiDdrOrWtrVideoHight                 = stPanelParam.usPanelVactive;
    pstVideoConfigParams->uiDtcTxHtotal                        = stPanelParam.usPanelHtotalType;

    pstVideoConfigParams->uiOutputVideoWidth                   = stPanelParam.usPanelHactive;
    pstVideoConfigParams->uiOutputVideoHight                   = stPanelParam.usPanelVactive;
    pstVideoConfigParams->uiOutputVideoHtotal                  = stPanelParam.usPanelHtotalType;
    pstVideoConfigParams->uiOutputVideoVtotal                  = stPanelParam.usPanelVtotalType;
    pstVideoConfigParams->uiOutputFrameRate                    = stPanelParam.usPanelFrameRateType;
    pstVideoConfigParams->enTimingMode                         = DIS_TIMING_MODE_FREE_RUN;
    
    pstVideoConfigParams->usVideoPanelHactive                   = stPanelParam.usPanelHactive;
    pstVideoConfigParams->usVideoPanelVactive                   = stPanelParam.usPanelVactive;
    pstVideoConfigParams->usVideoPanelHtotalType                = stPanelParam.usPanelHtotalType;
    pstVideoConfigParams->usVideoPanelVtotalType                = stPanelParam.usPanelVtotalType;
    pstVideoConfigParams->usPanelInchWidth                      = stPanelParam.usPanelInchWidth;
    pstVideoConfigParams->usPanelInchHeight                     = stPanelParam.usPanelInchHeight;
    /*color config*/
    pstVideoConfigParams->stColor.eClrFormat                   = ColorFormatType_RGB;
    pstVideoConfigParams->stColor.eClrDepth                    = ColorDepthType_8Bit;

    pstVideoConfigParams->stFrameBufferCfg.bUseFrameBuffer     = HV_TRUE;
    pstVideoConfigParams->stFrameBufferCfg.bUseCompress        = HV_TRUE;
    pstVideoConfigParams->enDataPathMode                       = DATA_PATH_MODE_COMPRESS_COLORFORMAT_YUV444;
    pstVideoConfigParams->stFrameBufferCfg.ucFrameBufferNumber = 2;
    pstVideoConfigParams->stFrameBufferCfg.enFBColorFormat     = ColorFormatType_RGB;
    pstVideoConfigParams->stFrameBufferCfg.enFBColorDepth      = ColorDepthType_8Bit;
    pstVideoConfigParams->stFrameBufferCfg.enCompressRatio     = COMPRESS_RATIO_TWO_POINT_FIVE;

    pstVideoConfigParams->enAspectRatio                        = OUTPUTRATIO_AUTO;
    pstVideoConfigParams->bHdrSwitch                           = HV_TRUE;
    //pstVideoConfigParams->enSpecResType                        = SPECIAL_RESOLUTION_NORMAL;
    pstVideoConfigParams->bConfigValid                         = HV_FALSE;


    pstVideoTiming->usHTotal  = stPanelParam.usPanelHtotalType;
    pstVideoTiming->usVTotal  = stPanelParam.usPanelVtotalType;
    pstVideoTiming->usHActive = stPanelParam.usPanelHactive;
    pstVideoTiming->usVActive = stPanelParam.usPanelVactive;

    pstVideoTiming->usFrameRate = stPanelParam.usPanelFrameRateType;
    pstVideoTiming->uiRxDpllSetFreqKHz = ((UINT32)stPanelParam.usPanelHtotalType) * ((UINT32)stPanelParam.usPanelVtotalType) * ((UINT32)stPanelParam.usPanelFrameRateType);

    return;
}

Status Hv_Mw_Video_DataPathReconfig(VOID)
{
    SystemEvent stSystemEvent = {0};
    HV_VOS_QUEUE_S* xSystembQueue = Hv_Mw_System_GetSystemQueue();
    HV_ASSERT_VALID_PTR(xSystembQueue);
    stSystemEvent.enEventType = SYSTEM_REV_EVENT_TYPE_OSD_SETTING;
    stSystemEvent.usEventId = SETTING_PARAM_ID_DATA_PATH_RECONFIG;
    stSystemEvent.uiValue = 0;
    HV_ASSERT_TRUE(Hv_Vos_QueueSend(xSystembQueue, (void *)&stSystemEvent));
    return HV_SUCCESS;
}

#ifdef HV_SCALER_DEBUG_VERSION
VOID ForceDataPathUsingDebugMode(DisplayDataPathMode* penBestDisplayDataPathMode, DisplayTimingMode* penDisplayTimingMode)
{
    UCHAR8 ucCurrentForceMode = HV_COMMON_DATABASE_GET(DiagData, stDisplayDebug.ucVideoDataPathMode);
    switch (ucCurrentForceMode)
    {
        case 0:
        {
            /*close 无需处理*/
            break;
        }
        case 1:
        {
            /*framesync模式*/
            *penBestDisplayDataPathMode = DATA_PATH_MODE_FRAMESYNC;
            *penDisplayTimingMode = DIS_TIMING_MODE_FRAMESYNC;
            break;
        }
        case 2:
        {
            /*frc-throught-ddr YUV444*/
            *penBestDisplayDataPathMode = DATA_PATH_MODE_THROUGH_COLORFORMAT_YUV444;
            *penDisplayTimingMode = DIS_TIMING_MODE_FREE_RUN;
            break;
        }
        case 3:
        {
            /*frc-throught-ddr YUV422*/
            *penBestDisplayDataPathMode = DATA_PATH_MODE_THROUGH_COLORFORMAT_YUV422;
            *penDisplayTimingMode = DIS_TIMING_MODE_FREE_RUN;
            break;
        }
        case 4:
        {
            /*frc-throught-ddr YUV420*/
            *penBestDisplayDataPathMode = DATA_PATH_MODE_THROUGH_COLORFORMAT_YUV420;
            *penDisplayTimingMode = DIS_TIMING_MODE_FREE_RUN;
            break;
        }
        case 5:
        {
            /*KTX*/
            *penBestDisplayDataPathMode = DATA_PATH_MODE_THROUGH_COLORFORMAT_YUV422;
            *penDisplayTimingMode = DIS_TIMING_MODE_TCON;
            break;
        }
        case 6:
        {
            /*free_run_node1*/
            *penBestDisplayDataPathMode = DATA_PATH_MODE_THROUGH_COLORFORMAT_YUV422;
            *penDisplayTimingMode = DIS_TIMING_MODE_FREE_RUN_MODE1;
            break;
        }
        case 7:
        {
            /*compress yuv444*/
            *penBestDisplayDataPathMode = DATA_PATH_MODE_COMPRESS_COLORFORMAT_YUV444;
            *penDisplayTimingMode = DIS_TIMING_MODE_FREE_RUN;
            break;
        }
        case 8:
        {
            /*compress yuv422*/
            *penBestDisplayDataPathMode = DATA_PATH_MODE_COMPRESS_COLORFORMAT_YUV422;
            *penDisplayTimingMode = DIS_TIMING_MODE_FREE_RUN;
            break;
        }
        case 9:
        {
            /*compress 1.6 rx*/
            *penBestDisplayDataPathMode = DATA_PATH_MODE_COMPRESS_COLORFORMAT1_6_RX;
            *penDisplayTimingMode = DIS_TIMING_MODE_FREE_RUN;
            break;
        }
        default:
        {
            break;
        }
    }
    return;
}

static CHAR8* DatapathConvert(DisplayDataPathMode enType)
{
    CHAR8* paType[] =
    {
        "Framesync",
        "DDR pack rx",
        "DDR CPR 1.6 rx",
        "DDR CPR rx",
        "DDR pack YUV444",
        "DDR pack YUV422",
        "DDR pack YUV420",
        "DDR CPR YUV444",
        "DDR CPR YUV422",
        "DDR CPR3 YUB444",
        "DDR CPR3 YUB422",
        "DDR CPR4 YUB444",
        "DDR CPR4 YUB422",
    };
    if(enType >= sizeof(paType)/sizeof(paType[0]))
    {
        return "NULL";
    }
    else
    {
        return paType[enType];
    }
}

static CHAR8* RatioConvert(VideoRatio enType)
{
    CHAR8* paType[] =
    {
        "auto",
        "16:9",
        "4:3",
        "21:9",
        "5:3",
        "1:1",
        "16:10",
        "5:4",
    };
    if(enType >= sizeof(paType)/sizeof(paType[0]))
    {
        return "NULL";
    }
    else
    {
        return paType[enType];
    }
}

#endif

static Status CalcWhByRatio(VideoConfigParams* pstVideoConfigParams, ScalerInfo *pstScalerInfo, UCHAR8 ucIsSub)
{
    const PanelParam stPanelParam = Hv_Mw_Panel_GetCurrentPanelParam();
    UINT32 uiRatioConst = 0;
    uiRatioConst =  10000*stPanelParam.usPanelHactive / stPanelParam.usPanelVactive;
    USHORT16 usRatioW = stPanelParam.usPanelHactive;
    USHORT16 usRatioH = stPanelParam.usPanelVactive;
    USHORT16 usInputW = pstVideoConfigParams->uiInputVideoWidth;
    USHORT16 usInputH = pstVideoConfigParams->uiInputVideoHight;
    VideoRatio enRatio = pstVideoConfigParams->enAspectRatio;
    HV_LOG_DEBUG(PQ, "%d Calc input %d %d, cut %d %d ddr %d %d , out %d %d", enRatio, pstVideoConfigParams->uiInputVideoWidth, pstVideoConfigParams->uiInputVideoHight, pstVideoConfigParams->usInputCutHsize, pstVideoConfigParams->usInputCutVsize, pstVideoConfigParams->uiDdrOrWtrVideoWidth, pstVideoConfigParams->uiDdrOrWtrVideoHight, pstVideoConfigParams->uiOutputVideoWidth, pstVideoConfigParams->uiOutputVideoHight);
    RatioParam astRatioArr[OUTPUTRATIO_MAX] = 
    {
        {stPanelParam.usPanelHactive, stPanelParam.usPanelVactive},{16,9}, {4,3},{21,9},{5,3},{1,1}, {16,10},{5,4}, {stPanelParam.usPanelHactive, stPanelParam.usPanelVactive},
        /* 显示不同屏幕尺寸大小 */
        {4,3}, {4,3}, {5,4}, {16,10}, {16,9}, {16,10}, {16,9}, {16,9}, {16,9}
    };

    USHORT16 usPanelInchWidth  = HV_COMMON_DATABASE_GET_STARRAY(UserData, astPanelInch, enRatio, usPanelInchW);
    USHORT16 usPanelInchHeight = HV_COMMON_DATABASE_GET_STARRAY(UserData, astPanelInch, enRatio, usPanelInchH);
    USHORT16 usPanelRealOutWidth  = 0;
    USHORT16 usPanelRealOutHeight = 0;
    /* 如果需要显示其他尺寸的图像大小，需要计算对应尺寸的范围 */
    if ((enRatio >= OUTPUTRATIO_17INCH_4TO3) && (usPanelInchWidth!= 0) && (usPanelInchHeight != 0)
        && (stPanelParam.usPanelInchWidth != 0) && (stPanelParam.usPanelInchHeight != 0))
    {
        usPanelRealOutWidth = (USHORT16)((FLOAT32)stPanelParam.usPanelHactive * (FLOAT32)usPanelInchWidth/ (FLOAT32)stPanelParam.usPanelInchWidth + 0.5);
        usPanelRealOutHeight = (USHORT16)((FLOAT32)stPanelParam.usPanelVactive * (FLOAT32)usPanelInchHeight / (FLOAT32)stPanelParam.usPanelInchHeight + 0.5);
        usPanelRealOutWidth = usPanelRealOutWidth + usPanelRealOutWidth%2;//must be even for Width
        usPanelRealOutHeight = usPanelRealOutHeight + usPanelRealOutHeight%2;//
    }
    else
    {
        usPanelRealOutWidth = stPanelParam.usPanelHactive;
        usPanelRealOutHeight = stPanelParam.usPanelVactive;
    }

    USHORT16 usPbpMainH = 0;
    if(ucIsSub == 0)
    {
        #ifdef CONFIG_USER_DOUBLE_CHANNEL_ON
        usPbpMainH = Hv_Drv_DpuScaler_GetPbpMainWindowHSize(stPanelParam.usPanelHactive);
        #else
        usPbpMainH = stPanelParam.usPanelHactive >> 1;
        #endif
        
    }
    else
    {
        #ifdef CONFIG_USER_DOUBLE_CHANNEL_ON
        usPbpMainH = Hv_Drv_DpuScaler_GetPbpSubWindowHSize();
        #else
        usPbpMainH = stPanelParam.usPanelHactive >> 1;
        #endif
    }
    if (PXP_MODE_PBP_ENABLE == pstVideoConfigParams->enPxpMode)
    {
        usRatioW = astRatioArr[enRatio].usRatioW*1000 *usPbpMainH/stPanelParam.usPanelHactive;
        usRatioH = astRatioArr[enRatio].usRatioH*1000;
        //see we should keep W or H
        HV_LOG_DEBUG(PQ, "input %d %d %d %d", usInputW, usInputH, usPbpMainH, stPanelParam.usPanelVactive);
        if((usInputW < usPbpMainH)&&(usInputH < stPanelParam.usPanelVactive))
        {
            pstScalerInfo->usDownOutW = usInputW;
            pstScalerInfo->usDownOutH = usInputH;
            //pstScalerInfo->usUpOutW   = usInputW;
            //pstScalerInfo->usUpOutH   = usInputH;
        }
        else
        {
            if(usInputW * stPanelParam.usPanelVactive > usInputH * (usPbpMainH))//fill W
            {
                pstScalerInfo->usDownOutW = (USHORT16)((FLOAT32)usPbpMainH + 0.5);
                //pstScalerInfo->usDownOutH = (USHORT16)((FLOAT32)(stPanelParam.usPanelVactive * usInputW / (stPanelParam.usPanelHactive / 2))+ 0.5);
                pstScalerInfo->usDownOutH = (USHORT16)(((FLOAT32)(usPbpMainH)*usInputH / usInputW)+ 0.5);
                HV_LOG_DEBUG(PQ, "1calc PBP,  down Wh %d %d", pstScalerInfo->usDownOutW, pstScalerInfo->usDownOutH);
            }
            else//fill H
            {
                pstScalerInfo->usDownOutH = stPanelParam.usPanelVactive;
                pstScalerInfo->usDownOutW = (USHORT16)((FLOAT32)(stPanelParam.usPanelVactive*usInputW/usInputH));
                HV_LOG_DEBUG(PQ, "2calc PBP,  down Wh %d %d", pstScalerInfo->usDownOutW, pstScalerInfo->usDownOutH);
            }
        }
        HV_LOG_DEBUG(PQ, "1input %d %d ", pstScalerInfo->usDownOutH, pstScalerInfo->usDownOutW);
        ////PBP scaledown out_W max Panel_H/2
        //if(usInputW < stPanelParam.usPanelHactive / 2)
        //{
        //    pstScalerInfo->usDownOutW = usInputW;
        //}
        //else
        //{
        //    pstScalerInfo->usDownOutW = stPanelParam.usPanelHactive / 2;
        //}
        //if(usInputH > stPanelParam.usPanelHactive)
        //{
        //    pstScalerInfo->usDownOutH  = stPanelParam.usPanelHactive;
        //}
        //else
        //{
        //    //get scaledown out_H by ratio 
        //    pstScalerInfo->usDownOutH  = pstScalerInfo->usDownOutW * usInputH / usInputW;
        //}
        
        return HV_SUCCESS;
    }
    else if(PXP_MODE_PIP_ENABLE == pstVideoConfigParams->enPxpMode)
    {
        //ignore when pip mode
        pstScalerInfo->usDownOutW = usInputW;
        pstScalerInfo->usDownOutH = usInputH;
        pstScalerInfo->usUpOutW   = usInputW;
        pstScalerInfo->usUpOutH   = usInputH;
        if ((enRatio == OUTPUTRATIO_1TO1) && (usInputH < stPanelParam.usPanelVactive))
        {
            /* 1:1输出时，输入的高小于输出的高，需要进入FRC模式 */
            pstVideoConfigParams->bForceFrc = HV_TRUE;
        }
        HV_LOG_DEBUG(PQ, "calc PiP,  down Wh %d %d", pstScalerInfo->usDownOutW, pstScalerInfo->usDownOutH);
        HV_LOG_DEBUG(PQ, "calc PiP,  up Wh %d %d", pstScalerInfo->usUpOutW, pstScalerInfo->usUpOutH);
        return HV_SUCCESS;
    }
    else//normal mode
    {
        usRatioW = astRatioArr[enRatio].usRatioW;
        usRatioH = astRatioArr[enRatio].usRatioH;
        HV_LOG_DEBUG(PQ, "NORMAL %d %d", usRatioW, usRatioH);
    }
    /*insert black top and bottom, switch to FRC mode*/
    if((enRatio == OUTPUTRATIO_21TO9) ||(enRatio >= OUTPUTRATIO_17INCH_4TO3))
    {
        pstVideoConfigParams->bForceFrc = HV_TRUE;
    }
    else if ((enRatio == OUTPUTRATIO_1TO1) && (usInputH < stPanelParam.usPanelVactive))
    {
        /* 1:1输出时，输入的高小于输出的高，需要进入FRC模式 */
        pstVideoConfigParams->bForceFrc = HV_TRUE;
    }
    else if((enRatio == OUTPUTRATIO_16TO9) && ((stPanelParam.usPanelHactive*9) < (stPanelParam.usPanelVactive*16)))
    {   //Ratio 16:9, In case Panel is not 16:9
        pstVideoConfigParams->bForceFrc = HV_TRUE;
    }
    else
    {

    }

    if (OUTPUTRATIO_1TO1 == enRatio)
    {
        UINT32 uiW = 0;
        UINT32 uiH = 0;
        if(PXP_MODE_PBP_ENABLE == pstVideoConfigParams->enPxpMode)
        {
            uiW = stPanelParam.usPanelHactive >> 1;
            uiH = stPanelParam.usPanelVactive;
        }
        else
        {
            uiW = stPanelParam.usPanelHactive;
            uiH = stPanelParam.usPanelVactive;
        }

        /*if input > display area, ignore 1:1, set full screen*/
        if ((usInputW >  uiW) || (usInputH > uiH))
        {
            //based on pbp or other
            if(PXP_MODE_PBP_ENABLE == pstVideoConfigParams->enPxpMode)
            {
                usRatioW = stPanelParam.usPanelHactive >> 1;
            }
            else
            {
                usRatioW = stPanelParam.usPanelHactive;
            }
            usRatioH = stPanelParam.usPanelVactive;
        }
        else if(uiH > usInputH)
        {
            usRatioW = 0;
            usRatioH = 0;
            pstVideoConfigParams->bForceFrc = HV_TRUE;
        }
        //1:1
        else
        {
            usRatioW = 0;
            usRatioH = 0;
        }
    }
    else if(OUTPUTRATIO_AUTO == enRatio)
    {
        usRatioW  = usInputW;
        usRatioH  = usInputH;
        if (pstVideoConfigParams->bInterlacedMode)
        {
            usRatioH  = usInputH << 1;
            if((stPanelParam.usPanelHactive * usRatioH) < (stPanelParam.usPanelVactive * usRatioW))/*insert black top and bottom, switch to FRC mode*/
            {
                pstVideoConfigParams->bForceFrc = HV_TRUE;
                HV_LOG_INFO(VIDEO, "Interlaced need insert black top and bottom, switch to cpr mode");
            }
        }
        else
        {
            if ((stPanelParam.usPanelHactive * usRatioH) < (stPanelParam.usPanelVactive * usRatioW))/*insert black top and bottom, switch to FRC mode*/
            {
                pstVideoConfigParams->bForceFrc = HV_TRUE;
                HV_LOG_INFO(VIDEO, "need insert black top and bottom, switch to cpr mode");
            }
        }
    }
    HV_LOG_DEBUG(VIDEO, "Ratio %u : %u", usRatioW, usRatioH);
    //ratio NOT 1:1
    if ((usRatioW + usRatioH) != 0)
    {
        UINT32 uiPh = 0;
        UINT32 uiPv = 0;
        if (PXP_MODE_PBP_ENABLE == pstVideoConfigParams->enPxpMode)
        {
            uiPh = usPanelRealOutWidth / 2; 
        }
        else
        {
            uiPh = usPanelRealOutWidth; 
        }
        HV_LOG_DEBUG(VIDEO, "h %d %d W %u  %u", usInputH, usPanelRealOutHeight, usInputW, uiPh);
        /* 输入大小小于输出大小，需要看当前缩放比例 */
        if ((usInputH < usPanelRealOutHeight) && (usInputW < uiPh))
        {
            HV_LOG_DEBUG(VIDEO, "<<<< %d %d ", usInputW, usInputH);
            if((enRatio == OUTPUTRATIO_AUTO)||(enRatio == OUTPUTRATIO_16TO9))//不需要放大时候比例切换
            {
                pstScalerInfo->usDownOutW = usInputW;
                pstScalerInfo->usDownOutH = usInputH;
            }
            else//放大模块要求，输入必须小于输出
            {
                pstScalerInfo->usDownOutW = usInputW;
                pstScalerInfo->usDownOutH = usInputH;
                if((usInputW > usPanelRealOutHeight*usRatioW/usRatioH)&&(usRatioW*10000/usRatioH < uiRatioConst))//4:3 etc
                {
                    pstScalerInfo->usDownOutW = (USHORT16)((FLOAT32)usPanelRealOutHeight*usRatioW/usRatioH + 0.5);
                    pstScalerInfo->usDownOutW = pstScalerInfo->usDownOutW + pstScalerInfo->usDownOutW%2;
                }
                if((usInputH > uiPh* usRatioH/usRatioW)&&(usRatioW*10000/usRatioH > uiRatioConst))//21:9
                {
                    pstScalerInfo->usDownOutH = (USHORT16)((FLOAT32)uiPh* usRatioH/usRatioW + 0.5);
                    pstScalerInfo->usDownOutH = pstScalerInfo->usDownOutH + pstScalerInfo->usDownOutH%2;
                }
                HV_LOG_DEBUG(VIDEO, "%d %d ", pstScalerInfo->usDownOutH, pstScalerInfo->usDownOutW);
            }
        }
        else
        {
            HV_LOG_DEBUG(VIDEO, ">>>> %d %d ", usInputW, usInputH);
            if(usRatioW * usPanelRealOutHeight > usRatioH * uiPh)//H方向需要缩小
            {
                pstScalerInfo->usDownOutW = uiPh;
                pstScalerInfo->usDownOutH = (USHORT16)((FLOAT32)uiPh * usRatioH / usRatioW + 0.5);

            }
            else//W方向需要缩小
            {
                pstScalerInfo->usDownOutW = (USHORT16)((FLOAT32)usPanelRealOutHeight * usRatioW / usRatioH + 0.5);
                pstScalerInfo->usDownOutH = usPanelRealOutHeight;

            }
            if(pstScalerInfo->usDownOutW > usInputW)
            {
                pstScalerInfo->usDownOutW = usInputW;
            }
            if(pstScalerInfo->usDownOutH > usInputH)
            {
                pstScalerInfo->usDownOutH = usInputH;
            }
            pstScalerInfo->usDownOutW = pstScalerInfo->usDownOutW + pstScalerInfo->usDownOutW%2;//keep it even
            pstScalerInfo->usDownOutH = pstScalerInfo->usDownOutH + pstScalerInfo->usDownOutH%2;//keep it even

        }
        HV_LOG_DEBUG(VIDEO, "usDownOutW %d usDownOutH %d", pstScalerInfo->usDownOutW, pstScalerInfo->usDownOutH);
    }
    else/*Ratio 1:1*/
    {
        pstScalerInfo->usDownOutW = usInputW + usInputW%2;
        pstScalerInfo->usDownOutH = usInputH + usInputH%2;
        pstScalerInfo->usUpOutW   = usInputW;
        pstScalerInfo->usUpOutH   = usInputH;
    }
    return HV_SUCCESS;
}

static VOID CalcMainFrameBufferResolutionSize(VideoConfigParams* pstVideoConfigParams, const VideoTimingParam* pstVideoTiming)
{
    USHORT16 usMaxMainFbHsize = HV_COMMON_DATABASE_GET(DiagData, stDisplayDebug.usMaxMainFrameBufferHsize);
    USHORT16 usMaxMainFBVsize = HV_COMMON_DATABASE_GET(DiagData, stDisplayDebug.usMaxMainFrameBufferVsize);
    const PanelParam stPanelParam = Hv_Mw_Panel_GetCurrentPanelParam();
    ScalerInfo stScalerInfo = {0};
    HV_LOG_INFO(VIDEO, "usMaxMainFbHsize = %u,usMaxMainFBVsize = %u", usMaxMainFbHsize,usMaxMainFBVsize);
    
    CalcWhByRatio(pstVideoConfigParams, &stScalerInfo, 0);
    HV_LOG_DEBUG(VIDEO, "Width = %u, Hight = %u after calc by ratio %s", stScalerInfo.usDownOutW, stScalerInfo.usDownOutH,RatioConvert(pstVideoConfigParams->enAspectRatio));
    HV_LOG_DEBUG(VIDEO, " %d %d ", pstVideoTiming->usHActive, pstVideoTiming->usVActive);
    
    if(PXP_MODE_PBP_ENABLE == pstVideoConfigParams->enPxpMode)
    {
        #ifdef CONFIG_USER_DOUBLE_CHANNEL_ON
        USHORT16 usPbpMianWindowHSize = Hv_Drv_DpuScaler_GetPbpMainWindowHSize(stPanelParam.usPanelHactive);
        #else
        USHORT16 usPbpMianWindowHSize = stPanelParam.usPanelHactive >> 1;
        #endif
        /*ddr最多支持1920*1080，过DDR之前cap只能做scaler down相对于DDR.*/
        if (pstVideoTiming->usHActive > MIN(MIN(usMaxMainFbHsize, usPbpMianWindowHSize), stScalerInfo.usDownOutW))
        {
            pstVideoConfigParams->uiDdrOrWtrVideoWidth = MIN(MIN(usMaxMainFbHsize, usPbpMianWindowHSize),stScalerInfo.usDownOutW);
            pstVideoConfigParams->bHorizontalNeedScaler = HV_TRUE;
        }
        else
        {
            pstVideoConfigParams->uiDdrOrWtrVideoWidth = pstVideoTiming->usHActive;
            pstVideoConfigParams->bHorizontalNeedScaler = HV_FALSE;
        }
        /*PBP模式V方向最大值默认是PANEL_V_ACTIVE*/
        if (pstVideoTiming->usVActive > MIN(MIN(usMaxMainFBVsize, stPanelParam.usPanelVactive), stScalerInfo.usDownOutH))
        {
            pstVideoConfigParams->uiDdrOrWtrVideoHight = MIN(MIN(usMaxMainFBVsize, stPanelParam.usPanelVactive),stScalerInfo.usDownOutH);
            pstVideoConfigParams->bVerticalNeedScaler = HV_TRUE;
        }
        else
        {
            pstVideoConfigParams->uiDdrOrWtrVideoHight = pstVideoTiming->usVActive;
            pstVideoConfigParams->bVerticalNeedScaler = HV_FALSE;
        }

        HV_LOG_DEBUG(VIDEO, "ddr Hight = %u width %u", pstVideoConfigParams->uiDdrOrWtrVideoHight, pstVideoConfigParams->uiDdrOrWtrVideoWidth);
    }
    else/*pip和正常模式都是全屏*/
    {
        UINT32 uiDdrHactiveTemp = stPanelParam.usPanelHactive;
        UINT32 uiDdrVactiveTemp = stPanelParam.usPanelVactive;
        if (HV_TRUE == HV_COMMON_DATABASE_GET(UserData, ucProEsportSwitch))
        {
            uiDdrHactiveTemp = HV_COMMON_DATABASE_GET(UserData, usProEsportHSize);
            uiDdrVactiveTemp = HV_COMMON_DATABASE_GET(UserData, usProEsportVSize);
        }
        if (pstVideoTiming->usHActive > MIN(MIN(usMaxMainFbHsize, uiDdrHactiveTemp), stScalerInfo.usDownOutW))
        {
            pstVideoConfigParams->uiDdrOrWtrVideoWidth = MIN(MIN(usMaxMainFbHsize, uiDdrHactiveTemp), stScalerInfo.usDownOutW);
            pstVideoConfigParams->bHorizontalNeedScaler = HV_TRUE;
        }
        else
        {
            pstVideoConfigParams->uiDdrOrWtrVideoWidth = pstVideoTiming->usHActive;
            pstVideoConfigParams->bHorizontalNeedScaler = HV_FALSE;
        }

        if (pstVideoTiming->usVActive > MIN(MIN(usMaxMainFBVsize, uiDdrVactiveTemp), stScalerInfo.usDownOutH))
        {
            pstVideoConfigParams->uiDdrOrWtrVideoHight = MIN(MIN(usMaxMainFBVsize, uiDdrVactiveTemp), stScalerInfo.usDownOutH);
            pstVideoConfigParams->bVerticalNeedScaler = HV_TRUE;
        }
        else
        {
            pstVideoConfigParams->uiDdrOrWtrVideoHight = pstVideoTiming->usVActive;
            pstVideoConfigParams->bVerticalNeedScaler = HV_FALSE;
        }
    }
#if (HV_CONFIG_ON == HV_PROJECT_CONFIG_MAIN_MONTAGE)
    if(HV_COMMON_DATABASE_GET(UserData, bMainMontageSw))
    {
        pstVideoConfigParams->uiDdrOrWtrVideoWidth = HV_COMMON_DATABASE_GET(UserData, usMontageInHend) - HV_COMMON_DATABASE_GET(UserData, usMontageInHsta);
        pstVideoConfigParams->bHorizontalNeedScaler = HV_FALSE;
        pstVideoConfigParams->uiDdrOrWtrVideoHight = HV_COMMON_DATABASE_GET(UserData, usMontageInVend) - HV_COMMON_DATABASE_GET(UserData, usMontageInVsta);
        pstVideoConfigParams->bVerticalNeedScaler = HV_FALSE;
    }
#endif
    HV_LOG_DEBUG(VIDEO, "main S-down H=%u, V=%u", pstVideoConfigParams->uiDdrOrWtrVideoWidth,pstVideoConfigParams->uiDdrOrWtrVideoHight);
    return;
}

#ifdef CONFIG_USER_DOUBLE_CHANNEL_ON

VOID Hv_Mw_video_CalcMagniferDdrVideoSize(VideoConfigParams* pstVideoConfigParams)
{
    HV_ASSERT_VALID_PTR_VOID(pstVideoConfigParams);
    HV_ASSERT_TRUE_VOID(0 != pstVideoConfigParams->fMainFakeRatio);
    pstVideoConfigParams->uiDdrOrWtrVideoWidth = (UINT32)((FLOAT32)pstVideoConfigParams->usMainFakeHsize / pstVideoConfigParams->fMainFakeRatio * pstVideoConfigParams->uiInputVideoWidth / s_stVideoPanelParam.usPanelHactive);
    pstVideoConfigParams->uiDdrOrWtrVideoHight = (UINT32)((FLOAT32)pstVideoConfigParams->usMainFakeVsize / pstVideoConfigParams->fMainFakeRatio * pstVideoConfigParams->uiInputVideoHight / s_stVideoPanelParam.usPanelVactive);
    if (pstVideoConfigParams->uiDdrOrWtrVideoWidth % 2 != 0)
    {
        pstVideoConfigParams->uiDdrOrWtrVideoWidth++; // 如果不是偶数，则加1使其变为偶数，scaler不支持hactive是奇数的情况
    }
    if (pstVideoConfigParams->uiDdrOrWtrVideoHight % 2 != 0)
    {
        pstVideoConfigParams->uiDdrOrWtrVideoHight++; // 如果不是偶数，则加1使其变为偶数，scaler不支持hactive是奇数的情况
    }
    pstVideoConfigParams->bHorizontalNeedScaler = HV_FALSE;
    pstVideoConfigParams->bVerticalNeedScaler = HV_FALSE;
    return;
}

VOID Hv_Mw_video_CalcDcwDdrOrWtrSize(VideoConfigParams* pstVideoConfigParams)
{
    HV_ASSERT_VALID_PTR_VOID(pstVideoConfigParams);
    HV_ASSERT_TRUE_VOID(0 != pstVideoConfigParams->fMainFakeRatio);
    if (pstVideoConfigParams->uiInputVideoWidth > pstVideoConfigParams->usVideoPanelHactive)
    {
        /*需要先down*/
        pstVideoConfigParams->uiDdrOrWtrVideoWidth = pstVideoConfigParams->usMainFakeHsize;
        pstVideoConfigParams->bHorizontalNeedScaler = HV_TRUE;
    }
    else
    {
        pstVideoConfigParams->uiDdrOrWtrVideoWidth = (UINT32)((FLOAT32)pstVideoConfigParams->usMainFakeHsize / pstVideoConfigParams->fMainFakeRatio * pstVideoConfigParams->uiInputVideoWidth / s_stVideoPanelParam.usPanelHactive);
        pstVideoConfigParams->bHorizontalNeedScaler = HV_FALSE;
    }
    if (pstVideoConfigParams->uiInputVideoHight > pstVideoConfigParams->usVideoPanelVactive)
    {
        pstVideoConfigParams->uiDdrOrWtrVideoHight = pstVideoConfigParams->usMainFakeVsize;
        pstVideoConfigParams->bVerticalNeedScaler = HV_TRUE;
    }
    else
    {
        pstVideoConfigParams->uiDdrOrWtrVideoHight = (UINT32)((FLOAT32)pstVideoConfigParams->usMainFakeVsize / pstVideoConfigParams->fMainFakeRatio * pstVideoConfigParams->uiInputVideoHight / s_stVideoPanelParam.usPanelVactive);
        pstVideoConfigParams->bVerticalNeedScaler = HV_FALSE;
    }
    if (pstVideoConfigParams->uiDdrOrWtrVideoWidth % 2 != 0)
    {
        pstVideoConfigParams->uiDdrOrWtrVideoWidth++; // 如果不是偶数，则加1使其变为偶数，scaler不支持hactive是奇数的情况
    }
    if (pstVideoConfigParams->uiDdrOrWtrVideoHight % 2 != 0)
    {
        pstVideoConfigParams->uiDdrOrWtrVideoHight++; // 如果不是偶数，则加1使其变为偶数，scaler不支持hactive是奇数的情况
    }
    return;
}

static VOID CalcSubFrameBufferResolutionSize(VideoConfigParams* pstVideoConfigParams, const VideoTimingParam* pstVideoTiming)
{
    USHORT16 usMaxSubFbHsize = HV_COMMON_DATABASE_GET(DiagData, stDisplayDebug.usMaxPipFrameBufferHsize);
    USHORT16 usMaxSubFBVsize = HV_COMMON_DATABASE_GET(DiagData, stDisplayDebug.usMaxPipFrameBufferVsize);
    const PanelParam stPanelParam = Hv_Mw_Panel_GetCurrentPanelParam();
    ScalerInfo stScalerInfo = {0};
    if (PXP_MODE_PIP_ENABLE == pstVideoConfigParams->enPxpMode)
    {
        if (pstVideoConfigParams->bMainFakeSwitch)
        {
#if (HV_CONFIG_ON == HV_PROJECT_CONFIG_MAGNIFY)
            if (HV_FALSE != HV_COMMON_DATABASE_GET(UserData, bMagnifyGlassSw))
            {
                /*开启了放大镜 用1:1做scaler，cap后端cut*/
                Hv_Mw_video_CalcMagniferDdrVideoSize(pstVideoConfigParams);
            }
#endif
#if (HV_CONFIG_ON == HV_PROJECT_CONFIG_DPU_BRIGHT_FRAME)
            if (HV_COMMON_DATABASE_GET(UserData, bBrightFrameEn))
            {
                Hv_Mw_video_CalcDcwDdrOrWtrSize(pstVideoConfigParams);
            }
#endif
        }
        else
        {
            /*按照之前设计Sub channel ddr最多支持1920*1080，过DDR之前cap只能做scaler down相对于DDR.
            * 由于srp的scaler只能做up，所以过DRR之前的大小必须小于等于PIP的大小
            */
            USHORT16 usPipWindowHSize = 0;
            USHORT16 usPipWindowVSize = 0;
            if (PIP_SIZE_SMALL == HV_COMMON_DATABASE_GET(UserData, ucPipSize))
            {
                usPipWindowHSize =  HV_COMMON_DATABASE_GET(UserData, usPipSmallWindowHSize);
                usPipWindowVSize =  HV_COMMON_DATABASE_GET(UserData, usPipSmallWindowVSize);
            }
            else if (PIP_SIZE_MIDDLE == HV_COMMON_DATABASE_GET(UserData, ucPipSize))
            {
                usPipWindowHSize =  HV_COMMON_DATABASE_GET(UserData, usPipMiddleWindowHSize);
                usPipWindowVSize =  HV_COMMON_DATABASE_GET(UserData, usPipMiddleWindowVSize);
            }
            else
            {
                usPipWindowHSize =  HV_COMMON_DATABASE_GET(UserData, usPipBigWindowHSize);
                usPipWindowVSize =  HV_COMMON_DATABASE_GET(UserData, usPipBigWindowVSize);
            }
            if (pstVideoTiming->usHActive > MIN(usMaxSubFbHsize, usPipWindowHSize))
            {
                pstVideoConfigParams->uiDdrOrWtrVideoWidth = MIN(usMaxSubFbHsize, usPipWindowHSize);
                pstVideoConfigParams->bHorizontalNeedScaler = HV_TRUE;
            }
            else
            {
                pstVideoConfigParams->uiDdrOrWtrVideoWidth = pstVideoTiming->usHActive;
            }
            if (pstVideoTiming->usVActive > MIN(usMaxSubFBVsize, usPipWindowVSize))
            {
                pstVideoConfigParams->uiDdrOrWtrVideoHight = MIN(usMaxSubFBVsize, usPipWindowVSize);
                pstVideoConfigParams->bVerticalNeedScaler = HV_TRUE;
            }
            else
            {
                pstVideoConfigParams->uiDdrOrWtrVideoHight = pstVideoTiming->usVActive;
            }
        }
    }
    else if(PXP_MODE_PBP_ENABLE == pstVideoConfigParams->enPxpMode)
    {
        CalcWhByRatio(pstVideoConfigParams, &stScalerInfo, 1);
        HV_LOG_DEBUG(VIDEO, "SubPBP usDownOutW=%u usDownOutH=%u usUpOutW=%u usUpOutH=%u", stScalerInfo.usDownOutW , stScalerInfo.usDownOutH, stScalerInfo.usUpOutW , stScalerInfo.usUpOutH );
        HV_LOG_DEBUG(PQ, "SSUB %d %d %d %d",pstVideoTiming->usHActive, pstVideoTiming->usVActive, stPanelParam.usPanelHactive, stPanelParam.usPanelVactive);
        USHORT16 usPbpSubWindowHSize = Hv_Drv_DpuScaler_GetPbpSubWindowHSize();
        if (pstVideoTiming->usHActive > usPbpSubWindowHSize)
        {
            if(stScalerInfo.usDownOutW > usPbpSubWindowHSize)
            {
                pstVideoConfigParams->uiDdrOrWtrVideoWidth = usPbpSubWindowHSize;
            }
            else
            {
                pstVideoConfigParams->uiDdrOrWtrVideoWidth = stScalerInfo.usDownOutW;
            }
            pstVideoConfigParams->bHorizontalNeedScaler = HV_TRUE;
        }
        else
        {
            pstVideoConfigParams->uiDdrOrWtrVideoWidth = pstVideoTiming->usHActive;
            if(pstVideoConfigParams->uiDdrOrWtrVideoWidth > stScalerInfo.usDownOutW)
            {
                pstVideoConfigParams->uiDdrOrWtrVideoWidth = pstVideoTiming->usHActive;
            }
            pstVideoConfigParams->bHorizontalNeedScaler = HV_FALSE;
        }
        if (pstVideoTiming->usVActive > stPanelParam.usPanelVactive)
        {
            if(stScalerInfo.usDownOutH < pstVideoTiming->usVActive)
            {
                pstVideoConfigParams->uiDdrOrWtrVideoHight = stScalerInfo.usDownOutH;
            }
            else
            {
                pstVideoConfigParams->uiDdrOrWtrVideoHight = pstVideoTiming->usVActive;
            }

            pstVideoConfigParams->bVerticalNeedScaler = HV_TRUE;
        }
        else
        {
            if(stScalerInfo.usDownOutH < pstVideoTiming->usVActive)
            {
                pstVideoConfigParams->uiDdrOrWtrVideoHight = stScalerInfo.usDownOutH;
            }
            else
            {
                pstVideoConfigParams->uiDdrOrWtrVideoHight = pstVideoTiming->usVActive;
            }

            if(pstVideoConfigParams->uiDdrOrWtrVideoHight == pstVideoTiming->usVActive) 
            {
                pstVideoConfigParams->bVerticalNeedScaler = HV_FALSE;
            }
            else
            {
                pstVideoConfigParams->bVerticalNeedScaler = HV_TRUE;
            }
        }

    }
    else
    {
        HV_LOG_DEBUG(VIDEO, "sub pxp is close");
        /*do nothing*/
    }
    return;
}
#endif

static VOID CalcMainOutputFrameRate(VideoConfigParams* pstVideoConfigParams)
{
    const PanelParam stPanelParam = Hv_Mw_Panel_GetCurrentPanelParam();
    /*如果输入的帧率在屏幕支持的帧率范围内则使用输入的帧率作为输出的帧率，否则归一化到屏参配置的推荐帧率*/
    if ((stPanelParam.usPanelFrameRateMin <= pstVideoConfigParams->uiInputFrameRate)
    && (pstVideoConfigParams->uiInputFrameRate <= stPanelParam.usPanelFrameRateMax)
    && (OUTPUTRATIO_21TO9 != pstVideoConfigParams->enAspectRatio))
    {
        pstVideoConfigParams->uiOutputFrameRate = pstVideoConfigParams->uiInputFrameRate;
    }
    else
    {
        pstVideoConfigParams->uiOutputFrameRate = stPanelParam.usPanelFrameRateType;
    }
}

UINT32 GetMainChannelConfigedOutPutRate(VOID)
{
    const ChannelManager* pstChannelManager = Hv_Mw_Channel_GetManager();
    const PanelParam stPanelParam = Hv_Mw_Panel_GetCurrentPanelParam();
    HV_ASSERT_VALID_PTR_RET(pstChannelManager, stPanelParam.usPanelFrameRateType);

    /*如果主通道处于config态和active则说明主通道已经选择了合适的输出帧率，否则使用默认的帧率*/
    if ((CHANNEL_STATE_CONFIG == pstChannelManager->astChannelData[CHANNEL_TYPE_MAIN].enCurrentCHState)
     || (CHANNEL_STATE_ACTIVE == pstChannelManager->astChannelData[CHANNEL_TYPE_MAIN].enCurrentCHState))
    {
        return pstChannelManager->astChannelData[CHANNEL_TYPE_MAIN].stVideoConfigParams.uiOutputFrameRate;
    }
    else
    {
        return stPanelParam.usPanelFrameRateType;
    }
    return stPanelParam.usPanelFrameRateType;
}

static VOID CalcSubOutputFrameRate(VideoConfigParams* pstVideoConfigParams)
{
    pstVideoConfigParams->uiOutputFrameRate = GetMainChannelConfigedOutPutRate();
}

BOOL Hv_Mw_Video_CheckUseFrameSync(BOOL bVflipEnable, const VideoTimingParam* pstVideoTiming, const VideoConfigParams* pstVideoConfigParams)
{
    const PanelParam stPanelParam = Hv_Mw_Panel_GetCurrentPanelParam();
    HV_ASSERT_VALID_PTR(pstVideoConfigParams);
    HV_ASSERT_VALID_PTR(pstVideoTiming);
    HV_ASSERT_TRUE_RET(pstVideoConfigParams->uiInputVideoHight > 0, HV_FALSE);
    HV_ASSERT_TRUE_RET(stPanelParam.usPanelVactive > 0, HV_FALSE);
    #ifdef CONFIG_USER_DOUBLE_CHANNEL_ON
    USHORT16 usPbpMianWindowHSize = Hv_Drv_DpuScaler_GetPbpMainWindowHSize(stPanelParam.usPanelHactive);
    #else
    USHORT16 usPbpMianWindowHSize = stPanelParam.usPanelHactive >> 1;
    #endif
    /*帧率允许情况下优先使用framesync模式，Vflip功能需要使用DDR才能工作*/
    if ((stPanelParam.usPanelFrameRateMin <= pstVideoTiming->usFrameRate) 
        && (pstVideoTiming->usFrameRate <= stPanelParam.usPanelFrameRateMax)
        && (HV_FALSE == bVflipEnable)
        && (OUTPUTRATIO_21TO9 != pstVideoConfigParams->enAspectRatio))
    {
        /*PBP模式下的主通道，如果RX timing的比例不等于PANEL_H_ACTIVE/2 : PANEL_V_ACTIVE，则进入FRC模式*/
        if (PXP_MODE_PBP_ENABLE == pstVideoConfigParams->enPxpMode)
        {
            if ((FLOAT32)pstVideoConfigParams->uiInputVideoWidth / pstVideoConfigParams->uiInputVideoHight != (FLOAT32)usPbpMianWindowHSize / stPanelParam.usPanelVactive)
            {
                HV_LOG_INFO(VIDEO, "PBP not point to point, need entery FRC");
                return HV_FALSE;
            }
            return HV_TRUE;
        }
        return HV_TRUE;
    }
    else
    {
        HV_LOG_INFO(VIDEO, "FRC mode, video timing frame rate:%u, bVflipEnable:%u", pstVideoTiming->usFrameRate, bVflipEnable);
        return HV_FALSE;
    }
}

/*Find sub channel data path*/
static DisplayDataPathMode FindSubDataPathMode(const VideoConfigParams* pstVideoConfigParams)
{
    DisplayDataPathMode enSubChannelDataPathMode = DATA_PATH_MODE_THROUGH_COLORFORMAT_YUV444;
    switch (pstVideoConfigParams->stColor.eClrFormat)
    {
        case ColorFormatType_YCbCr444:
        case ColorFormatType_RGB:
        {
            enSubChannelDataPathMode = DATA_PATH_MODE_THROUGH_COLORFORMAT_YUV444;
            break;
        }

        case ColorFormatType_YCbCr422:
        {
            enSubChannelDataPathMode = DATA_PATH_MODE_THROUGH_COLORFORMAT_YUV422;
            break;
        }

        case ColorFormatType_YCbCr420:
        {
            enSubChannelDataPathMode = DATA_PATH_MODE_THROUGH_COLORFORMAT_YUV420;
            break;
        }

        default:
        {
            enSubChannelDataPathMode = DATA_PATH_MODE_THROUGH_COLORFORMAT_YUV444;
            break;
        }

    }
#ifdef  CONFIG_USER_PANEL_RESOLUTION_TYPE_UHD
    if (PXP_MODE_PIP_ENABLE == pstVideoConfigParams->enPxpMode)
    {
        enSubChannelDataPathMode = DATA_PATH_MODE_THROUGH_COLORFORMAT_YUV422;
    }
#endif
    return enSubChannelDataPathMode;
}

/*Find Suitable DataPath Mode By Limited BandWith And Memory*/
DisplayDataPathMode FindMainDataPathMode(VideoConfigParams* pstVideoConfigParams)
{
    UINT32 uiMainTotalVideoBW = 0;
    UINT32 uiMainTotalMemory = 0;
    UINT32 uiPxlBits = 0;
    UINT32 uiMainWriteBW = 0;
    UINT32 uiMainReadBW = 0;

    UINT32 uiSubPxlBits = 0;
    UINT32 uiSubWriteBW = 0;
    UINT32 uiSubReadBW = 0;

    UINT32 uiSystemRemainBW = 0;
    UINT32 uiSystemRemainMemory = 0;

    BOOL bDdrSizePass = 0;
    MainCprDrrAddr stMainCprDrrAddr = {0};
    if (ColorFormatType_YCbCr420 == pstVideoConfigParams->stColor.eClrFormat)
    {
        /*cpr不支持420模式（有条件支持），所有420frc直接走422cpr或者420 pack，如果还存在放大镜可能带宽不够（422cpr是带宽最佳选择）*/
        HV_LOG_INFO(VIDEO, "input 420 FRC，422 cpr is beast sel");
        pstVideoConfigParams->uiSubChannelUsedMemory = Hv_Mw_Video_EstimateSubChannelMemSize(pstVideoConfigParams->enPxpMode);
        return DATA_PATH_MODE_COMPRESS_COLORFORMAT_YUV422;
    }
    const PanelParam stPanelParam = Hv_Mw_Panel_GetCurrentPanelParam();
#ifdef CONFIG_USER_DOUBLE_CHANNEL_ON
    USHORT16 usPbpSubWindowHSize = Hv_Drv_DpuScaler_GetPbpSubWindowHSize();
#else
    USHORT16 usPbpSubWindowHSize = stPanelParam.usPanelHactive >> 1;
#endif
    for (USHORT16 usLoopIndex = 0; usLoopIndex < ARRAY_SIZE(s_stDataPathSearchTabkeByEffect); ++usLoopIndex)
    {
        const DataPathSearchElem* pstElem = &s_stDataPathSearchTabkeByEffect[usLoopIndex];
        ColorFormatType enColorFormatType = pstVideoConfigParams->stColor.eClrFormat;
        if (pstElem->enDataPathMode > DATA_PATH_MODE_COMPRESS_COLORFORMAT_RX)
        {
            enColorFormatType = pstElem->enColorFormat;
        }
        uiPxlBits = Hv_Drv_DpuScaler_GetPxlBits(enColorFormatType, pstVideoConfigParams->stColor.eClrDepth);
        uiMainWriteBW = (((UINT64)pstVideoConfigParams->uiInputFrameRate * uiPxlBits * pstVideoConfigParams->uiInputVideoWidth * pstVideoConfigParams->uiInputVideoVtotal) /1000 / 1000) * 10 / pstElem->enCompressRatio; 
        uiMainReadBW = (((UINT64)stPanelParam.usPanelFrameRateType * uiPxlBits * pstVideoConfigParams->uiOutputVideoWidth * pstVideoConfigParams->uiOutputVideoVtotal) /1000 / 1000) * 10 / pstElem->enCompressRatio;
        uiMainTotalVideoBW = uiMainWriteBW + uiMainReadBW;
        uiMainTotalMemory = ((UINT64)pstVideoConfigParams->stFrameBufferCfg.ucFrameBufferNumber * ((UINT64)uiPxlBits * pstVideoConfigParams->uiInputVideoWidth * pstVideoConfigParams->uiInputVideoHight >> 3)) * 10 / pstElem->enCompressRatio;

        /*如果开启了PxP模式要加上辅通道的带宽, 为了辅通道切换timing 不影响主通道的显示辅助通道预留规格的最大值，放大镜开的情况下按照PIP预留*/
        uiSubPxlBits = Hv_Drv_DpuScaler_GetPxlBits(ColorFormatType_YCbCr444, ColorDepthType_10Bit);
        if(PXP_MODE_PBP_ENABLE == pstVideoConfigParams->enPxpMode)/*PBP */
        {
            uiSubWriteBW = ((UINT64)stPanelParam.usPanelFrameRateType * uiSubPxlBits * usPbpSubWindowHSize * stPanelParam.usPanelVtotalType) /1000 / 1000; 
            uiSubReadBW = ((UINT64)stPanelParam.usPanelFrameRateType * uiSubPxlBits * usPbpSubWindowHSize * stPanelParam.usPanelVtotalType) /1000 / 1000;
        }
        else
        {
            /*给PIP和放大镜关的情况下预留放大镜的地址*/
            uiSubWriteBW = ((UINT64)stPanelParam.usPanelFrameRateType * uiSubPxlBits * (stPanelParam.usPanelHactive / 2) * (stPanelParam.usPanelVtotalType / 2)) /1000 / 1000; 
            uiSubReadBW = ((UINT64)stPanelParam.usPanelFrameRateType * uiSubPxlBits * (stPanelParam.usPanelHactive / 2) * (stPanelParam.usPanelVtotalType / 2)) /1000 / 1000;
        }
        pstVideoConfigParams->uiSubChannelUsedMemory = Hv_Mw_Video_EstimateSubChannelMemSize(pstVideoConfigParams->enPxpMode);
#ifdef CONFIG_USER_DOUBLE_CHANNEL_ON
        uiMainTotalVideoBW += (uiSubWriteBW + uiSubReadBW);
        uiMainTotalMemory += pstVideoConfigParams->uiSubChannelUsedMemory;
#endif
        uiSystemRemainBW = Hv_Board_Memory_RemainBandForFRC(stPanelParam.usPanelFrameRateType);
        uiSystemRemainMemory = Hv_Board_Memory_RemainSizeForFRC();

        bDdrSizePass = Hv_Cal_DpuScaler_MainCprDdrAddr(pstVideoConfigParams, &stMainCprDrrAddr);
        HV_LOG_INFO(VIDEO, "Mode=%u, CF=%u, VBW = %u Mbits/s,RBWitdth = %u Mbits/s,VM = %u bytes,RM = %u bytes, bDdrSizePass = %u", 
                           pstElem->enDataPathMode, enColorFormatType, uiMainTotalVideoBW, uiSystemRemainBW, uiMainTotalMemory, uiSystemRemainMemory, bDdrSizePass); 
        if ((uiMainTotalVideoBW <= uiSystemRemainBW) && (uiMainTotalMemory <= uiSystemRemainMemory) && bDdrSizePass)
        {
            return pstElem->enDataPathMode;
        }

    }
    return DATA_PATH_MODE_COMPRESS_COLORFORMAT_YUV422;
}

UINT32 Hv_Mw_Video_EstimateSubChannelMemSize(PxpMode enPxpMode)
{
    UINT32 uiSubSize = 0;
#ifdef CONFIG_USER_DOUBLE_CHANNEL_ON
    USHORT16 usPbpSubWindowHSize = Hv_Drv_DpuScaler_GetPbpSubWindowHSize();
    const PanelParam stPanelParam = Hv_Mw_Panel_GetCurrentPanelParam();
    UINT32 uiSubPxlBits = Hv_Drv_DpuScaler_GetPxlBits(ColorFormatType_YCbCr444, ColorDepthType_10Bit);
    UINT32 uiWidthScf = usPbpSubWindowHSize + usPbpSubWindowHSize % 2;
    UINT32 uiBusBits = 128; //固定值
    UINT32 uiColDatNum = ROUND_DIV(uiWidthScf * uiSubPxlBits, uiBusBits);
    /*reg_dm_rd_col_step = reg_dm_rd_col_dat_num * iBusBits / 8*/
    UINT32 uiColStep = uiColDatNum * uiBusBits >> 3;
    #if (HV_CONFIG_ON == HV_PROJECT_CONFIG_DPU_BRIGHT_FRAME)
    if (HV_TRUE == HV_COMMON_DATABASE_GET(UserData, bBrightFrameEn))
    {
        #ifdef  CONFIG_USER_PANEL_RESOLUTION_TYPE_UHD
        uiSubPxlBits = Hv_Drv_DpuScaler_GetPxlBits(ColorFormatType_YCbCr444, ColorDepthType_8Bit);  /* UHD FRC 2buf 10bit时ddr size不够，UHD 10Bbit Main FRC下不支持开BF */
        #endif
        uiSubSize = (UINT64)2 * uiSubPxlBits * usPbpSubWindowHSize * stPanelParam.usPanelVactive >> 3;
        return uiSubSize;
    }
    else
    {
        if(PXP_MODE_PBP_ENABLE == enPxpMode)/*PBP */
        {
            uiSubSize = (UINT64)2 * uiColStep * stPanelParam.usPanelVactive;
        }
        else
        {
            /*给PIP和放大镜关的情况下预留放大镜的地址*/
            uiSubSize = (UINT64)2 * uiColStep * (stPanelParam.usPanelVactive / 2);
        }
    }
    #else
    if(PXP_MODE_PBP_ENABLE == enPxpMode)/*PBP */
    {
        uiSubSize = (UINT64)2 * uiColStep * stPanelParam.usPanelVactive;
    }
    else
    {
        /*给PIP和放大镜关的情况下预留放大镜的地址*/
        uiSubSize = (UINT64)2 * uiColStep * (stPanelParam.usPanelVactive / 2);
    }
    #endif
#endif
    return uiSubSize;
}

static VOID SelectDisplayDataPathMode(ChannelData* pstChannelData, VideoConfigParams* pstVideoConfigParams,
        const VideoTimingParam* pstVideoTiming)
{
    DisplayDataPathMode enBestDisplayDataPathMode = DATA_PATH_MODE_FRAMESYNC;
    ChannelType enChannelType = pstChannelData->enChannelType;
    const PanelParam stPanelParam = Hv_Mw_Panel_GetCurrentPanelParam();
    if (CHANNEL_TYPE_MAIN == enChannelType)
    {
#if (HV_CONFIG_ON == HV_PROJECT_CONFIG_CHANNEL_SEAMLESS_SWITCH)
        pstVideoConfigParams->bForceFrc = HV_TRUE;
#endif
#ifdef HV_SCALER_DEBUG_VERSION
        /*debug force datapath mode and timing mode*/
        if (0 != HV_COMMON_DATABASE_GET(DiagData, stDisplayDebug.ucVideoDataPathMode))
        {
            /*预留sub通道ddr*/
            pstVideoConfigParams->uiSubChannelUsedMemory = Hv_Mw_Video_EstimateSubChannelMemSize(pstChannelData->stVideoConfigParams.enPxpMode);
            ForceDataPathUsingDebugMode(&enBestDisplayDataPathMode, &pstVideoConfigParams->enTimingMode);
            //HV_COMMON_DATABASE_SET(DiagData, stDisplayDebug.ucVideoDataPathMode, 0);
            HV_LOG_INFO(VIDEO, "debug force datapath mode");
        }
        else if (HV_TRUE == pstVideoConfigParams->bForceFrc)
#else
        /*if force frc(ratio aspect 21:9 etc)*/
        if (HV_TRUE == pstVideoConfigParams->bForceFrc)
#endif
        {
            /*预留sub通道ddr*/
            pstVideoConfigParams->uiSubChannelUsedMemory = Hv_Mw_Video_EstimateSubChannelMemSize(pstChannelData->stVideoConfigParams.enPxpMode);
            enBestDisplayDataPathMode = DATA_PATH_MODE_COMPRESS_COLORFORMAT_YUV444;
            pstVideoConfigParams->enTimingMode = DIS_TIMING_MODE_FREE_RUN;
            HV_LOG_INFO(VIDEO, "dpuscl force datapath mode");
        }
        else/*auto calc datapath mode and timing mode*/
        {
            if ((pstChannelData->bOutofRangeFlag == 1) || (HV_TRUE == HV_COMMON_DATABASE_GET(UserData, ucProEsportSwitch)))
            {
                /*interlace模式硬件限制需要配置成3帧，否则画面卡顿*/
                pstVideoConfigParams->stFrameBufferCfg.ucFrameBufferNumber = pstVideoTiming->bInterlacedMode ? 3 : 2;
                /*根据带宽和内存限制，以及PXP开关等，选择出最优的DataPath类型*/
                enBestDisplayDataPathMode = FindMainDataPathMode(pstVideoConfigParams);
                pstVideoConfigParams->enTimingMode = DIS_TIMING_MODE_FREE_RUN;
                pstChannelData->bOutofRangeFlag = 0;
            }
            else
            {
                if (Hv_Mw_Video_CheckUseFrameSync(pstVideoConfigParams->bVflipEnable, pstVideoTiming, pstVideoConfigParams))
                {
                    enBestDisplayDataPathMode = DATA_PATH_MODE_FRAMESYNC;
                    pstVideoConfigParams->enTimingMode = DIS_TIMING_MODE_FRAMESYNC;
                }
                else
                {
                    /*interlace模式硬件限制需要配置成3帧，否则画面卡顿*/
                    pstVideoConfigParams->stFrameBufferCfg.ucFrameBufferNumber = pstVideoTiming->bInterlacedMode ? 3 : 2;
                    /*根据带宽和内存限制，以及PXP开关等，选择出最优的DataPath类型*/
                    enBestDisplayDataPathMode = FindMainDataPathMode(pstVideoConfigParams);
                    pstVideoConfigParams->enTimingMode = DIS_TIMING_MODE_FREE_RUN;
                    HV_LOG_INFO(VIDEO, "FRC mod");
                }
            }
#if (HV_CONFIG_ON == HV_PROJECT_CONFIG_DPU_BRIGHT_FRAME)
            if (HV_TRUE == HV_COMMON_DATABASE_GET(UserData, bBrightFrameEn))
            {
                if (DATA_PATH_MODE_FRAMESYNC == enBestDisplayDataPathMode)
                {
                    /*为了同步mian和sub帧率，都走frc*/
                    enBestDisplayDataPathMode = DATA_PATH_MODE_COMPRESS_COLORFORMAT_YUV444;
                    pstVideoConfigParams->enTimingMode = DIS_TIMING_MODE_FRAMESYNC;   /*bright frame是低延迟模式，timing走frame sync*/
                    /*预留sub通道ddr，1buf可以按照10bit预留*/
                    UINT32 uiSubPxlBits = Hv_Drv_DpuScaler_GetPxlBits(ColorFormatType_YCbCr444, ColorDepthType_10Bit);
                    pstVideoConfigParams->uiSubChannelUsedMemory = (UINT64)2 * uiSubPxlBits * (stPanelParam.usPanelHactive / 2) * stPanelParam.usPanelVactive >> 3;
                    Hv_Cal_DpuScaler_SetBrightFrameLowLatency(HV_TRUE);
                    HV_LOG_INFO(VIDEO, "Bright frame, timing framesync, data cpr444");
                }
                else
                {
                    Hv_Cal_DpuScaler_SetBrightFrameLowLatency(HV_FALSE);
                }
            }
#endif
        }
#if (HV_CONFIG_ON == HV_PROJECT_CONFIG_MAIN_MONTAGE)
        if (HV_COMMON_DATABASE_GET(UserData, bMainMontageSw))
        {
            enBestDisplayDataPathMode = FindMainDataPathMode(pstVideoConfigParams);
            pstVideoConfigParams->enTimingMode = DIS_TIMING_MODE_FREE_RUN;
        }
#endif
        if (pstVideoConfigParams->enTimingMode == DIS_TIMING_MODE_FREE_RUN)
        {
            pstVideoConfigParams->uiOutputFrameRate = stPanelParam.usPanelFrameRateType;
        }
    }
    else/*Sub通道*/
    {
        /*IP 对于sub通道仅支持frc模式，interlace模式硬件限制需要配置成3帧，否则画面卡顿*/
        pstVideoConfigParams->stFrameBufferCfg.ucFrameBufferNumber = pstVideoTiming->bInterlacedMode ? 3 : 2;
        /*SUB通道colorformat优先使用RX原始颜色格式，如果是UHD的屏则固定YUV422过DDR*/
        enBestDisplayDataPathMode = FindSubDataPathMode(pstVideoConfigParams);
        pstVideoConfigParams->enTimingMode = DIS_TIMING_MODE_FREE_RUN;
    }
    /*framebuffer不裁剪色深,使用原始色深*/
    pstVideoConfigParams->stFrameBufferCfg.enFBColorDepth = pstVideoConfigParams->stColor.eClrDepth;
    pstVideoConfigParams->stFrameBufferCfg.bUseFrameBuffer = HV_TRUE;
    /*记录当前通路模式,driver和debug会使用.*/
    pstVideoConfigParams->enDataPathMode = enBestDisplayDataPathMode;

    HV_LOG_INFO(VIDEO, "Datapath Mode %s,%u, ChannelType: %u", DatapathConvert(enBestDisplayDataPathMode), enBestDisplayDataPathMode, pstChannelData->enChannelType);

    switch (enBestDisplayDataPathMode)
    {
        case DATA_PATH_MODE_FRAMESYNC:
        {
            pstVideoConfigParams->stFrameBufferCfg.bUseFrameBuffer = HV_FALSE;
            pstVideoConfigParams->stFrameBufferCfg.bUseCompress    = HV_FALSE;
            pstVideoConfigParams->stFrameBufferCfg.enFBColorFormat = ColorFormatType_YCbCr444;
            break;
        }
        case DATA_PATH_MODE_THROUGH_COLORFORMAT_RX:
        {
            pstVideoConfigParams->stFrameBufferCfg.bUseCompress    = HV_FALSE;
            pstVideoConfigParams->stFrameBufferCfg.enFBColorFormat = pstVideoConfigParams->stColor.eClrFormat;
            pstVideoConfigParams->stFrameBufferCfg.enCompressRatio = COMPRESS_RATIO_1;
            break;
        }
        case DATA_PATH_MODE_COMPRESS_COLORFORMAT1_6_RX:
        {
            pstVideoConfigParams->stFrameBufferCfg.bUseCompress    = HV_TRUE;
            pstVideoConfigParams->stFrameBufferCfg.enFBColorFormat = pstVideoConfigParams->stColor.eClrFormat;
            pstVideoConfigParams->stFrameBufferCfg.enCompressRatio = COMPRESS_RATIO_ONE_POINT_SIX;
            break;
        }
        case DATA_PATH_MODE_COMPRESS_COLORFORMAT_RX:
        {
            pstVideoConfigParams->stFrameBufferCfg.bUseCompress    = HV_TRUE;
            pstVideoConfigParams->stFrameBufferCfg.enFBColorFormat = pstVideoConfigParams->stColor.eClrFormat;
            pstVideoConfigParams->stFrameBufferCfg.enCompressRatio = COMPRESS_RATIO_TWO_POINT_FIVE;
            break;
        }
        case DATA_PATH_MODE_THROUGH_COLORFORMAT_YUV444:
        {
            pstVideoConfigParams->stFrameBufferCfg.bUseCompress    = HV_FALSE;
            pstVideoConfigParams->stFrameBufferCfg.enFBColorFormat = ColorFormatType_YCbCr444;
            pstVideoConfigParams->stFrameBufferCfg.enCompressRatio = COMPRESS_RATIO_1;
            break;
        }
        case DATA_PATH_MODE_THROUGH_COLORFORMAT_YUV422:
        {
            pstVideoConfigParams->stFrameBufferCfg.bUseCompress    = HV_FALSE;
            pstVideoConfigParams->stFrameBufferCfg.enFBColorFormat = ColorFormatType_YCbCr422;
            pstVideoConfigParams->stFrameBufferCfg.enCompressRatio = COMPRESS_RATIO_1;
            break;
        }
        case DATA_PATH_MODE_THROUGH_COLORFORMAT_YUV420:
        {
            pstVideoConfigParams->stFrameBufferCfg.bUseCompress    = HV_FALSE;
            pstVideoConfigParams->stFrameBufferCfg.enFBColorFormat = ColorFormatType_YCbCr420;
            pstVideoConfigParams->stFrameBufferCfg.enCompressRatio = COMPRESS_RATIO_1;
            break;
        }
        case DATA_PATH_MODE_COMPRESS_COLORFORMAT_YUV444:
        {
            pstVideoConfigParams->stFrameBufferCfg.bUseCompress    = HV_TRUE;
            pstVideoConfigParams->stFrameBufferCfg.enFBColorFormat = ColorFormatType_YCbCr444;
            pstVideoConfigParams->stFrameBufferCfg.enCompressRatio = COMPRESS_RATIO_TWO_POINT_FIVE;
            break;
        }
        case DATA_PATH_MODE_COMPRESS_COLORFORMAT_YUV422:
        {
            pstVideoConfigParams->stFrameBufferCfg.bUseCompress    = HV_TRUE;
            pstVideoConfigParams->stFrameBufferCfg.enFBColorFormat = ColorFormatType_YCbCr422;
            pstVideoConfigParams->stFrameBufferCfg.enCompressRatio = COMPRESS_RATIO_TWO_POINT_FIVE;
            break;
        }
        case DATA_PATH_MODE_COMPRESS_RATIO_3_COLORFORMAT_YUV444:
        {
            pstVideoConfigParams->stFrameBufferCfg.bUseCompress    = HV_TRUE;
            pstVideoConfigParams->stFrameBufferCfg.enFBColorFormat = ColorFormatType_YCbCr444;
            pstVideoConfigParams->stFrameBufferCfg.enCompressRatio = COMPRESS_RATIO_THREE;
            break;
        }
        case DATA_PATH_MODE_COMPRESS_RATIO_3_COLORFORMAT_YUV422:
        {
            pstVideoConfigParams->stFrameBufferCfg.bUseCompress    = HV_TRUE;
            pstVideoConfigParams->stFrameBufferCfg.enFBColorFormat = ColorFormatType_YCbCr422;
            pstVideoConfigParams->stFrameBufferCfg.enCompressRatio = COMPRESS_RATIO_THREE;
            break;
        }
        default:
        {
            break;
        }
    }
    return;
}

static VOID CalcMainOverScanTiming(ChannelData* pstChannelData, VideoConfigParams* pstVideoConfigParams, const VideoTimingParam* pstVideoTiming)
{
#if (0 != HV_PROJECT_CONFIG_DPU_OVER_SCAN_SIDE_SIZE)
    {
        const PanelParam stPanelParam = Hv_Mw_Panel_GetCurrentPanelParam();
        if (HV_TRUE == HV_COMMON_DATABASE_GET(UserData, bOverScan))
        {
            /*超vtotal或pix clk可以走frc，但是存在带宽不够问题*/
            if (DIS_TIMING_MODE_FRAMESYNC == pstVideoConfigParams->enTimingMode)
            {
                UINT32 uiPixClk = pstVideoTiming->uiFreqKHz + ((UINT32)pstVideoTiming->uiFreqKHz * 2 * HV_PROJECT_CONFIG_DPU_OVER_SCAN_SIDE_SIZE / 10000);
                if (uiPixClk > stPanelParam.uiPanelPixelClockMax)
                {
                    HV_LOG_INFO(VIDEO, "Over Scan pix clk bigger than panel max clk, frc");
                    pstChannelData->bOutofRangeFlag = HV_TRUE;
                }
                USHORT16 usTheoryVtotal = pstVideoTiming->usVTotal * stPanelParam.usPanelVactive / pstVideoTiming->usVActive;
                UINT32 uiVtotal = usTheoryVtotal + ((UINT32)usTheoryVtotal * 2 * HV_PROJECT_CONFIG_DPU_OVER_SCAN_SIDE_SIZE / 10000);
                if (uiVtotal > stPanelParam.usPanelVtotalMax)
                {
                    HV_LOG_INFO(VIDEO, "Over Scan Vtotal bigger than panel max, frc");
                    pstChannelData->bOutofRangeFlag = HV_TRUE;
                }
            }

            pstVideoConfigParams->uiInputVideoWidth = pstVideoTiming->usHActive - ((UINT32)pstVideoTiming->usHActive * 2 * HV_PROJECT_CONFIG_DPU_OVER_SCAN_SIDE_SIZE / 10000 * pstVideoTiming->usHActive / stPanelParam.usPanelHactive);
            pstVideoConfigParams->uiInputVideoHight = pstVideoTiming->usVActive - ((UINT32)pstVideoTiming->usVActive * 2 * HV_PROJECT_CONFIG_DPU_OVER_SCAN_SIDE_SIZE / 10000 * pstVideoTiming->usVActive / stPanelParam.usPanelVactive);

            pstVideoConfigParams->uiInputVideoHtotal = pstVideoTiming->usHTotal + ((UINT32)pstVideoTiming->usHTotal * 2 * HV_PROJECT_CONFIG_DPU_OVER_SCAN_SIDE_SIZE / 10000);
            pstVideoConfigParams->uiInputVideoVtotal = pstVideoTiming->usVTotal + ((UINT32)pstVideoTiming->usVTotal * 2 * HV_PROJECT_CONFIG_DPU_OVER_SCAN_SIDE_SIZE / 10000);

            pstVideoConfigParams->usInputCutHsize = pstVideoTiming->usHActive - pstVideoConfigParams->uiInputVideoWidth;
            pstVideoConfigParams->usInputCutVsize = pstVideoTiming->usVActive - pstVideoConfigParams->uiInputVideoHight;
            HV_ASSERT_TRUE_VOID(pstVideoConfigParams->usInputCutHsize > 0);
            HV_ASSERT_TRUE_VOID(pstVideoConfigParams->usInputCutVsize > 0);
            CalcMainFrameBufferResolutionSize(pstVideoConfigParams, pstVideoTiming);
            if(HV_TRUE == pstChannelData->bOutofRangeFlag)
            {
                /*重配置frc通路*/
                SelectDisplayDataPathMode(pstChannelData, &(pstChannelData->stVideoConfigParams), pstVideoTiming);
            }
        }
    }
#endif
    return;
}

#define TUNE_HVTOTAL_COUNT              (5)
#define TUNE_HVTOTAL_DCLK_TOLERANCE     (1)//Khz
#define TUNE_PANEL_DCLK_LIMIT           (1000)//Khz

static UINT32 CalcDestIDClk(USHORT16 usPanelHtotal, const VideoTimingParam* pstVideoTiming)
{
    UINT32 uiDstDclk = 0;
    const PanelParam stPanelParam = Hv_Mw_Panel_GetCurrentPanelParam();
    HV_ASSERT_TRUE_RET(pstVideoTiming->usVActive > 0, 0);
    /*Calc Display Clock*/
    uiDstDclk = (UINT64)usPanelHtotal * stPanelParam.usPanelVactive * pstVideoTiming->fFrameRate * pstVideoTiming->usVTotal / pstVideoTiming->usVActive / 1000;
    HV_LOG_DEBUG(VIDEO, "dyHtotal %u usFrameRate %u usVTotal %u uiDstDclk %u", usPanelHtotal, pstVideoTiming->usFrameRate, pstVideoTiming->usVTotal, uiDstDclk);
    return uiDstDclk;
}

static USHORT16 AutoTuneOutputHtotal(const VideoTimingParam* pstRxVideoTiming)
{
    UINT32 uiDstDclk = 0;
    UINT32 uiTuneCnt = 0;
    const PanelParam stPanelParam = Hv_Mw_Panel_GetCurrentPanelParam();
    UINT32 uiPnlPixelClkMax = stPanelParam.uiPanelPixelClockMax;
    UINT32 uiPnlPixelClkMin = stPanelParam.uiPanelPixelClockMin;
    USHORT16 usPanelHtotalTemp = stPanelParam.usPanelHtotalType;
#if (HV_CONFIG_ON == HV_PROJECT_CONFIG_OVER_PANEL_CLOCK_EN)
    if (HV_TRUE == HV_COMMON_DATABASE_GET(UserData, ucOverClocking))
    {
        uiPnlPixelClkMax += HV_PROJECT_CONFIG_OVER_PANEL_CLOCK_UP;
        uiPnlPixelClkMin -= HV_PROJECT_CONFIG_OVER_PANEL_CLOCK_DOWN;
    }
#endif
    uiPnlPixelClkMax -= TUNE_PANEL_DCLK_LIMIT;  /*保留余地*/
    uiPnlPixelClkMin += TUNE_PANEL_DCLK_LIMIT;

    while (uiTuneCnt < TUNE_HVTOTAL_COUNT)
    {
        uiDstDclk = CalcDestIDClk(usPanelHtotalTemp, pstRxVideoTiming);
        HV_ASSERT_TRUE_RET(uiDstDclk > 0, usPanelHtotalTemp);
        /* If dclk out of panel spec , then try to modify output htotal */
        if ((uiDstDclk > uiPnlPixelClkMax)
            && (ABS(uiDstDclk, uiPnlPixelClkMax) > TUNE_HVTOTAL_DCLK_TOLERANCE))
        {
            usPanelHtotalTemp = (UINT32)((UINT64)stPanelParam.usPanelHtotalType \
                                                        * uiPnlPixelClkMax / uiDstDclk);
            if (usPanelHtotalTemp < stPanelParam.usPanelHtotalMin)
            {
                usPanelHtotalTemp = stPanelParam.usPanelHtotalMin;
                break;
            }
        }
        else if ((uiDstDclk < uiPnlPixelClkMin)
                  && (ABS(uiDstDclk, uiPnlPixelClkMin) > TUNE_HVTOTAL_DCLK_TOLERANCE))
        {
            usPanelHtotalTemp = (UINT32)((UINT64)stPanelParam.usPanelHtotalType \
                                                        * uiPnlPixelClkMin / uiDstDclk);
            if (usPanelHtotalTemp > stPanelParam.usPanelHtotalMax)
            {
                usPanelHtotalTemp = stPanelParam.usPanelHtotalMax;
                break;
            }
        }
        else
        {
            /*恢复默认PanelHtotalType*/
            //usPanelHtotalTemp = stPanelParam.usPanelHtotalType;
           break;
        }
        uiTuneCnt++;
    }
    Hv_Cal_DpuScaler_DtcFrameSyncHtotal(usPanelHtotalTemp);

    if (usPanelHtotalTemp != stPanelParam.usPanelHtotalType)
    {
        HV_LOG_INFO(VIDEO, "##### Tune[%u] DHtotal %u -> %u, DstDclk:%u", uiTuneCnt, stPanelParam.usPanelHtotalType,
                                                        usPanelHtotalTemp, uiDstDclk);
    }
    return usPanelHtotalTemp;
}

static BOOL IsDtcTxTheoryVtotalInPanelSpec(const VideoTimingParam* pstVideoTiming)
{
    const PanelParam stPanelParam = Hv_Mw_Panel_GetCurrentPanelParam();
    HV_ASSERT_TRUE_RET(pstVideoTiming->usVActive > 0, HV_TRUE);
    USHORT16 usTheoryVtotal = pstVideoTiming->usVTotal * stPanelParam.usPanelVactive / pstVideoTiming->usVActive;

    if (usTheoryVtotal >= (stPanelParam.usPanelVtotalMin) && usTheoryVtotal <= (stPanelParam.usPanelVtotalMax))
    {
        return HV_TRUE;
    }
    else
    {
        HV_LOG_INFO(CHANNEL, "DTC vtotal out of range panle %u", usTheoryVtotal);
        return HV_FALSE;
    }
}

static VOID InputTimingIsOutOfPanelRange(ChannelData* pstChannelData, const VideoTimingParam* pstVideoTiming)
{
    HV_ASSERT_TRUE_VOID(pstVideoTiming->usVActive > 0);
    const PanelParam stPanelParam = Hv_Mw_Panel_GetCurrentPanelParam();
    UINT32 uiPanelClockMax = stPanelParam.uiPanelPixelClockMax;
    UINT32 uiPanelClockMin = stPanelParam.uiPanelPixelClockMin;
#if (HV_CONFIG_ON == HV_PROJECT_CONFIG_OVER_PANEL_CLOCK_EN)
    if (HV_TRUE == HV_COMMON_DATABASE_GET(UserData, ucOverClocking))
    {
        uiPanelClockMax += HV_PROJECT_CONFIG_OVER_PANEL_CLOCK_UP;
        uiPanelClockMin -= HV_PROJECT_CONFIG_OVER_PANEL_CLOCK_DOWN;
    }
#endif
    USHORT16 usDynamicPanelHtotal = stPanelParam.usPanelHtotalType;
    UINT32 uiDClockDst = CalcDestIDClk(stPanelParam.usPanelHtotalType, pstVideoTiming);
    if ((uiDClockDst < uiPanelClockMin) || (uiDClockDst > uiPanelClockMax))
    {
        /*需要调整htotal*/
        HV_LOG_INFO(VIDEO, "orang clk %u", uiDClockDst);
        usDynamicPanelHtotal =  AutoTuneOutputHtotal(pstVideoTiming);
        uiDClockDst = CalcDestIDClk(usDynamicPanelHtotal, pstVideoTiming);
        if((uiDClockDst > uiPanelClockMax) || (uiDClockDst == 0))
        {
            HV_LOG_INFO(VIDEO, "DTC pix clk %u bigger than panel max clk %u, frc mode", uiDClockDst, uiPanelClockMax);
            pstChannelData->bOutofRangeFlag = HV_TRUE;
        }
        else if (uiDClockDst < uiPanelClockMin)
        {
            HV_LOG_INFO(VIDEO, "DTC pix clk %u is smaller than panel min clk %u, frc mode", uiDClockDst, uiPanelClockMin);
            pstChannelData->bOutofRangeFlag = HV_TRUE;
        }
        else
        {
            pstChannelData->bOutofRangeFlag = HV_FALSE;
        }
    }
    else
    {
        /*不需要调整htotal*/
        Hv_Cal_DpuScaler_DtcFrameSyncHtotal(stPanelParam.usPanelHtotalType);
    }

    if((HV_FALSE == IsDtcTxTheoryVtotalInPanelSpec(pstVideoTiming)) && (CHANNEL_TYPE_MAIN == pstChannelData->enChannelType))
    {
        pstChannelData->bOutofRangeFlag = 1;
        usDynamicPanelHtotal = stPanelParam.usPanelHtotalType;
        Hv_Cal_DpuScaler_DtcFrameSyncHtotal(stPanelParam.usPanelHtotalType);
        HV_LOG_INFO(CHANNEL, "DTC vtotal out of range by panel max, frc mode");
    }

    if(pstChannelData->bOutofRangeFlag == 1)
    {
        /*重配置frc通路*/
        SelectDisplayDataPathMode(pstChannelData, &(pstChannelData->stVideoConfigParams), pstVideoTiming);
    }
    pstChannelData->stVideoConfigParams.uiDtcTxHtotal = usDynamicPanelHtotal;

    return;
}


Status PreConfigDpuDataPath(ChannelData* pstChannelData, VideoConfigParams* pstVideoConfigParams, const VideoTimingParam* pstVideoTiming)
{
    ChannelType enChannelType = pstChannelData->enChannelType;
    const ChannelManager* pstChannelManager =  Hv_Mw_Channel_GetManager();
    const PanelParam stPanelParam = Hv_Mw_Panel_GetCurrentPanelParam();
    HV_ASSERT_VALID_PTR(pstVideoTiming);
    /*config param from database*/
    pstVideoConfigParams->bOsdVrrEnable = HV_COMMON_DATABASE_GET(UserData, ucFreeSync);
    pstVideoConfigParams->enPxpMode     = pstChannelManager->stChannelFlashConfig.enFlashPxPMode;
#if (HV_CONFIG_ON == HV_PROJECT_CONFIG_MAIN_FLIP)
    pstVideoConfigParams->bHflipEnable  = HV_COMMON_DATABASE_GET(UserData, bMainHfilpEn);
    pstVideoConfigParams->bVflipEnable  = HV_COMMON_DATABASE_GET(UserData, bMainVfilpEn);
#else
    pstVideoConfigParams->bHflipEnable  = HV_COMMON_DATABASE_GET(DiagData, stDisplayDebug.bHflipEnable);
    pstVideoConfigParams->bVflipEnable  = HV_COMMON_DATABASE_GET(DiagData, stDisplayDebug.bVflipEnable);
#endif
    UCHAR8 ucRatio = 0;
    ucRatio = pstChannelManager->astChannelData[CHANNEL_TYPE_MAIN].pfPQCallback(PQCALLBACK_RATIOMAPPING, pstVideoConfigParams);
    pstVideoConfigParams->enAspectRatio = ucRatio;
    pstVideoConfigParams->bForceFrc     = 0;
    pstVideoConfigParams->bHdrSwitch    = Hv_Mw_PQ_GetHDREnable(0);
    /*copy input timing params from RX timing*/
    pstVideoConfigParams->bInterlacedMode    = pstVideoTiming->bInterlacedMode;
    pstVideoConfigParams->uiInputFrameRate   = pstVideoTiming->usFrameRate;
    pstVideoConfigParams->uiInputVideoWidth  = pstVideoTiming->usHActive;
    pstVideoConfigParams->uiInputVideoHight  = pstVideoTiming->usVActive;
    pstVideoConfigParams->uiInputVideoHtotal = pstVideoTiming->usHTotal;
    pstVideoConfigParams->uiInputVideoVtotal = pstVideoTiming->usVTotal;
    pstVideoConfigParams->usVideoPanelHactive = stPanelParam.usPanelHactive;
    pstVideoConfigParams->usVideoPanelVactive = stPanelParam.usPanelVactive;
    pstVideoConfigParams->usVideoPanelHtotalType = stPanelParam.usPanelHtotalType;
    pstVideoConfigParams->usVideoPanelVtotalType = stPanelParam.usPanelVtotalType;
    pstVideoConfigParams->usPanelInchWidth       = stPanelParam.usPanelInchWidth;
    pstVideoConfigParams->usPanelInchHeight      = stPanelParam.usPanelInchHeight;
    pstVideoConfigParams->uiDtcTxHtotal          = stPanelParam.usPanelHtotalType;
#if (HV_CONFIG_ON == HV_PROJECT_CONFIG_MAGNIFY)
    if (HV_COMMON_DATABASE_GET(UserData, bMagnifyGlassSw))
    {
        pstVideoConfigParams->bMainFakeSwitch     = pstChannelManager->stChannelFlashConfig.bFlashSubFakeVideoSw;
        pstVideoConfigParams->fMainFakeRatio      = HV_COMMON_DATABASE_GET(UserData, fMagnifyGlassScalerUpRatio);
        pstVideoConfigParams->usMainFakeHsize     = HV_COMMON_DATABASE_GET(UserData, usMagnifyGlassHsize);
        pstVideoConfigParams->usMainFakeVsize     = HV_COMMON_DATABASE_GET(UserData, usMagnifyGlassVsize);
        pstVideoConfigParams->usMainFakePosH      = HV_COMMON_DATABASE_GET(UserData, usMagnifyGlassPositionH);
        pstVideoConfigParams->usMainFakePosV      = HV_COMMON_DATABASE_GET(UserData, usMagnifyGlassPositionV);
    }
#endif
#if (HV_CONFIG_ON == HV_PROJECT_CONFIG_DPU_BRIGHT_FRAME)
    if (pstVideoTiming->bInterlacedMode)  /*interlace下因为4K ddr size问题暂不支持bright frame*/
    {
        HV_COMMON_DATABASE_SET(UserData, bBrightFrameEn, 0);
    }
    if (HV_COMMON_DATABASE_GET(UserData, bBrightFrameEn))
    {
        pstVideoConfigParams->bMainFakeSwitch     = pstChannelManager->stChannelFlashConfig.bFlashSubFakeVideoSw;
        pstVideoConfigParams->fMainFakeRatio      = HV_COMMON_DATABASE_GET(UserData, usBrightFrameRatio);
        pstVideoConfigParams->usMainFakeHsize     = HV_COMMON_DATABASE_GET(UserData, usBrightFrameHsize);
        pstVideoConfigParams->usMainFakeVsize     = HV_COMMON_DATABASE_GET(UserData, usBrightFrameVsize);
        pstVideoConfigParams->usMainFakePosH      = HV_COMMON_DATABASE_GET(UserData, usBrightFramePosH);
        pstVideoConfigParams->usMainFakePosV      = HV_COMMON_DATABASE_GET(UserData, usBrightFramePosV);
        /*为了同步mian和sub帧率，都走frc*/
        //pstVideoConfigParams->bForceFrc     = HV_COMMON_DATABASE_GET(UserData, bBrightFrameEn);
    }
#endif
    if (CHANNEL_TYPE_MAIN == enChannelType)
    {
        Hv_Drv_DpuMainScaler_CapVgsfMainCapInSize(pstVideoTiming->usHActive, pstVideoTiming->usVActive);
        //CalcMainOverScanTiming(pstVideoConfigParams, pstVideoTiming);
        CalcMainFrameBufferResolutionSize(pstVideoConfigParams, pstVideoTiming);
        CalcMainOutputFrameRate(pstVideoConfigParams);
        if (HV_TRUE == HV_COMMON_DATABASE_GET(UserData, ucProEsportSwitch))
        {
            /*电竞模式，与PXP互斥，重新设置main输出大小*/
            pstVideoConfigParams->uiOutputVideoWidth = HV_COMMON_DATABASE_GET(UserData, usProEsportHSize);
            pstVideoConfigParams->uiOutputVideoHight = HV_COMMON_DATABASE_GET(UserData, usProEsportVSize);
            pstVideoConfigParams->uiOutputVideoHtotal = stPanelParam.usPanelHtotalType;
            pstVideoConfigParams->uiOutputVideoVtotal = stPanelParam.usPanelVtotalType;
        }
        else if (PXP_MODE_PBP_ENABLE != pstVideoConfigParams->enPxpMode)/*PIP和PXP关闭场景主通道均时全屏*/
        {
            pstVideoConfigParams->uiOutputVideoWidth = stPanelParam.usPanelHactive;
            pstVideoConfigParams->uiOutputVideoHight = stPanelParam.usPanelVactive;
            pstVideoConfigParams->uiOutputVideoHtotal = stPanelParam.usPanelHtotalType;
            pstVideoConfigParams->uiOutputVideoVtotal = stPanelParam.usPanelVtotalType;
        }
        else /*PBP H方向只能占用屏幕一半*/
        {
            pstVideoConfigParams->uiOutputVideoHight = stPanelParam.usPanelVactive;
            #ifdef CONFIG_USER_DOUBLE_CHANNEL_ON
            pstVideoConfigParams->uiOutputVideoWidth = Hv_Drv_DpuScaler_GetPbpMainWindowHSize(stPanelParam.usPanelHactive);
            pstVideoConfigParams->uiOutputVideoHtotal = Hv_Drv_DpuScaler_GetPbpMainWindowHTotal(stPanelParam.usPanelHactive, stPanelParam.usPanelHtotalType);
            #else
            pstVideoConfigParams->uiOutputVideoWidth = stPanelParam.usPanelHactive >> 1;
            pstVideoConfigParams->uiOutputVideoHtotal = stPanelParam.usPanelHtotalType >> 1;
            #endif
            pstVideoConfigParams->uiOutputVideoVtotal = stPanelParam.usPanelVtotalType;
        }
    }
#ifdef CONFIG_USER_DOUBLE_CHANNEL_ON
    else
    {
        CalcSubFrameBufferResolutionSize(pstVideoConfigParams, pstVideoTiming);
        HV_LOG_INFO(PQ, "SSSSSUB video %d %d ",  pstVideoConfigParams->uiDdrOrWtrVideoWidth,  pstVideoConfigParams->uiDdrOrWtrVideoHight);
        CalcSubOutputFrameRate(pstVideoConfigParams);
        Hv_Drv_DpuScaler_CalcSubWindowOutPut(pstVideoConfigParams);
    }
#endif

    /*根据输入输出的timing以及帧率，选择framesync模式还是FRC模式，在FRC模式下根据带宽和内存选择合适的framebuffer配置*/
    SelectDisplayDataPathMode(pstChannelData, pstVideoConfigParams, pstVideoTiming);

    if ((CHANNEL_TYPE_MAIN == enChannelType)
    && (DATA_PATH_MODE_FRAMESYNC == pstVideoConfigParams->enDataPathMode)
#ifdef HV_SCALER_DEBUG_VERSION
    && (0 == HV_COMMON_DATABASE_GET(DiagData, stDisplayDebug.ucVideoDataPathMode))
#endif
    )
    {   /*只有在main且是framesync才调节*/
        InputTimingIsOutOfPanelRange(pstChannelData, pstVideoTiming);
    }
#ifdef HV_SCALER_DEBUG_VERSION
    HV_COMMON_DATABASE_SET(DiagData, stDisplayDebug.ucVideoDataPathMode, 0);
#endif
#if (0 != HV_PROJECT_CONFIG_DPU_OVER_SCAN_SIDE_SIZE)
    if (CHANNEL_TYPE_MAIN == enChannelType)
    {
        CalcMainOverScanTiming(pstChannelData, pstVideoConfigParams, pstVideoTiming);
    }
#endif
    return HV_SUCCESS;
}

/*Some PQ APIs must be called after every Video-config*/
Status VideoConfigPQ(ChannelType enChannelType, VideoConfigParams* pstVideoConfigParams)
{
    const ChannelManager* pstChannelManager =  Hv_Mw_Channel_GetManager();
    /* PQ callback when config HDR */
    pstChannelManager->astChannelData[CHANNEL_TYPE_MAIN].pfPQCallback(PQCALLBACK_TIMECHANGED, pstVideoConfigParams);
    
    if(1 == HV_COMMON_DATABASE_GET(DiagData, ucDBPqBypassEn))
    {
        Hv_Drv_PQPathBypass(0);
    }

    return HV_SUCCESS;
}

static VOID SetVideoDataPathClkEn(VideoConfigParams* pstVideoConfigParams)
{
    if (DIS_TIMING_MODE_FRAMESYNC == pstVideoConfigParams->enTimingMode)  /*frame sync*/
    {
        Hv_Cal_DpuScaler_DpcSrpMainDecClkEn(0);
        Hv_Cal_DpuScaler_DpcSrpMainEnc1ClkEn(0);
        Hv_Cal_DpuScaler_DpcSrpMainUnpackClkEn(0);
        Hv_Cal_DpuScaler_DpcSrpMainEncClkEn(0);
    }
    else if ((DATA_PATH_MODE_THROUGH_COLORFORMAT_RX == pstVideoConfigParams->enDataPathMode)
    || (DATA_PATH_MODE_THROUGH_COLORFORMAT_YUV444 == pstVideoConfigParams->enDataPathMode)
    || (DATA_PATH_MODE_THROUGH_COLORFORMAT_YUV422 == pstVideoConfigParams->enDataPathMode)
    || (DATA_PATH_MODE_THROUGH_COLORFORMAT_YUV420  == pstVideoConfigParams->enDataPathMode))
    {
        Hv_Cal_DpuScaler_DpcSrpMainDecClkEn(0);
        Hv_Cal_DpuScaler_DpcSrpMainEnc1ClkEn(0);
        Hv_Cal_DpuScaler_DpcSrpMainUnpackClkEn(1);
        Hv_Cal_DpuScaler_DpcSrpMainEncClkEn(0);
    }
    else
    {
        Hv_Cal_DpuScaler_DpcSrpMainDecClkEn(1);
        Hv_Cal_DpuScaler_DpcSrpMainEnc1ClkEn(1);
        Hv_Cal_DpuScaler_DpcSrpMainUnpackClkEn(0);
        Hv_Cal_DpuScaler_DpcSrpMainEncClkEn(1);
    }
#if (HV_CONFIG_ON == HV_PROJECT_CONFIG_DPU_BRIGHT_FRAME)
    if (HV_TRUE == HV_COMMON_DATABASE_GET(UserData, bBrightFrameEn))
    {
        Hv_Cal_DpuScaler_DpcSrpMainDecClkEn(1);
        Hv_Cal_DpuScaler_DpcSrpMainEnc1ClkEn(1);
        Hv_Cal_DpuScaler_DpcSrpMainUnpackClkEn(1);
        Hv_Cal_DpuScaler_DpcSrpMainEncClkEn(1);
    }
#endif
}

Status Hv_Mw_Video_ConfigDisplayDataPath(ChannelData* pstChannelData, VideoConfigParams* pstVideoConfigParams, VideoTimingParam* pstRxVideoTiming)
{
    UINT32 uiDClkCfg = 0;
    UINT64 uiDClockDst = 0;
    HV_ASSERT_VALID_PTR(pstChannelData);
    HV_ASSERT_VALID_PTR(pstRxVideoTiming);
    HV_ASSERT_VALID_PTR(pstVideoConfigParams);
    ChannelType enChannelType = pstChannelData->enChannelType;
    const PanelManager* pstPanelManager = Hv_Mw_Panel_GetManagerPtr();
    const PanelParam stPanelParam = Hv_Mw_Panel_GetCurrentPanelParam();
    HV_ASSERT_SUCCESS(Hv_Drv_PLL_SetRxdpllPixelClock(enChannelType, &pstRxVideoTiming->uiRxDpllSetFreqKHz, pstRxVideoTiming->uiFreqKHz));
    pstVideoConfigParams->uiRxDpllFreq = pstRxVideoTiming->uiRxDpllSetFreqKHz;

    /*DPU通路配置预配置，timing选择,压缩，非压缩选择，输出帧率等。放大镜，hflip，vflip等*/
    HV_ASSERT_SUCCESS(PreConfigDpuDataPath(pstChannelData, pstVideoConfigParams, pstRxVideoTiming));

    /*配置DPU Display clock 辅通道不修改Display 时钟相关参数*/
    if (CHANNEL_TYPE_MAIN == enChannelType)
    {
        /*设置通路clk*/
        SetVideoDataPathClkEn(pstVideoConfigParams);
        Hv_Drv_DpuScaler_MainWindowConfig(pstVideoConfigParams);
        if (DIS_TIMING_MODE_FRAMESYNC == pstVideoConfigParams->enTimingMode)
        {
            uiDClockDst = CalcDestIDClk(pstVideoConfigParams->uiDtcTxHtotal, pstRxVideoTiming);
#if (0 != HV_PROJECT_CONFIG_DPU_OVER_SCAN_SIDE_SIZE)
            if (HV_TRUE == HV_COMMON_DATABASE_GET(UserData, bOverScan))
            {
                uiDClockDst = uiDClockDst + ((UINT32)uiDClockDst * 2 * HV_PROJECT_CONFIG_DPU_OVER_SCAN_SIDE_SIZE / 10000);
            }
#endif
        }
        else /*FRC*/
        {
            uiDClockDst = s_stVideoPanelParam.usPanelHtotalType * s_stVideoPanelParam.usPanelVtotalType * s_stVideoPanelParam.usPanelFrameRateType / 1000;
        }

        if(NULL != pstPanelManager->stPanelControl.pfCalMNTuSize)
        {
            pstPanelManager->stPanelControl.pfCalMNTuSize(pstVideoConfigParams, &(pstPanelManager->stPanelParam), (UINT32)uiDClockDst);
        }

        HV_ASSERT_SUCCESS(Hv_Drv_DpuScaler_DpuClockConfig(&uiDClkCfg,(UINT32)uiDClockDst,pstVideoConfigParams));

        pstVideoConfigParams->uiDisplayPllFreq = uiDClkCfg;
        pstVideoConfigParams->uiDestDisplayPllFreq = uiDClockDst;
        HV_LOG_INFO(VIDEO,"Channel Reconfig Ip %u,D %u,D_dst %u",pstVideoConfigParams->uiRxDpllFreq,pstVideoConfigParams->uiDisplayPllFreq,(UINT32)uiDClockDst);
    }

    pstVideoConfigParams->bConfigValid = HV_TRUE;
    /*设置mute模块寄存器*/
    HV_ASSERT_SUCCESS(pstChannelData->pfSetMuteTiming(pstRxVideoTiming,pstRxVideoTiming->uiRxDpllSetFreqKHz, pstVideoConfigParams->bOsdVrrEnable));

    /*配置DPU driver*/
    HV_ASSERT_SUCCESS(pstChannelData->pfDpuScalerConfig(pstVideoConfigParams));

    /*Config PQ APIs that vary depending on INPUT*/
    VideoConfigPQ(enChannelType, pstVideoConfigParams);
#if (HV_CONFIG_ON == HV_PROJECT_CONFIG_DPU_BRIGHT_FRAME)
    /*为了减少main和sub帧率不同步问题，main timing走frame sync，buf都走frc 1 buf*/
    BOOL bEn = HV_COMMON_DATABASE_GET(UserData, bBrightFrameEn);
    BOOL bLowLatency = (bEn && Hv_Cal_DpuScaler_GetBrightFrameLowLatency());
    if (CHANNEL_TYPE_MAIN == pstChannelData->enChannelType)
    {
        Hv_Cal_DpuScaler_MainFrcLowLatencyMode(bLowLatency, pstChannelData->stVideoConfigParams.uiDdrOrWtrVideoHight);
    }
    else
    {
        Hv_Cal_DpuScaler_DcwFrcLowLatencyMode(bLowLatency, pstChannelData->stVideoConfigParams.uiDdrOrWtrVideoHight);
    }
#endif
    return HV_SUCCESS;
}

Status Hv_Mw_Video_SetPqCalibrateFrameRate(UINT32 uiFrameRate)
{
    const PanelParam stPanelParam = Hv_Mw_Panel_GetCurrentPanelParam();
    HV_ASSERT_TRUE(uiFrameRate >= stPanelParam.usPanelFrameRateMin && uiFrameRate <= stPanelParam.usPanelFrameRateMax);
    Hv_Mw_Mute_Interrupt_Disable(CHANNEL_TYPE_MAIN);
    VideoTimingParam stRxVideoTiming = {0};
    VideoConfigParams stVideoConfigParams = {0};
    Hv_Mw_Video_GetFakeVideoConfigParams(&stRxVideoTiming, &stVideoConfigParams);
    stVideoConfigParams.uiInputFrameRate = uiFrameRate;
    stVideoConfigParams.uiOutputFrameRate = uiFrameRate;

    /*设置默认dclock*/
    UINT64 uiDClockDst = (UINT64) stPanelParam.usPanelHtotalType * stPanelParam.usPanelVtotalType * uiFrameRate / 1000;
    const PanelManager* pstPanelManager = Hv_Mw_Panel_GetManagerPtr();
    if(NULL != pstPanelManager->stPanelControl.pfCalMNTuSize)
    {
        pstPanelManager->stPanelControl.pfCalMNTuSize(&stVideoConfigParams,&(pstPanelManager->stPanelParam), (UINT32)uiDClockDst);
        HV_LOG_INFO(VIDEO, "EdpTuSize:%u, Mvid:%u",stVideoConfigParams.uiEdpTuDataSize, stVideoConfigParams.uiMvid);
    }
    Hv_Mw_Channel_UpdateVideoConfigParam(CHANNEL_TYPE_MAIN, stVideoConfigParams);

    /*reconfig dpu*/
    UINT32 uiDClkCfg = 0;
    HV_LOG_INFO(VIDEO, "PqCalibrateFrameRate DClockDst = %u",uiDClockDst);
    HV_ASSERT_SUCCESS(Hv_Drv_DpuScaler_DpuClockConfig(&uiDClkCfg,uiDClockDst,&stVideoConfigParams));  
    Hv_Drv_PLL_SetPtcdpllSscgPlln(stVideoConfigParams.uiPtcdFBDivInt, stVideoConfigParams.uiPtcdFBDivFrac, stVideoConfigParams.uiPtcdPostDiv);
    const ChannelManager* pstChannelData = Hv_Mw_Channel_GetManager();
    pstChannelData->astChannelData[CHANNEL_TYPE_MAIN].pfSetMuteTiming(&stRxVideoTiming, stVideoConfigParams.uiRxDpllFreq, HV_TRUE);
    stVideoConfigParams.uiDisplayPllFreq = uiDClkCfg;
    stVideoConfigParams.uiDestDisplayPllFreq = uiDClockDst;
    Hv_Drv_DpuScaler_InitFrcModeMain(HV_TRUE);
    HV_ASSERT_SUCCESS(Hv_Drv_DpuMainScaler_Config(&stVideoConfigParams));
    Hv_Drv_DpuScaler_MainSoftwareModeVideoMute(CHANNEL_TYPE_MAIN, HV_FALSE);
    Hv_Drv_DpuScaler_BurnInConfig();
    Hv_Mw_PQ_SetInpPatt(HV_TRUE, 0);
    return HV_SUCCESS;
}

Status Hv_Mw_Video_SetAspectRatio(VideoRatio enVideoRatio)
{
    HV_LOG_DEBUG(VIDEO, "set aspect ratio = %u",enVideoRatio);
    HV_COMMON_DATABASE_SET(UserData, ucProportion, enVideoRatio);
    HV_ASSERT_SUCCESS(SendNotifyMessageToSystemTask(SETTING_PARAM_ID_ASPECT_RATIO, enVideoRatio));
    return HV_SUCCESS;
}

Status Hv_Mw_Video_SetMainVideoSource(LinkPortIndex enLinkPortIndex)
{
    HV_LOG_DEBUG(VIDEO, "Hv_Mw_Video_SetMainVideoSource %u",enLinkPortIndex);
#if (HV_CONFIG_ON == HV_PROJECT_CONFIG_CHANNEL_SEAMLESS_SWITCH)
    //Hv_Cal_DpuScaler_MainReadFreezeEn(1);  /*已经放弃使用freeze方式，改用IndexFwMode*/
#endif
    HV_COMMON_DATABASE_SET(UserData, ucVideoSource, enLinkPortIndex);
    HV_ASSERT_SUCCESS(SendNotifyMessageToSystemTask(SETTING_PARAM_ID_MAIN_SOURCE, enLinkPortIndex));
#if (HV_CONFIG_ON == HV_PROJECT_CONFIG_MAGNIFY)
    if (HV_FALSE != HV_COMMON_DATABASE_GET(UserData, bMagnifyGlassSw))
    {
        HV_ASSERT_SUCCESS(SendNotifyMessageToSystemTask(SETTING_PARAM_ID_MAGNIFY_GLASS_SWITCH, 1));
    }
#endif
#if (HV_CONFIG_ON == HV_PROJECT_CONFIG_DPU_BRIGHT_FRAME)
    if (HV_FALSE != HV_COMMON_DATABASE_GET(UserData, bBrightFrameEn))
    {
        HV_ASSERT_SUCCESS(SendNotifyMessageToSystemTask(SETTING_PARAM_ID_MAGNIFY_GLASS_SWITCH, 1));
    }
#endif

    switch (enLinkPortIndex)
    {
    case 0:
        Hv_Drv_Gpio_SetPinLevel(HV_BOARD_CONFIG_GPIO_CH444G_YA, GPIO_LEVEL_HIGH);
        Hv_Drv_Gpio_SetPinLevel(HV_BOARD_CONFIG_GPIO_CH444G_YB, GPIO_LEVEL_LOW);
        break;

    case 1:
        Hv_Drv_Gpio_SetPinLevel(HV_BOARD_CONFIG_GPIO_CH444G_YA, GPIO_LEVEL_LOW);
        Hv_Drv_Gpio_SetPinLevel(HV_BOARD_CONFIG_GPIO_CH444G_YB, GPIO_LEVEL_LOW);
        break;    

    default:
        Hv_Drv_Gpio_SetPinLevel(HV_BOARD_CONFIG_GPIO_CH444G_YA, GPIO_LEVEL_HIGH);
        Hv_Drv_Gpio_SetPinLevel(HV_BOARD_CONFIG_GPIO_CH444G_YB, GPIO_LEVEL_LOW);
        break;
    }
    return HV_SUCCESS;
}

#ifdef CONFIG_USER_DOUBLE_CHANNEL_ON

Status Hv_Mw_Video_SetPxpMode(PxpMode enPxpMode)
{
    HV_LOG_DEBUG(VIDEO, "set ucPxPMode = %u",enPxpMode); 
    HV_COMMON_DATABASE_SET(UserData, bMagnifyGlassSw, 0);
    HV_COMMON_DATABASE_SET(UserData, ucPxPMode, enPxpMode);
    HV_ASSERT_SUCCESS(SendNotifyMessageToSystemTask(SETTING_PARAM_ID_PXP_CONFIG, enPxpMode));
    return HV_SUCCESS;
}

Status Hv_Mw_Video_SetSubVideoSource(LinkPortIndex enLinkPortIndex)
{
    HV_LOG_DEBUG(VIDEO, "Hv_Mw_Video_SetSubVideoSource %u",enLinkPortIndex);
    HV_COMMON_DATABASE_SET(UserData, ucPxPVideoSource, enLinkPortIndex);
    HV_ASSERT_SUCCESS(SendNotifyMessageToSystemTask(SETTING_PARAM_ID_SUB_SOURCE, enLinkPortIndex));
    return HV_SUCCESS;
}


Status Hv_Mw_Video_SetMainSubVideoSourceSwap()
{
    /*发送消息给channel通知链路需要重新配置*/
    HV_LOG_DEBUG(VIDEO, "Hv_Mw_Video_SetMainSubVideoSourceSwap");
    UCHAR8  ucMainSrc = HV_COMMON_DATABASE_GET(UserData, ucVideoSource);
    UCHAR8  ucSubSrc = HV_COMMON_DATABASE_GET(UserData, ucPxPVideoSource);
    HV_COMMON_DATABASE_SET(UserData, ucVideoSource, ucSubSrc);
    HV_COMMON_DATABASE_SET(UserData, ucPxPVideoSource, ucMainSrc);
    HV_ASSERT_SUCCESS(SendNotifyMessageToSystemTask(SETTING_PARAM_ID_MAIN_OR_SUB_SOURCE_SWAP, 0));
    return HV_SUCCESS;
}

Status Hv_Mw_Video_SetSubVideoWindowPosition(PipPos enPipPos)
{
    HV_COMMON_DATABASE_SET(UserData, ucPipPosition, enPipPos);
    if (PXP_MODE_CLOSE == HV_COMMON_DATABASE_GET(UserData, ucPxPMode))
    {
        /*PIP还未开启，则只设database*/
        return HV_SUCCESS;
    }
    else
    {
        const PanelParam stPanelParam = Hv_Mw_Panel_GetCurrentPanelParam();
        Hv_Drv_DpuScaler_SubWindowConfig(stPanelParam.usPanelHactive, stPanelParam.usPanelVactive);
        return HV_SUCCESS;
    }
}

#define PIP_POSITION_ALIGNMENT      (100)
static VOID CalcPipSubChSizePos(VOID)
{
    const PanelParam stPanelParam = Hv_Mw_Panel_GetCurrentPanelParam();
    USHORT16 usHsize = 0;
    UCHAR8 ucHPosLevel = HV_COMMON_DATABASE_GET(UserData, usOsdPipHPosLevel);
    USHORT16 usHPos = 0;

    USHORT16 usVsize = 0;
    UCHAR8 ucVPosLevel = HV_COMMON_DATABASE_GET(UserData, usOsdPipVPosLevel);
    USHORT16 usVPos = 0;

    DpuWindowParam stSubChannelWindowParam = {0};

    if (PIP_SIZE_SMALL == HV_COMMON_DATABASE_GET(UserData, ucPipSize))
    {
        usHsize =  HV_COMMON_DATABASE_GET(UserData, usPipSmallWindowHSize);
        usVsize =  HV_COMMON_DATABASE_GET(UserData, usPipSmallWindowVSize);
    }
    else if (PIP_SIZE_MIDDLE == HV_COMMON_DATABASE_GET(UserData, ucPipSize))
    {
        usHsize =  HV_COMMON_DATABASE_GET(UserData, usPipMiddleWindowHSize);
        usVsize =  HV_COMMON_DATABASE_GET(UserData, usPipMiddleWindowVSize);
    }
    else
    {
        usHsize =  HV_COMMON_DATABASE_GET(UserData, usPipBigWindowHSize);
        usVsize =  HV_COMMON_DATABASE_GET(UserData, usPipBigWindowVSize);
    }

    if (stPanelParam.usPanelHactive >= usHsize)
    {   /*画面左上角点坐标*/
        usHPos = ucHPosLevel * (stPanelParam.usPanelHactive - usHsize) / PIP_POSITION_ALIGNMENT;
    }

    if (stPanelParam.usPanelVactive >= usVsize)
    {   /*画面左上角点坐标*/
        usVPos = ucVPosLevel * (stPanelParam.usPanelVactive - usVsize) / PIP_POSITION_ALIGNMENT;
    }

    stSubChannelWindowParam.usDtcChHsta = usHPos;
    stSubChannelWindowParam.usDtcChHend = usHPos + usHsize - 1;
    stSubChannelWindowParam.usDtcChVsta = usVPos;
    stSubChannelWindowParam.usDtcChVend = usVPos + usVsize - 1;
    stSubChannelWindowParam.usBorderHstart = usHPos;
    stSubChannelWindowParam.usBorderVstart = usVPos;
    stSubChannelWindowParam.usBorderLength = usHsize;
    stSubChannelWindowParam.usBorderHeight = usVsize;

    SubWindowBorderCfg stBorderCfg = HV_COMMON_DATABASE_GET(SystemData, stSubWindowBorderCfg);
    stSubChannelWindowParam.bBorderEn = stBorderCfg.ucPxpBorderEnable;
    stSubChannelWindowParam.ucBorderWidth = stBorderCfg.ucSubWindowBorderWidth;
    stSubChannelWindowParam.ucBborderColor = ((UINT32)stBorderCfg.ucSubWindowBorderColorR << 16) | ((UINT32)stBorderCfg.ucSubWindowBorderColorG << 8) | stBorderCfg.ucSubWindowBorderColorB;

    Hv_Cal_DpuScaler_SetSubWindowConifg(&stSubChannelWindowParam);
    return;
}

VOID Hv_Mw_Video_SetPipWindowHPosition(USHORT16 usHPosLevel)
{
    HV_COMMON_DATABASE_SET(UserData, usOsdPipHPosLevel, usHPosLevel);
    CalcPipSubChSizePos();
    return;
}

VOID Hv_Mw_Video_SetPipWindowVPosition(USHORT16 usVPosLevel)
{
    HV_COMMON_DATABASE_SET(UserData, usOsdPipVPosLevel, usVPosLevel);
    CalcPipSubChSizePos();
    return;
}

USHORT16 Hv_Mw_Video_GetPipWindowHPosition(VOID)
{
    return HV_COMMON_DATABASE_GET(UserData, usOsdPipHPosLevel);
}

USHORT16 Hv_Mw_Video_GetPipWindowVPosition(VOID)
{
    return HV_COMMON_DATABASE_GET(UserData, usOsdPipVPosLevel);
}

Status Hv_Mw_Video_SetPbpSize(PbpSize enPbpSize)
{
    /*发送消息给channel通知链路需要重新配置*/
    HV_COMMON_DATABASE_SET(UserData, ucPbpSize, enPbpSize);
    if (PBP_SIZE_SMALL == enPbpSize)
    {
        HV_COMMON_DATABASE_SET(UserData, usPbpWindowHSize, HV_COMMON_DATABASE_GET(UserData, usPbpSmallWindowHSize));
    }
    else if (PBP_SIZE_MIDDLE == enPbpSize)
    {
        HV_COMMON_DATABASE_SET(UserData, usPbpWindowHSize, HV_COMMON_DATABASE_GET(UserData, usPbpMiddleWindowHSize));
    }
    else
    {
        HV_COMMON_DATABASE_SET(UserData, usPbpWindowHSize, HV_COMMON_DATABASE_GET(UserData, usPbpBigWindowHSize));
    }
    if (PXP_MODE_CLOSE == HV_COMMON_DATABASE_GET(UserData, ucPxPMode))
    {
        /*PBP还未开启，则只设database*/
        return HV_SUCCESS;
    }
    else
    {
        Hv_Mw_Video_DataPathReconfig();
        return HV_SUCCESS;
    }
}

Status Hv_Mw_Video_SetSubVideoWindowSize(PipSize enPipSize)
{
    /*发送消息给channel通知链路需要重新配置*/
    HV_COMMON_DATABASE_SET(UserData, ucPipSize, enPipSize);
    if (PXP_MODE_CLOSE == HV_COMMON_DATABASE_GET(UserData, ucPxPMode))
    {
        /*PIP还未开启，则只设database*/
        return HV_SUCCESS;
    }
    else
    {
        HV_ASSERT_SUCCESS(SendNotifyMessageToSystemTask(SETTING_PARAM_ID_PIP_SUB_WINDOW_SIZE_RECONFIG, enPipSize));
        return HV_SUCCESS;
    }
}
#endif

VOID Hv_Mw_Video_SetProEsportSwitch(UCHAR8 ucSw)
{
    HV_LOG_DEBUG(DEFAULT, "set professional esport switch =%u", ucSw);
    /*发送消息给channel通知链路需要重新配置,重设DTC大小*/
    HV_COMMON_DATABASE_SET(UserData, ucProEsportSwitch, ucSw);
    HV_ASSERT_SUCCESS_VOID(SendNotifyMessageToSystemTask(SETTING_PARAM_ID_PRO_ESPORT_SWITCH, ucSw));
    return;
}

Status Hv_Mw_Video_SetFreeSyncSwitch(UCHAR8 ucSw)
{
    HV_LOG_DEBUG(DEFAULT, "set freeSync=%u", ucSw);
    /*发送消息给channel通知链路需要重新配置打开了VRR*/
    HV_COMMON_DATABASE_SET(UserData, ucFreeSync, ucSw);
    HV_ASSERT_SUCCESS(SendNotifyMessageToSystemTask(SETTING_PARAM_ID_FREE_SYNC_SWITCH, ucSw));
    return HV_SUCCESS;
}

VOID Hv_Mw_Video_SetEdidHdrSwitch(UINT32 uiValue)
{
    HV_LOG_DEBUG(DEFAULT, "set EdidHdr=%u", uiValue);
    /*给PQ使用，发送消息给channel,更新EDID里面hdr flag，重配通路*/
    HV_ASSERT_SUCCESS_VOID(SendNotifyMessageToSystemTask(SETTING_PARAM_ID_HDR_SWITCH, uiValue));
    return;
}

Status Hv_Mw_Video_SetHflipSwitch(UCHAR8 ucSw)
{
#if (HV_CONFIG_ON == HV_PROJECT_CONFIG_MAIN_FLIP)
    HV_COMMON_DATABASE_SET(UserData, bMainHfilpEn, ucSw);
#endif
    Hv_Drv_DpuScaler_SetHflipSwitch(ucSw);
    return HV_SUCCESS;
}

Status Hv_Mw_Video_SetVflipSwitch(UCHAR8 ucSw)
{
    /*Vflip需要重新配置DDR模式为FRC，并且需要翻转，发送消息给channel通知链路需要重新配置*/
#if (HV_CONFIG_ON == HV_PROJECT_CONFIG_MAIN_FLIP)
    HV_COMMON_DATABASE_SET(UserData, bMainVfilpEn, ucSw);
#endif
    HV_ASSERT_SUCCESS(SendNotifyMessageToSystemTask(SETTING_PARAM_ID_DATA_PATH_RECONFIG, ucSw));
    return HV_SUCCESS;
}

Status Hv_Mw_Video_SetVideoAutoSelectSw(UCHAR8 ucSw)
{
    /*打开自动搜索信号开关无需通知状态机，搜索信号时已根据database配置自动选择是否进行自动信号搜索*/
    HV_COMMON_DATABASE_SET(UserData, bAutoVideoSrcSelSw, ucSw);
    return HV_SUCCESS;
}

static MainRxFakeVideoParam UpdateMainRxFakeVideoParam(FLOAT32 fRatio, USHORT16 usHsize, USHORT16 usVsize, USHORT16 usPosH, USHORT16 usPosV)
{
    MainRxFakeVideoParam stMainRxFakeVideoParam = {0};
    stMainRxFakeVideoParam.fMainFakeRatio = fRatio;
    stMainRxFakeVideoParam.usMainFakeHsize = usHsize;
    stMainRxFakeVideoParam.usMainFakeVsize = usVsize;
    stMainRxFakeVideoParam.usMainFakePosH = usPosH;
    stMainRxFakeVideoParam.usMainFakePosV = usPosV;
    return stMainRxFakeVideoParam;
}

#if (HV_CONFIG_ON == HV_PROJECT_CONFIG_MAGNIFY)
Status Hv_Mw_Video_SetMagnifyGlassSwitch(UCHAR8 ucSw)
{
#if (HV_CONFIG_ON == HV_PROJECT_CONFIG_DPU_BRIGHT_FRAME)
    if (HV_OFF != ucSw)
    {
        HV_COMMON_DATABASE_SET(UserData, bBrightFrameEn, 0);
    }
#endif
    HV_COMMON_DATABASE_SET(UserData, bMagnifyGlassSw, ucSw);
    HV_COMMON_DATABASE_SET(UserData, ucPxPMode, ucSw != 0 ? PXP_MODE_PIP_ENABLE : PXP_MODE_CLOSE);
    HV_ASSERT_SUCCESS(SendNotifyMessageToSystemTask(SETTING_PARAM_ID_MAGNIFY_GLASS_SWITCH, ucSw));
    return HV_SUCCESS;
}

Status Hv_Mw_Video_SetMagnifyGlassRatio(FLOAT32 fMgRatio)
{
    HV_COMMON_DATABASE_SET(UserData, fMagnifyGlassScalerUpRatio, fMgRatio);
    if (0 != HV_COMMON_DATABASE_GET(UserData, bMagnifyGlassSw))
    {
        HV_COMMON_DATABASE_SET(UserData, ucPxPMode, PXP_MODE_PIP_ENABLE);
        /*放大镜已经打开，直接修改倍率*/
        const ChannelManager* pstChannelManager = Hv_Mw_Channel_GetManager();
        USHORT16 usMgSwitch = (HV_COMMON_DATABASE_GET(UserData, bMagnifyGlassSw) != HV_FALSE) ? HV_TRUE : HV_FALSE;
        USHORT16 usMgHsize  = HV_COMMON_DATABASE_GET(UserData, usMagnifyGlassHsize);
        USHORT16 usMgVsize  = HV_COMMON_DATABASE_GET(UserData, usMagnifyGlassVsize);
        USHORT16 usMgPosH   = HV_COMMON_DATABASE_GET(UserData, usMagnifyGlassPositionH);
        USHORT16 usMgPosV   = HV_COMMON_DATABASE_GET(UserData, usMagnifyGlassPositionV);
        //FLOAT32 fMgRatio = HV_COMMON_DATABASE_GET(UserData, fMagnifyGlassScalerUpRatio);
        HV_ASSERT_TRUE(fMgRatio != 0);
        MainRxFakeVideoParam stMagnifierDynamicParam = UpdateMainRxFakeVideoParam(fMgRatio, usMgHsize, usMgVsize, usMgPosH, usMgPosV);
        if (usMgSwitch)
        {
            Hv_Drv_DpuScaler_SubLdgTopSubBlendEn(0);
            DpuCapCutParam stDpuCapCutParam = {0};
            Hv_Mw_Channel_UpdateMainRxFakeVideoParam(stMagnifierDynamicParam);
            Hv_Drv_DpuScaler_CalcCapCutParam(&(pstChannelManager->astChannelData[CHANNEL_TYPE_SUB].stVideoConfigParams), &stDpuCapCutParam);
            HV_ASSERT_SUCCESS(Hv_Drv_DpuScaler_CapVgsfSettingsSub(&(pstChannelManager->astChannelData[CHANNEL_TYPE_SUB].stVideoConfigParams)));
            Hv_Drv_DpuScaler_FrameBufferConfig01(&(pstChannelManager->astChannelData[CHANNEL_TYPE_SUB].stVideoConfigParams));
            HV_ASSERT_SUCCESS(Hv_Drv_DpuScaler_DpcSrpSubSettings(&(pstChannelManager->astChannelData[CHANNEL_TYPE_SUB].stVideoConfigParams)));
            HV_ASSERT_SUCCESS(Hv_Drv_DpuScaler_DpuVdm01Settings(&(pstChannelManager->astChannelData[CHANNEL_TYPE_SUB].stVideoConfigParams)));
            HV_ASSERT_SUCCESS(Hv_Drv_DpuScaler_SrpTopSubSettings(&(pstChannelManager->astChannelData[CHANNEL_TYPE_SUB].stVideoConfigParams)));
            Hv_Drv_DpuScaler_SubRatio(&(pstChannelManager->astChannelData[CHANNEL_TYPE_SUB].stVideoConfigParams));
            //Hv_Vos_Delayus(100000);
            Hv_Drv_DpuScaler_SetMainFakeBlendFlag(HV_TRUE);
            //Hv_Drv_DpuScaler_SubLdgTopSubBlendEn(1);
        }
    }
    else
    {
        /*放大镜没有开，重走开的流程即可*/
        Hv_Mw_Video_SetMagnifyGlassSwitch(HV_TRUE);
    }

    return HV_SUCCESS;
}

Status Hv_Mw_Video_SetMagnifyGlassPos(USHORT16 usMgPosH, USHORT16 usMgPosV)
{
    const ChannelManager* pstChannelManager = Hv_Mw_Channel_GetManager();
    const PanelParam stPanelParam = Hv_Mw_Panel_GetCurrentPanelParam();

    USHORT16 usMgSwitch = (HV_COMMON_DATABASE_GET(UserData, bMagnifyGlassSw) != HV_FALSE) ? HV_TRUE : HV_FALSE;
    USHORT16 usMgHsize  = HV_COMMON_DATABASE_GET(UserData, usMagnifyGlassHsize);
    USHORT16 usMgVsize  = HV_COMMON_DATABASE_GET(UserData, usMagnifyGlassVsize);
    FLOAT32 fMgRatio = HV_COMMON_DATABASE_GET(UserData, fMagnifyGlassScalerUpRatio);
    HV_COMMON_DATABASE_SET(UserData, usMagnifyGlassPositionH, usMgPosH);
    HV_COMMON_DATABASE_SET(UserData, usMagnifyGlassPositionV, usMgPosV);
    MainRxFakeVideoParam stMagnifierDynamicParam = UpdateMainRxFakeVideoParam(fMgRatio, usMgHsize, usMgVsize, usMgPosH, usMgPosV);
    if (usMgSwitch)
    {
        Hv_Mw_Channel_UpdateMainRxFakeVideoParam(stMagnifierDynamicParam);
        /*调用Hv_Drv_DpuScaler_CapVgsfSettingsSub实现放大rx的位置跟随panel上的位置变化，不调用实现固定放大中间位置，只panel位置变化*/
        HV_ASSERT_SUCCESS(Hv_Drv_DpuScaler_CapVgsfSettingsSub(&(pstChannelManager->astChannelData[CHANNEL_TYPE_SUB].stVideoConfigParams)));
        Hv_Drv_DpuScaler_SubWindowConfig(stPanelParam.usPanelHactive, stPanelParam.usPanelVactive);
    }
    return HV_SUCCESS;
}

VOID Hv_Mw_Video_SetMagnifyGlassSamplingLocation(USHORT16 usSampleLocH, USHORT16 usSampleLocV)
{
#if (HV_CONFIG_OFF == HV_PROJECT_CONFIG_MAGNIFY_SAMPLING_FLOW_POS)
    HV_COMMON_DATABASE_SET(UserData, usMagnifyGlassSamplingLocH, usSampleLocH);
    HV_COMMON_DATABASE_SET(UserData, usMagnifyGlassSamplingLocV, usSampleLocV);
    const ChannelManager* pstChannelManager = Hv_Mw_Channel_GetManager();
    USHORT16 usMgSwitch = (HV_COMMON_DATABASE_GET(UserData, bMagnifyGlassSw) != HV_FALSE) ? HV_TRUE : HV_FALSE;
    if (usMgSwitch)
    {
        Hv_Drv_DpuScaler_UpdataSubCapOutMask(&(pstChannelManager->astChannelData[CHANNEL_TYPE_SUB].stVideoConfigParams));
    }
#else
    Hv_Mw_Video_SetMagnifyGlassPos(usSampleLocH, usSampleLocV);
#endif
    return;
}


Status Hv_Mw_Video_SetMagnifyGlassSize(USHORT16 usMgHsize, USHORT16 usMgVsize)
{
    const ChannelManager* pstChannelManager = Hv_Mw_Channel_GetManager();
    const PanelParam stPanelParam = Hv_Mw_Panel_GetCurrentPanelParam();
    USHORT16 usMgSwitch = (HV_COMMON_DATABASE_GET(UserData, bMagnifyGlassSw) != HV_FALSE) ? HV_TRUE : HV_FALSE;
    USHORT16 usMgPosH   = HV_COMMON_DATABASE_GET(UserData, usMagnifyGlassPositionH);
    USHORT16 usMgPosV   = HV_COMMON_DATABASE_GET(UserData, usMagnifyGlassPositionV);
    FLOAT32 fMgRatio = HV_COMMON_DATABASE_GET(UserData, fMagnifyGlassScalerUpRatio);
    HV_COMMON_DATABASE_SET(UserData, usMagnifyGlassHsize, usMgHsize);
    HV_COMMON_DATABASE_SET(UserData, usMagnifyGlassVsize, usMgVsize);
    MainRxFakeVideoParam stMagnifierDynamicParam = UpdateMainRxFakeVideoParam(fMgRatio, usMgHsize, usMgVsize, usMgPosH, usMgPosV);
    if (usMgSwitch)
    {
        Hv_Cal_DpuScaler_SetLdgLatch(1);
        Hv_Cal_DpuScaler_SetSubSrpLatch(1);
        Hv_Drv_DpuScaler_SetSubSeamlessApplyInEn(1);

        DpuCapCutParam stDpuCapCutParam = {0};
        Hv_Drv_DpuScaler_SubLdgTopSubBlendEn(0);
        Hv_Mw_Channel_UpdateMainRxFakeVideoParam(stMagnifierDynamicParam);
        Hv_Drv_DpuScaler_CalcCapCutParam(&(pstChannelManager->astChannelData[CHANNEL_TYPE_SUB].stVideoConfigParams), &stDpuCapCutParam);
        HV_ASSERT_SUCCESS(Hv_Drv_DpuScaler_CapVgsfSettingsSub(&(pstChannelManager->astChannelData[CHANNEL_TYPE_SUB].stVideoConfigParams)));
        Hv_Drv_DpuScaler_FrameBufferConfig01(&(pstChannelManager->astChannelData[CHANNEL_TYPE_SUB].stVideoConfigParams));
        HV_ASSERT_SUCCESS(Hv_Drv_DpuScaler_DpcSrpSubSettings(&(pstChannelManager->astChannelData[CHANNEL_TYPE_SUB].stVideoConfigParams)));
        HV_ASSERT_SUCCESS(Hv_Drv_DpuScaler_DpuVdm01Settings(&(pstChannelManager->astChannelData[CHANNEL_TYPE_SUB].stVideoConfigParams)));
        HV_ASSERT_SUCCESS(Hv_Drv_DpuScaler_SrpTopSubSettings(&(pstChannelManager->astChannelData[CHANNEL_TYPE_SUB].stVideoConfigParams)));
        Hv_Drv_DpuScaler_SubRatio(&(pstChannelManager->astChannelData[CHANNEL_TYPE_SUB].stVideoConfigParams));
        Hv_Drv_DpuScaler_SubWindowConfig(stPanelParam.usPanelHactive, stPanelParam.usPanelVactive);
        //Hv_Vos_Delayus(20000);
        Hv_Drv_DpuScaler_SetMainFakeBlendFlag(HV_TRUE);
        //Hv_Drv_DpuScaler_SubLdgTopSubBlendEn(1);
    }
    return HV_SUCCESS;
}

#endif

VOID Hv_Mw_Video_SetOutMprtPwmEnable(MprtType enMprtType)
{
#if (HV_CONFIG_ON == HV_PROJECT_CONFIG_MPRT) 
    HV_COMMON_DATABASE_SET(UserData, ucMprt, enMprtType);
    Hv_Drv_MPRT_SetOutMprtPwmEnable(enMprtType);
    return;
#endif
}


#if (HV_CONFIG_ON == HV_PROJECT_CONFIG_MAIN_MONTAGE)
Status Hv_Mw_Video_SetMainMontageSw(UCHAR8 ucSw)
{
    HV_COMMON_DATABASE_SET(UserData, bMainMontageSw, ucSw);
    Hv_Mw_Video_DataPathReconfig();
    return HV_SUCCESS;
}

Status Hv_Mw_Video_SetMainMontageParam(USHORT16 usCutHsta, USHORT16 usCutHend, USHORT16 usCutVsta, USHORT16 usCutVend)
{
    HV_COMMON_DATABASE_SET(UserData, usMontageInHsta, usCutHsta);
    HV_COMMON_DATABASE_SET(UserData, usMontageInHend, usCutHend);
    HV_COMMON_DATABASE_SET(UserData, usMontageInVsta, usCutVsta);
    HV_COMMON_DATABASE_SET(UserData, usMontageInVend, usCutVend);
    if (HV_COMMON_DATABASE_GET(UserData, bMainMontageSw))
    {
        Hv_Mw_Video_DataPathReconfig();
    }
    return HV_SUCCESS;
}
#endif

BOOL Hv_Mw_Video_SetMainALLMStatus(VOID)
{
    const ChannelManager* pstChannelManager = Hv_Mw_Channel_GetManager();
    const PanelParam stPanelParam = Hv_Mw_Panel_GetCurrentPanelParam();
    HV_ASSERT_VALID_PTR(pstChannelManager);
    BOOL bTimingAllmEn = pstChannelManager->astChannelData[CHANNEL_TYPE_MAIN].stRxVideoTiming.bIsEnterALLM;
    USHORT16 usFrameRate = pstChannelManager->astChannelData[CHANNEL_TYPE_MAIN].stRxVideoTiming.usFrameRate;
    BOOL bAllmStatus = HV_FALSE;
    if (bTimingAllmEn)
    {
        if ((usFrameRate >= stPanelParam.usPanelFrameRateMin) && (usFrameRate <= stPanelParam.usPanelFrameRateMax))
        {
            bAllmStatus = HV_TRUE;
        }
        else
        {
            bAllmStatus = HV_FALSE;
        }
    }
    else
    {
        bAllmStatus = HV_FALSE;
    }
    return bAllmStatus;
}

VOID Hv_Mw_Video_SetOverScanEn(UCHAR8 ucSw)
{
#if (0 != HV_PROJECT_CONFIG_DPU_OVER_SCAN_SIDE_SIZE)
    HV_COMMON_DATABASE_SET(UserData, bOverScan, ucSw);
    Hv_Mw_Video_DataPathReconfig();
#endif
    return;
}

BOOL Hv_Mw_Video_GetOverScanEn(VOID)
{
#if (0 != HV_PROJECT_CONFIG_DPU_OVER_SCAN_SIDE_SIZE)
    return HV_COMMON_DATABASE_GET(UserData, bOverScan);
#else
    return HV_FALSE;
#endif
}

#if (HV_CONFIG_ON == HV_PROJECT_CONFIG_OVER_PANEL_CLOCK_EN)
VOID Hv_Mw_Video_SetOverClockEn(UCHAR8 ucSw)
{
    HV_COMMON_DATABASE_SET(UserData, ucOverClocking, ucSw);
    Hv_Mw_Video_DataPathReconfig();
    return;
}

BOOL Hv_Mw_Video_GetOverClockEn(VOID)
{
    return HV_COMMON_DATABASE_GET(UserData, ucOverClocking);
}
#endif

BOOL Hv_Mw_Video_IsDtcVtotalInPanlSpec(VOID)
{
    BOOL bInPanlSpec = HV_FALSE;
    const ChannelManager* pstChannelManager =  Hv_Mw_Channel_GetManager();
    const PanelParam stPanelParam = Hv_Mw_Panel_GetCurrentPanelParam();
    VideoTimingParam stVideoTiming = pstChannelManager->astChannelData[CHANNEL_TYPE_MAIN].stRxVideoTiming;
    HV_ASSERT_TRUE_RET(stVideoTiming.usVActive > 0, HV_TRUE);
    USHORT16 usTheoryVtotal = stVideoTiming.usVTotal * stPanelParam.usPanelVactive / stVideoTiming.usVActive;
    if (DIS_TIMING_MODE_FRAMESYNC == pstChannelManager->astChannelData[CHANNEL_TYPE_MAIN].stVideoConfigParams.enTimingMode)
    {
        if (usTheoryVtotal >= stPanelParam.usPanelVtotalMin && usTheoryVtotal <= stPanelParam.usPanelVtotalMax)
        {
            bInPanlSpec = HV_TRUE;
        }
        else
        {
            bInPanlSpec = HV_FALSE;
        }
    }
    else
    {
        bInPanlSpec = HV_TRUE;
    }
    return bInPanlSpec;
}

USHORT16 Hv_Mw_Video_GetDtcDynamicHtotal(VOID)
{
    const ChannelManager* pstChannelManager =  Hv_Mw_Channel_GetManager();
    return pstChannelManager->astChannelData[CHANNEL_TYPE_MAIN].stVideoConfigParams.uiDtcTxHtotal;
}

VOID Hv_Mw_Video_SetVideoPanelParam(VOID)
{
    const PanelManager* pstPanelManager = Hv_Mw_Panel_GetManagerPtr();
    HV_ASSERT_VALID_PTR_VOID(pstPanelManager);
    s_stVideoPanelParam = pstPanelManager->stPanelParam;
    return;
}

VOID Hv_Mw_Video_SetLineInt(UCHAR8 ucIndex, USHORT16 usLine)
{
    Hv_Drv_DpuScaler_SetLineInt(ucIndex, usLine);
    return;
}

VOID Hv_Mw_Video_SetLineIntEn(UINT32 uiEn)
{
    Hv_Drv_DpuScaler_SetLineIntEn(uiEn);
    return;
}

VOID Hv_Mw_Video_SetDpuIntEn(UCHAR8 ucEn)
{
    Hv_Drv_DpuScaler_SetDpuIntEn(ucEn);
    return;
}


VOID Hv_Mw_Video_SetMainPicPos(VideoConfigParams* pstVideoConfigParams, USHORT16 usHoffset, USHORT16 usVoffset)
{
    Hv_Drv_DpuScaler_MainSetPicPos(pstVideoConfigParams, usHoffset, usVoffset);
    return;
}
