//<MStar Software>
//******************************************************************************
// MStar Software
// Copyright (c) 2010 - 2012 MStar Semiconductor, Inc. All rights reserved.
// All software, firmware and related documentation herein ("MStar Software") are
// intellectual property of MStar Semiconductor, Inc. ("MStar") and protected by
// law, including, but not limited to, copyright law and international treaties.
// Any use, modification, reproduction, retransmission, or republication of all
// or part of MStar Software is expressly prohibited, unless prior written
// permission has been granted by MStar.
//
// By accessing, browsing and/or using MStar Software, you acknowledge that you
// have read, understood, and agree, to be bound by below terms ("Terms") and to
// comply with all applicable laws and regulations:
//
// 1. MStar shall retain any and all right, ownership and interest to MStar
//    Software and any modification/derivatives thereof.
//    No right, ownership, or interest to MStar Software and any
//    modification/derivatives thereof is transferred to you under Terms.
//
// 2. You understand that MStar Software might include, incorporate or be
//    supplied together with third party`s software and the use of MStar
//    Software may require additional licenses from third parties.
//    Therefore, you hereby agree it is your sole responsibility to separately
//    obtain any and all third party right and license necessary for your use of
//    such third party`s software.
//
// 3. MStar Software and any modification/derivatives thereof shall be deemed as
//    MStar`s confidential information and you agree to keep MStar`s
//    confidential information in strictest confidence and not disclose to any
//    third party.
//
// 4. MStar Software is provided on an "AS IS" basis without warranties of any
//    kind. Any warranties are hereby expressly disclaimed by MStar, including
//    without limitation, any warranties of merchantability, non-infringement of
//    intellectual property rights, fitness for a particular purpose, error free
//    and in conformity with any international standard.  You agree to waive any
//    claim against MStar for any loss, damage, cost or expense that you may
//    incur related to your use of MStar Software.
//    In no event shall MStar be liable for any direct, indirect, incidental or
//    consequential damages, including without limitation, lost of profit or
//    revenues, lost or damage of data, and unauthorized system use.
//    You agree that this Section 4 shall still apply without being affected
//    even if MStar Software has been modified by MStar in accordance with your
//    request or instruction for your use, except otherwise agreed by both
//    parties in writing.
//
// 5. If requested, MStar may from time to time provide technical supports or
//    services in relation with MStar Software to you for your use of
//    MStar Software in conjunction with your or your customer`s product
//    ("Services").
//    You understand and agree that, except otherwise agreed by both parties in
//    writing, Services are provided on an "AS IS" basis and the warranty
//    disclaimer set forth in Section 4 above shall apply.
//
// 6. Nothing contained herein shall be construed as by implication, estoppels
//    or otherwise:
//    (a) conferring any license or right to use MStar name, trademark, service
//        mark, symbol or any other identification;
//    (b) obligating MStar or any of its affiliates to furnish any person,
//        including without limitation, you and your customers, any assistance
//        of any kind whatsoever, or any information; or
//    (c) conferring any license or right under any intellectual property right.
//
// 7. These terms shall be governed by and construed in accordance with the laws
//    of Taiwan, R.O.C., excluding its conflict of law rules.
//    Any and all dispute arising out hereof or related hereto shall be finally
//    settled by arbitration referred to the Chinese Arbitration Association,
//    Taipei in accordance with the ROC Arbitration Law and the Arbitration
//    Rules of the Association by three (3) arbitrators appointed in accordance
//    with the said Rules.
//    The place of arbitration shall be in Taipei, Taiwan and the language shall
//    be English.
//    The arbitration award shall be final and binding to both parties.
//
//******************************************************************************
//<MStar Software>
////////////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2008-2009 MStar Semiconductor, Inc.
// All rights reserved.
//
// Unless otherwise stipulated in writing, any and all information contained
// herein regardless in any format shall remain the sole proprietary of
// MStar Semiconductor Inc. and be kept in strict confidence
// ("MStar Confidential Information") by the recipient.
// Any unauthorized act including without limitation unauthorized disclosure,
// copying, use, reproduction, sale, distribution, modification, disassembling,
// reverse engineering and compiling of the contents of MStar Confidential
// Information is unlawful and strictly prohibited. MStar hereby reserves the
// rights to any and all damages, losses, costs and expenses resulting therefrom.
//
////////////////////////////////////////////////////////////////////////////////

///////////////////////////////////////////////////////////////////////////////////////////////////
///
/// file    QoS.c
/// @brief  QoS Driver Interface
/// @author MStar Semiconductor Inc.
///////////////////////////////////////////////////////////////////////////////////////////////////

#ifdef MSOS_TYPE_LINUX_KERNEL

//-------------------------------------------------------------------------------------------------
//  Include Files
//-------------------------------------------------------------------------------------------------

// MTK
#include "MsFS.h"
#include "MsCommon.h"
#include "drvMIU.h"
#include "apiXC.h"
#include "apiVDEC_EX.h"
#include "drvPQ.h"
#include "apiDMS.h"
#include "apiGOP.h"
#include "drvSYS.h"
#include "drvSYS_priv.h"
#include "MsVersion.h"
#include "utopia_dapi.h"
#include "utopia.h"
#include "ULog.h"
#include "apiGOP.h"

// Linux kernel
#include <linux/slab.h>


//-------------------------------------------------------------------------------------------------
//  Local Defines
//-------------------------------------------------------------------------------------------------
#define QOS_TASK_STACK_SIZE             (4096UL)
#define QOS_BW_MONITOR_STACK_SIZE       (4096UL)
#define QOS_XC_REGISTER_STACK_SIZE      (4096UL)
#define TAG_QOS                         "QOS"
#define QOS_DEFAULT_POLLING_INTERVAL    (32)
#define QOS_RESOLUTION_TOLERANCE        (20)
#define QOS_RESOLUTION_HD_W             (1280)
#define QOS_RESOLUTION_HD_H             (720)
#define QOS_RESOLUTION_FHD_W            (1920)
#define QOS_RESOLUTION_FHD_H            (1080)
#define QOS_RESOLUTION_4K_W             (3840)
#define QOS_RESOLUTION_4K_H             (2160)
#define QOS_RESOLUTION_8K_W             (7680)
#define QOS_RESOLUTION_8K_H             (4320)
#define QOS_MONITOR_WINDOW              (5)
#define QOS_AUTOADJ_UPPER_THRESHOLD     (9000)
#define QOS_AUTOADJ_LOWER_THRESHOLD     (7000)

//-------------------------------------------------------------------------------------------------
//  Local Variables
//-------------------------------------------------------------------------------------------------

static MS_BOOL                   _bQosInit = FALSE;
static void                      *_pQosTaskStack;
static MS_S32                    _s32QosTaskId = -1;
static MS_S32                    _s32QosEventId;
static MS_BOOL                   g_bQosTask = TRUE;
static void                      *_pQosBwMonitorStack;
static void                      *_pQosXcRegisterStack;
static MS_S32                    _s32QosBwMonitorId = -1;
static MS_S32                    _s32QosXcRegisterId = -1;
static MS_BOOL                   g_bQosBwMonitor = TRUE;
static MS_U8                     _u8QosDbgLevel = E_QOS_DBGLV_1;
static MS_BOOL                   bSysEnable = FALSE;
static MS_BOOL                   bAutoAdjBwEnable = FALSE;
static MS_U32                    Qos_Polling_Interval = QOS_DEFAULT_POLLING_INTERVAL;
static MS_U32                    QosAutoUpperThreshold = QOS_AUTOADJ_UPPER_THRESHOLD;
static MS_U32                    QosAutoLowerThreshold = QOS_AUTOADJ_LOWER_THRESHOLD;
static ST_QOS_BW_ADJUST_INFO     _stAdjustInfo;
static ST_QOS_SITUATION_INFO     _stSituation;
static ST_QOS_TABLE              *QosTable;
static ST_QOS_INPUT              *CurrentInput;
static ST_QOS_OUTPUT             *CurrentOutput;
static ST_QOS_BW_INFO            *_pstBwInfo = NULL;
static MS_S32                    _s32GlobalMutexId = -1;
static MS_U32                    MiuChannelNum = 0;
static MS_U32                    QosTableDefaultLevel = 1;
static ST_XC_QOS_CALLBACK_INFO   *XCQoSCallback = NULL;
static MS_S8                     CurrentIdx = -1;
static MS_U8                     OsdShow = 0;

//-------------------------------------------------------------------------------------------------
//  Debug Functions
//-------------------------------------------------------------------------------------------------

#define QOS_DBG_LV_1(x, args...)    if (_u8QosDbgLevel >= E_QOS_DBGLV_1) \
                                        {ULOGE(TAG_QOS, x, ##args);}
#define QOS_DBG_LV_2(x, args...)    if (_u8QosDbgLevel >= E_QOS_DBGLV_2 ) \
                                        {ULOGE(TAG_QOS, x, ##args);}
#define QOS_DBG_LV_3(x, args...)    if (_u8QosDbgLevel >= E_QOS_DBGLV_3) \
                                        {ULOGE(TAG_QOS, x, ##args);}
#define QOS_DBG_LV_4(x, args...)    if (_u8QosDbgLevel >= E_QOS_DBGLV_4) \
                                        {ULOGE(TAG_QOS, x, ##args);}

//-------------------------------------------------------------------------------------------------
//  Local Functions
//-------------------------------------------------------------------------------------------------
static MS_BOOL QosXcInputSourceMapping(INPUT_SOURCE_TYPE_t SourceType, EN_QOS_SOURCE *retSrcType)
{
    switch (SourceType)
    {
        case INPUT_SOURCE_DTV:
        case INPUT_SOURCE_DTV2:
        case INPUT_SOURCE_DTV3:
            *retSrcType = E_QOS_DTV;
            break;
        case INPUT_SOURCE_TV:
            *retSrcType = E_QOS_ATV;
            break;
        case INPUT_SOURCE_STORAGE:
            *retSrcType = E_QOS_MM;
            break;
        case INPUT_SOURCE_HDMI:
        case INPUT_SOURCE_HDMI2:
        case INPUT_SOURCE_HDMI3:
        case INPUT_SOURCE_HDMI4:
        case INPUT_SOURCE_HDMI_MAX:
            *retSrcType = E_QOS_HDMI;
            break;
	    default:
            *retSrcType = E_QOS_SOURCE_NONE;
            break;
    }
    return TRUE;
}

static MS_BOOL QosResolutionMapping(MS_U32 u32Height,MS_U32 u32Width, EN_QOS_RESOLUTION *retResolution)
{
    MS_U32 _u32Width = 0x0, _u32Height = 0x0;
    if ( u32Width >= (QOS_RESOLUTION_8K_W - QOS_RESOLUTION_TOLERANCE))
    {
        _u32Width = QOS_RESOLUTION_8K_W;
    }
    else if ( u32Width >= (QOS_RESOLUTION_4K_W - QOS_RESOLUTION_TOLERANCE))
    {
        _u32Width = QOS_RESOLUTION_4K_W;
    }
    else if ( u32Width <= (QOS_RESOLUTION_FHD_W + QOS_RESOLUTION_TOLERANCE) &&
         u32Width >= (QOS_RESOLUTION_FHD_W - QOS_RESOLUTION_TOLERANCE))
    {
        _u32Width = QOS_RESOLUTION_FHD_W;
    }
    else if ( u32Width < (QOS_RESOLUTION_FHD_W - QOS_RESOLUTION_TOLERANCE))
    {
        //To set the width to HD_W if the width is smaller than TIMING_FHD_W
        _u32Width = QOS_RESOLUTION_HD_W;
    }

    if ( u32Height >= (QOS_RESOLUTION_8K_H - QOS_RESOLUTION_TOLERANCE))
    {
        _u32Height = QOS_RESOLUTION_8K_H;
    }
    else if ( u32Height >= (QOS_RESOLUTION_4K_H - QOS_RESOLUTION_TOLERANCE))
    {
        _u32Height = QOS_RESOLUTION_4K_H;
    }
    else if ( u32Height <= (QOS_RESOLUTION_FHD_H + QOS_RESOLUTION_TOLERANCE) &&
         u32Height >= (QOS_RESOLUTION_FHD_H - QOS_RESOLUTION_TOLERANCE))
    {
        _u32Height = QOS_RESOLUTION_FHD_H;
    }
    else if ( u32Height < (QOS_RESOLUTION_FHD_H - QOS_RESOLUTION_TOLERANCE))
    {
        //To set the width to HD_H if the width is smaller than TIMING_FHD_H
        _u32Height = QOS_RESOLUTION_HD_H;
    }

    if (_u32Width == QOS_RESOLUTION_FHD_W && _u32Height == QOS_RESOLUTION_FHD_H)
    {
        *retResolution = E_QOS_FHD;
    }
    else if (_u32Width == QOS_RESOLUTION_4K_W && _u32Height == QOS_RESOLUTION_4K_H)
    {
        *retResolution = E_QOS_UHD;
    }
    else if (_u32Width == QOS_RESOLUTION_HD_W && _u32Height == QOS_RESOLUTION_HD_H)
    {
        *retResolution = E_QOS_HD;
    }
    else if (_u32Width == QOS_RESOLUTION_8K_W && _u32Height == QOS_RESOLUTION_8K_H)
    {
        *retResolution = E_QOS_8K;
    }
    else
    {
        QOS_DBG_LV_2 ("No Mapped timing! W: %d, H: %d,\n", u32Width, u32Height);
        *retResolution = E_QOS_RESOLUTION_NONE;
        return FALSE;
    }

    return TRUE;
}

static MS_BOOL QosVdecFpsMapping(MS_U32 fps, EN_QOS_FPS *retFps)
{
    if (fps <= 24000)
    {
        *retFps = E_QOS_24P;
    }
    else if (fps == 25000)
    {
        *retFps = E_QOS_25P;
    }
    else if (fps >= 29970 && fps <= 30000)
    {
        *retFps = E_QOS_30P;
    }
    else if (fps == 50000)
    {
        *retFps = E_QOS_50P;
    }
    else if (fps >= 59940 && fps <= 60000)
    {
        *retFps = E_QOS_60P;
    }
    else
    {
        *retFps = E_QOS_FPS_NONE;
    }

    return TRUE;
}

static MS_BOOL QosXCFpsMapping(MS_U32 InputVFreq, EN_QOS_FPS *retFps)
{
    if(InputVFreq > 235 && InputVFreq < 245)
    {
        *retFps = E_QOS_24P;
    }
    else if (InputVFreq > 245 && InputVFreq < 255)
    {
        *retFps = E_QOS_25P;
    }
    else if (InputVFreq > 295 && InputVFreq < 305)
    {
        *retFps = E_QOS_30P;
    }
    else if (InputVFreq > 490 && InputVFreq < 510)
    {
        *retFps = E_QOS_50P;
    }
    else if (InputVFreq > 590 && InputVFreq < 610)
    {
        *retFps = E_QOS_60P;
    }
    else
    {
        *retFps = E_QOS_FPS_NONE;
    }

    return TRUE;
}

static MS_BOOL QosCodecMapping(VDEC_EX_CodecType codecType, EN_QOS_CODEC_TYPE *retCodec)
{
    switch (codecType)
    {
        case E_VDEC_EX_CODEC_TYPE_H264:
        case E_VDEC_EX_CODEC_TYPE_H264_DV:
            *retCodec = E_QOS_H264;
            break;
        case E_VDEC_EX_CODEC_TYPE_HEVC:
        case E_VDEC_EX_CODEC_TYPE_HEVC_DV:
            *retCodec = E_QOS_H265;
            break;
        case E_VDEC_EX_CODEC_TYPE_VP9:
            *retCodec = E_QOS_VP9;
            break;
#if (VDEC_HEADER_TYPEDEF_VERSION >= 0x00000006UL)
        case E_VDEC_EX_CODEC_TYPE_AV1:
            *retCodec = E_QOS_AV1;
            break;
#endif
        default:
            *retCodec = E_QOS_CODEC_TYPE_NONE;
            break;
    }
    return TRUE;
}

static MS_BOOL QosTableCompareFunc(ST_QOS_INPUT *Input,ST_QOS_INPUT *Table)
{
    MS_U32 i = 0;

    if (Table->source != E_QOS_SOURCE_IGNORE && Input->source != Table->source)
    {
        QOS_DBG_LV_4("%s %d Input source Current:%d != qosable:%d\n",__FUNCTION__,__LINE__,Input->source,Table->source);
        return FALSE;
    }
    if (Table->main.in_resolution != E_QOS_RESOLUTION_IGNORE && Input->main.in_resolution != Table->main.in_resolution)
    {
        QOS_DBG_LV_4("%s %d main in resolution current:%d != qostable:%d\n",__FUNCTION__,__LINE__,Input->main.in_resolution,Table->main.in_resolution);
        return FALSE;
    }
    if (Table->main.out_resolution != E_QOS_RESOLUTION_IGNORE && Input->main.out_resolution != Table->main.out_resolution)
    {
        QOS_DBG_LV_4("%s %d main out resolution current:%d != qostable:%d\n",__FUNCTION__,__LINE__,Input->main.out_resolution,Table->main.out_resolution);
        return FALSE;
    }

    if (Table->main.fps != E_QOS_FPS_IGNORE && Input->main.fps != Table->main.fps)
    {
        QOS_DBG_LV_4("%s %d main fps current:%d != qostable:%d\n",__FUNCTION__,__LINE__,Input->main.fps,Table->main.fps);
        return FALSE;
    }

    if (Table->main.codec != E_QOS_CODEC_TYPE_IGNORE && Input->main.codec != Table->main.codec)
    {
        QOS_DBG_LV_4("%s %d main codec current:%d != qostable:%d\n",__FUNCTION__,__LINE__,Input->main.codec,Table->main.codec);
        return FALSE;
    }


    if (Table->sub.in_resolution != E_QOS_RESOLUTION_IGNORE && Input->sub.in_resolution != Table->sub.in_resolution)
    {
        QOS_DBG_LV_4("%s %d sub in resolution current:%d != qostable:%d\n",__FUNCTION__,__LINE__,Input->sub.in_resolution,Table->sub.in_resolution);
        return FALSE;
    }

    if (Table->sub.out_resolution != E_QOS_RESOLUTION_IGNORE && Input->sub.out_resolution != Table->sub.out_resolution)
    {
        QOS_DBG_LV_4("%s %d sub out_resolution current:%d != qostable:%d\n",__FUNCTION__,__LINE__,Input->sub.out_resolution,Table->sub.out_resolution);
        return FALSE;
    }
    if (Table->sub.fps != E_QOS_FPS_IGNORE && Input->sub.fps != Table->sub.fps)
    {
        QOS_DBG_LV_4("%s %d sub fps current:%d != qostable:%d\n",__FUNCTION__,__LINE__,Input->sub.fps,Table->sub.fps);
        return FALSE;
    }
    if (Table->sub.codec != E_QOS_CODEC_TYPE_IGNORE && Input->sub.codec != Table->sub.codec)
    {
        QOS_DBG_LV_4("%s %d sub codec current:%d != qostable:%d\n",__FUNCTION__,__LINE__,Input->sub.codec,Table->sub.codec);
        return FALSE;
    }

    if (Table->bEnablePVR != QOS_TABLE_IGNORE_FLAG && Input->bEnablePVR != Table->bEnablePVR)
    {
        QOS_DBG_LV_4("%s %d bEnablePVR current:%d != qostable:%d\n",__FUNCTION__,__LINE__,Input->bEnablePVR,Table->bEnablePVR);
        return FALSE;
    }
    if (Table->bEnablePIP != QOS_TABLE_IGNORE_FLAG && Input->bEnablePIP != Table->bEnablePIP)
    {
        QOS_DBG_LV_4("%s %d bEnablePIP current:%d != qostable:%d\n",__FUNCTION__,__LINE__,Input->bEnablePIP,Table->bEnablePIP);
        return FALSE;
    }
    if (Table->bEnableAIPQ != QOS_TABLE_IGNORE_FLAG && Input->bEnableAIPQ != Table->bEnableAIPQ)
    {
        QOS_DBG_LV_4("%s %d bEnablePVR current:%d != qostable:%d\n",__FUNCTION__,__LINE__,Input->bEnableAIPQ,Table->bEnableAIPQ);
        return FALSE;
    }
    if (Table->bEnableGA != QOS_TABLE_IGNORE_FLAG && Input->bEnableGA != Table->bEnableGA)
    {
        QOS_DBG_LV_4("%s %d bEnableGA current:%d != qostable%d\n",__FUNCTION__,__LINE__,Input->bEnableGA,Table->bEnableGA);
        return FALSE;
    }
    if (Table->bEnableRotate != QOS_TABLE_IGNORE_FLAG && Input->bEnableRotate != Table->bEnableRotate)
    {
        QOS_DBG_LV_4("%s %d bEnableRotate current:%d != qostable:%d\n",__FUNCTION__,__LINE__,Input->bEnableRotate,Table->bEnableRotate);
        return FALSE;
    }

    if (Table->bEnableVR360 != QOS_TABLE_IGNORE_FLAG && Input->bEnableVR360 != Table->bEnableVR360)
    {
        QOS_DBG_LV_4("%s %d bEnableVR360 current:%d != qostable:%d\n",__FUNCTION__,__LINE__,Input->bEnableVR360,Table->bEnableVR360);
        return FALSE;
    }
#if 0  //Currently doesn't need to check dip function
    if (Table->bEnableDIP != QOS_TABLE_IGNORE_FLAG && Input->bEnableDIP != Table->bEnableDIP)
    {
        QOS_DBG_LV_4("%s %d bEnableDIP current:%d != qostable:%d\n",__FUNCTION__,__LINE__,Input->bEnableVR360,Table->bEnableDIP);
        return FALSE;
    }
#endif
    for (i = 0 ; i < MAX_CUSTOMIZE; i++)
    {
        if (Input->bEnableCustomized[i] != Table->bEnableCustomized[i])
        {
            QOS_DBG_LV_4("%s %d bEnableCustomized[%d] current:%d != qostable:%d\n",__FUNCTION__,__LINE__,i,Input->bEnableCustomized[i],Table->bEnableCustomized[i]);
            return FALSE;
        }
    }

    // all case match
    return TRUE;
}

static MS_U32 SearchQosTableUseCase(ST_QOS_INPUT *Input,ST_QOS_TABLE *Table)
{
    MS_U32 i = 0;

    QOS_DBG_LV_2("%s %d QosTable have %d cases\n",__FUNCTION__,__LINE__,Table->cases);
    for (;i < Table->cases; i++)
    {
        QOS_DBG_LV_2("%s %d QosTable index:%d\n",__FUNCTION__,__LINE__,i);
        if (QosTableCompareFunc(Input,(ST_QOS_INPUT *)&Table->scenario[i]) == TRUE)
        {
            QOS_DBG_LV_2("%s %d Found match table, index:%d\n",__FUNCTION__,__LINE__,i);
            break;
        }
    }
    if (i >= Table->cases)
    {
        QOS_DBG_LV_2("%s %d Search finsih, no match table\n",__FUNCTION__,__LINE__);
    }
    return i;
}

static MS_BOOL QosGetCurrentVdecInfo(void)
{
    VDEC_EX_DispInfo stVDECInfo;
    VDEC_StreamId stStreamId, stGetStreamId;

    memset(&stVDECInfo, 0, sizeof(VDEC_EX_DispInfo));
    if (MApi_VDEC_EX_GetControl(&stStreamId, E_VDEC_EX_USER_CMD_GET_MAIN_STREAM_ID, (MS_U32 *)&stGetStreamId) != E_VDEC_EX_OK)
    {
        QOS_DBG_LV_3("%s %d Get main stream id fail \n",__FUNCTION__,__LINE__);
        CurrentInput->main.codec = E_QOS_CODEC_TYPE_NONE;
        CurrentInput->main.in_resolution = E_QOS_RESOLUTION_NONE;
        CurrentInput->main.fps = E_QOS_FPS_NONE;
        return E_QOS_RESULT_FAIL;
    }

    QosCodecMapping(MApi_VDEC_EX_GetActiveCodecType(&stGetStreamId),&CurrentInput->main.codec);
    if (CurrentInput->main.codec == E_QOS_CODEC_TYPE_NONE)
    {
        QOS_DBG_LV_3("%s %d Get main codec type fail \n",__FUNCTION__,__LINE__);
        CurrentInput->main.in_resolution = E_QOS_RESOLUTION_NONE;
        CurrentInput->main.fps = E_QOS_FPS_NONE;
        return E_QOS_RESULT_FAIL;
    }
    if(MApi_VDEC_EX_GetDispInfo(&stGetStreamId, &stVDECInfo) != E_VDEC_EX_OK)
    {
        QOS_DBG_LV_3("%s %d Get main vdec disp info fail \n",__FUNCTION__,__LINE__);
        CurrentInput->main.in_resolution = E_QOS_RESOLUTION_NONE;
        CurrentInput->main.fps = E_QOS_FPS_NONE;
        return E_QOS_RESULT_FAIL;
    }
    QOS_DBG_LV_3("%s %d Get main codec:%d vdec disp info width:%d height:%d fps:%d\n",__FUNCTION__,__LINE__,CurrentInput->main.codec,stVDECInfo.u16HorSize,stVDECInfo.u16VerSize,stVDECInfo.u32FrameRate);
    QosResolutionMapping(stVDECInfo.u16VerSize,stVDECInfo.u16HorSize,&CurrentInput->main.in_resolution);
    QosVdecFpsMapping(stVDECInfo.u32FrameRate,&CurrentInput->main.fps);
    QOS_DBG_LV_3("%s %d input resolution :%d fps:%d\n",__FUNCTION__,__LINE__,CurrentInput->main.in_resolution,CurrentInput->main.fps);

    memset(&stVDECInfo, 0, sizeof(VDEC_EX_DispInfo));
    if (MApi_VDEC_EX_GetControl(&stStreamId, E_VDEC_EX_USER_CMD_GET_SUB_STREAM_ID, (MS_U32 *)&stGetStreamId))
    {
        QOS_DBG_LV_3("%s %d Get sub stream id fail \n",__FUNCTION__,__LINE__);
        CurrentInput->sub.codec = E_QOS_CODEC_TYPE_NONE;
        CurrentInput->sub.in_resolution = E_QOS_RESOLUTION_NONE;
        CurrentInput->sub.fps = E_QOS_FPS_NONE;
        return E_QOS_RESULT_FAIL;
    }
    QosCodecMapping(MApi_VDEC_EX_GetActiveCodecType(&stGetStreamId),&CurrentInput->sub.codec);
    if (CurrentInput->sub.codec == E_QOS_CODEC_TYPE_NONE)
    {
        QOS_DBG_LV_3("%s %d Get sub codec type fail \n",__FUNCTION__,__LINE__);
        CurrentInput->sub.in_resolution = E_QOS_RESOLUTION_NONE;
        CurrentInput->sub.fps = E_QOS_FPS_NONE;
        return E_QOS_RESULT_FAIL;
    }

    if(MApi_VDEC_EX_GetDispInfo(&stGetStreamId, &stVDECInfo) != E_VDEC_EX_OK)
    {
        QOS_DBG_LV_3("%s %d Get sub vdec disp info fail \n",__FUNCTION__,__LINE__);
        CurrentInput->sub.in_resolution = E_QOS_RESOLUTION_NONE;
        CurrentInput->sub.fps = E_QOS_FPS_NONE;
        return E_QOS_RESULT_FAIL;
    }
    QOS_DBG_LV_3("%s %d Get sub codec:%d vdec disp info width:%d height:%d fps:%d\n",__FUNCTION__,__LINE__,CurrentInput->sub.codec,stVDECInfo.u16HorSize,stVDECInfo.u16VerSize,stVDECInfo.u32FrameRate);
    QosResolutionMapping(stVDECInfo.u16VerSize,stVDECInfo.u16HorSize,&CurrentInput->sub.in_resolution);
    QosVdecFpsMapping(stVDECInfo.u32FrameRate,&CurrentInput->sub.fps);
    QOS_DBG_LV_3("%s %d input resolution :%d fps:%d\n",__FUNCTION__,__LINE__,CurrentInput->sub.in_resolution,CurrentInput->sub.fps);

    return E_QOS_RESULT_OK;
}

static EN_QOS_RESULT QosSetModuleLevel(MS_U32 Level,EN_QOS_BW_MODULE Module)
{
    ST_XC_QOS_SCALER_BW_INFO XcQosBWInfo;
    ST_XC_QOS_FRC_BW_INFO FrcQosBWInfo;
    ST_PNL_QOS_BW_INFO PnlQosBWInfo;
    ST_PQ_QOS_BW_INFO PqQosBWInfo;
#ifdef QOS_OUTPUT_AIPQ_ENABLE
    ST_DMS_BW_INFO AipqQosBWInfo;
#endif
    VDEC_StreamId stStreamId, stGetStreamId;
    if (Module == E_QOS_BW_SCALER)
    {
        QOS_DBG_LV_3("%s %d Adjust XC level to :%d\n",__FUNCTION__,__LINE__,Level);

        memset(&XcQosBWInfo, 0, sizeof(ST_XC_QOS_SCALER_BW_INFO));
        XcQosBWInfo.enScalerBWmode = (EN_XC_SCALER_BW_MODE)Level;
        XcQosBWInfo.enWin = MAIN_WINDOW;

        if (MApi_XC_SetScalerBWLevel(&XcQosBWInfo)== TRUE)
        {
            QOS_DBG_LV_3("%s %d Adjust xc bw level to %d success\n",__FUNCTION__,__LINE__,Level);
        }
        else
        {
            QOS_DBG_LV_3("%s %d Adjust xc bw level to %d failed\n",__FUNCTION__,__LINE__,Level);
            return E_QOS_RESULT_FAIL;
        }
    }
    else if (Module == E_QOS_BW_FRC)
    {
       QOS_DBG_LV_3("%s %d Adjust FRC \n",__FUNCTION__,__LINE__);
       memset(&FrcQosBWInfo, 0, sizeof(ST_XC_QOS_FRC_BW_INFO));
       FrcQosBWInfo.u32Length = sizeof(ST_XC_QOS_FRC_BW_INFO);
       FrcQosBWInfo.u32Version = ST_XC_QOS_FRC_BW_INFO_VERSION;
       FrcQosBWInfo.enFRCBWmode = (EN_XC_FRC_BW_MODE)Level;
       FrcQosBWInfo.enWin = MAIN_WINDOW;

       if (MApi_XC_SetFRCBWLevel(&FrcQosBWInfo)== TRUE)
       {
           QOS_DBG_LV_3("%s %d Adjust FRC bw level to %d Success",__FUNCTION__,__LINE__,Level);
       }
       else
       {
           QOS_DBG_LV_3("%s %d Adjust FRC bw level to %d failed\n",__FUNCTION__,__LINE__,Level);
           return E_QOS_RESULT_FAIL;
       }

    }
    else if (Module == E_QOS_BW_PNL)
    {
       QOS_DBG_LV_3("%s %d Adjust PNL \n",__FUNCTION__,__LINE__);
       memset(&PnlQosBWInfo, 0, sizeof(ST_PNL_QOS_BW_INFO));
       PnlQosBWInfo.u32Length = sizeof(ST_PNL_QOS_BW_INFO);
       PnlQosBWInfo.u32Version = ST_PNL_QOS_BW_INFO_VERSION;
       PnlQosBWInfo.enOverdriveMode = (EN_PNL_OVERDRIVE_MODE)Level;
       PnlQosBWInfo.enPNLWin = E_PNL_MAIN_WINDOW;

       if (MApi_PNL_SetBWLevel(&PnlQosBWInfo)== TRUE)
       {
           QOS_DBG_LV_3("%s %d Adjust PNL bw level to %d Success\n",__FUNCTION__,__LINE__,Level);
       }
       else
       {
           QOS_DBG_LV_3("%s %d Adjust PNL bw level to %d failed\n",__FUNCTION__,__LINE__,Level);
           return E_QOS_RESULT_FAIL;
       }


    }
    else if (Module == E_QOS_BW_PQ)
    {
       QOS_DBG_LV_3("%s %d Adjust PQ \n",__FUNCTION__,__LINE__);
       memset(&PqQosBWInfo, 0, sizeof(ST_PQ_QOS_BW_INFO));
       PqQosBWInfo.u32Length = sizeof(ST_PQ_QOS_BW_INFO);
       PqQosBWInfo.u32Version = ST_PQ_QOS_BW_INFO_VERSION;
       PqQosBWInfo.enBWDType = (PQ_BWD_TYPE)Level;
       PqQosBWInfo.enWindow = PQ_MAIN_WINDOW;
       if (MDrv_PQ_SetBWLevel(&PqQosBWInfo)== TRUE)
       {
           QOS_DBG_LV_3("%s %d Adjust PQ bw level to %d Success\n",__FUNCTION__,__LINE__,Level);
       }
       else
       {
           QOS_DBG_LV_3("%s %d Adjust PQ bw level to %d failed\n",__FUNCTION__,__LINE__,Level);
           return E_QOS_RESULT_FAIL;
       }
    }
    else if (Module == E_QOS_BW_VDEC)
    {
       QOS_DBG_LV_3("%s %d Adjust VDEC \n",__FUNCTION__,__LINE__);
       if (MApi_VDEC_EX_GetControl(&stStreamId, E_VDEC_EX_USER_CMD_GET_MAIN_STREAM_ID, (MS_U32 *)&stGetStreamId) != E_VDEC_EX_OK)
       {
           QOS_DBG_LV_3("%s %d Get main streamd id faile\n",__FUNCTION__,__LINE__);
           return E_QOS_RESULT_FAIL;
       }

       if (MApi_VDEC_EX_SetControl((VDEC_StreamId *)&stGetStreamId, E_VDEC_EX_USER_CMD_SET_MIN_VDEC_PLUS_DROP_RATIO,(MS_VIRT)Level) == E_VDEC_EX_OK)
       {
           QOS_DBG_LV_3("%s %d Adjust Vdec level to %d Success\n",__FUNCTION__,__LINE__,Level);
       }
       else
       {
           QOS_DBG_LV_3("%s %d Adjust Vdec level to %d failed\n",__FUNCTION__,__LINE__,Level);
           return E_QOS_RESULT_FAIL;
       }
    }
#ifdef QOS_OUTPUT_AIPQ_ENABLE
    else if (Module == E_QOS_BW_AI_PQ)
    {
       QOS_DBG_LV_3("%s %d Adjust AIPQ \n",__FUNCTION__,__LINE__);
       memset(&AipqQosBWInfo, 0, sizeof(ST_DMS_BW_INFO));
       AipqQosBWInfo.u32Length = sizeof(ST_DMS_BW_INFO);
       AipqQosBWInfo.u32Version = VERSION_ST_DMS_BW_INFO;
       AipqQosBWInfo.enDMSBWMode = (EN_DMS_BW_MODE)Level;
       if (MApi_DMS_SetBWLevel(MAIN_WINDOW,&AipqQosBWInfo) == E_FUNC_OK)
       {
           QOS_DBG_LV_3("%s %d Adjust AIPQ bw level to %d Success\n",__FUNCTION__,__LINE__,Level);
       }
       else
       {
           QOS_DBG_LV_3("%s %d Adjust AIPQ bw level to %d failed\n",__FUNCTION__,__LINE__,Level);
           return E_QOS_RESULT_FAIL;
       }
    }
#endif

    return E_QOS_RESULT_OK;
}

static EN_QOS_RESULT QosSetAllModuleBestLevel(void)
{
    MS_U32 Level = 0;

    Level =(MS_U32)PQ_BWD_OFF;
    if (QosSetModuleLevel(Level,E_QOS_BW_PQ) == E_QOS_RESULT_OK)
    {
        QOS_DBG_LV_1("%s %d set best PQ level %d\n",__FUNCTION__,__LINE__,Level);
    }
    Level = (MS_U32)E_XC_FRC_BW_NORMAL_MODE;
    if (QosSetModuleLevel(Level,E_QOS_BW_FRC) == E_QOS_RESULT_OK)
    {
        QOS_DBG_LV_1("%s %d set best FRC level %d\n",__FUNCTION__,__LINE__,Level);
    }
    Level = (MS_U32)E_PNL_OVERDRIVE_ON;
    if (QosSetModuleLevel(Level,E_QOS_BW_PNL) == E_QOS_RESULT_OK)
    {
        QOS_DBG_LV_1("%s %d set best PNL OD level %d\n",__FUNCTION__,__LINE__,Level);
    }
    Level = (MS_U32)E_VDEC_EX_VDEC_PLUS_DROP_RATIO_1;
    if (QosSetModuleLevel(Level,E_QOS_BW_VDEC) == E_QOS_RESULT_OK)
    {
        QOS_DBG_LV_1("%s %d set best VDEC level %d\n",__FUNCTION__,__LINE__,Level);
    }
#ifdef QOS_OUTPUT_AIPQ_ENABLE
    Level = (MS_U32)E_DMS_BW_NORMAL_MODE;
    if (QosSetModuleLevel(Level,E_QOS_BW_AI_PQ) == E_QOS_RESULT_OK)
    {
        QOS_DBG_LV_1("%s %d set best AIPQ level %d\n",__FUNCTION__,__LINE__,Level);
    }
#endif
    return E_QOS_RESULT_OK;
}

static EN_QOS_RESULT QosSetAllModuleDefaultLevel(MS_U32 index)
{
    MS_U32 Level = 0;
    MS_U32 DefaultLevel = 0;

    DefaultLevel = QosTable->scenario[index].input.default_setting;
    if (DefaultLevel >=0 && DefaultLevel < LEVEL_MAX)
    {
        QOS_DBG_LV_1("%s %d Default level:%d\n",__FUNCTION__,__LINE__,DefaultLevel);
    }
    else
    {
        DefaultLevel = QosTableDefaultLevel;
        QOS_DBG_LV_1("%s %d Qos table default_setting error, reset default level to :%d\n",__FUNCTION__,__LINE__,DefaultLevel);
    }
    _stSituation.u8VdecLevel = DefaultLevel;
    _stSituation.u8ScalerLevel = DefaultLevel;
    _stSituation.u8FrcLevel = DefaultLevel;
    _stSituation.u8PnlLevel = DefaultLevel;
    _stSituation.u8PqLevel = DefaultLevel;
#ifdef QOS_OUTPUT_AIPQ_ENABLE
    _stSituation.u8AipqLevel = DefaultLevel;
#endif

    QOS_DBG_LV_1("%s %d Default level:%d\n",__FUNCTION__,__LINE__,DefaultLevel);
    Level = (MS_U32)QosTable->scenario[index].output.pq[DefaultLevel].type;
    if (QosTable->scenario[index].output.pq[DefaultLevel].base != E_QOS_PQ_NONE)
    {
        if (QosSetModuleLevel(Level,E_QOS_BW_PQ) == E_QOS_RESULT_OK)
        {
            QOS_DBG_LV_1("%s %d set default PQ level\n",__FUNCTION__,__LINE__);
        }
    }
    Level = (MS_U32)QosTable->scenario[index].output.frc[DefaultLevel].type;
    if (QosTable->scenario[index].output.frc[DefaultLevel].base != E_QOS_FRC_NONE)
    {
        if (QosSetModuleLevel(Level,E_QOS_BW_FRC) == E_QOS_RESULT_OK)
        {
            QOS_DBG_LV_1("%s %d set default FRC level\n",__FUNCTION__,__LINE__);
        }
    }
    Level = (MS_U32)QosTable->scenario[index].output.od[DefaultLevel].type;
    if (QosTable->scenario[index].output.od[DefaultLevel].base != E_QOS_OD_NONE)
    {
        if (QosSetModuleLevel(Level,E_QOS_BW_PNL) == E_QOS_RESULT_OK)
        {
            QOS_DBG_LV_1("%s %d set default PNL OD level\n",__FUNCTION__,__LINE__);
        }
    }
    Level = (MS_U32)QosTable->scenario[index].output.vdec[DefaultLevel].type;
    if (QosTable->scenario[index].output.vdec[DefaultLevel].base != E_QOS_CODEC_NONE)
    {
        if (QosSetModuleLevel(Level,E_QOS_BW_VDEC) == E_QOS_RESULT_OK)
        {
            QOS_DBG_LV_1("%s %d set default VDEC level\n",__FUNCTION__,__LINE__);
        }
    }
#ifdef QOS_OUTPUT_AIPQ_ENABLE
    Level = (MS_U32)QosTable->scenario[index].output.aipq[DefaultLevel].type;
    if (QosTable->scenario[index].output.aipq[DefaultLevel].base != E_QOS_AIPQ_NONE)
    {
        if (QosSetModuleLevel(Level,E_QOS_BW_AI_PQ) == E_QOS_RESULT_OK)
        {
            QOS_DBG_LV_1("%s %d set default AIPQ level\n",__FUNCTION__,__LINE__);
        }
    }
#endif
    return E_QOS_RESULT_OK;
}

static void _Qos_Task(void* pInstance)
{
    MS_U32 u32Events = 0;
    MS_U32 index = 0;
    MS_S32 PqLevel = 0;
    MS_S32 PnlLevel = 0;
    MS_S32 FrcLevel = 0;
    MS_S32 VdecLevel = 0;
#ifdef QOS_OUTPUT_AIPQ_ENABLE
    MS_S32 AipqLevel = 0;
#endif
    MS_U32 Level;
    while ( g_bQosTask == TRUE)
    {

//        MsOS_WaitEvent(_s32QosEventId, E_QOS_EVENT_BW_ADJUST|E_QOS_EVENT_CODEC_CHANGE|E_QOS_EVENT_INPUT_SOURCE_CHANGE|E_QOS_EVENT_INPUT_SOURCE_READY|E_QOS_EVENT_PVR|E_QOS_EVENT_CAPTURE|E_QOS_EVENT_AIPQ|E_QOS_EVENT_VR360|E_QOS_EVENT_ROTATE, &u32Events, E_OR_CLEAR, MSOS_WAIT_FOREVER);
        MsOS_WaitEvent(_s32QosEventId, E_QOS_EVENT_BW_ADJUST, &u32Events, E_OR_CLEAR, MSOS_WAIT_FOREVER);

        QOS_DBG_LV_2("%s %d Event:%d \n",__FUNCTION__,__LINE__,u32Events);

        if (u32Events & E_QOS_EVENT_BW_ADJUST)
        {
            QOS_DBG_LV_2("%s %d Event Adjust BW \n",__FUNCTION__,__LINE__);

            index = SearchQosTableUseCase(CurrentInput,QosTable);
            if (index >= QosTable->cases)
                continue;

            if (_stAdjustInfo.enModule & E_QOS_BW_SCALER)
            {
                QOS_DBG_LV_2("%s %d Adjust XC, do nothing now\n",__FUNCTION__,__LINE__);
            }
            if (_stAdjustInfo.enModule & E_QOS_BW_VDEC)
            {
                QOS_DBG_LV_2("%s %d Adjust VDEC\n",__FUNCTION__,__LINE__);
                VdecLevel = _stSituation.u8VdecLevel;
                if ((VdecLevel + _stAdjustInfo.s32BwValue) <=0)
                    VdecLevel = 0;
                else if ((VdecLevel + _stAdjustInfo.s32BwValue) > LEVEL_MAX - 1)
                    VdecLevel = LEVEL_MAX - 1;
                else
                    VdecLevel = VdecLevel + _stAdjustInfo.s32BwValue;

                Level = QosTable->scenario[index].output.vdec[VdecLevel].type;
                if (QosTable->scenario[index].output.vdec[Level].base != E_QOS_CODEC_NONE)
                {
                    if (QosTable->scenario[index].output.vdec[_stSituation.u8VdecLevel].type != (VDEC_EX_VdecPlusDropRatio)Level)
                    {
                       QosSetModuleLevel((MS_U32)Level,E_QOS_BW_VDEC);
                    }
                }
                _stSituation.u8VdecLevel = VdecLevel;

            }
            if (_stAdjustInfo.enModule & E_QOS_BW_FRC)
            {
                QOS_DBG_LV_2("%s %d Adjust FRC \n",__FUNCTION__,__LINE__);
                FrcLevel = _stSituation.u8FrcLevel;
                if ((FrcLevel + _stAdjustInfo.s32BwValue) <=0)
                    FrcLevel = 0;
                else if ((FrcLevel + _stAdjustInfo.s32BwValue) > LEVEL_MAX - 1)
                    FrcLevel = LEVEL_MAX - 1;
                else
                    FrcLevel = FrcLevel + _stAdjustInfo.s32BwValue;

                Level = (MS_U32)QosTable->scenario[index].output.frc[FrcLevel].type;
                if (QosTable->scenario[index].output.frc[Level].base != E_QOS_FRC_NONE)
                {
                    if (QosTable->scenario[index].output.frc[_stSituation.u8FrcLevel].type != (EN_XC_FRC_BW_MODE)Level)
                    {
                        QosSetModuleLevel((MS_U32)Level,E_QOS_BW_FRC);
                    }
                }
                _stSituation.u8FrcLevel = FrcLevel;

            }
            if (_stAdjustInfo.enModule & E_QOS_BW_PNL)
            {
                QOS_DBG_LV_2("%s %d Adjust PNL \n",__FUNCTION__,__LINE__);
                PnlLevel = _stSituation.u8PnlLevel;
                if ((PnlLevel + _stAdjustInfo.s32BwValue) <=0)
                    PnlLevel = 0;
                else if ((PnlLevel + _stAdjustInfo.s32BwValue) > LEVEL_MAX - 1)
                    PnlLevel = LEVEL_MAX - 1;
                else
                    PnlLevel = PnlLevel + _stAdjustInfo.s32BwValue;

                Level = (MS_U32)QosTable->scenario[index].output.od[PnlLevel].type;
                if (QosTable->scenario[index].output.od[Level].base != E_QOS_OD_NONE)
                {
                    if (QosTable->scenario[index].output.od[_stSituation.u8PnlLevel].type != (EN_PNL_OVERDRIVE_MODE)Level)
                    {
                        QosSetModuleLevel((MS_U32)Level,E_QOS_BW_PNL);
                    }
                }
                _stSituation.u8PnlLevel = PnlLevel;
            }
            if (_stAdjustInfo.enModule & E_QOS_BW_PQ)
            {
                QOS_DBG_LV_2("%s %d Adjust PQ \n",__FUNCTION__,__LINE__);
                PqLevel = _stSituation.u8PqLevel;
                if ((PqLevel + _stAdjustInfo.s32BwValue) <=0)
                    PqLevel = 0;
                else if ((PqLevel + _stAdjustInfo.s32BwValue) > LEVEL_MAX - 1)
                    PqLevel = LEVEL_MAX - 1;
                else
                    PqLevel = PqLevel + _stAdjustInfo.s32BwValue;

                Level = (MS_U32)QosTable->scenario[index].output.pq[PqLevel].type;
                if (QosTable->scenario[index].output.pq[Level].base != E_QOS_PQ_NONE)
                {
                    if (QosTable->scenario[index].output.pq[_stSituation.u8PqLevel].type != (PQ_BWD_TYPE)Level)
                    {
                        _stSituation.u8PqLevel = PqLevel;
                        QosSetModuleLevel((MS_U32)Level,E_QOS_BW_PQ);
                    }
                }
                _stSituation.u8PqLevel = PqLevel;
            }
#ifdef QOS_OUTPUT_AIPQ_ENABLE
            if (_stAdjustInfo.enModule & E_QOS_BW_AI_PQ)
            {
                QOS_DBG_LV_2("%s %d Adjust AIPQ \n",__FUNCTION__,__LINE__);
                AipqLevel = _stSituation.u8AipqLevel;
                if ((AipqLevel + _stAdjustInfo.s32BwValue) <=0)
                    AipqLevel = 0;
                else if ((AipqLevel + _stAdjustInfo.s32BwValue) > LEVEL_MAX - 1)
                    AipqLevel = LEVEL_MAX - 1;
                else
                    AipqLevel = AipqLevel + _stAdjustInfo.s32BwValue;

                Level = (MS_U32)QosTable->scenario[index].output.aipq[AipqLevel].type;
                QOS_DBG_LV_1("%s %d Adjust AIPQ Level:%d\n",__FUNCTION__,__LINE__,Level);
                if (QosTable->scenario[index].output.aipq[Level].base != E_QOS_AIPQ_NONE)
                {
                    if (QosTable->scenario[index].output.aipq[_stSituation.u8AipqLevel].type != (EN_DMS_BW_MODE)Level)
                    {
                        _stSituation.u8AipqLevel = AipqLevel;
                        QosSetModuleLevel((MS_U32)Level,E_QOS_BW_AI_PQ);
                    }
                }
                _stSituation.u8AipqLevel = AipqLevel;
            }
#endif
        }
    }
}

static void _OSD_Handle(void)
{
    ST_DMS_BW_INFO QosMutelessInfo;
    QOS_DBG_LV_1("%s %d osd:%d, match_idx:%d\n",__FUNCTION__,__LINE__,OsdShow, CurrentIdx);
    memset(&QosMutelessInfo, 0, sizeof(ST_DMS_BW_INFO));
    QosMutelessInfo.u32Length = sizeof(ST_DMS_BW_INFO);
    QosMutelessInfo.u32Version = VERSION_ST_DMS_BW_INFO;
    QosMutelessInfo.enDMSBWMode = E_DMS_BW_PQ_DEFAULT;

    if (OsdShow == 1)
    {
        QosMutelessInfo.enDMSBWMode = E_DMS_BW_PQ_OFF_MODE;
    }
    else
    {
        QosMutelessInfo.enDMSBWMode = E_DMS_BW_PQ_DEFAULT;
    }

    if (MApi_DMS_SetBWLevel(MAIN_WINDOW,&QosMutelessInfo) == E_FUNC_OK)
    {
        QOS_DBG_LV_1("%s %d Adjust Muteless Success\n",__FUNCTION__,__LINE__);
    }
    else
    {
        QOS_DBG_LV_1("%s %d Adjust Muteless Failed\n",__FUNCTION__,__LINE__);
    }
}


static void _Qos_BwMonitor(void* pInstance)
{
    MS_U32 u32Events = 0;
    MS_BOOL pSecureBuffSlot = FALSE;
    MS_U32 BwUsage[QOS_MONITOR_WINDOW];
    MS_U32 BwCounter = 0;
    MS_U32 i = 0;
    //Monitor all channel
    MS_U8 u8MiuDev = E_MIU_CHANNEL_ALL;
    MIU_BandwidthMonitorInfo pBWInfo;
    MS_U32 CurrentBW = 0;
    MS_U32 WindowBW = 0;
    ST_QOS_BW_ADJUST_INFO AutoAdjustInfo;
    MS_BOOL bMaxLevel = FALSE;
    MS_BOOL bMinLevel = FALSE;
    MS_U32 OsdPixel = 0;
    QOS_DBG_LV_1("%s %d \n",__FUNCTION__,__LINE__);

    memset(BwUsage, 0, sizeof(MS_U32)*QOS_MONITOR_WINDOW);
    memset(&AutoAdjustInfo, 0,sizeof(ST_QOS_BW_ADJUST_INFO));

    //select monitor index 7 to get setting
    pBWInfo.u32MonitorIndex = E_MONITOR_INDEX_7;
    pBWInfo.bMonitorAllMIU = TRUE;
    QOS_DBG_LV_1("%s %d Qos BW monitor interval:%lu \n",__FUNCTION__,__LINE__,Qos_Polling_Interval);
    while (g_bQosBwMonitor == TRUE)
    {
        if ( bSysEnable == FALSE || bAutoAdjBwEnable == FALSE)
        {
            QOS_DBG_LV_1("%s %d QoS sys disable, stop bw monitor\n",__FUNCTION__,__LINE__);
            MsOS_WaitEvent(_s32QosEventId, E_QOS_EVENT_RESTART, &u32Events, E_OR_CLEAR, MSOS_WAIT_FOREVER);
            QOS_DBG_LV_1("%s %d QoS sys enable, start bw monitor\n",__FUNCTION__,__LINE__);
        }

#ifdef QOS_OSD_DETECT_ENABLE
        if ( (CurrentIdx != -1 ) && \
             (CurrentInput->osd_event.bEnable == 1) && \
             (CurrentInput->osd_event.NonTransCntThreshold != 0)) // only detect when use case in QoS table matched.
        {
            if(MApi_GOP_GetOsdNonTransCnt(&OsdPixel) != GOP_API_SUCCESS)
            {
                QOS_DBG_LV_1("%s %d Get OSD Status fail\n",__FUNCTION__,__LINE__);
            }
            else
            {
                if ( (OsdPixel >= CurrentInput->osd_event.NonTransCntThreshold) && (OsdShow == 0) )
                {
                    OsdShow = 1;
                    _OSD_Handle();
                    QOS_DBG_LV_2("%s %d OSD is showing\n",__FUNCTION__,__LINE__);
                }
                else if ( (OsdPixel < CurrentInput->osd_event.NonTransCntThreshold) && (OsdShow == 1) )
                {
                    OsdShow = 0;
                    _OSD_Handle();
                    QOS_DBG_LV_2("%s %d OSD is not showing\n",__FUNCTION__,__LINE__);
                }
            }
         }
#endif

        pBWInfo.stSamplingFrequency.u32UpdateFrequencyValue = Qos_Polling_Interval;
        pSecureBuffSlot = MDrv_MIU_Set_BW_Monitor(u8MiuDev, &pBWInfo);

        if(pSecureBuffSlot == FALSE)
        {
            QOS_DBG_LV_1("%s %d warning!! set bw monitor error \n",__FUNCTION__,__LINE__);
            continue;
        }

        MDrv_MIU_Start_BW_Monitor(u8MiuDev);
        MsOS_DelayTask(pBWInfo.stSamplingFrequency.u32UpdateFrequencyValue);
        QOS_DBG_LV_4("%s %d Qos BW monitor after delay:%d \n",__FUNCTION__,__LINE__,pBWInfo.stSamplingFrequency.u32UpdateFrequencyValue);

        if( MDrv_MIU_Get_BW(u8MiuDev, &pBWInfo) != TRUE)
        {
            QOS_DBG_LV_1("%s %d warning!! get bw error \n",__FUNCTION__,__LINE__);
            continue;
        }

        if (BwCounter >= QOS_MONITOR_WINDOW)
        {
            BwCounter = 0;
        }

        CurrentBW = pBWInfo.stCurrentBandwidth.u32ReportImmediateUsage/MiuChannelNum;
        BwUsage[BwCounter] = CurrentBW;
        BwCounter++;
        WindowBW = 0;

        for (i = 0; i < QOS_MONITOR_WINDOW; i++)
        {
            WindowBW += BwUsage[i];
        }

        WindowBW = WindowBW/QOS_MONITOR_WINDOW;
	    _pstBwInfo->u32BwUsage = CurrentBW;
        QOS_DBG_LV_4("%s %d Current BW:%d \n",__FUNCTION__,__LINE__,CurrentBW);
        QOS_DBG_LV_2("%s %d Current adam Current BW:%d Window BW:%d \n",__FUNCTION__,__LINE__,CurrentBW,WindowBW);

        if (bAutoAdjBwEnable == TRUE)
        {
            if (CurrentBW > QosAutoUpperThreshold)
            {
                bMaxLevel = (_stSituation.u8VdecLevel == (LEVEL_MAX - 1))?TRUE:FALSE;
                bMaxLevel = (_stSituation.u8ScalerLevel == (LEVEL_MAX - 1))?TRUE:FALSE;
                bMaxLevel = (_stSituation.u8FrcLevel == (LEVEL_MAX - 1))?TRUE:FALSE;
                bMaxLevel = (_stSituation.u8PnlLevel == (LEVEL_MAX - 1))?TRUE:FALSE;
                bMaxLevel = (_stSituation.u8PqLevel == (LEVEL_MAX - 1))?TRUE:FALSE;
#ifdef QOS_OUTPUT_AIPQ_ENABLE
                bMaxLevel = (_stSituation.u8AipqLevel == (LEVEL_MAX - 1))?TRUE:FALSE;
#endif

                QOS_DBG_LV_4("%s %d bMaxLevel:%d \n",__FUNCTION__,__LINE__,bMaxLevel);
                if (bMaxLevel == FALSE)
                {
                    AutoAdjustInfo.enModule = E_QOS_BW_ALL;
                    AutoAdjustInfo.enBwType = E_QOS_BW_LEVEL;
                    AutoAdjustInfo.s32BwValue = 1;
                    AutoAdjustInfo.enAdjType = E_QOS_ADJUST_MAX;
                    MDrv_QOS_AdjustBw(AutoAdjustInfo);
                }
            }
            else if (WindowBW < QosAutoLowerThreshold)
            {
                bMinLevel = (_stSituation.u8VdecLevel == 0)?TRUE:FALSE;
                bMinLevel = (_stSituation.u8ScalerLevel == 0)?TRUE:FALSE;
                bMinLevel = (_stSituation.u8FrcLevel == 0)?TRUE:FALSE;
                bMinLevel = (_stSituation.u8PnlLevel == 0)?TRUE:FALSE;
                bMinLevel = (_stSituation.u8PqLevel == 0)?TRUE:FALSE;
#ifdef QOS_OUTPUT_AIPQ_ENABLE
                bMinLevel = (_stSituation.u8AipqLevel == 0)?TRUE:FALSE;
#endif

                QOS_DBG_LV_4("%s %d bMinLevel:%d \n",__FUNCTION__,__LINE__,bMinLevel);
                if (bMinLevel == FALSE)
                {
                    AutoAdjustInfo.enModule = E_QOS_BW_ALL;
                    AutoAdjustInfo.enBwType = E_QOS_BW_LEVEL;
                    AutoAdjustInfo.s32BwValue = -1;
                    AutoAdjustInfo.enAdjType = E_QOS_ADJUST_MAX;
                    MDrv_QOS_AdjustBw(AutoAdjustInfo);
                }
            }
            else
            {
                QOS_DBG_LV_2("%s %d keep same level \n",__FUNCTION__,__LINE__);
            }


        }
    }
}

static MS_BOOL MDrv_QOS_XcNotifyModuleStatusCb(ST_XC_QOS_INPUTSOURCE_INFO *pstQosInputSourceInf)
{
    MS_U32 index = 0;
    MS_U32 Level = 0;
    static MS_BOOL bBestLevel = 0;

    QOS_DBG_LV_1("%s %d event type:%d\n",__FUNCTION__,__LINE__, pstQosInputSourceInf->enXCQosEvntStatus);

    if (_bQosInit == FALSE)
    {
        QOS_DBG_LV_1("[%s][%d] Qos doesn't init, couldn't call %s\n", __FUNCTION__, __LINE__,__FUNCTION__);
        return E_QOS_RESULT_FAIL;
    }

    if (bSysEnable == FALSE)
    {
        QOS_DBG_LV_1("%s %d QoS sys disable!!!\n",__FUNCTION__,__LINE__);
        return E_QOS_RESULT_FAIL;
    }

    QOS_DBG_LV_1("%s %d input source type:%d\n",__FUNCTION__,__LINE__, pstQosInputSourceInf->enInputSourceType);
    QOS_DBG_LV_1("%s %d event type:%d\n",__FUNCTION__,__LINE__, pstQosInputSourceInf->enXCQosEvntStatus);
    QosXcInputSourceMapping(pstQosInputSourceInf->enInputSourceType,&CurrentInput->source);
    QOS_DBG_LV_1("%s %d Current input source type:%d\n",__FUNCTION__,__LINE__, CurrentInput->source);
    if (pstQosInputSourceInf->enXCQosEvntStatus == E_XC_QOS_EVENT_SETWINDOW_INFO)
    {
        QOS_DBG_LV_1("%s %d input resolution height:%d width:%d\n",__FUNCTION__,__LINE__, pstQosInputSourceInf->stXC_SetWin_Info.stCapWin.height,pstQosInputSourceInf->stXC_SetWin_Info.stCapWin.width);
        QOS_DBG_LV_1("%s %d display resolution height:%d width:%d\n",__FUNCTION__,__LINE__, pstQosInputSourceInf->stXC_SetWin_Info.stDispWin.height,pstQosInputSourceInf->stXC_SetWin_Info.stDispWin.width);
        QOS_DBG_LV_1("%s %d inputvfreq:%d\n",__FUNCTION__,__LINE__, pstQosInputSourceInf->stXC_SetWin_Info.u16InputVFreq);

        if (CurrentInput->source == E_QOS_MM || CurrentInput->source == E_QOS_DTV || CurrentInput->source == E_QOS_YOUTUBE || CurrentInput->source == E_QOS_NETFLIX )
        {
            QosGetCurrentVdecInfo(); // MM case, input information is from vdec
        }
        else                         // HDMI case, input information is from xc
        {
            if (pstQosInputSourceInf->enWin == MAIN_WINDOW)
            {
                CurrentInput->main.codec = E_QOS_CODEC_TYPE_NONE;
                QosResolutionMapping(pstQosInputSourceInf->stXC_SetWin_Info.stCapWin.height,pstQosInputSourceInf->stXC_SetWin_Info.stCapWin.width,&CurrentInput->main.in_resolution);
                QosXCFpsMapping(pstQosInputSourceInf->stXC_SetWin_Info.u16InputVFreq,&CurrentInput->main.fps);
            }
            else if (pstQosInputSourceInf->enWin == SUB_WINDOW)
            {
                CurrentInput->sub.codec = E_QOS_CODEC_TYPE_NONE;
                QosResolutionMapping(pstQosInputSourceInf->stXC_SetWin_Info.stCapWin.height,pstQosInputSourceInf->stXC_SetWin_Info.stCapWin.width,&CurrentInput->sub.in_resolution);
                QosXCFpsMapping(pstQosInputSourceInf->stXC_SetWin_Info.u16InputVFreq,&CurrentInput->sub.fps);
            }
            else
            {
                QOS_DBG_LV_1("%s %d unknown enWin !!\n",__FUNCTION__,__LINE__);
            }
        }
    }
    if (pstQosInputSourceInf->enXCQosEvntStatus == E_XC_QOS_EVENT_PANELTIMING_INFO)
    {
        QOS_DBG_LV_1("%s %d panel resolution height:%d width:%d\n",__FUNCTION__,__LINE__, pstQosInputSourceInf->stPanelSize.height,pstQosInputSourceInf->stPanelSize.width);
        QosResolutionMapping(pstQosInputSourceInf->stPanelSize.height,pstQosInputSourceInf->stPanelSize.width,&CurrentInput->main.out_resolution);
        QOS_DBG_LV_1("%s %d QoS panel resolution:%d\n",__FUNCTION__,__LINE__, CurrentInput->main.out_resolution);
        CurrentInput->sub.out_resolution = E_QOS_RESOLUTION_NONE;
    }
    if (bBestLevel == 0)
    {
        QosSetAllModuleBestLevel();
        QOS_DBG_LV_1("%s %d using all module best level\n",__FUNCTION__,__LINE__);
        bBestLevel = 1;
    }
    index = SearchQosTableUseCase(CurrentInput,QosTable);
    if (index >= QosTable->cases)
    {
        CurrentIdx = -1;
        QOS_DBG_LV_1("%s %d no matching scenario\n",__FUNCTION__,__LINE__);
        return TRUE;
    }
    QosSetAllModuleDefaultLevel(index);
    QOS_DBG_LV_1("%s %d using all Qos default level\n",__FUNCTION__,__LINE__);
    bBestLevel = 0;
    CurrentIdx = index;
#ifdef QOS_OSD_DETECT_ENABLE
    CurrentInput->osd_event.bEnable = QosTable->scenario[index].input.osd_event.bEnable;
    CurrentInput->osd_event.NonTransCntThreshold = QosTable->scenario[index].input.osd_event.NonTransCntThreshold;
    QOS_DBG_LV_1("id = %d, enable = %d, threshold = 0x%x\n", CurrentIdx, CurrentInput->osd_event.bEnable, CurrentInput->osd_event.NonTransCntThreshold);
#endif
    return TRUE;
}

static void _Qos_XcRegister(void* pInstance)
{
    MS_U32 Value = 500; //Delay 500 ms
    XCQoSCallback = utopia_malloc(sizeof(ST_XC_QOS_CALLBACK_INFO));
    XCQoSCallback->u32Version = ST_XC_QOS_CALLBACK_INFO_VERSION;
    XCQoSCallback->u32Length = sizeof(ST_XC_QOS_CALLBACK_INFO);
    XCQoSCallback->pfnFunInputSourceInfo = MDrv_QOS_XcNotifyModuleStatusCb;
    while (MApi_XC_QOS_CallBackFun(XCQoSCallback) == E_APIXC_RET_FAIL)
    {
        QOS_DBG_LV_1("%s %d Register CallBackFunction fail\n",__FUNCTION__,__LINE__);
        MsOS_DelayTask(Value);
    }
}
#ifdef CONFIG_UTOPIA_PROC_DBG_SUPPORT
QOSINFO_CMD stQosInfoCmd[QOSINFO_END_OF_CMD] = {
    {QOSINFO_HELP, "help"},
    {QOSINFO_ENABLE, "enable"},
    {QOSINFO_DISABLE, "disable"},
    {QOSINFO_SET_DEBUG_LEVEL, "debuglevel"},
    {QOSINFO_SET_POLLING_INTERVAL, "setinterval"},
    {QOSINFO_ALL_INFO, "info"},
    {QOSINFO_AUTO_ADJUST,"autoadjust"},
    {QOSINFO_VOICE_ENABLE,"voice"},
    {QOSINFO_UPPER_THRESHOLD,"autoupper"},
    {QOSINFO_LOWER_THRESHOLD,"autolower"},
    {QOSINFO_RELOAD_QOSTABLE,"reloadqostable"},
    {QOSINFO_SET_VDECPLUS_LEVEL,"vdecplus"},
    {QOSINFO_SET_BWD_LEVEL,"bwd"},
    {QOSINFO_SET_OD_LEVEL,"od"},
    {QOSINFO_SET_FRC_LEVEL,"frc"},
    {QOSINFO_DUMP_QOSTABLE,"dumpqostable"},
#ifdef QOS_OUTPUT_AIPQ_ENABLE
    {QOSINFO_SET_AIPQ_LEVEL,"aipq"},
#endif
};
static MS_U32 QOSMdbHelp(MS_U64* u64ReqHdl)
{
    MdbPrint(u64ReqHdl,"---------QOS---------\n");
    MdbPrint(u64ReqHdl,"1. Enable QoS e.x. echo enable > qos  \n\n");
    MdbPrint(u64ReqHdl,"2. Disable QoS e.x. echo disable > qos  \n\n");
    MdbPrint(u64ReqHdl,"3. Set debug level e.x. echo debuglevel 1 > qos  \n\n");
    MdbPrint(u64ReqHdl,"4. Set polling interval(ms) e.x. echo setinterval 100 > qos  \n\n");
    MdbPrint(u64ReqHdl,"5. Get current info e.x. echo info > qos  \n\n");
    MdbPrint(u64ReqHdl,"6. Enable/Disable auto adjust BW function e.x. echo autoadjust 0 > qos  \n\n");
    MdbPrint(u64ReqHdl,"7. Enter google assistant or other 3rd party voice service, set to 1 otherwise set to 0 e.x. echo voice 1 > qos  \n\n");
    MdbPrint(u64ReqHdl,"8. Set auto adjust upper/lower threshold 8000 = 80%s 6000 = 60%s e.x. echo autoupper 8000 > qos , e.x. echo autolower 6000 > qos \n\n","%","%");
    MdbPrint(u64ReqHdl,"9. Reload QoS table(/vendor/tvconfig/config/Qos.bin) e.x. echo reloadqostable > qos \n\n");
    MdbPrint(u64ReqHdl,"10. Set vdecplus level, 1 = no skip, 2 = drop 1/2, 4 = drop 3/4 e.x. echo vdecplus 2 > qos \n\n");
    MdbPrint(u64ReqHdl,"11. Set bwd level, 0 = PQ_BWD_OFF  , 1 = PQ_BWD_LOW, 2 = PQ_BWD_MID, 3 = PQ_BWD_HIGH e.x. echo bwd 2 > qos \n\n");
    MdbPrint(u64ReqHdl,"12. Set od level, 0 = off, 1 = on e.x. echo od 1 > qos \n\n");
    MdbPrint(u64ReqHdl,"13. Set frc level, 0 = repeat mode , 1 = normal mode e.x. echo frc 0 > qos \n\n");
    MdbPrint(u64ReqHdl,"14. Dump Qos table, e.x. echo dumpqostable > qos \n\n");
#ifdef QOS_OUTPUT_AIPQ_ENABLE
    MdbPrint(u64ReqHdl,"15. Set aipq level, 0 = off , 1 = on e.x. echo aipq 0 > qos \n\n");
#endif
    return 0;
}

static MS_U32 QosAllInfo(MS_U64* u64ReqHdl)
{
    MS_U32 index = 0;

    if (_bQosInit == FALSE)
    {
        return 0;
    }
    MdbPrint(u64ReqHdl,"BW monitor current polling interval: %d\n",Qos_Polling_Interval);

    MdbPrint(u64ReqHdl,"Current input source: %d, 0=MM 1=DTV 2=ATV 5=HDMI\n",CurrentInput->source);
    MdbPrint(u64ReqHdl,"Current main codec: %d, 0=H264 1=H265 2=VP9 3=AV1 \n",CurrentInput->main.codec);
    MdbPrint(u64ReqHdl,"Current main in_resolution: %d, 1=HD or below HD 2=FHD 3=UHD 4=8K\n",CurrentInput->main.in_resolution);
    MdbPrint(u64ReqHdl,"Current main in fps: %d, 0=60 1=50 2=30 3=25 4=24\n",CurrentInput->main.fps);
    MdbPrint(u64ReqHdl,"Current main out_resolution: %d, 1=HD or below HD 2=FHD 3=UHD 4=8K\n",CurrentInput->main.out_resolution);

    MdbPrint(u64ReqHdl,"Current sub codec: %d, 0=H264 1=H265 2=VP9 3=AV1\n",CurrentInput->sub.codec);
    MdbPrint(u64ReqHdl,"Current sub in_resolution: %d, 1=HD or below HD 2=FHD 3=UHD 4=8K\n",CurrentInput->sub.in_resolution);
    MdbPrint(u64ReqHdl,"Current sub in fps: %d, 0=60 1=50 2=30 3=25 4=24\n",CurrentInput->sub.fps);
    MdbPrint(u64ReqHdl,"Current sub out_resolution: %d, 1=HD or below HD 2=FHD 3=UHD 4=8K\n",CurrentInput->sub.out_resolution);

    MdbPrint(u64ReqHdl,"Current PVR : %d \n",CurrentInput->bEnablePVR);
    MdbPrint(u64ReqHdl,"Current PIP : %d \n",CurrentInput->bEnablePIP);
    MdbPrint(u64ReqHdl,"Current AIPQ : %d \n",CurrentInput->bEnableAIPQ);
    MdbPrint(u64ReqHdl,"Current GA : %d \n",CurrentInput->bEnableGA);
    MdbPrint(u64ReqHdl,"Current Rotate : %d \n",CurrentInput->bEnableRotate);
    MdbPrint(u64ReqHdl,"Current VR360 : %d \n",CurrentInput->bEnableVR360);
    MdbPrint(u64ReqHdl,"Current DIP : %d \n",CurrentInput->bEnableDIP);

    MdbPrint(u64ReqHdl,"Current BW(percentage) : %d.%d%s BW : %d MB \n",_pstBwInfo->u32BwUsage/100,_pstBwInfo->u32BwUsage%100,"%",_pstBwInfo->u32BwUsage*_pstBwInfo->u32TotalBw/10000);
    MdbPrint(u64ReqHdl,"Total BW : %d MB \n",_pstBwInfo->u32TotalBw);
    MdbPrint(u64ReqHdl,"Auto upper threshold : %d \n",QosAutoUpperThreshold);
    MdbPrint(u64ReqHdl,"Auto lower threshold : %d \n",QosAutoLowerThreshold);

    MdbPrint(u64ReqHdl,"vdec level: %d\n",_stSituation.u8VdecLevel);
    MdbPrint(u64ReqHdl,"Frc level: %d\n",_stSituation.u8FrcLevel);
    MdbPrint(u64ReqHdl,"Pnl level: %d\n",_stSituation.u8PnlLevel);
    MdbPrint(u64ReqHdl,"Pq level: %d\n",_stSituation.u8PqLevel);
#ifdef QOS_OUTPUT_AIPQ_ENABLE
    MdbPrint(u64ReqHdl,"Aipq level: %d\n",_stSituation.u8AipqLevel);
#endif
    index = SearchQosTableUseCase(CurrentInput,QosTable);
    if (index >= QosTable->cases)
    {
        MdbPrint(u64ReqHdl,"no mapping use case!!\n");
    }
    else
    {
        MdbPrint(u64ReqHdl,"mapping to QoS table use case: %d\n",index);
        MdbPrint(u64ReqHdl,"Qos table default level: %d\n",QosTable->scenario[index].input.default_setting);
        MdbPrint(u64ReqHdl,"Qos table vdec level: %d, 1=no skip, 2=drop 1/2, 4=drop 3/4\n",QosTable->scenario[index].output.vdec[_stSituation.u8VdecLevel].type);
        MdbPrint(u64ReqHdl,"Qos table frc level: %d, 0=REPEAT_MODE 1=LOW_BANDWIDTH 2=NORMAL_MODE 3=no FRC\n",QosTable->scenario[index].output.frc[_stSituation.u8FrcLevel].type);
        MdbPrint(u64ReqHdl,"Qos table od level: %d, 0=off, 1 = on \n",QosTable->scenario[index].output.od[_stSituation.u8PnlLevel].type);
        MdbPrint(u64ReqHdl,"Qos table pq level: %d, 0=PQ_BWD_OFF 1=PQ_BWD_LOW 2=PQ_BWD_MID 3=PQ_BWD_HIGH \n",QosTable->scenario[index].output.pq[_stSituation.u8PqLevel].type);
#ifdef QOS_OUTPUT_AIPQ_ENABLE
        MdbPrint(u64ReqHdl,"Qos table aipq level: %d, 0=E_DMS_BW_AIPQ_OFF_MODE 1=E_DMS_BW_NORMAL_MODE \n",QosTable->scenario[index].output.aipq[_stSituation.u8AipqLevel].type);
#endif
    }

    return 0;
}
static void dump_qos_table(MS_U64* u64ReqHdl)
{
    MS_U32 index = 0;
    MS_U32 output_index = 0;
    MdbPrint(u64ReqHdl,"Version: %d\n",QosTable->version);
    MdbPrint(u64ReqHdl,"Case: %d\n",QosTable->cases);
    for ( index == 0; index < QosTable->cases; index++)
    {

        MdbPrint(u64ReqHdl,"======================================================================\n");
        MdbPrint(u64ReqHdl,"scenario: %d\n",index);
        MdbPrint(u64ReqHdl,"INPUT\n");
        MdbPrint(u64ReqHdl,"source: %d 0=MM 1=DTV 2=ATV 5=HDMI\n",QosTable->scenario[index].input.source);
        MdbPrint(u64ReqHdl,"main input resolution: %d, SD=0, HD=1, FHD=2, UHD=3, 8K=4, NONE=5\n",QosTable->scenario[index].input.main.in_resolution);
        MdbPrint(u64ReqHdl,"main output resolution: %d, SD=0, HD=1, FHD=2, UHD=3, 8K=4, NONE=5\n",QosTable->scenario[index].input.main.out_resolution);
        MdbPrint(u64ReqHdl,"main input fps: %d, 60P=0, 50P=1, 30P=2, 25P=3, 24P=4, NONE=5\n",QosTable->scenario[index].input.main.fps);
        MdbPrint(u64ReqHdl,"main input codec: %d, H264=0, H265=1, VP9=2, AV1=3, NONE=4\n",QosTable->scenario[index].input.main.codec);
        MdbPrint(u64ReqHdl,"sub input resolution: %d, SD=0, HD=1, FHD=2, UHD=3, 8K=4, NONE=5\n",QosTable->scenario[index].input.sub.in_resolution);
        MdbPrint(u64ReqHdl,"sub output resolution: %d, SD=0, HD=1, FHD=2, UHD=3, 8K=4, NONE=5\n",QosTable->scenario[index].input.sub.out_resolution);
        MdbPrint(u64ReqHdl,"sub input fps: %d, 60P=0, 50P=1, 30P=2, 25P=3, 24P=4, NONE=5\n",QosTable->scenario[index].input.sub.fps);
        MdbPrint(u64ReqHdl,"sub input codec: %d, H264=0, H265=1, VP9=2, AV1=3, NONE=4\n",QosTable->scenario[index].input.sub.codec);
        MdbPrint(u64ReqHdl,"PVR: %d\n",QosTable->scenario[index].input.bEnablePVR);
        MdbPrint(u64ReqHdl,"PIP: %d\n",QosTable->scenario[index].input.bEnablePIP);
#ifdef QOS_OUTPUT_AIPQ_ENABLE
        MdbPrint(u64ReqHdl,"AIPQ: %d\n",QosTable->scenario[index].input.bEnableAIPQ);
#endif
        MdbPrint(u64ReqHdl,"VOICE wakeup: %d\n",QosTable->scenario[index].input.bEnableGA);
        MdbPrint(u64ReqHdl,"ROTATE: %d\n",QosTable->scenario[index].input.bEnableRotate);
        MdbPrint(u64ReqHdl,"VR360: %d\n",QosTable->scenario[index].input.bEnableRotate);
        MdbPrint(u64ReqHdl,"DIP: %d\n",QosTable->scenario[index].input.bEnableDIP);
        MdbPrint(u64ReqHdl,"default level: %d\n",QosTable->scenario[index].input.default_setting);
        MdbPrint(u64ReqHdl,"----------------------------------------------------------------------\n");
        MdbPrint(u64ReqHdl,"OUTPUT\n");
        MdbPrint(u64ReqHdl,"Level\tPQ\tFRC\tOD\tVDEC\n");
#ifdef QOS_OUTPUT_AIPQ_ENABLE
        MdbPrint(u64ReqHdl,"AIPQ\n");
#endif
        for (output_index = 0; output_index < LEVEL_MAX; output_index++)
        {
            MdbPrint(u64ReqHdl,"%d\t%d\t%d\t%d\t%d\n",output_index,QosTable->scenario[index].output.pq[output_index].type,QosTable->scenario[index].output.frc[output_index].type,QosTable->scenario[index].output.od[output_index].type,QosTable->scenario[index].output.vdec[output_index].type);
#ifdef QOS_OUTPUT_AIPQ_ENABLE
            MdbPrint(u64ReqHdl,"%d\n",QosTable->scenario[index].output.aipq[output_index].type);
#endif
        }
        MdbPrint(u64ReqHdl,"PQ level: 0=PQ_BWD_OFF 1=PQ_BWD_LOW 2=PQ_BWD_MID 3=PQ_BWD_HIGH \n");
        MdbPrint(u64ReqHdl,"FRC level: 0=REPEAT_MODE 1=LOW_BANDWIDTH 2=NORMAL_MODE 3=no FRC\n");
        MdbPrint(u64ReqHdl,"OD level: 0=off, 1 = on \n");
        MdbPrint(u64ReqHdl,"VDEC level: 1=no skip, 2=drop 1/2, 4=drop 3/4\n");
#ifdef QOS_OUTPUT_AIPQ_ENABLE
        MdbPrint(u64ReqHdl,"AIPQ level: 1=on, 0=off\n");
#endif

    }
}
MS_U32 QOSMdbIoctl(MS_U32 cmd, const void* const pArgs)
{
    MDBCMD_CMDLINE_PARAMETER *paraCmdLine;
    MDBCMD_GETINFO_PARAMETER *paraGetInfo;
    E_QOSINFO_CMD u32Cmd = QOSINFO_HELP;
    MS_U8 i,j;
    MS_U8 level = E_QOS_DBGLV_0;
    MS_U32 Interval = 0;
    MS_U32 bAutoAdjust = 0;
    MS_U32 bVoiceEnable = 0;
    MS_U32 UpperThreshold = 0;
    MS_U32 LowerThreshold = 0;
    MS_U32 VdecPlusLevel = 0;
    MS_U32 BwdLevel = 0;
    MS_U32 OdLevel = 0;
    MS_U32 FrcLevel = 0;
#ifdef QOS_OUTPUT_AIPQ_ENABLE
    MS_U32 AipqLevel = 0;
    ST_DMS_BW_INFO AipqQosBWInfo;
#endif
    ST_XC_QOS_FRC_BW_INFO FrcQosBWInfo;
    ST_PNL_QOS_BW_INFO PnlQosBWInfo;
    ST_PQ_QOS_BW_INFO PqQosBWInfo;
    VDEC_StreamId stStreamId, stGetStreamId;
    ST_QOS_INIT_INFO stInitInfotest;
    ST_QOS_STATUS ProcStStatus;
    ST_QOS_EVENT_INFO ProcStEvent;
    char *pch, tok[]=" ", *psep;
    FILE *f = NULL;
    MS_S32 fileMode = O_RDONLY;

    memset(&ProcStStatus,0,sizeof(ST_QOS_STATUS));

    switch(cmd)
    {
        case MDBCMD_CMDLINE:
            paraCmdLine = (MDBCMD_CMDLINE_PARAMETER *)pArgs;
            psep = paraCmdLine->pcCmdLine;
            for(i=0;(pch = strsep(&psep, tok))!=NULL;i++)
            {
                switch(i)
                {
                    case QOSINFO_PARA_CMD:
                        for(j=0;j<QOSINFO_END_OF_CMD;j++)
                        {
                            if(0 == strncasecmp(pch,stQosInfoCmd[j].sQosInfoCmdList,strlen(stQosInfoCmd[j].sQosInfoCmdList)-1))
                            {
                                u32Cmd = stQosInfoCmd[j].eCmd;
                                break;
                            }
                        }
                        switch(u32Cmd)
                        {
                            case QOSINFO_ENABLE:
                                MdbPrint(paraCmdLine->u64ReqHdl,"\nEnable QoS\n");

                                ProcStStatus.bSysEnable = TRUE;
                                ProcStStatus.bAutoAdjBwEnable = TRUE;

                                MDrv_QOS_SetStatus(ProcStStatus);
                                goto CMD_DONE;
                            case QOSINFO_DISABLE:
                                MdbPrint(paraCmdLine->u64ReqHdl,"\nDisable QoS\n");
                                ProcStStatus.bSysEnable = FALSE;
                                ProcStStatus.bAutoAdjBwEnable = FALSE;
                                MDrv_QOS_SetStatus(ProcStStatus);
                                goto CMD_DONE;
                            case QOSINFO_ALL_INFO:
                                MdbPrint(paraCmdLine->u64ReqHdl,"\nQoS all info\n");
                                QosAllInfo(paraCmdLine->u64ReqHdl);
                                goto CMD_DONE;
                            case QOSINFO_RELOAD_QOSTABLE:
                                MdbPrint(paraCmdLine->u64ReqHdl,"\nReload Qos table(/vendor/tvconfig/config/Qos.bin)\n");
                                f = MsFS_Fopen("/vendor/tvconfig/config/Qos.bin",(const char*)&fileMode);
                                if (f == NULL)
                                {
                                    MdbPrint(paraCmdLine->u64ReqHdl,"\nno QoS table, Qos table reload fail\n");
                                    goto CMD_DONE;
                                }
                                MsFS_Fread(QosTable, sizeof(ST_QOS_TABLE), 1, f);
                                MsFS_Fclose(f);
                                goto CMD_DONE;
                            case QOSINFO_DUMP_QOSTABLE:
                                MdbPrint(paraCmdLine->u64ReqHdl,"\nDump Qos table \n");
                                dump_qos_table(paraCmdLine->u64ReqHdl);
                                goto CMD_DONE;

                        }

                        if(QOSINFO_HELP == u32Cmd || QOSINFO_END_OF_CMD == j)
                        {
                            QOSMdbHelp(paraCmdLine->u64ReqHdl);
                            goto CMD_DONE;
                        }
                        break;
                    case QOSINFO_PARA_FIRST:
                        if (u32Cmd == QOSINFO_SET_DEBUG_LEVEL)
                        {
                            level = mst_atoi(pch);
                            MDrv_QOS_SetDebugType(level);
                            MsOS_SetEvent(_s32QosEventId, E_QOS_EVENT_BW_ADJUST);
                            MdbPrint(paraCmdLine->u64ReqHdl,"\nset debug level %d\n",level);
                            goto CMD_DONE;
                        }
                        else if (u32Cmd == QOSINFO_SET_POLLING_INTERVAL)
                        {
                            Interval = mst_atoi(pch);
                            Qos_Polling_Interval = Interval;
                            MdbPrint(paraCmdLine->u64ReqHdl,"\nset polling interval %d ms\n",Interval);
                            goto CMD_DONE;
                        }
                        else if (u32Cmd == QOSINFO_AUTO_ADJUST)
                        {
                            bAutoAdjust = mst_atoi(pch);
                            if (bAutoAdjust != 1 && bAutoAdjust != 0 )
                            {
                                MdbPrint(paraCmdLine->u64ReqHdl,"\ninvalid setting \n");
                                goto CMD_DONE;
                            }
                            MdbPrint(paraCmdLine->u64ReqHdl,"\nset auto adjust setting:%d \n",bAutoAdjust);
                            ProcStStatus.bSysEnable = bSysEnable;
                            ProcStStatus.bAutoAdjBwEnable = bAutoAdjust;
                            MDrv_QOS_SetStatus(ProcStStatus);
                            goto CMD_DONE;
                        }
                        else if (u32Cmd == QOSINFO_VOICE_ENABLE)
                        {
                            bVoiceEnable = mst_atoi(pch);
                            memset(&ProcStEvent,0,sizeof(ST_QOS_EVENT_INFO));
                            ProcStEvent.bVoiceEn = bVoiceEnable;
                            ProcStEvent.enEventType = E_QOS_EVENT_VOICE;
                            MDrv_QOS_SetModuleStatus(ProcStEvent);
                            MdbPrint(paraCmdLine->u64ReqHdl,"\nset Voice enable:%d \n",bVoiceEnable);
                            goto CMD_DONE;
                        }
                        else if (u32Cmd == QOSINFO_UPPER_THRESHOLD)
                        {
                            UpperThreshold = mst_atoi(pch);
                            if (UpperThreshold >= 0 && UpperThreshold <= 10000 )
                            {
                                QosAutoUpperThreshold = UpperThreshold;
                                MdbPrint(paraCmdLine->u64ReqHdl,"\nset Qos auto upper threshold to %d \n",QosAutoUpperThreshold);
                                goto CMD_DONE;
                            }
                            else
                            {
                                MdbPrint(paraCmdLine->u64ReqHdl,"\nInvalid value:%d \n",UpperThreshold);
                            }
                            goto CMD_DONE;
                        }
                        else if (u32Cmd == QOSINFO_LOWER_THRESHOLD)
                        {
                            LowerThreshold = mst_atoi(pch);
                            if (LowerThreshold >= 0 && LowerThreshold <= 10000 )
                            {
                                QosAutoLowerThreshold = LowerThreshold;
                                MdbPrint(paraCmdLine->u64ReqHdl,"\nset Qos auto upper threshold to %d \n",QosAutoLowerThreshold);
                                goto CMD_DONE;
                            }
                            else
                            {
                                MdbPrint(paraCmdLine->u64ReqHdl,"\nInvalid value:%d \n",LowerThreshold);
                            }
                            goto CMD_DONE;
                        }
                        else if (u32Cmd == QOSINFO_SET_VDECPLUS_LEVEL)
                        {
                            VdecPlusLevel = mst_atoi(pch);
                            if (VdecPlusLevel == E_VDEC_EX_VDEC_PLUS_DROP_RATIO_1 || VdecPlusLevel == E_VDEC_EX_VDEC_PLUS_DROP_RATIO_2 || VdecPlusLevel == E_VDEC_EX_VDEC_PLUS_DROP_RATIO_4)
                            {
                                if (MApi_VDEC_EX_GetControl(&stStreamId, E_VDEC_EX_USER_CMD_GET_MAIN_STREAM_ID, (MS_U32 *)&stGetStreamId) != E_VDEC_EX_OK)
                                {
                                    MdbPrint(paraCmdLine->u64ReqHdl,"%s %d Get main streamd id failed\n",__FUNCTION__,__LINE__);
                                    goto CMD_DONE;
                                }

                                if (MApi_VDEC_EX_SetControl((VDEC_StreamId *)&stGetStreamId, E_VDEC_EX_USER_CMD_SET_MIN_VDEC_PLUS_DROP_RATIO,(MS_VIRT)VdecPlusLevel) == E_VDEC_EX_OK)
                                {
                                    MdbPrint(paraCmdLine->u64ReqHdl,"%s %d Adjust Vdec level to %d Success\n",__FUNCTION__,__LINE__,VdecPlusLevel);
                                }
                                else
                                {
                                    MdbPrint(paraCmdLine->u64ReqHdl,"%s %d Adjust Vdec level to %d failed\n",__FUNCTION__,__LINE__,VdecPlusLevel);
                                }
                                goto CMD_DONE;
                            }
                        }
                        else if (u32Cmd == QOSINFO_SET_BWD_LEVEL)
                        {
                            BwdLevel = mst_atoi(pch);
                            if (BwdLevel == PQ_BWD_OFF || BwdLevel == PQ_BWD_LOW || BwdLevel == PQ_BWD_MID || BwdLevel == PQ_BWD_HIGH)
                            {
                                memset(&PqQosBWInfo, 0, sizeof(ST_PQ_QOS_BW_INFO));
                                PqQosBWInfo.u32Length = sizeof(ST_PQ_QOS_BW_INFO);
                                PqQosBWInfo.u32Version = ST_PQ_QOS_BW_INFO_VERSION;
                                PqQosBWInfo.enBWDType = (PQ_BWD_TYPE)BwdLevel;
                                PqQosBWInfo.enWindow = PQ_MAIN_WINDOW;
                                if (MDrv_PQ_SetBWLevel(&PqQosBWInfo) == TRUE)
                                {
                                    MdbPrint(paraCmdLine->u64ReqHdl,"%s %d Set bwd level to :%d\n",__FUNCTION__,__LINE__,PqQosBWInfo.enBWDType);
                                }
                                else
                                {
                                    MdbPrint(paraCmdLine->u64ReqHdl,"%s %d Set bwd level to :%d fail\n",__FUNCTION__,__LINE__,PqQosBWInfo.enBWDType);
                                }
                                goto CMD_DONE;
                            }
                            goto CMD_DONE;
                        }
                        else if (u32Cmd == QOSINFO_SET_OD_LEVEL)
                        {
                            OdLevel = mst_atoi(pch);
                            if (OdLevel == E_PNL_OVERDRIVE_OFF || OdLevel == E_PNL_OVERDRIVE_ON)
                            {
                                memset(&PnlQosBWInfo, 0, sizeof(ST_PNL_QOS_BW_INFO));
                                PnlQosBWInfo.u32Length = sizeof(ST_PNL_QOS_BW_INFO);
                                PnlQosBWInfo.u32Version = ST_PNL_QOS_BW_INFO_VERSION;
                                PnlQosBWInfo.enOverdriveMode = OdLevel;
                                PnlQosBWInfo.enPNLWin = E_PNL_MAIN_WINDOW;

                                if (MApi_PNL_SetBWLevel(&PnlQosBWInfo) == TRUE)
                                {
                                    MdbPrint(paraCmdLine->u64ReqHdl,"%s %d Set OD level to :%d\n",__FUNCTION__,__LINE__,PnlQosBWInfo.enOverdriveMode);
                                }
                                else
                                {
                                    MdbPrint(paraCmdLine->u64ReqHdl,"%s %d Set OD level to :%d fail\n",__FUNCTION__,__LINE__,PnlQosBWInfo.enOverdriveMode);
                                }
                                goto CMD_DONE;
                            }
                            goto CMD_DONE;
                        }
                        else if (u32Cmd == QOSINFO_SET_FRC_LEVEL)
                        {
                            FrcLevel = mst_atoi(pch);
                            if (FrcLevel == E_XC_FRC_BW_REPEAT_MODE || FrcLevel == E_XC_FRC_BW_LOW_BANDWIDTH_MODE || FrcLevel == E_XC_FRC_BW_NORMAL_MODE )
                            {
                                memset(&FrcQosBWInfo, 0, sizeof(ST_XC_QOS_FRC_BW_INFO));
                                FrcQosBWInfo.u32Length = sizeof(ST_XC_QOS_FRC_BW_INFO);
                                FrcQosBWInfo.u32Version = ST_XC_QOS_FRC_BW_INFO_VERSION;
                                FrcQosBWInfo.enFRCBWmode = FrcLevel;
                                FrcQosBWInfo.enWin = MAIN_WINDOW;

                                if (MApi_XC_SetFRCBWLevel(&FrcQosBWInfo) == TRUE)
                                {
                                    MdbPrint(paraCmdLine->u64ReqHdl,"%s %d Set Frc level to :%d\n",__FUNCTION__,__LINE__,FrcQosBWInfo.enFRCBWmode);
                                }
                                else
                                {
                                    MdbPrint(paraCmdLine->u64ReqHdl,"%s %d Set Frc level to :%d fail\n",__FUNCTION__,__LINE__,FrcQosBWInfo.enFRCBWmode);
                                }
                                goto CMD_DONE;
                            }
                            goto CMD_DONE;
                        }
#ifdef QOS_OUTPUT_AIPQ_ENABLE
                        else if (u32Cmd == QOSINFO_SET_AIPQ_LEVEL)
                        {
                            AipqLevel = mst_atoi(pch);
                            if (AipqLevel == E_DMS_BW_NORMAL_MODE || AipqLevel == E_DMS_BW_AIPQ_OFF_MODE )
                            {
                                memset(&AipqQosBWInfo, 0, sizeof(ST_DMS_BW_INFO));
                                AipqQosBWInfo.u32Length = sizeof(ST_DMS_BW_INFO);
                                AipqQosBWInfo.u32Version = VERSION_ST_DMS_BW_INFO;
                                AipqQosBWInfo.enDMSBWMode = AipqLevel;

                                if (MApi_DMS_SetBWLevel(MAIN_WINDOW,&AipqQosBWInfo) == E_FUNC_OK)
                                {
                                    MdbPrint(paraCmdLine->u64ReqHdl,"%s %d Set Aipq level to :%d\n",__FUNCTION__,__LINE__,AipqQosBWInfo.enDMSBWMode);
                                }
                                else
                                {
                                    MdbPrint(paraCmdLine->u64ReqHdl,"%s %d Set Aipq level to :%d fail\n",__FUNCTION__,__LINE__,AipqQosBWInfo.enDMSBWMode);
                                }
                                goto CMD_DONE;
                            }
                            goto CMD_DONE;
                        }
#endif
                        break;
                }
            }
CMD_PARSING_OK:
CMD_DONE:
            paraCmdLine->result = MDBRESULT_SUCCESS_FIN;
            break;
        case MDBCMD_GETINFO:
            paraGetInfo = (MDBCMD_GETINFO_PARAMETER *)pArgs;
            QOSMdbHelp(paraGetInfo->u64ReqHdl);
            paraGetInfo->result = MDBRESULT_SUCCESS_FIN;
            break;
        default:
            paraGetInfo = (MDBCMD_GETINFO_PARAMETER *)pArgs;
            MdbPrint(paraGetInfo->u64ReqHdl,"unknown cmd\n");
            break;
    }
    return 0;
}
EXPORT_SYMBOL(QOSMdbIoctl);
#endif
//-------------------------------------------------------------------------------------------------
//  Global Functions
//-------------------------------------------------------------------------------------------------

EN_QOS_RESULT SYMBOL_WEAK MDrv_QOS_Initialize(ST_QOS_INIT_INFO stInitInfo)
{
    MIU_Info stMIUInfo;
#ifdef MSOS_TYPE_LINUX_KERNEL
    FILE *f = NULL;
    MS_S32 fileMode = O_RDONLY;
#endif
    MS_U32 MIUDramBus = 0;
    QOS_DBG_LV_1("%s %d \n",__FUNCTION__,__LINE__);

    if ((_s32GlobalMutexId == -1) &&
    ((_s32GlobalMutexId = MsOS_CreateMutex(E_MSOS_FIFO, "QoSInit", MSOS_PROCESS_SHARED)) < 0))
    {
        QOS_DBG_LV_1("[%s][%d] Create Mutex failed\n", __FUNCTION__, __LINE__);
        return E_QOS_RESULT_FAIL;
    }
    if (_bQosInit == TRUE)
    {
        QOS_DBG_LV_1("[%s][%d] Already inited.\n", __FUNCTION__, __LINE__);
        return E_QOS_RESULT_OK;
    }

    _stSituation.u8VdecLevel = 0;
    _stSituation.u8ScalerLevel = 0;
    _stSituation.u8FrcLevel = 0;
    _stSituation.u8PnlLevel = 0;
    _stSituation.u8PqLevel = 0;
#ifdef QOS_OUTPUT_AIPQ_ENABLE
    _stSituation.u8AipqLevel = 0;
#endif

    bSysEnable = FALSE;
    bAutoAdjBwEnable = FALSE;

    if (stInitInfo.u32CheckBwPeriod > 0)
        Qos_Polling_Interval = stInitInfo.u32CheckBwPeriod;

    QOS_DBG_LV_1("%s %d Open customer QoS table %s \n",__FUNCTION__,__LINE__,stInitInfo.sCustomerBinFileName);
#ifdef MSOS_TYPE_LINUX_KERNEL
    f = MsFS_Fopen(stInitInfo.sCustomerBinFileName,(const char*)&fileMode);
    if (f == NULL)
    {
        QOS_DBG_LV_1("%s %d no customer QoS table, use reference board QoS table %s\n",__FUNCTION__,__LINE__,stInitInfo.sCommonBinFileName);
        f = MsFS_Fopen(stInitInfo.sCommonBinFileName,(const char*)&fileMode);
    }
    if (f == NULL)
    {
        QOS_DBG_LV_1("%s %d no QoS table, Qos init fail\n",__FUNCTION__,__LINE__);
        return E_QOS_RESULT_FAIL;
    }

    QosTable = utopia_malloc(sizeof(ST_QOS_TABLE));
    if (QosTable == NULL)
    {
        QOS_DBG_LV_1("%s %d QoS table malloc fail\n",__FUNCTION__,__LINE__);
        return E_QOS_RESULT_FAIL;
    }

    MsFS_Fread(QosTable, sizeof(ST_QOS_TABLE), 1, f);
    MsFS_Fclose(f);
#endif
    if (QosTable->cases > QOS_MAX_SCENARIO)
    {
        QOS_DBG_LV_1("%s %d cases:%d > QOS_MAX_SCENARIO:%d, QoS bin error\n",__FUNCTION__,__LINE__,QosTable->cases,QOS_MAX_SCENARIO);
        return E_QOS_RESULT_FAIL;
    }
    CurrentInput = utopia_malloc(sizeof(ST_QOS_INPUT));
    if (CurrentInput == NULL)
    {
        QOS_DBG_LV_1("%s %d Current input malloc fail\n",__FUNCTION__,__LINE__);
        return E_QOS_RESULT_FAIL;
    }

    CurrentOutput = utopia_malloc(sizeof(ST_QOS_OUTPUT));
    if (CurrentOutput == NULL)
    {
        QOS_DBG_LV_1("%s %d Current output malloc fail\n",__FUNCTION__,__LINE__);
        return E_QOS_RESULT_FAIL;
    }

    memset(CurrentInput, 0 ,sizeof(ST_QOS_INPUT));
    CurrentInput->source = E_QOS_SOURCE_NONE;
    CurrentInput->main.in_resolution = E_QOS_RESOLUTION_NONE;
    CurrentInput->main.out_resolution = E_QOS_RESOLUTION_NONE;
    CurrentInput->main.fps = E_QOS_FPS_NONE;
    CurrentInput->main.codec = E_QOS_CODEC_TYPE_NONE;
    CurrentInput->sub.in_resolution = E_QOS_RESOLUTION_NONE;
    CurrentInput->sub.out_resolution = E_QOS_RESOLUTION_NONE;
    CurrentInput->sub.fps = E_QOS_FPS_NONE;
    CurrentInput->sub.codec = E_QOS_CODEC_TYPE_NONE;
    CurrentInput->bEnablePVR = 0;
    CurrentInput->bEnablePIP = 0;
    CurrentInput->bEnableAIPQ = 0;
    CurrentInput->bEnableGA = 0;
    CurrentInput->bEnableRotate = 0;
    CurrentInput->bEnableVR360 = 0;

    _pstBwInfo = utopia_malloc(sizeof(ST_QOS_BW_INFO));
    memset(_pstBwInfo,0,sizeof(ST_QOS_BW_INFO));
    if (_pstBwInfo == NULL)
    {
        QOS_DBG_LV_1("%s %d BW info malloc fail\n",__FUNCTION__,__LINE__);
        return E_QOS_RESULT_FAIL;
    }

    MiuChannelNum = 0;
    if (MDrv_MIU_GetMIUInfo(E_MIU_0,&stMIUInfo) == TRUE)
    {
        _pstBwInfo->u32TotalBw = stMIUInfo.u32MIUDramFreq * (stMIUInfo.u32MIUDramBus/8);
        MIUDramBus = stMIUInfo.u32MIUDramBus;
        if (stMIUInfo.u32MIUDramBus != 0 && stMIUInfo.u32MIUDramFreq != 0)
        {
            MiuChannelNum++;
        }
    }
    if (MDrv_MIU_GetMIUInfo(E_MIU_1,&stMIUInfo) == TRUE)
    {
        _pstBwInfo->u32TotalBw += stMIUInfo.u32MIUDramFreq * (stMIUInfo.u32MIUDramBus/8);
        MIUDramBus += stMIUInfo.u32MIUDramBus;
        if (stMIUInfo.u32MIUDramBus != 0 && stMIUInfo.u32MIUDramFreq != 0)
        {
            MiuChannelNum++;
        }
    }
    if (MDrv_MIU_GetMIUInfo(E_MIU_2,&stMIUInfo) == TRUE)
    {
        _pstBwInfo->u32TotalBw += stMIUInfo.u32MIUDramFreq * (stMIUInfo.u32MIUDramBus/8);
        MIUDramBus += stMIUInfo.u32MIUDramBus;
        if (stMIUInfo.u32MIUDramBus != 0 && stMIUInfo.u32MIUDramFreq != 0)
        {
            MiuChannelNum++;
        }
    }
    QOS_DBG_LV_1("%s %d Total miu channel:%d\n",__FUNCTION__,__LINE__,MiuChannelNum);
    QOS_DBG_LV_1("%s %d DramFreq:%d Mhz, Miu dram bus width:%d\n",__FUNCTION__,__LINE__,stMIUInfo.u32MIUDramFreq,stMIUInfo.u32MIUDramBus/8);
    QOS_DBG_LV_1("%s %d Total BW:%d MB\n",__FUNCTION__,__LINE__,_pstBwInfo->u32TotalBw);

    if (stInitInfo.bAutoAdjBwEnable == TRUE)
    {
        bAutoAdjBwEnable = stInitInfo.bAutoAdjBwEnable;
        QOS_DBG_LV_1("%s %d Enable auto adjust BW function\n",__FUNCTION__,__LINE__);
    }

#ifdef QOS_OSD_DETECT_ENABLE
    if (MApi_GOP_DWIN_Init() != GOP_API_SUCCESS)
    {
        QOS_DBG_LV_1("%s %d OSD Initialization fail\n",__FUNCTION__,__LINE__);
        return E_QOS_RESULT_FAIL;
    }
#endif

    if (stInitInfo.bSysEnable == TRUE)
    {
        bSysEnable = stInitInfo.bSysEnable;
        _s32QosEventId = MsOS_CreateEventGroup("QOS_Event");
        _s32QosTaskId = MsOS_CreateTask((TaskEntry)_Qos_Task,
                                    NULL,//(MS_U32)pInstance,
                                    E_TASK_PRI_HIGH,
                                    TRUE,
                                    _pQosTaskStack,
                                    QOS_TASK_STACK_SIZE,
                                    "QOS_Task");
        if (_s32QosTaskId < 0)
        {
            QOS_DBG_LV_1("%s %d cREATE QoS Task fail\n",__FUNCTION__,__LINE__);
            return E_QOS_RESULT_FAIL;

        }
        _s32QosBwMonitorId = MsOS_CreateTask((TaskEntry)_Qos_BwMonitor,
                                    NULL,//(MS_U32)pInstance,
                                    E_TASK_PRI_HIGH,
                                    TRUE,
                                    _pQosBwMonitorStack,
                                    QOS_BW_MONITOR_STACK_SIZE,
                                    "QOS_BW_Monitor");
        if (_s32QosBwMonitorId < 0)
        {
            QOS_DBG_LV_1("%s %d cREATE QoS Task fail\n",__FUNCTION__,__LINE__);
            return E_QOS_RESULT_FAIL;

        }
        QOS_DBG_LV_1("%s %d Enable Qos sys\n",__FUNCTION__,__LINE__);

        _s32QosXcRegisterId = MsOS_CreateTask((TaskEntry)_Qos_XcRegister,
                                    NULL,//(MS_U32)pInstance,
                                    E_TASK_PRI_HIGH,
                                    TRUE,
                                    _pQosXcRegisterStack,
                                    QOS_XC_REGISTER_STACK_SIZE,
                                    "QOS_XC_Register");
        if (_s32QosXcRegisterId < 0)
        {
            QOS_DBG_LV_1("%s %d Create QoS XC register task fail\n",__FUNCTION__,__LINE__);
            return E_QOS_RESULT_FAIL;

        }


    }
    _bQosInit = TRUE;

    return E_QOS_RESULT_OK;
}

EN_QOS_RESULT SYMBOL_WEAK MDrv_QOS_SetModuleStatus(ST_QOS_EVENT_INFO stEvent)
{
    QOS_DBG_LV_1("%s %d \n",__FUNCTION__,__LINE__);
    MS_U32 index = 0;
    MS_U32 Level = 0;

    if (_bQosInit == FALSE)
    {
        QOS_DBG_LV_1("[%s][%d] Qos doesn't init, couldn't call %s\n", __FUNCTION__, __LINE__,__FUNCTION__);
        return E_QOS_RESULT_FAIL;
    }

    if (bSysEnable == FALSE)
    {
        QOS_DBG_LV_1("%s %d QoS sys disable, couldn't set module status\n",__FUNCTION__,__LINE__);
        return E_QOS_RESULT_FAIL;
    }

    if (stEvent.enEventType == E_QOS_EVENT_PVR)
    {
        CurrentInput->bEnablePVR = stEvent.bPvrEn;
        QOS_DBG_LV_1("%s %d Event PVR : %d\n",__FUNCTION__,__LINE__,CurrentInput->bEnablePVR);
    }
    if (stEvent.enEventType == E_QOS_EVENT_AIPQ)
    {
        CurrentInput->bEnableAIPQ = stEvent.bAiPqEn;
        QOS_DBG_LV_1("%s %d Event AIPQ : %d\n",__FUNCTION__,__LINE__,CurrentInput->bEnableAIPQ);
    }
    if (stEvent.enEventType == E_QOS_EVENT_VR360)
    {
        CurrentInput->bEnableVR360 = stEvent.bVr360En;
        QOS_DBG_LV_1("%s %d Event VR360 : %d\n",__FUNCTION__,__LINE__,CurrentInput->bEnableVR360);
    }
    if (stEvent.enEventType == E_QOS_EVENT_ROTATE)
    {
        CurrentInput->bEnableRotate = stEvent.bRotateEn;
        QOS_DBG_LV_1("%s %d Event ROTATE : %d\n",__FUNCTION__,__LINE__,CurrentInput->bEnableRotate);
    }
    if (stEvent.enEventType == E_QOS_EVENT_VOICE)
    {
        CurrentInput->bEnableGA = stEvent.bVoiceEn;
        QOS_DBG_LV_1("%s %d Event VOICE : %d\n",__FUNCTION__,__LINE__,CurrentInput->bEnableGA);
    }
    if (stEvent.enEventType == E_QOS_EVENT_CAPTURE)
    {
        CurrentInput->bEnableDIP = stEvent.bCapEn;
        QOS_DBG_LV_1("%s %d Event Capture : %d\n",__FUNCTION__,__LINE__,CurrentInput->bEnableDIP);
    }

    index = SearchQosTableUseCase(CurrentInput,QosTable);
    if (index >= QosTable->cases)
    {
        QOS_DBG_LV_1("%s %d no matching scenario\n",__FUNCTION__,__LINE__);
        QosSetAllModuleBestLevel();
        return E_QOS_RESULT_OK;
    }
    QosSetAllModuleDefaultLevel(index);

    return E_QOS_RESULT_OK;
}

EN_QOS_RESULT SYMBOL_WEAK MDrv_QOS_GetStatus(ST_QOS_STATUS *pstStatus)
{
    QOS_DBG_LV_1("%s %d \n",__FUNCTION__,__LINE__);

    if (_bQosInit == FALSE)
    {
        QOS_DBG_LV_1("[%s][%d] Qos doesn't init, couldn't call %s\n", __FUNCTION__, __LINE__,__FUNCTION__);
        return E_QOS_RESULT_FAIL;
    }

    pstStatus->bSysEnable = bSysEnable;
    pstStatus->bAutoAdjBwEnable = bAutoAdjBwEnable;

    QOS_DBG_LV_1("%s %d pstStatus->bSysEnable:%d pstStatus->bAutoAdjBwEnable:%d\n",__FUNCTION__,__LINE__,pstStatus->bSysEnable,pstStatus->bAutoAdjBwEnable);

    return E_QOS_RESULT_OK;
}

EN_QOS_RESULT SYMBOL_WEAK MDrv_QOS_SetStatus(ST_QOS_STATUS stStatus)
{
    QOS_DBG_LV_1("%s %d \n",__FUNCTION__,__LINE__);

    if (_bQosInit == FALSE)
    {
        QOS_DBG_LV_1("[%s][%d] Qos doesn't init, couldn't call %s\n", __FUNCTION__, __LINE__,__FUNCTION__);
        return E_QOS_RESULT_FAIL;
    }


    bSysEnable = stStatus.bSysEnable;
    bAutoAdjBwEnable = stStatus.bAutoAdjBwEnable;

    if (bSysEnable == TRUE && bAutoAdjBwEnable == TRUE)
    {
        MsOS_SetEvent(_s32QosEventId, E_QOS_EVENT_RESTART);
        QOS_DBG_LV_1("%s %d QoS Sys enable  \n",__FUNCTION__,__LINE__);
        QOS_DBG_LV_1("%s %d SetEvent:%d \n",__FUNCTION__,__LINE__,E_QOS_EVENT_TIMEOUT);
    }

    QOS_DBG_LV_1("%s %d bSysEnable:%d bAutoAdjBwEnable:%d \n",__FUNCTION__,__LINE__,bSysEnable,bAutoAdjBwEnable);

    return E_QOS_RESULT_OK;
}

EN_QOS_RESULT SYMBOL_WEAK MDrv_QOS_AdjustBw (ST_QOS_BW_ADJUST_INFO stAdjustInfo)
{
    QOS_DBG_LV_2("%s %d \n",__FUNCTION__,__LINE__);

    if (_bQosInit == FALSE)
    {
        QOS_DBG_LV_1("[%s][%d] Qos doesn't init, couldn't call %s\n", __FUNCTION__, __LINE__,__FUNCTION__);
        return E_QOS_RESULT_FAIL;
    }

    if (bSysEnable == FALSE)
    {
        QOS_DBG_LV_1("%s %d QoS sys disable!!!\n couldn't adjust BW\n",__FUNCTION__,__LINE__);
        return E_QOS_RESULT_FAIL;
    }

    if (stAdjustInfo.enAdjType == E_QOS_ADJUST_MAX)
    {
        QOS_DBG_LV_2("%s %d Call from AutoAdjustBw\n",__FUNCTION__,__LINE__);
    }

    MsOS_ObtainMutex(_s32GlobalMutexId, MSOS_WAIT_FOREVER);

    _stAdjustInfo.enModule = stAdjustInfo.enModule;
    _stAdjustInfo.enBwType = stAdjustInfo.enBwType;
    _stAdjustInfo.s32BwValue = stAdjustInfo.s32BwValue;
    _stAdjustInfo.enAdjType = stAdjustInfo.enAdjType;

    if (_stAdjustInfo.enBwType == E_QOS_BW_USAGE)
    {
        QOS_DBG_LV_2("%s %d Not support adjust by bandwidth usage \n",__FUNCTION__,__LINE__);
        return E_QOS_RESULT_FAIL;
    }

    if (_stAdjustInfo.s32BwValue == 0)
    {
        QOS_DBG_LV_2("%s %d adjust level is 0, no need to adjust \n",__FUNCTION__,__LINE__);
        goto MDrv_QOS_AdjustBw_End;
    }
    MsOS_SetEvent(_s32QosEventId, E_QOS_EVENT_BW_ADJUST);

MDrv_QOS_AdjustBw_End:
    MsOS_ReleaseMutex(_s32GlobalMutexId);

    return E_QOS_RESULT_OK;
}

EN_QOS_RESULT SYMBOL_WEAK MDrv_QOS_SetDebugType(MS_U8 u8Type)
{
    _u8QosDbgLevel = u8Type;
    QOS_DBG_LV_1("%s %d debug level:%d \n",__FUNCTION__,__LINE__,u8Type);

    return E_QOS_RESULT_OK;
}

EN_QOS_RESULT SYMBOL_WEAK MDrv_QOS_GetBwInfo(ST_QOS_BW_INFO *pstBwInfo)
{
    if (_bQosInit == FALSE)
    {
        QOS_DBG_LV_4("[%s][%d] Qos doesn't init, couldn't call %s\n", __FUNCTION__, __LINE__,__FUNCTION__);
        return E_QOS_RESULT_FAIL;
    }

    if (bSysEnable == FALSE)
    {
        QOS_DBG_LV_4("%s %d QoS sys disable, couldn't get BW info\n",__FUNCTION__,__LINE__);
        return E_QOS_RESULT_FAIL;
    }

    QOS_DBG_LV_4("%s %d \n",__FUNCTION__,__LINE__);
    pstBwInfo->u32BwUsage = _pstBwInfo->u32BwUsage;
    pstBwInfo->u32TotalBw = _pstBwInfo->u32TotalBw;

    QOS_DBG_LV_4("%s %d BwUsage:%d TotalBw:%d\n",__FUNCTION__,__LINE__,pstBwInfo->u32BwUsage,pstBwInfo->u32TotalBw);
    return E_QOS_RESULT_OK;
}

EN_QOS_RESULT SYMBOL_WEAK MDrv_QOS_Suspend(void)
{
    QOS_DBG_LV_1("%s %d \n",__FUNCTION__,__LINE__);
    return E_QOS_RESULT_OK;
}

EN_QOS_RESULT SYMBOL_WEAK MDrv_QOS_Resume(void)
{
    QOS_DBG_LV_1("%s %d \n",__FUNCTION__,__LINE__);
    return E_QOS_RESULT_OK;
}


#endif
