/**
 * @file hv_drv_OsdRotate.c
 * @brief Osd Driver Rotate c file.
 * @details This file provides the following functions: \n
 *          (1) Osd Rotate functions \n
 *
 * @author HiView SoC Software Team
 * @version 1.0.0
 * @date 2022-08-31
 * @copyright Copyright(c),2022-8, Hiview Software. All rights reserved.
 * @par History:
 * <table>
 * <tr><th>Author         <th>Date        <th>Change Description
 * <tr><td>OSD Group      <td>2022-08-31   <td>create
 * </table>
*/

#include "hv_vos_Memory.h"
#include "hv_mw_OsdLog.h"
#include "hv_comm_MemoryConfig.h"
#include "hv_drv_OsdRotate.h"
#include "hv_drv_OsdDataPath.h"
#include "hv_drv_OsdCommon.h"

#if (HV_PROJECT_CONFIG_OSD_ROTATION == HV_CONFIG_ON)
typedef struct _OsdRotateData {
    UCHAR8* pucSrcBuf;
    UINT32 uiSrcTotalWidth;
    UINT32 uiSrcTotalHeight;
    UINT32 uiSrcX;
    UINT32 uiSrcY;
    UINT32 uiSrcWidth;
    UINT32 uiSrcHeight;
    UCHAR8* pucDstBuf;
    UINT32 uiDstTotalWidth;
    UINT32 uiDstTotalHeight;
    UINT32 uiDstX;
    UINT32 uiDstY;
    USHORT16 usPixelBit;
} OsdRotateData;

#define OSD_BOX_NUM         (64)

static OsdRotationType s_enRotate = OSD_ROTATION_NONE;
static BOOL s_bRotateSkip = HV_FALSE;
static OsdBox s_astOsdBoxList[OSD_BOX_NUM] = {0};
static USHORT16 s_usBoxNum = 0;
static UCHAR8 s_ucRotationPartId = SCENE_ID_MAX;

static BOOL s_bAbsolutePostion = HV_FALSE;
static USHORT16 s_usAbsoluteX = 0;
static USHORT16 s_usAbsoluteY = 0;

VOID Hv_Drv_OsdSetRotateType(OsdRotationType enRotate)
{
    s_enRotate = enRotate;
}

OsdRotationType Hv_Drv_OsdGetRotateType(VOID)
{
    return s_enRotate;
}

VOID Hv_Drv_OsdSetRotateSkip(BOOL bSkip)
{
    s_bRotateSkip = bSkip;
}

BOOL Hv_Drv_OsdGetRotateSkip(VOID)
{
    return s_bRotateSkip;
}

OsdRotationType Hv_Drv_OsdGetRealRotateType(VOID)
{
    return (HV_TRUE == Hv_Drv_OsdGetRotateSkip()) ? OSD_ROTATION_NONE : Hv_Drv_OsdGetRotateType();
}


static VOID Hv_Drv_OsdRotatePart2Part(OsdRotateData *pstRotateData, OsdRotationType enRotate)
{
    HV_ASSERT_VALID_PTR_VOID(pstRotateData);
    HV_ASSERT_VALID_PTR_VOID(pstRotateData->pucSrcBuf);
    HV_ASSERT_VALID_PTR_VOID(pstRotateData->pucDstBuf);
    HV_ASSERT_TRUE_VOID((pstRotateData->uiSrcTotalWidth > 0) && (pstRotateData->uiSrcTotalHeight > 0));
    HV_ASSERT_TRUE_VOID((pstRotateData->uiSrcX < pstRotateData->uiSrcTotalWidth) && (pstRotateData->uiSrcY < pstRotateData->uiSrcTotalHeight));
    HV_ASSERT_TRUE_VOID((pstRotateData->uiSrcWidth > 0) && (pstRotateData->uiSrcHeight > 0));
    HV_ASSERT_TRUE_VOID((pstRotateData->uiDstTotalWidth > 0) && (pstRotateData->uiDstTotalHeight > 0));
    HV_ASSERT_TRUE_VOID((pstRotateData->uiDstX < pstRotateData->uiDstTotalWidth) && (pstRotateData->uiDstY < pstRotateData->uiDstTotalHeight));
    HV_ASSERT_TRUE_VOID((pstRotateData->usPixelBit == 4) || ((pstRotateData->usPixelBit % 8 == 0) && (pstRotateData->usPixelBit > 0)));

    UINT32 uiX = 0, uiY = 0, uiSX = 0, uiSY = 0, uiIdSrc = 0, uiIdDst = 0;
    UINT32 uiDX = 0, uiDY = 0, uiDWidth = 0, uiDHeight = 0;
    USHORT16 usPixelWidth = 0, usByte = 0;
    UCHAR8 ucTemp = 0;

    usPixelWidth = pstRotateData->usPixelBit / 8;

    switch (enRotate)
    {
        case OSD_ROTATION_90:
        {
            uiDWidth = pstRotateData->uiSrcHeight;
            uiDHeight = pstRotateData->uiSrcWidth;
            if (pstRotateData->usPixelBit == 4)
            {
                for (uiY = 0; uiY < pstRotateData->uiSrcHeight; uiY++)
                {
                    uiSY = pstRotateData->uiSrcY + uiY;
                    if (uiSY >= pstRotateData->uiSrcTotalHeight)
                    {
                        break;
                    }

                    uiDX = pstRotateData->uiSrcHeight - uiY - 1;
                    if (uiDX + pstRotateData->uiDstX >= pstRotateData->uiDstTotalWidth)
                    {
                        continue;
                    }

                    for (uiX = 0; uiX < pstRotateData->uiSrcWidth; uiX++)
                    {
                        uiSX = pstRotateData->uiSrcX + uiX;
                        if (uiSX >= pstRotateData->uiSrcTotalWidth)
                        {
                            break;
                        }

                        uiDY = uiX;
                        if (uiDY + pstRotateData->uiDstY >= pstRotateData->uiDstTotalHeight)
                        {
                            break;
                        }

                        uiIdSrc = (uiSY * pstRotateData->uiSrcTotalWidth + uiSX) / 2;
                        if ((uiSY * pstRotateData->uiSrcTotalWidth + uiSX) % 2)
                        {
                            ucTemp = pstRotateData->pucSrcBuf[uiIdSrc] & 0x0f;
                        }
                        else
                        {
                            ucTemp = (pstRotateData->pucSrcBuf[uiIdSrc] >> 4) & 0x0f;
                        }

                        uiIdDst = (pstRotateData->uiDstTotalWidth * (pstRotateData->uiDstY + uiDY) + pstRotateData->uiDstX + uiDX) / 2;
                        if ((uiDY * uiDWidth + uiDX) % 2)
                        {
                            pstRotateData->pucDstBuf[uiIdDst] &= 0xf0;
                            pstRotateData->pucDstBuf[uiIdDst] |= ucTemp;
                        }
                        else
                        {
                            pstRotateData->pucDstBuf[uiIdDst] &= 0x0f;
                            pstRotateData->pucDstBuf[uiIdDst] |= ucTemp << 4;
                        }
                    }
                }
            }
            else if (usPixelWidth != 0)
            {
                for (uiY = 0; uiY < pstRotateData->uiSrcHeight; uiY++)
                {
                    uiSY = pstRotateData->uiSrcY + uiY;
                    if (uiSY >= pstRotateData->uiSrcTotalHeight)
                    {
                        break;
                    }

                    uiDX = pstRotateData->uiSrcHeight - uiY - 1;
                    if (uiDX + pstRotateData->uiDstX >= pstRotateData->uiDstTotalWidth)
                    {
                        continue;
                    }

                    for (uiX = 0; uiX < pstRotateData->uiSrcWidth; uiX++)
                    {
                        uiSX = pstRotateData->uiSrcX + uiX;
                        if (uiSX >= pstRotateData->uiSrcTotalWidth)
                        {
                            break;
                        }

                        uiDY = uiX;
                        if (uiDY + pstRotateData->uiDstY >= pstRotateData->uiDstTotalHeight)
                        {
                            break;
                        }

                        uiIdSrc = (uiSY * pstRotateData->uiSrcTotalWidth + uiSX) * usPixelWidth;
                        uiIdDst = (pstRotateData->uiDstTotalWidth * (pstRotateData->uiDstY + uiDY) + pstRotateData->uiDstX + uiDX) * usPixelWidth;
                        for (usByte = 0; usByte < usPixelWidth; usByte++)
                        {
                            pstRotateData->pucDstBuf[uiIdDst + usByte] = pstRotateData->pucSrcBuf[uiIdSrc + usByte];
                        }
                    }
                }
            }
            break;
        }
        case OSD_ROTATION_180:
        {
            uiDWidth = pstRotateData->uiSrcWidth;
            uiDHeight = pstRotateData->uiSrcHeight;
            if (pstRotateData->usPixelBit == 4)
            {
                for (uiY = 0; uiY < pstRotateData->uiSrcHeight; uiY++)
                {
                    uiSY = pstRotateData->uiSrcY + uiY;
                    if (uiSY >= pstRotateData->uiSrcTotalHeight)
                    {
                        break;
                    }

                    uiDY = pstRotateData->uiSrcHeight - uiY - 1;
                    if (uiDY + pstRotateData->uiDstY >= pstRotateData->uiDstTotalHeight)
                    {
                        continue;
                    }

                    for (uiX = 0; uiX < pstRotateData->uiSrcWidth; uiX++)
                    {
                        uiSX = pstRotateData->uiSrcX + uiX;
                        if (uiSX >= pstRotateData->uiSrcTotalWidth)
                        {
                            break;
                        }

                        uiDX = pstRotateData->uiSrcWidth - uiX - 1;
                        if (uiDX + pstRotateData->uiDstX >= pstRotateData->uiDstTotalWidth)
                        {
                            continue;
                        }

                        uiIdSrc = (uiSY * pstRotateData->uiSrcTotalWidth + uiSX) / 2;
                        if ((uiSY * pstRotateData->uiSrcTotalWidth + uiSX) % 2)
                        {
                            ucTemp = pstRotateData->pucSrcBuf[uiIdSrc] & 0x0f;
                        }
                        else
                        {
                            ucTemp = (pstRotateData->pucSrcBuf[uiIdSrc] >> 4) & 0x0f;
                        }

                        uiIdDst = (pstRotateData->uiDstTotalWidth * (pstRotateData->uiDstY + uiDY) + pstRotateData->uiDstX + uiDX) / 2;
                        if ((uiDY * uiDWidth + uiDX) % 2)
                        {
                            pstRotateData->pucDstBuf[uiIdDst] &= 0xf0;
                            pstRotateData->pucDstBuf[uiIdDst] |= ucTemp;
                        }
                        else
                        {
                            pstRotateData->pucDstBuf[uiIdDst] &= 0x0f;
                            pstRotateData->pucDstBuf[uiIdDst] |= ucTemp << 4;
                        }
                    }
                }
            }
            else if (usPixelWidth != 0)
            {
                for (uiY = 0; uiY < pstRotateData->uiSrcHeight; uiY++)
                {
                    uiSY = pstRotateData->uiSrcY + uiY;
                    if (uiSY >= pstRotateData->uiSrcTotalHeight)
                    {
                        break;
                    }

                    uiDY = pstRotateData->uiSrcHeight - uiY - 1;
                    if (uiDY + pstRotateData->uiDstY >= pstRotateData->uiDstTotalHeight)
                    {
                        continue;
                    }

                    for (uiX = 0; uiX < pstRotateData->uiSrcWidth; uiX++)
                    {
                        uiSX = pstRotateData->uiSrcX + uiX;
                        if (uiSX >= pstRotateData->uiSrcTotalWidth)
                        {
                            break;
                        }

                        uiDX = pstRotateData->uiSrcWidth - uiX - 1;
                        if (uiDX + pstRotateData->uiDstX >= pstRotateData->uiDstTotalWidth)
                        {
                            continue;
                        }

                        uiIdSrc = (uiSY * pstRotateData->uiSrcTotalWidth + uiSX) * usPixelWidth;
                        uiIdDst = (pstRotateData->uiDstTotalWidth * (pstRotateData->uiDstY + uiDY) + pstRotateData->uiDstX + uiDX) * usPixelWidth;
                        for (usByte = 0; usByte < usPixelWidth; usByte++)
                        {
                            pstRotateData->pucDstBuf[uiIdDst + usByte] = pstRotateData->pucSrcBuf[uiIdSrc + usByte];
                        }
                    }
                }
            }
            break;
        }
        case OSD_ROTATION_270:
        {
            uiDWidth = pstRotateData->uiSrcHeight;
            uiDHeight = pstRotateData->uiSrcWidth;
            if (pstRotateData->usPixelBit == 4)
            {
                for (uiY = 0; uiY < pstRotateData->uiSrcHeight; uiY++)
                {
                    uiSY = pstRotateData->uiSrcY + uiY;
                    if (uiSY >= pstRotateData->uiSrcTotalHeight)
                    {
                        break;
                    }

                    uiDX = uiY;
                    if (uiDX + pstRotateData->uiDstX >= pstRotateData->uiDstTotalWidth)
                    {
                        break;
                    }

                    for (uiX = 0; uiX < pstRotateData->uiSrcWidth; uiX++)
                    {
                        uiSX = pstRotateData->uiSrcX + uiX;
                        if (uiSX >= pstRotateData->uiSrcTotalWidth)
                        {
                            break;
                        }

                        uiDY = pstRotateData->uiSrcWidth - uiX - 1;
                        if (uiDY + pstRotateData->uiDstY >= pstRotateData->uiDstTotalHeight)
                        {
                            continue;
                        }

                        uiIdSrc = (uiSY * pstRotateData->uiSrcTotalWidth + uiSX) / 2;
                        if ((uiSY * pstRotateData->uiSrcTotalWidth + uiSX) % 2)
                        {
                            ucTemp = pstRotateData->pucSrcBuf[uiIdSrc] & 0x0f;
                        }
                        else
                        {
                            ucTemp = (pstRotateData->pucSrcBuf[uiIdSrc] >> 4) & 0x0f;
                        }

                        uiIdDst = (pstRotateData->uiDstTotalWidth * (pstRotateData->uiDstY + uiDY) + pstRotateData->uiDstX + uiDX) / 2;
                        if ((uiDY * uiDWidth + uiDX) % 2)
                        {
                            pstRotateData->pucDstBuf[uiIdDst] &= 0xf0;
                            pstRotateData->pucDstBuf[uiIdDst] |= ucTemp;
                        }
                        else
                        {
                            pstRotateData->pucDstBuf[uiIdDst] &= 0x0f;
                            pstRotateData->pucDstBuf[uiIdDst] |= ucTemp << 4;
                        }
                    }
                }
            }
            else if (usPixelWidth != 0)
            {
                for (uiY = 0; uiY < pstRotateData->uiSrcHeight; uiY++)
                {
                    uiSY = pstRotateData->uiSrcY + uiY;
                    if (uiSY >= pstRotateData->uiSrcTotalHeight)
                    {
                        break;
                    }

                    uiDX = uiY;
                    if (uiDX + pstRotateData->uiDstX >= pstRotateData->uiDstTotalWidth)
                    {
                        break;
                    }

                    for (uiX = 0; uiX < pstRotateData->uiSrcWidth; uiX++)
                    {
                        uiSX = pstRotateData->uiSrcX + uiX;
                        if (uiSX >= pstRotateData->uiSrcTotalWidth)
                        {
                            break;
                        }

                        uiDY = pstRotateData->uiSrcWidth - uiX - 1;
                        if (uiDY + pstRotateData->uiDstY >= pstRotateData->uiDstTotalHeight)
                        {
                            continue;
                        }

                        uiIdSrc = (uiSY * pstRotateData->uiSrcTotalWidth + uiSX) * usPixelWidth;
                        uiIdDst = (pstRotateData->uiDstTotalWidth * (pstRotateData->uiDstY + uiDY) + pstRotateData->uiDstX + uiDX) * usPixelWidth;
                        for (usByte = 0; usByte < usPixelWidth; usByte++)
                        {
                            pstRotateData->pucDstBuf[uiIdDst + usByte] = pstRotateData->pucSrcBuf[uiIdSrc + usByte];
                        }
                    }
                }
            }
            break;
        }
        default:
        {
            UINT32 uiLen = min3(pstRotateData->uiSrcWidth,
                                pstRotateData->uiSrcTotalWidth - pstRotateData->uiSrcX,
                                pstRotateData->uiDstTotalWidth - pstRotateData->uiDstX) * pstRotateData->usPixelBit / 8;
            if (uiLen == 0)
            {
                break;
            }
            uiSX = pstRotateData->uiSrcX;
            uiDX = pstRotateData->uiDstX;
            for (uiY = 0; uiY < pstRotateData->uiSrcHeight; uiY++)
            {
                uiSY = pstRotateData->uiSrcY + uiY;
                if (uiSY >= pstRotateData->uiSrcTotalHeight)
                {
                    break;
                }

                uiDY = pstRotateData->uiDstY + uiY;
                if (uiDY >= pstRotateData->uiDstTotalHeight)
                {
                    break;
                }

                uiIdSrc = (uiSY * pstRotateData->uiSrcTotalWidth + uiSX) * pstRotateData->usPixelBit / 8;
                uiIdDst = (uiDY * pstRotateData->uiDstTotalWidth + uiDX) * pstRotateData->usPixelBit / 8;

                HV_MEMCPY(&pstRotateData->pucDstBuf[uiIdDst], &pstRotateData->pucSrcBuf[uiIdSrc], uiLen);
            }
            break;
        }
    }
}

static VOID Hv_Drv_OsdRotationDo(OsdRotateData *pstRotateData, OsdRotationType enRotate)
{
    HV_ASSERT_VALID_PTR_VOID(pstRotateData);

    OSD_LOG_DEBUG("RotateData info:");
    OSD_LOG_DEBUG("     Src:");
    OSD_LOG_DEBUG("         Addr = 0x%x", pstRotateData->pucSrcBuf);
    OSD_LOG_DEBUG("         Total Width = %d, Total Height = %d", pstRotateData->uiSrcTotalWidth, pstRotateData->uiSrcTotalHeight);
    OSD_LOG_DEBUG("         X = %d, Y = %d", pstRotateData->uiSrcX, pstRotateData->uiSrcY);
    OSD_LOG_DEBUG("         Width = %d, Height = %d", pstRotateData->uiSrcWidth, pstRotateData->uiSrcHeight);
    OSD_LOG_DEBUG("     Dst:");
    OSD_LOG_DEBUG("         Addr = 0x%x", pstRotateData->pucDstBuf);
    OSD_LOG_DEBUG("         Total Width = %d, Total Height = %d", pstRotateData->uiDstTotalWidth, pstRotateData->uiDstTotalHeight);
    OSD_LOG_DEBUG("         X = %d, Y = %d", pstRotateData->uiDstX, pstRotateData->uiDstY);
    OSD_LOG_DEBUG("     PixelBit = %d", pstRotateData->usPixelBit);
    OSD_LOG_DEBUG("     Rotate type = %d", enRotate);
    OSD_LOG_DEBUG("     Data size = %d Byte, %d KB", pstRotateData->uiSrcWidth * pstRotateData->uiSrcHeight * pstRotateData->usPixelBit / 8,
                                                    pstRotateData->uiSrcWidth * pstRotateData->uiSrcHeight * pstRotateData->usPixelBit / 8 / 1024);

#ifdef HV_SCALER_DEBUG_VERSION
    UINT64 currTick = Hv_Vos_GetTick();
#endif

    Hv_Drv_OsdRotatePart2Part(pstRotateData, enRotate);

#ifdef HV_SCALER_DEBUG_VERSION
    currTick = Hv_Vos_GetTick() - currTick;
    OSD_LOG_DEBUG("Rotate: Tick passed %llu", currTick);
#endif
}

static VOID Hv_Drv_OsdCalculateRotateBox(OsdBox *pstBox, UINT32 uiTotalWidth, UINT32 uiTotalHeight, OsdRotationType enRotate)
{
    HV_ASSERT_VALID_PTR_VOID(pstBox);
    HV_ASSERT_TRUE_VOID((uiTotalWidth > 0) && (uiTotalHeight > 0));
    USHORT16 usX = pstBox->usX;
    USHORT16 usY = pstBox->usY;
    USHORT16 usW = pstBox->usW;
    USHORT16 usH = pstBox->usH;

    switch(enRotate)
    {
        case OSD_ROTATION_90:
        {
            pstBox->usX = (uiTotalHeight < (usH + usY)) ? 0 : (uiTotalHeight - usH - usY);
            pstBox->usY = usX;
            pstBox->usH = usW;
            pstBox->usW = usH;
            break;
        }
        case OSD_ROTATION_180:
        {
            pstBox->usX = (uiTotalWidth < (usW + usX)) ? 0 : (uiTotalWidth - usW - usX);
            pstBox->usY = (uiTotalHeight < (usH + usY)) ? 0 : (uiTotalHeight - usH - usY);
            break;
        }
        case OSD_ROTATION_270:
        {
            pstBox->usX = usY;
            pstBox->usY = (uiTotalWidth < (usW + usX)) ? 0 : (uiTotalWidth - usW - usX);
            pstBox->usH = usW;
            pstBox->usW = usH;
            break;
        }
        default:
        {
            break;
        }
    }
    OSD_LOG_DEBUG("Calculate Rotate-%d Box: (%d, %d), size = %d*%d ==> RotateBox: (%d, %d), size = %d*%d",
                      enRotate, usX, usY, usW, usH, pstBox->usX, pstBox->usY, pstBox->usW, pstBox->usH);
}

#if (HV_PROJECT_CONFIG_OSD_ROTATION_TYPE == OSD_ROTATE_IN_PLACE_ALL)
VOID Hv_Drv_OsdCalculateUnrotateBoxOnScreen(OsdBox *pstBox, UINT32 uiTotalWidth, UINT32 uiTotalHeight, OsdRotationType enRotate)
{
    HV_ASSERT_VALID_PTR_VOID(pstBox);
    UINT32 uiX = pstBox->usX;
    UINT32 uiY = pstBox->usY;
    UINT32 uiW = pstBox->usW;
    UINT32 uiH = pstBox->usH;
    HV_ASSERT_TRUE_VOID((uiTotalWidth >= uiW + uiX) && (uiTotalHeight >= uiH + uiY));

    OSD_LOG_DEBUG("Calculate on Screen Rotate-%d Box: (%d, %d), size = %d*%d", enRotate, uiX, uiY, uiW, uiH);
    switch(enRotate)
    {
        case OSD_ROTATION_90:
        {
            if (uiTotalWidth < uiH)
            {
                OSD_LOG_WARN("rotate 90 error, TotalWidth(%d) < H(%d), fix H = %d", uiTotalWidth, uiH, uiTotalWidth);
                uiH = uiTotalWidth;
            }

            if (uiTotalHeight < uiW)
            {
                OSD_LOG_WARN("rotate 90 error, TotalHeight(%d) < W(%d), fix W = %d", uiTotalHeight, uiW, uiTotalHeight);
                uiW = uiTotalHeight;
            }

            if (uiTotalWidth > uiW)
            {
                pstBox->usX = uiX * (uiTotalWidth - uiH) / (uiTotalWidth - uiW);
            }
            else
            {
                pstBox->usX = (uiTotalWidth - uiH) / 2;
            }

            if ((uiTotalHeight > uiH))
            {
                pstBox->usY = uiY * (uiTotalHeight - uiW) / (uiTotalHeight - uiH);
            }
            else
            {
                pstBox->usY = (uiTotalHeight - uiW) / 2;
            }

            pstBox->usH = MIN(uiW, uiTotalHeight - pstBox->usY);
            pstBox->usW = MIN(uiH, uiTotalWidth - pstBox->usX);
            break;
        }
        case OSD_ROTATION_270:
        {
            if (uiTotalWidth < uiH)
            {
                OSD_LOG_WARN("rotate 270 error, TotalWidth(%d) < H(%d), fix H = %d", uiTotalWidth, uiH, uiTotalWidth);
                uiH = uiTotalWidth;
            }

            if (uiTotalHeight < uiW)
            {
                OSD_LOG_WARN("rotate 270 error, TotalHeight(%d) < W(%d), fix W = %d", uiTotalHeight, uiW, uiTotalHeight);
                uiW = uiTotalHeight;
            }

            if (uiTotalWidth > uiW)
            {
                pstBox->usX = uiX * (uiTotalWidth - uiH) / (uiTotalWidth - uiW);
            }
            else
            {
                pstBox->usX = (uiTotalWidth - uiH) / 2;
            }

            if ((uiTotalHeight > uiH))
            {
                pstBox->usY = uiY * (uiTotalHeight - uiW) / (uiTotalHeight - uiH);
            }
            else
            {
                pstBox->usY = (uiTotalHeight - uiW) / 2;
            }

            pstBox->usH = MIN(uiW, uiTotalHeight - pstBox->usY);
            pstBox->usW = MIN(uiH, uiTotalWidth - pstBox->usX);
            break;
        }
        default:
        {
            break;
        }
    }
    OSD_LOG_DEBUG("Result RotateBox: (%d, %d), size = %d*%d", pstBox->usX, pstBox->usY, pstBox->usW, pstBox->usH);
}
#else
VOID Hv_Drv_OsdCalculateRotateBoxOnScreen(OsdBox *pstBox, UINT32 uiTotalWidth, UINT32 uiTotalHeight, OsdRotationType enRotate)
{
    HV_ASSERT_VALID_PTR_VOID(pstBox);
    UINT32 uiX = pstBox->usX;
    UINT32 uiY = pstBox->usY;
    UINT32 uiW = pstBox->usW;
    UINT32 uiH = pstBox->usH;
    HV_ASSERT_TRUE_VOID((uiTotalWidth >= uiW + uiX) && (uiTotalHeight >= uiH + uiY));

    OSD_LOG_DEBUG("Calculate on Screen Rotate-%d Box: (%d, %d), size = %d*%d", enRotate, uiX, uiY, uiW, uiH);
    switch(enRotate)
    {
        case OSD_ROTATION_90:
        {
            if (uiTotalWidth < uiH)
            {
                OSD_LOG_WARN("rotate 90 error, TotalWidth(%d) < H(%d), fix H = %d", uiTotalWidth, uiH, uiTotalWidth);
                uiH = uiTotalWidth;
            }

            if (uiTotalHeight < uiW)
            {
                OSD_LOG_WARN("rotate 90 error, TotalHeight(%d) < W(%d), fix W = %d", uiTotalHeight, uiW, uiTotalHeight);
                uiW = uiTotalHeight;
            }

            if ((uiTotalHeight > uiH))
            {
                pstBox->usX = (uiTotalWidth - uiH) - (uiY * (uiTotalWidth - uiH) / (uiTotalHeight - uiH));
            }
            else
            {
                pstBox->usX = (uiTotalWidth - uiH) / 2;
            }

            if (uiTotalWidth > uiW)
            {
                pstBox->usY = uiX * (uiTotalHeight - uiW) / (uiTotalWidth - uiW);
            }
            else
            {
                pstBox->usY = (uiTotalHeight - uiW) / 2;
            }

            pstBox->usH = MIN(uiW, uiTotalHeight - pstBox->usY);
            pstBox->usW = MIN(uiH, uiTotalWidth - pstBox->usX);
            break;
        }
        case OSD_ROTATION_180:
        {
            pstBox->usX = (uiTotalWidth < (uiW + uiX)) ? 0 : (uiTotalWidth - uiW - uiX);
            pstBox->usY = (uiTotalHeight < (uiH + uiY)) ? 0 : (uiTotalHeight - uiH - uiY);
            break;
        }
        case OSD_ROTATION_270:
        {
            if (uiTotalWidth < uiH)
            {
                OSD_LOG_WARN("rotate 270 error, TotalWidth(%d) < H(%d), fix H = %d", uiTotalWidth, uiH, uiTotalWidth);
                uiH = uiTotalWidth;
            }

            if (uiTotalHeight < uiW)
            {
                OSD_LOG_WARN("rotate 270 error, TotalHeight(%d) < W(%d), fix W = %d", uiTotalHeight, uiW, uiTotalHeight);
                uiW = uiTotalHeight;
            }

            if ((uiTotalHeight > uiH))
            {
                pstBox->usX = uiY * (uiTotalWidth - uiH) / (uiTotalHeight - uiH);
            }
            else
            {
                pstBox->usX = (uiTotalWidth - uiH) / 2;
            }

            if (uiTotalWidth > uiW)
            {
                pstBox->usY = (uiTotalHeight - uiW) - (uiX * (uiTotalHeight - uiW) / (uiTotalWidth - uiW));
            }
            else
            {
                pstBox->usY = (uiTotalHeight - uiW) / 2;
            }

            pstBox->usH = MIN(uiW, uiTotalHeight - pstBox->usY);
            pstBox->usW = MIN(uiH, uiTotalWidth - pstBox->usX);
            break;
        }
        default:
        {
            break;
        }
    }
    OSD_LOG_DEBUG("Result RotateBox: (%d, %d), size = %d*%d", pstBox->usX, pstBox->usY, pstBox->usW, pstBox->usH);
}
#endif

BOOL Hv_Drv_OsdCheckAreaBoxContain(OsdBox stBox)
{
    if (s_usBoxNum == 0)
    {
        return HV_FALSE;
    }

    for (USHORT16 usId = 0; usId < s_usBoxNum; usId++)
    {
        if (stBox.usIndex != s_astOsdBoxList[usId].usIndex)
        {
            continue;
        }

        if ((stBox.usX >= s_astOsdBoxList[usId].usX) &&
            (stBox.usY >= s_astOsdBoxList[usId].usY) &&
            (stBox.usX + stBox.usW <= s_astOsdBoxList[usId].usX + s_astOsdBoxList[usId].usW) &&
            (stBox.usY + stBox.usH <= s_astOsdBoxList[usId].usY + s_astOsdBoxList[usId].usH))
        {
            OSD_LOG_VERBOSE("s_astOsdBoxList[%d]: xy = (%d, %d), wh = %d*%d contain the new box: xy = (%d, %d), wh = %d*%d",
                            usId, s_astOsdBoxList[usId].usX, s_astOsdBoxList[usId].usY, s_astOsdBoxList[usId].usW, s_astOsdBoxList[usId].usH,
                            stBox.usX, stBox.usY, stBox.usW, stBox.usH);
            return HV_TRUE;
        }
        else if ((stBox.usX <= s_astOsdBoxList[usId].usX) &&
                 (stBox.usY <= s_astOsdBoxList[usId].usY) &&
                 (stBox.usX + stBox.usW >= s_astOsdBoxList[usId].usX + s_astOsdBoxList[usId].usW) &&
                 (stBox.usY + stBox.usH >= s_astOsdBoxList[usId].usY + s_astOsdBoxList[usId].usH))
        {
            OSD_LOG_VERBOSE("the new box: xy = (%d, %d), wh = %d*%d contain s_astOsdBoxList[%d]: xy = (%d, %d), wh = %d*%d",
                            stBox.usX, stBox.usY, stBox.usW, stBox.usH,
                            usId, s_astOsdBoxList[usId].usX, s_astOsdBoxList[usId].usY, s_astOsdBoxList[usId].usW, s_astOsdBoxList[usId].usH);
            s_astOsdBoxList[usId] = stBox;
            return HV_TRUE;
        }
    }

    return HV_FALSE;
}

VOID Hv_Drv_OsdAppendDrawAreaBox(OsdBox stBox)
{
    if (s_ucRotationPartId != SCENE_ID_MAX)
    {
        if (OSD_ROTATION_NONE != Hv_Drv_OsdGetRotateType())
        {
            if (!Hv_Drv_OsdCheckAreaBoxContain(stBox))
            {
                HV_ASSERT_TRUE_VOID(s_usBoxNum < OSD_BOX_NUM);
                OSD_LOG_DEBUG("s_astOsdBoxList[%d]: xy = (%d, %d), wh = %d * %d",
                            s_usBoxNum, stBox.usX, stBox.usY, stBox.usW, stBox.usH);
                s_astOsdBoxList[s_usBoxNum] = stBox;
                s_astOsdBoxList[s_usBoxNum].usIndex = s_ucRotationPartId;
                s_usBoxNum++;
            }
        }
    }
}

VOID Hv_Drv_OsdClearDrawAreaBox(VOID)
{
    s_usBoxNum = 0;
}

VOID Hv_Drv_OsdSetRotationPartFlag(UCHAR8 ucSceneId)
{
    s_ucRotationPartId = ucSceneId;
}

VOID Hv_Drv_OsdRecordAbsolutePostion(USHORT16 usX, USHORT16 usY)
{
    s_bAbsolutePostion = HV_TRUE;
    s_usAbsoluteX = usX;
    s_usAbsoluteY = usY;
}

BOOL Hv_Drv_OsdGetAbsolutePostion(USHORT16 *pusX, USHORT16 *pusY)
{
    *pusX = s_usAbsoluteX;
    *pusY = s_usAbsoluteY;

    return s_bAbsolutePostion;
}

VOID Hv_Drv_OsdCancelAbsolutePostion(VOID)
{
    s_bAbsolutePostion = HV_FALSE;
}

VOID Hv_Drv_OsdRotationArea(UCHAR8 ucSceneId)
{
    OsdDataPathParam *pstDataPathData = Hv_Drv_OsdDataPath_GetDataPathParam();
    HV_ASSERT_VALID_PTR_VOID(pstDataPathData);
    OsdRotationType enRotate = (HV_TRUE == Hv_Drv_OsdGetRotateSkip()) ? OSD_ROTATION_NONE : Hv_Drv_OsdGetRotateType();
    OsdRotateData stRotateData = {0};
    OsdBox stWindowBox = {0};
    OsdBox stBox = {0};
#ifdef HV_SCALER_DEBUG_VERSION
    UINT64 currTick = Hv_Vos_GetTick();
#endif

#if (HV_OSD_CONFIG_REAL_DDR_CANVAS == HV_CONFIG_ON)
    BOOL bFound = HV_FALSE;
    OsdSceneDrawPart *pstScenePart = NULL;
#endif

    if (s_usBoxNum == 0)
    {
        OSD_LOG_DEBUG("No area box to rotate");
        return;
    }

    /* Rotation buffer */
    stRotateData.pucSrcBuf = (UCHAR8 *)pstDataPathData->uiRotateBuffer;
    stRotateData.uiSrcTotalWidth = pstDataPathData->usRotateBufferWidth;
    stRotateData.uiSrcTotalHeight = pstDataPathData->usRotateBufferHeight + pstDataPathData->usMargin;

    /* Show buffer */
    stRotateData.pucDstBuf = (UCHAR8 *)pstDataPathData->uiDrawBuffer;
#if (HV_OSD_CONFIG_REAL_DDR_CANVAS == HV_CONFIG_ON)
    stRotateData.uiDstTotalWidth = pstDataPathData->stDDRCanvas.usWidth;
    stRotateData.uiDstTotalHeight = pstDataPathData->stDDRCanvas.usHeight;
#else
    stRotateData.uiDstTotalWidth = Hv_Drv_OsdDP_GetRealHActive();
    stRotateData.uiDstTotalHeight = Hv_Drv_OsdDP_GetRealVActive();
#endif

    stWindowBox.usW = pstDataPathData->usRotateOriWidth;
    stWindowBox.usH = pstDataPathData->usRotateOriHeight;
    stWindowBox.usX = pstDataPathData->usRotateX;
    stWindowBox.usY = pstDataPathData->usRotateY;

#if (HV_OSD_CONFIG_REAL_DDR_CANVAS == HV_CONFIG_ON)
    for (UCHAR8 ucSceneIndex = 0; ucSceneIndex < pstDataPathData->ucScenePartCount; ucSceneIndex++)
    {
        pstScenePart = &pstDataPathData->astAllDrawParts[ucSceneIndex];

        if (pstScenePart->ucSceneId == ucSceneId)
        {
            bFound = HV_TRUE;
            break;
        }
    }

    if (bFound)
    {
        if (s_bAbsolutePostion)
        {
            stWindowBox.usX = s_usAbsoluteX - pstDataPathData->stDDRCanvas.usX;
            stWindowBox.usY = s_usAbsoluteY - pstDataPathData->stDDRCanvas.usY;
        }
        else
        {
            stWindowBox.usX = pstScenePart->stRotateArea.usX - pstDataPathData->stDDRCanvas.usX;
            stWindowBox.usY = pstScenePart->stRotateArea.usY - pstDataPathData->stDDRCanvas.usY;
        }
    }
    else
    {
        OSD_DRV_LOG_ERROR("scene (%d, %d, %d, %d) not set before drawing to ddr", stWindowBox.usX, stWindowBox.usY, stWindowBox.usW, stWindowBox.usH);
    }
#else

#if (HV_PROJECT_CONFIG_OSD_ROTATION_TYPE == OSD_ROTATE_IN_PLACE_ALL)
    Hv_Drv_OsdCalculateUnrotateBoxOnScreen(&stWindowBox, stRotateData.uiDstTotalWidth, stRotateData.uiDstTotalHeight, enRotate);
#else
    Hv_Drv_OsdCalculateRotateBoxOnScreen(&stWindowBox, stRotateData.uiDstTotalWidth, stRotateData.uiDstTotalHeight, enRotate);
#endif

    if (s_bAbsolutePostion)
    {
        stWindowBox.usX = s_usAbsoluteX;
        stWindowBox.usY = s_usAbsoluteY;
    }
#endif

    stRotateData.usPixelBit = Hv_Drv_OsdCommon_GetPixelBits(HV_OSD_CONFIG_DDR_FORMAT);

    for (USHORT16 usAreaCount = 0; usAreaCount < s_usBoxNum; usAreaCount++)
    {
        /* get box */
        stBox = s_astOsdBoxList[usAreaCount];
        if (stBox.usIndex != ucSceneId)
        {
            continue;
        }
        /* get area x,y,w,h */
        stRotateData.uiSrcX = stBox.usX;
        stRotateData.uiSrcY = stBox.usY;
        stRotateData.uiSrcWidth = stBox.usW;
        stRotateData.uiSrcHeight = stBox.usH;

        /* Calculate dst area x,y */
        Hv_Drv_OsdCalculateRotateBox(&stBox, pstDataPathData->usRotateOriWidth, pstDataPathData->usRotateOriHeight, enRotate);
        stRotateData.uiDstX = stBox.usX + stWindowBox.usX;
        stRotateData.uiDstY = stBox.usY + stWindowBox.usY;

        stRotateData.uiSrcY += pstDataPathData->usMargin;
        /* rotate area */
        OSD_LOG_DEBUG("Rotate area-%d: X=%d, Y=%d, Width=%d, Height=%d, DstX=%d, DstY=%d",
                          usAreaCount, stRotateData.uiSrcX, stRotateData.uiSrcY, stRotateData.uiSrcWidth, stRotateData.uiSrcHeight,
                          stRotateData.uiDstX, stRotateData.uiDstY);

        Hv_Drv_OsdRotationDo(&stRotateData, enRotate);
    }

    Hv_Vos_InvalidAllDCache();

#ifdef HV_SCALER_DEBUG_VERSION
    currTick = Hv_Vos_GetTick() - currTick;
    OSD_LOG_DEBUG("Rotate Area: Tick passed %llu", currTick);
#endif
}

VOID Hv_Drv_OsdRotationWhole(VOID)
{
    OsdDataPathParam *pstDataPathData = Hv_Drv_OsdDataPath_GetDataPathParam();
    HV_ASSERT_VALID_PTR_VOID(pstDataPathData);
    OsdRotationType enRotate = (HV_TRUE == Hv_Drv_OsdGetRotateSkip()) ? OSD_ROTATION_NONE : Hv_Drv_OsdGetRotateType();
    OsdRotateData stRotateData = {0};
    OsdBox stBox = {0};
#ifdef HV_SCALER_DEBUG_VERSION
    UINT64 currTick = Hv_Vos_GetTick();
#endif

#if (HV_OSD_CONFIG_REAL_DDR_CANVAS == HV_CONFIG_ON)
    BOOL bFound = HV_FALSE;
    OsdSceneDrawPart *pstScenePart = NULL;
#endif

    /* Rotation buffer */
    stRotateData.pucSrcBuf = (UCHAR8 *)pstDataPathData->uiRotateBuffer;
    stRotateData.uiSrcTotalWidth = pstDataPathData->usRotateBufferWidth;
    stRotateData.uiSrcTotalHeight = pstDataPathData->usRotateBufferHeight + pstDataPathData->usMargin;
    stRotateData.uiSrcX = 0;
    stRotateData.uiSrcY = pstDataPathData->usMargin;
    stRotateData.uiSrcWidth = pstDataPathData->usRotateOriWidth;
    stRotateData.uiSrcHeight = pstDataPathData->usRotateOriHeight;

    /* Show buffer */
    stRotateData.pucDstBuf = (UCHAR8 *)pstDataPathData->uiDrawBuffer;
#if (HV_OSD_CONFIG_REAL_DDR_CANVAS == HV_CONFIG_ON)
    stRotateData.uiDstTotalWidth = pstDataPathData->stDDRCanvas.usWidth;
    stRotateData.uiDstTotalHeight = pstDataPathData->stDDRCanvas.usHeight;
#else
    stRotateData.uiDstTotalWidth = Hv_Drv_OsdDP_GetRealHActive();
    stRotateData.uiDstTotalHeight = Hv_Drv_OsdDP_GetRealVActive();
#endif

    stBox.usH = stRotateData.uiSrcHeight;
    stBox.usW = stRotateData.uiSrcWidth;
    stBox.usX = pstDataPathData->usRotateX;
    stBox.usY = pstDataPathData->usRotateY;

#if (HV_OSD_CONFIG_REAL_DDR_CANVAS == HV_CONFIG_ON)
    for (UCHAR8 ucSceneIndex = 0; ucSceneIndex < pstDataPathData->ucScenePartCount; ucSceneIndex++)
    {
        pstScenePart = &pstDataPathData->astAllDrawParts[ucSceneIndex];

        if ((stBox.usX == pstScenePart->stDrawArea.usX) && (stBox.usY == pstScenePart->stDrawArea.usY) &&
            (stBox.usW == pstScenePart->stDrawArea.usWidth) && (stBox.usH == pstScenePart->stDrawArea.usHeight))
        {
            bFound = HV_TRUE;
            break;
        }
    }

    if (bFound)
    {
        if (s_bAbsolutePostion)
        {
            stRotateData.uiDstX = s_usAbsoluteX - pstDataPathData->stDDRCanvas.usX;
            stRotateData.uiDstY = s_usAbsoluteY - pstDataPathData->stDDRCanvas.usY;
        }
        else
        {
            stRotateData.uiDstX = pstScenePart->stRotateArea.usX - pstDataPathData->stDDRCanvas.usX;
            stRotateData.uiDstY = pstScenePart->stRotateArea.usY - pstDataPathData->stDDRCanvas.usY;
        }
    }
    else
    {
        OSD_DRV_LOG_ERROR("scene (%d, %d, %d, %d) not set before drawing to ddr", stBox.usX, stBox.usY, stBox.usW, stBox.usH);
    }
#else

#if (HV_PROJECT_CONFIG_OSD_ROTATION_TYPE == OSD_ROTATE_IN_PLACE_ALL)
    Hv_Drv_OsdCalculateUnrotateBoxOnScreen(&stBox, stRotateData.uiDstTotalWidth, stRotateData.uiDstTotalHeight, enRotate);
#else
    Hv_Drv_OsdCalculateRotateBoxOnScreen(&stBox, stRotateData.uiDstTotalWidth, stRotateData.uiDstTotalHeight, enRotate);
#endif

    if (s_bAbsolutePostion)
    {
        stRotateData.uiDstX = s_usAbsoluteX;
        stRotateData.uiDstY = s_usAbsoluteY;
    }
    else
    {
        stRotateData.uiDstX = stBox.usX;
        stRotateData.uiDstY = stBox.usY;
    }
#endif

    stRotateData.usPixelBit = Hv_Drv_OsdCommon_GetPixelBits(HV_OSD_CONFIG_DDR_FORMAT);

    Hv_Drv_OsdRotationDo(&stRotateData, enRotate);

    Hv_Vos_InvalidAllDCache();

#ifdef HV_SCALER_DEBUG_VERSION
    currTick = Hv_Vos_GetTick() - currTick;
    OSD_LOG_DEBUG("Rotate Whole: Tick passed %llu", currTick);
#endif
}

#endif
