/*
* Copyright (c) 2017-2022, Intel Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
//!
//! \file     codechal_encode_avc_base.cpp
//! \brief    Defines base class for AVC encoder.
//!
#include "codechal_encode_avc_base.h"
#include "codechal_vdenc_avc.h"
#include "codechal_encode_avc.h"
#include "codechal_mmc_encode_avc.h"
#include "hal_oca_interface.h"

#define CODECHAL_ENCODE_AVC_CQP_NUM_OF_PASSES 2
#define CODECHAL_ENCODE_AVC_ICQ_NUM_OF_PASSES 2
#define CODECHAL_ENCODE_AVC_EXTENDED_SAR 255

const uint8_t CODECHAL_ENCODE_AVC_SFD_CostTable_P_FRAME[CODEC_AVC_NUM_QP] =
    {
        44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 60, 60, 60, 60, 73, 73, 73, 76, 76, 76, 88, 89, 89, 91, 92, 93, 104, 104, 106, 107, 108, 109, 120, 120, 122, 123, 124, 125, 136, 136, 138, 139, 140, 141, 143, 143};

const uint8_t CODECHAL_ENCODE_AVC_SFD_CostTable_B_FRAME[CODEC_AVC_NUM_QP] =
    {
        57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 73, 73, 73, 73, 77, 77, 77, 89, 89, 89, 91, 93, 93, 95, 105, 106, 107, 108, 110, 111, 121, 122, 123, 124, 125, 127, 137, 138, 139, 140, 142, 143, 143, 143, 143, 143};

uint32_t CodecHalAvcEncode_GetMaxVmvR(uint8_t levelIdc)
{
    int maxVmvR = 128 * 4;

    // See JVT Spec Annex A Table A-1 Level limits for below mapping
    // maxVmvR is in luma quarter pel unit
    switch (levelIdc)
    {
    case CODEC_AVC_LEVEL_1:
    case CODEC_AVC_LEVEL_1b:
        maxVmvR = 64 * 4;
        break;
    case CODEC_AVC_LEVEL_11:
    case CODEC_AVC_LEVEL_12:
    case CODEC_AVC_LEVEL_13:
    case CODEC_AVC_LEVEL_2:
        maxVmvR = 128 * 4;
        break;
    case CODEC_AVC_LEVEL_21:
    case CODEC_AVC_LEVEL_22:
    case CODEC_AVC_LEVEL_3:
        maxVmvR = 256 * 4;
        break;
    case CODEC_AVC_LEVEL_31:
    case CODEC_AVC_LEVEL_32:
    case CODEC_AVC_LEVEL_4:
    case CODEC_AVC_LEVEL_41:
    case CODEC_AVC_LEVEL_42:
    case CODEC_AVC_LEVEL_5:
    case CODEC_AVC_LEVEL_51:
    case CODEC_AVC_LEVEL_52:
        maxVmvR = 512 * 4;
        break;
    default:
        CODECHAL_ENCODE_NORMALMESSAGE("Unsupported LevelIDC setting.");
        CODECHAL_ENCODE_ASSERT(false);
        break;
    }

    return maxVmvR;
}

uint32_t CodecHalAvcEncode_GetMaxMvLen(uint8_t levelIdc)
{
    int maxMvLen = 127;

    // See JVT Spec Annex A Table A-1 Level limits for below mapping
    // MaxVmvR is in luma quarter pel unit
    switch (levelIdc)
    {
    case CODEC_AVC_LEVEL_1:
    case CODEC_AVC_LEVEL_1b:
        maxMvLen = 63;
        break;
    case CODEC_AVC_LEVEL_11:
    case CODEC_AVC_LEVEL_12:
    case CODEC_AVC_LEVEL_13:
    case CODEC_AVC_LEVEL_2:
        maxMvLen = 127;
        break;
    case CODEC_AVC_LEVEL_21:
    case CODEC_AVC_LEVEL_22:
    case CODEC_AVC_LEVEL_3:
        maxMvLen = 255;
        break;
    case CODEC_AVC_LEVEL_31:
    case CODEC_AVC_LEVEL_32:
    case CODEC_AVC_LEVEL_4:
    case CODEC_AVC_LEVEL_41:
    case CODEC_AVC_LEVEL_42:
    case CODEC_AVC_LEVEL_5:
    case CODEC_AVC_LEVEL_51:
    case CODEC_AVC_LEVEL_52:
        maxMvLen = 511;
        break;
    default:
        CODECHAL_ENCODE_NORMALMESSAGE("Unsupported LevelIDC setting.");
        CODECHAL_ENCODE_ASSERT(false);
        break;
    }

    return maxMvLen;
}

bool CodecHalAvcEncode_GetFieldParity(
    PCODEC_AVC_ENCODE_SLICE_PARAMS slcParams,
    uint32_t                       list,
    uint32_t                       index)
{
    uint32_t fieldParity = 0;

    if (slcParams == nullptr)
    {
        CODECHAL_ENCODE_ASSERTMESSAGE("Invalid (NULL) Pointer.");
        return false;
    }
    CODECHAL_ENCODE_ASSERT(list == LIST_0 || list == LIST_1);
    CODECHAL_ENCODE_ASSERT(index < CODEC_AVC_MAX_NUM_REF_FRAME * 2);

    if (!CodecHal_PictureIsInvalid(slcParams->RefPicList[list][index]))
    {
        fieldParity = CodecHal_PictureIsBottomField(slcParams->RefPicList[list][index]);
    }

    return (fieldParity ? true : false);
}

MOS_STATUS CodechalEncodeAvcBase::SendSlice(
    PMOS_COMMAND_BUFFER        cmdBuffer,
    PMHW_VDBOX_AVC_SLICE_STATE params)
{
    PCODEC_AVC_ENCODE_SLICE_PARAMS      avcSlcParams;
    MHW_VDBOX_AVC_REF_IDX_PARAMS        refIdxParams;
    MHW_VDBOX_AVC_WEIGHTOFFSET_PARAMS   weightOffsetParams;
    MHW_BATCH_BUFFER                    secondLevelBatchBuffer;
    MHW_VDBOX_PAK_INSERT_PARAMS         pakInsertObjectParams;
    MHW_VDBOX_VDENC_WALKER_STATE_PARAMS vdencWalkerStateParams;
    PMOS_COMMAND_BUFFER                 cmdBufferInUse;
    PMHW_BATCH_BUFFER                   batchBufferInUse;
    uint32_t                            bitSize, offSet;
    uint32_t                            maxBytesInPakInsertObjCmd;
    uint32_t                            nalunitPosiSize, nalunitPosiOffset;
    bool                                insertZeroByteWA = false;

    CODECHAL_ENCODE_FUNCTION_ENTER;

    CODECHAL_ENCODE_CHK_NULL_RETURN(cmdBuffer);
    CODECHAL_ENCODE_CHK_NULL_RETURN(params);
    CODECHAL_ENCODE_CHK_NULL_RETURN(params->pAvcPicIdx);
    CODECHAL_ENCODE_CHK_NULL_RETURN(params->presDataBuffer);
    CODECHAL_ENCODE_CHK_NULL_RETURN(params->pEncodeAvcSeqParams);
    CODECHAL_ENCODE_CHK_NULL_RETURN(params->pEncodeAvcPicParams);
    CODECHAL_ENCODE_CHK_NULL_RETURN(params->pEncodeAvcSliceParams);
    CODECHAL_ENCODE_CHK_NULL_RETURN(params->pBsBuffer);
    CODECHAL_ENCODE_CHK_NULL_RETURN(params->ppNalUnitParams);

    avcSlcParams              = params->pEncodeAvcSliceParams;
    maxBytesInPakInsertObjCmd = ((2 << 11) - 1) * 4;  // 12 bits for DwordLength field in PAK_INSERT_OBJ cmd
    nalunitPosiSize           = 0;
    nalunitPosiOffset         = 0;

    // VDENC does not use batch buffer for slice state
    if (params->bSingleTaskPhaseSupported && !params->bVdencInUse)
    {
        CODECHAL_ENCODE_CHK_NULL_RETURN(params->pBatchBufferForPakSlices);
        batchBufferInUse = params->pBatchBufferForPakSlices;
        cmdBufferInUse   = nullptr;
    }
    else
    {
        batchBufferInUse = nullptr;
        cmdBufferInUse   = cmdBuffer;
    }

    // Add reference index and weight offset commands
    refIdxParams.CurrPic         = params->pEncodeAvcPicParams->CurrReconstructedPic;
    refIdxParams.isEncode        = true;
    refIdxParams.bVdencInUse     = params->bVdencInUse;
    refIdxParams.pAvcPicIdx      = params->pAvcPicIdx;
    refIdxParams.avcRefList      = (void **)m_refList;
    refIdxParams.oneOnOneMapping = params->oneOnOneMapping;

    CODECHAL_ENCODE_CHK_STATUS_RETURN(MOS_SecureMemcpy(
        &refIdxParams.RefPicList,
        2 * 32 * sizeof(CODEC_PICTURE),
        avcSlcParams->RefPicList,
        2 * 32 * sizeof(CODEC_PICTURE)));
    if (Slice_Type[avcSlcParams->slice_type] == SLICE_P)
    {
        refIdxParams.uiList                  = LIST_0;
        refIdxParams.uiNumRefForList[LIST_0] = avcSlcParams->num_ref_idx_l0_active_minus1 + 1;

        CODECHAL_ENCODE_CHK_STATUS_RETURN(m_mfxInterface->AddMfxAvcRefIdx(cmdBufferInUse, batchBufferInUse, &refIdxParams));

        if (params->pEncodeAvcPicParams->weighted_pred_flag == EXPLICIT_WEIGHTED_INTER_PRED_MODE)
        {
            weightOffsetParams.uiList                 = LIST_0;
            weightOffsetParams.uiLumaLogWeightDenom   = avcSlcParams->luma_log2_weight_denom;
            weightOffsetParams.uiChromaLogWeightDenom = avcSlcParams->chroma_log2_weight_denom;
            weightOffsetParams.uiLumaWeightFlag       = avcSlcParams->luma_weight_flag[LIST_0];
            weightOffsetParams.uiChromaWeightFlag     = avcSlcParams->chroma_weight_flag[LIST_0];
            weightOffsetParams.uiNumRefForList        = avcSlcParams->num_ref_idx_l0_active_minus1 + 1;

            CODECHAL_ENCODE_CHK_STATUS_RETURN(MOS_SecureMemcpy(
                &weightOffsetParams.Weights,
                sizeof(weightOffsetParams.Weights),
                &avcSlcParams->Weights,
                sizeof(avcSlcParams->Weights)));
            CODECHAL_ENCODE_CHK_STATUS_RETURN(m_mfxInterface->AddMfxAvcWeightOffset(
                cmdBufferInUse,
                batchBufferInUse,
                &weightOffsetParams));
        }
    }

    else if (Slice_Type[avcSlcParams->slice_type] == SLICE_B)
    {
        refIdxParams.uiList                  = LIST_0;
        refIdxParams.uiNumRefForList[LIST_0] = avcSlcParams->num_ref_idx_l0_active_minus1 + 1;

        CODECHAL_ENCODE_CHK_STATUS_RETURN(m_mfxInterface->AddMfxAvcRefIdx(cmdBufferInUse, batchBufferInUse, &refIdxParams));

        refIdxParams.uiList                  = LIST_1;
        refIdxParams.uiNumRefForList[LIST_1] = avcSlcParams->num_ref_idx_l1_active_minus1 + 1;

        CODECHAL_ENCODE_CHK_STATUS_RETURN(m_mfxInterface->AddMfxAvcRefIdx(cmdBufferInUse, batchBufferInUse, &refIdxParams));

        if (params->pEncodeAvcPicParams->weighted_bipred_idc == EXPLICIT_WEIGHTED_INTER_PRED_MODE)
        {
            CODECHAL_ENCODE_CHK_STATUS_RETURN(MOS_SecureMemcpy(
                &weightOffsetParams.Weights,
                sizeof(weightOffsetParams.Weights),
                &avcSlcParams->Weights,
                sizeof(avcSlcParams->Weights)));
            weightOffsetParams.uiList                 = LIST_0;
            weightOffsetParams.uiLumaLogWeightDenom   = avcSlcParams->luma_log2_weight_denom;
            weightOffsetParams.uiChromaLogWeightDenom = avcSlcParams->chroma_log2_weight_denom;
            weightOffsetParams.uiLumaWeightFlag       = avcSlcParams->luma_weight_flag[LIST_0];
            weightOffsetParams.uiChromaWeightFlag     = avcSlcParams->chroma_weight_flag[LIST_0];
            weightOffsetParams.uiNumRefForList        = avcSlcParams->num_ref_idx_l0_active_minus1 + 1;
            CODECHAL_ENCODE_CHK_STATUS_RETURN(m_mfxInterface->AddMfxAvcWeightOffset(
                cmdBufferInUse,
                batchBufferInUse,
                &weightOffsetParams));

            weightOffsetParams.uiList                 = LIST_1;
            weightOffsetParams.uiLumaLogWeightDenom   = avcSlcParams->luma_log2_weight_denom;
            weightOffsetParams.uiChromaLogWeightDenom = avcSlcParams->chroma_log2_weight_denom;
            weightOffsetParams.uiLumaWeightFlag       = avcSlcParams->luma_weight_flag[LIST_1];
            weightOffsetParams.uiChromaWeightFlag     = avcSlcParams->chroma_weight_flag[LIST_1];
            weightOffsetParams.uiNumRefForList        = avcSlcParams->num_ref_idx_l1_active_minus1 + 1;
            CODECHAL_ENCODE_CHK_STATUS_RETURN(m_mfxInterface->AddMfxAvcWeightOffset(
                cmdBufferInUse,
                batchBufferInUse,
                &weightOffsetParams));
        }
    }

    // add AVC Slice state commands
    CODECHAL_ENCODE_CHK_STATUS_RETURN(AddMfxAvcSlice(cmdBufferInUse, batchBufferInUse, params));

    //insert AU, SPS, PSP headers before first slice header
    if (params->bInsertBeforeSliceHeaders)
    {
        uint8_t *dataBase = (uint8_t *)(params->pBsBuffer->pBase);
        uint32_t data     = ((*dataBase) << 24) + ((*(dataBase + 1)) << 16) + ((*(dataBase + 2)) << 8) + (*(dataBase + 3));
        // Only apply the WaSuperSliceHeaderPacking for the cases with 00 00 00 01 start code
        if (data == 0x00000001)
        {
            insertZeroByteWA = true;
        }

        bool     isInsert;
        uint32_t i;
        for (i = 0; i < CODECHAL_ENCODE_AVC_MAX_NAL_TYPE; i++)
        {
            nalunitPosiSize   = params->ppNalUnitParams[i]->uiSize;
            nalunitPosiOffset = params->ppNalUnitParams[i]->uiOffset;
            while (nalunitPosiSize > 0)
            {
                isInsert = params->ppNalUnitParams[i]->bInsertEmulationBytes;
                bitSize  = MOS_MIN(maxBytesInPakInsertObjCmd * 8, nalunitPosiSize * 8);
                offSet   = nalunitPosiOffset;

                MOS_ZeroMemory(&pakInsertObjectParams, sizeof(pakInsertObjectParams));
                pakInsertObjectParams.bEmulationByteBitsInsert    = isInsert;
                pakInsertObjectParams.uiSkipEmulationCheckCount   = params->ppNalUnitParams[i]->uiSkipEmulationCheckCount;
                pakInsertObjectParams.pBsBuffer                   = params->pBsBuffer;
                pakInsertObjectParams.dwBitSize                   = bitSize;
                pakInsertObjectParams.dwOffset                    = offSet;
                pakInsertObjectParams.bHeaderLengthExcludeFrmSize = true;  // Exclude header length from size calculation for accurate Cabac Zero Word Insertion

                if (pakInsertObjectParams.bEmulationByteBitsInsert)
                {
                    CODECHAL_ENCODE_VERBOSEMESSAGE("The emulation prevention bytes are not inserted by the app and are requested to be inserted by HW.");
                }

                CODECHAL_ENCODE_CHK_STATUS_RETURN(m_mfxInterface->AddMfxPakInsertObject(
                    cmdBufferInUse, batchBufferInUse, &pakInsertObjectParams));

                if (nalunitPosiSize > maxBytesInPakInsertObjCmd)
                {
                    nalunitPosiSize -= maxBytesInPakInsertObjCmd;
                    nalunitPosiOffset += maxBytesInPakInsertObjCmd;
                }
                else
                {
                    nalunitPosiSize = 0;
                }

                insertZeroByteWA = false;
            }
        }
    }

    uint8_t *dataBase = (uint8_t *)(params->pBsBuffer->pBase + params->dwOffset);
    uint32_t data     = ((*dataBase) << 24) + ((*(dataBase + 1)) << 16) + ((*(dataBase + 2)) << 8) + (*(dataBase + 3));

    if (data == 0x00000001)
    {
        insertZeroByteWA = true;
    }

    // Insert 0x00 for super slice case when PPS/AUD is not inserted
    if (MEDIA_IS_WA(m_hwInterface->GetWaTable(), WaSuperSliceHeaderPacking) && insertZeroByteWA && params->bVdencInUse && m_hwInterface->m_isVdencSuperSliceEnabled)
    {
        MOS_ZeroMemory(&pakInsertObjectParams, sizeof(pakInsertObjectParams));
        pakInsertObjectParams.pBsBuffer = params->pBsBuffer;
        pakInsertObjectParams.dwBitSize = 8;
        pakInsertObjectParams.dwOffset  = params->dwOffset;

        CODECHAL_ENCODE_CHK_STATUS_RETURN(m_mfxInterface->AddMfxPakInsertObject(
            cmdBufferInUse, batchBufferInUse, &pakInsertObjectParams));
    }

    // Insert slice header
    MOS_ZeroMemory(&pakInsertObjectParams, sizeof(pakInsertObjectParams));
    pakInsertObjectParams.bLastHeader              = true;
    pakInsertObjectParams.bEmulationByteBitsInsert = true;

    if (params->bAcceleratorHeaderPackingCaps)
    {
        // If driver does slice header packing set the skip count to 4
        pakInsertObjectParams.uiSkipEmulationCheckCount = 4;
    }
    else
    {
        // App does the slice header packing, set the skip count passed by the app
        pakInsertObjectParams.uiSkipEmulationCheckCount = params->uiSkipEmulationCheckCount;
    }
    pakInsertObjectParams.pBsBuffer = params->pBsBuffer;
    // Slice Header Indicator should be set for VDENC for multi-slice case
    pakInsertObjectParams.bSliceHeaderIndicator = (!params->bVdencInUse) ? false : true;

    // Remove one byte of 00 for super slice case when PPS/AUD is not inserted, so that HW could patch slice header correctly
    if (MEDIA_IS_WA(m_hwInterface->GetWaTable(), WaSuperSliceHeaderPacking) && insertZeroByteWA && params->bVdencInUse && m_hwInterface->m_isVdencSuperSliceEnabled)
    {
        pakInsertObjectParams.dwBitSize = params->dwLength - 8;
        pakInsertObjectParams.dwOffset  = params->dwOffset + 1;
    }
    else
    {
        pakInsertObjectParams.dwBitSize = params->dwLength;
        pakInsertObjectParams.dwOffset  = params->dwOffset;
    }

    CODECHAL_ENCODE_CHK_STATUS_RETURN(m_mfxInterface->AddMfxPakInsertObject(
        cmdBufferInUse, batchBufferInUse, &pakInsertObjectParams));

    if (params->bVdencInUse)
    {
        //For CNL VDENC Walker command and WeightsOffsets cmds are sent per Super slice
        if (m_hwInterface->m_isVdencSuperSliceEnabled)
        {
            weightOffsetParams.pAvcPicParams = params->pEncodeAvcPicParams;
            CODECHAL_ENCODE_CHK_STATUS_RETURN(m_vdencInterface->AddVdencAvcWeightsOffsetsStateCmd(cmdBuffer, &weightOffsetParams));
            CODECHAL_ENCODE_CHK_STATUS_RETURN(AddVdencSliceStateCmd(cmdBuffer, params));

            vdencWalkerStateParams.Mode          = CODECHAL_ENCODE_MODE_AVC;
            vdencWalkerStateParams.slcIdx        = params->dwSliceIndex;
            vdencWalkerStateParams.pAvcSeqParams = params->pEncodeAvcSeqParams;
            vdencWalkerStateParams.pAvcPicParams = params->pEncodeAvcPicParams;
            vdencWalkerStateParams.pAvcSlcParams = avcSlcParams;
            CODECHAL_ENCODE_CHK_STATUS_RETURN(m_vdencInterface->AddVdencWalkerStateCmd(cmdBuffer, &vdencWalkerStateParams));
        }
    }
    else
    {
        if (params->bSingleTaskPhaseSupported)
        {
            CODECHAL_ENCODE_CHK_STATUS_RETURN(m_miInterface->AddMiBatchBufferEnd(nullptr, batchBufferInUse));

            // Insert Batch Buffer Start command to send AVC_PAK_OBJ data for MBs in this slice
            MOS_ZeroMemory(&secondLevelBatchBuffer, sizeof(MHW_BATCH_BUFFER));
            CODECHAL_ENCODE_CHK_NULL_RETURN(batchBufferInUse);
            secondLevelBatchBuffer.OsResource   = batchBufferInUse->OsResource;
            secondLevelBatchBuffer.dwOffset     = params->dwBatchBufferForPakSlicesStartOffset;
            secondLevelBatchBuffer.bSecondLevel = true;
            CODECHAL_ENCODE_CHK_STATUS_RETURN(m_miInterface->AddMiBatchBufferStartCmd(cmdBuffer, &secondLevelBatchBuffer));
        }

        // Insert Batch Buffer Start command to send AVC_PAK_OBJ data for MBs in this slice
        MOS_ZeroMemory(&secondLevelBatchBuffer, sizeof(MHW_BATCH_BUFFER));
        secondLevelBatchBuffer.OsResource   = *params->presDataBuffer;
        secondLevelBatchBuffer.dwOffset     = params->dwDataBufferOffset;
        secondLevelBatchBuffer.bSecondLevel = true;
        CODECHAL_ENCODE_CHK_STATUS_RETURN(m_miInterface->AddMiBatchBufferStartCmd(cmdBuffer, &secondLevelBatchBuffer));
    }

    return MOS_STATUS_SUCCESS;
}
static int32_t GetMaxMBPS(uint8_t levelIdc)
{
    int maxMBPS = 11880;

    // See JVT Spec Annex A Table A-1 Level limits for below mapping
    // maxMBPS is in MB/s
    switch (levelIdc)
    {
    case CODEC_AVC_LEVEL_1:
    case CODEC_AVC_LEVEL_1b:
        maxMBPS = 1485;
        break;
    case CODEC_AVC_LEVEL_11:
        maxMBPS = 3000;
        break;
    case CODEC_AVC_LEVEL_12:
        maxMBPS = 6000;
        break;
    case CODEC_AVC_LEVEL_13:
    case CODEC_AVC_LEVEL_2:
        maxMBPS = 11880;
        break;
    case CODEC_AVC_LEVEL_21:
        maxMBPS = 19800;
        break;
    case CODEC_AVC_LEVEL_22:
        maxMBPS = 20250;
        break;
    case CODEC_AVC_LEVEL_3:
        maxMBPS = 40500;
        break;
    case CODEC_AVC_LEVEL_31:
        maxMBPS = 108000;
        break;
    case CODEC_AVC_LEVEL_32:
        maxMBPS = 216000;
        break;
    case CODEC_AVC_LEVEL_4:
    case CODEC_AVC_LEVEL_41:
        maxMBPS = 245760;
        break;
    case CODEC_AVC_LEVEL_42:
        maxMBPS = 522240;
        break;
    case CODEC_AVC_LEVEL_5:
        maxMBPS = 589824;
        break;
    case CODEC_AVC_LEVEL_51:
        maxMBPS = 983040;
        break;
    case CODEC_AVC_LEVEL_52:
        maxMBPS = 2073600;
        break;
    default:
        maxMBPS = 0;
        break;
    }

    return maxMBPS;
}

MOS_STATUS CodecHalAvcEncode_GetProfileLevelMaxFrameSize(
    PCODEC_AVC_ENCODE_SEQUENCE_PARAMS seqParams,
    CodechalEncoderState *            encoder,
    uint32_t *                        pdwProfileLevelMaxFrame)
{
    double     bitsPerMB, tmpf;
    int32_t    iMaxMBPS, numMBPerFrame, minCR;
    uint64_t   maxBytePerPic, maxBytePerPicNot0;
    uint32_t   profileLevelMaxFrame, userMaxFrameSize;
    MOS_STATUS eStatus    = MOS_STATUS_SUCCESS;
    double     frameRateD = 100;

    CODECHAL_ENCODE_CHK_NULL_RETURN(seqParams);
    CODECHAL_ENCODE_CHK_NULL_RETURN(encoder);
    CODECHAL_ENCODE_CHK_NULL_RETURN(pdwProfileLevelMaxFrame);

    minCR = 4;

    if (seqParams->Level >= CODEC_AVC_LEVEL_31 && seqParams->Level <= CODEC_AVC_LEVEL_4)
    {
        bitsPerMB = 96;
    }
    else
    {
        bitsPerMB = 192;
        minCR     = 2;
    }

    iMaxMBPS = GetMaxMBPS(seqParams->Level);
    if (!iMaxMBPS)
    {
        CODECHAL_ENCODE_ASSERTMESSAGE("Unsupported LevelIDC setting.");
        return MOS_STATUS_UNKNOWN;
    }

    numMBPerFrame = encoder->m_picWidthInMb * encoder->m_frameFieldHeightInMb;

    tmpf = (double)numMBPerFrame;
    if (tmpf < iMaxMBPS / 172.)
    {
        tmpf = iMaxMBPS / 172.;
    }

    maxBytePerPic = (uint64_t)(tmpf * bitsPerMB);
    maxBytePerPicNot0 =
        (uint64_t)((((double)iMaxMBPS * frameRateD) /
                       (double)seqParams->FramesPer100Sec) *
                   bitsPerMB);
    userMaxFrameSize = seqParams->UserMaxFrameSize;

    if ((encoder->m_pictureCodingType != I_TYPE) && (seqParams->UserMaxPBFrameSize > 0))
    {
        userMaxFrameSize = seqParams->UserMaxPBFrameSize;
    }

    if (userMaxFrameSize != 0)
    {
        profileLevelMaxFrame = (uint32_t)MOS_MIN(userMaxFrameSize, maxBytePerPic);
        profileLevelMaxFrame = (uint32_t)MOS_MIN(maxBytePerPicNot0, profileLevelMaxFrame);
    }
    else
    {
        profileLevelMaxFrame = (uint32_t)MOS_MIN(maxBytePerPicNot0, maxBytePerPic);
    }

    // minCR related changes are added to match hardware behavior
    if (encoder->m_vdencEnabled)
    {
        *pdwProfileLevelMaxFrame = (uint32_t)MOS_MIN((encoder->m_frameHeight * encoder->m_frameHeight), profileLevelMaxFrame);
    }
    else
    {
        *pdwProfileLevelMaxFrame = (uint32_t)MOS_MIN(encoder->m_frameHeight * encoder->m_frameWidth * 3 / (2 * minCR), profileLevelMaxFrame);
    }

    return eStatus;
}

static void PutVLCCode(BSBuffer *bsbuffer, uint32_t code)
{
    uint8_t  leadingZeroBits, bitcount;
    uint32_t code1, bits;

    code1    = code + 1;
    bitcount = 0;
    while (code1)
    {
        code1 >>= 1;
        bitcount++;
    }

    if (bitcount == 1)
    {
        PutBit(bsbuffer, 1);
    }
    else
    {
        leadingZeroBits = bitcount - 1;
        bits            = code + 1 - (1 << leadingZeroBits);
        PutBits(bsbuffer, 1, leadingZeroBits + 1);
        PutBits(bsbuffer, bits, leadingZeroBits);
    }
}

//!
//! \brief    Pack HRD data
//!
//! \param    [in] params
//!           Pointer to codechal encode Avc pack picture header parameter
//!
//! \return   MOS_STATUS
//!           Return MOS_STATUS_SUCCESS if call success, else fail reason
//!
MOS_STATUS CodecHal_PackPictureHeader_HrdParams(
    PCODECHAL_ENCODE_AVC_PACK_PIC_HEADER_PARAMS params)
{
    PCODECHAL_ENCODE_AVC_VUI_PARAMS vuiParams;
    PBSBuffer                       bsbuffer;
    int                             schedSelIdx;
    MOS_STATUS                      eStatus = MOS_STATUS_SUCCESS;

    CODECHAL_ENCODE_CHK_NULL_RETURN(params);

    vuiParams = params->pAvcVuiParams;
    bsbuffer  = params->pBsBuffer;

    PutVLCCode(bsbuffer, vuiParams->cpb_cnt_minus1);
    PutBits(bsbuffer, vuiParams->bit_rate_scale, 4);
    PutBits(bsbuffer, vuiParams->cpb_size_scale, 4);

    for (schedSelIdx = 0; schedSelIdx <= vuiParams->cpb_cnt_minus1; schedSelIdx++)
    {
        PutVLCCode(bsbuffer, vuiParams->bit_rate_value_minus1[schedSelIdx]);
        PutVLCCode(bsbuffer, vuiParams->cpb_size_value_minus1[schedSelIdx]);
        PutBit(bsbuffer, ((vuiParams->cbr_flag >> schedSelIdx) & 1));
    }

    PutBits(bsbuffer, vuiParams->initial_cpb_removal_delay_length_minus1, 5);
    PutBits(bsbuffer, vuiParams->cpb_removal_delay_length_minus1, 5);
    PutBits(bsbuffer, vuiParams->dpb_output_delay_length_minus1, 5);
    PutBits(bsbuffer, vuiParams->time_offset_length, 5);

    return eStatus;
}

static void PackScalingList(BSBuffer *bsbuffer, uint8_t *scalingList, uint8_t sizeOfScalingList)
{
    uint8_t lastScale, nextScale, j;
    char    delta_scale;

    lastScale = nextScale = 8;

    for (j = 0; j < sizeOfScalingList; j++)
    {
        if (nextScale != 0)
        {
            delta_scale = (char)(scalingList[j] - lastScale);

            PutVLCCode(bsbuffer, SIGNED(delta_scale));

            nextScale = scalingList[j];
        }
        lastScale = (nextScale == 0) ? lastScale : nextScale;
    }
}

//!
//! \brief    Pack VUI data
//!
//! \param    [in] params
//!           Pointer to codechal encode Avc pack picture header parameter
//!
//! \return   MOS_STATUS
//!           Return MOS_STATUS_SUCCESS if call success, else fail reason
//!
MOS_STATUS CodecHal_PackPictureHeader_VuiParams(
    PCODECHAL_ENCODE_AVC_PACK_PIC_HEADER_PARAMS params)
{
    PCODECHAL_ENCODE_AVC_VUI_PARAMS vuiParams;
    PBSBuffer                       bsbuffer;
    MOS_STATUS                      eStatus = MOS_STATUS_SUCCESS;

    CODECHAL_ENCODE_CHK_NULL_RETURN(params);
    CODECHAL_ENCODE_CHK_NULL_RETURN(params->pAvcVuiParams);

    vuiParams = params->pAvcVuiParams;
    bsbuffer  = params->pBsBuffer;

    PutBit(bsbuffer, vuiParams->aspect_ratio_info_present_flag);
    if (vuiParams->aspect_ratio_info_present_flag)
    {
        PutBits(bsbuffer, vuiParams->aspect_ratio_idc, 8);
        if (vuiParams->aspect_ratio_idc == CODECHAL_ENCODE_AVC_EXTENDED_SAR)
        {
            PutBits(bsbuffer, vuiParams->sar_width, 16);
            PutBits(bsbuffer, vuiParams->sar_height, 16);
        }
    }

    PutBit(bsbuffer, vuiParams->overscan_info_present_flag);
    if (vuiParams->overscan_info_present_flag)
    {
        PutBit(bsbuffer, vuiParams->overscan_appropriate_flag);
    }

    PutBit(bsbuffer, vuiParams->video_signal_type_present_flag);
    if (vuiParams->video_signal_type_present_flag)
    {
        PutBits(bsbuffer, vuiParams->video_format, 3);
        PutBit(bsbuffer, vuiParams->video_full_range_flag);
        PutBit(bsbuffer, vuiParams->colour_description_present_flag);
        if (vuiParams->colour_description_present_flag)
        {
            PutBits(bsbuffer, vuiParams->colour_primaries, 8);
            PutBits(bsbuffer, vuiParams->transfer_characteristics, 8);
            PutBits(bsbuffer, vuiParams->matrix_coefficients, 8);
        }
    }

    PutBit(bsbuffer, vuiParams->chroma_loc_info_present_flag);
    if (vuiParams->chroma_loc_info_present_flag)
    {
        PutVLCCode(bsbuffer, vuiParams->chroma_sample_loc_type_top_field);
        PutVLCCode(bsbuffer, vuiParams->chroma_sample_loc_type_bottom_field);
    }

    PutBit(bsbuffer, vuiParams->timing_info_present_flag);
    if (vuiParams->timing_info_present_flag)
    {
        PutBits(bsbuffer, vuiParams->num_units_in_tick, 32);
        PutBits(bsbuffer, vuiParams->time_scale, 32);
        PutBit(bsbuffer, vuiParams->fixed_frame_rate_flag);
    }

    PutBit(bsbuffer, vuiParams->nal_hrd_parameters_present_flag);
    if (vuiParams->nal_hrd_parameters_present_flag)
    {
        CODECHAL_ENCODE_CHK_STATUS_RETURN(CodecHal_PackPictureHeader_HrdParams(params));
    }

    PutBit(bsbuffer, vuiParams->vcl_hrd_parameters_present_flag);
    if (vuiParams->vcl_hrd_parameters_present_flag)
    {
        CODECHAL_ENCODE_CHK_STATUS_RETURN(CodecHal_PackPictureHeader_HrdParams(params));
    }

    if (vuiParams->nal_hrd_parameters_present_flag || vuiParams->vcl_hrd_parameters_present_flag)
    {
        PutBit(bsbuffer, vuiParams->low_delay_hrd_flag);
    }

    PutBit(bsbuffer, vuiParams->pic_struct_present_flag);
    PutBit(bsbuffer, vuiParams->bitstream_restriction_flag);
    if (vuiParams->bitstream_restriction_flag)
    {
        PutBit(bsbuffer, vuiParams->motion_vectors_over_pic_boundaries_flag);
        PutVLCCode(bsbuffer, vuiParams->max_bytes_per_pic_denom);
        PutVLCCode(bsbuffer, vuiParams->max_bits_per_mb_denom);
        PutVLCCode(bsbuffer, vuiParams->log2_max_mv_length_horizontal);
        PutVLCCode(bsbuffer, vuiParams->log2_max_mv_length_vertical);
        PutVLCCode(bsbuffer, vuiParams->num_reorder_frames);
        PutVLCCode(bsbuffer, vuiParams->max_dec_frame_buffering);
    }

    return eStatus;
}

static void SetNalUnit(uint8_t **bsbuffer, uint8_t refIDC, CODECHAL_ENCODE_AVC_NAL_UNIT_TYPE nalType)
{
    uint8_t *byte = *bsbuffer;

    // for SPS and PPS NAL units zero_byte should exist
    if (nalType == CODECHAL_ENCODE_AVC_NAL_UT_SPS || nalType == CODECHAL_ENCODE_AVC_NAL_UT_PPS || nalType == CODECHAL_ENCODE_AVC_NAL_UT_AUD)
    {
        *byte++ = 0;
    }

    *byte++   = 0;
    *byte++   = 0;
    *byte++   = 1;
    *byte++   = (uint8_t)((refIDC << 5) | nalType);
    *byte     = 0;  // Clear the next byte
    *bsbuffer = byte;
}

static void SetTrailingBits(BSBuffer *bsbuffer)
{
    // Write Stop Bit
    PutBits(bsbuffer, 1, 1);
    // Make byte aligned
    while (bsbuffer->BitOffset)
    {
        PutBit(bsbuffer, 0);
    }
}

static void CodecHal_PackSliceHeader_SetInitialRefPicList(
    PCODECHAL_ENCODE_AVC_PACK_SLC_HEADER_PARAMS params)
{
    PCODEC_AVC_ENCODE_SLICE_PARAMS slcParams;
    PCODEC_REF_LIST *              refList;
    CODEC_PIC_REORDER *            picOrder, pTempPicOrder[32];
    CODEC_PICTURE                  picture;
    uint8_t                        i, j, botField;
    uint32_t                       picNum, picOC;
    uint8_t                        topIdx, botIdx, listSize;
    uint32_t                       defaultPicNumOrder[32];
    bool                           reorder;

    CODECHAL_ENCODE_FUNCTION_ENTER;

    CODECHAL_ENCODE_CHK_NULL_NO_STATUS_RETURN(params);
    CODECHAL_ENCODE_CHK_NULL_NO_STATUS_RETURN(params->pAvcSliceParams);
    CODECHAL_ENCODE_CHK_NULL_NO_STATUS_RETURN(params->ppRefList);

    slcParams = params->pAvcSliceParams;
    refList   = params->ppRefList;
    reorder   = false;
    topIdx    = 0;
    botIdx    = 0;
    listSize  = 0;

    if (params->wPictureCodingType == P_TYPE)
    {
        CodecHal_PackSliceHeader_GetPicNum(params, 0);  // list 0
        picOrder = &slcParams->PicOrder[0][0];
        // Save the default pic order.
        for (i = 0; i < (slcParams->num_ref_idx_l0_active_minus1 + 1); i++)
        {
            defaultPicNumOrder[i] = picOrder[i].PicNum;
        }
        for (i = 1; i < (slcParams->num_ref_idx_l0_active_minus1 + 1); i++)
        {
            picNum  = picOrder[i].PicNum;
            picture = picOrder[i].Picture;
            picOC   = picOrder[i].POC;
            j       = i;
            while ((j > 0) && (picOrder[j - 1].PicNum < picNum))
            {
                picOrder[j].PicNum  = picOrder[j - 1].PicNum;
                picOrder[j].Picture = picOrder[j - 1].Picture;
                picOrder[j].POC     = picOrder[j - 1].POC;
                j--;
                reorder = true;
            }
            picOrder[j].PicNum  = picNum;
            picOrder[j].Picture = picture;
            picOrder[j].POC     = picOC;
        }

        // Sort picOrder[] based on polarity in field case
        if (CodecHal_PictureIsTopField(params->CurrPic))
        {
            while ((topIdx < (slcParams->num_ref_idx_l0_active_minus1 + 1)) ||
                   (botIdx < (slcParams->num_ref_idx_l0_active_minus1 + 1)))
            {
                for (; topIdx < (slcParams->num_ref_idx_l0_active_minus1 + 1); topIdx++)
                {
                    if (CodecHal_PictureIsTopField(picOrder[topIdx].Picture))  //TOP_FIELD
                    {
                        pTempPicOrder[listSize].PicNum  = picOrder[topIdx].PicNum;
                        pTempPicOrder[listSize].Picture = picOrder[topIdx].Picture;
                        pTempPicOrder[listSize].POC     = picOrder[topIdx].POC;
                        listSize++;
                        topIdx++;
                        break;
                    }
                }
                for (; botIdx < (slcParams->num_ref_idx_l0_active_minus1 + 1); botIdx++)
                {
                    if (CodecHal_PictureIsBottomField(picOrder[botIdx].Picture))  //BOTTOM_FIELD
                    {
                        pTempPicOrder[listSize].PicNum  = picOrder[botIdx].PicNum;
                        pTempPicOrder[listSize].Picture = picOrder[botIdx].Picture;
                        pTempPicOrder[listSize].POC     = picOrder[botIdx].POC;
                        listSize++;
                        botIdx++;
                        break;
                    }
                }
            }
        }
        if (CodecHal_PictureIsBottomField(params->CurrPic))
        {
            while ((topIdx < (slcParams->num_ref_idx_l0_active_minus1 + 1)) ||
                   (botIdx < (slcParams->num_ref_idx_l0_active_minus1 + 1)))
            {
                for (; botIdx < (slcParams->num_ref_idx_l0_active_minus1 + 1); botIdx++)
                {
                    if (CodecHal_PictureIsBottomField(picOrder[botIdx].Picture))  //BOTTOM_FIELD
                    {
                        pTempPicOrder[listSize].PicNum  = picOrder[botIdx].PicNum;
                        pTempPicOrder[listSize].Picture = picOrder[botIdx].Picture;
                        pTempPicOrder[listSize].POC     = picOrder[botIdx].POC;
                        listSize++;
                        botIdx++;
                        break;
                    }
                }
                for (; topIdx < (slcParams->num_ref_idx_l0_active_minus1 + 1); topIdx++)
                {
                    if (CodecHal_PictureIsTopField(picOrder[topIdx].Picture))  //TOP_FIELD
                    {
                        pTempPicOrder[listSize].PicNum  = picOrder[topIdx].PicNum;
                        pTempPicOrder[listSize].Picture = picOrder[topIdx].Picture;
                        pTempPicOrder[listSize].POC     = picOrder[topIdx].POC;
                        listSize++;
                        topIdx++;
                        break;
                    }
                }
            }
        }

        if (!CodecHal_PictureIsFrame(params->CurrPic))
        {
            listSize = MOS_MIN(listSize, 32);
            // Copy temp array back to picOrder[]
            for (i = 0; i < listSize; i++)
            {
                picOrder[i].PicNum  = pTempPicOrder[i].PicNum;
                picOrder[i].Picture = pTempPicOrder[i].Picture;
                picOrder[i].POC     = pTempPicOrder[i].POC;
            }

            // Check if picOrder[] has been shuffled compared to the original list
            reorder = false;
            for (i = 0; i < (slcParams->num_ref_idx_l0_active_minus1 + 1); i++)
            {
                if (defaultPicNumOrder[i] != picOrder[i].PicNum)
                {
                    reorder = true;
                    break;
                }
            }
        }

        if (reorder)
        {
            slcParams->ref_pic_list_reordering_flag_l0 = 1;
        }
        else
        {
            slcParams->ref_pic_list_reordering_flag_l0 = 0;
        }
        for (i = 0; i < (slcParams->num_ref_idx_l0_active_minus1 + 1); i++)
        {
            botField                                                         = (CodecHal_PictureIsBottomField(picOrder[i].Picture)) ? 1 : 0;
            refList[picOrder[i].Picture.FrameIdx]->ucInitialIdx[0][botField] = i;
        }
    }
    if (params->wPictureCodingType == B_TYPE)
    {
    }

    return;
}

static void CodecHal_PackSliceHeader_GetPicNum(
    PCODECHAL_ENCODE_AVC_PACK_SLC_HEADER_PARAMS params,
    uint8_t                                     list)
{
    PCODEC_AVC_ENCODE_SLICE_PARAMS slcParams;
    PCODEC_REF_LIST *              refList;
    uint32_t                       frameNum, frameNumWrap, picNum;
    uint8_t                        i, botField, size;
    CODEC_PICTURE                  picture;

    CODECHAL_ENCODE_FUNCTION_ENTER;

    CODECHAL_ENCODE_CHK_NULL_NO_STATUS_RETURN(params);
    CODECHAL_ENCODE_CHK_NULL_NO_STATUS_RETURN(params->pAvcSliceParams);
    CODECHAL_ENCODE_CHK_NULL_NO_STATUS_RETURN(params->ppRefList);

    slcParams = params->pAvcSliceParams;
    refList   = params->ppRefList;

    size = list ? (slcParams->num_ref_idx_l1_active_minus1 + 1) : (slcParams->num_ref_idx_l0_active_minus1 + 1);

    for (i = 0; i < size; i++)
    {
        picture                                               = slcParams->PicOrder[list][i].Picture;
        botField                                              = (CodecHal_PictureIsBottomField(picture)) ? 1 : 0;
        refList[picture.FrameIdx]->ucFinalIdx[list][botField] = i;
        frameNum                                              = refList[picture.FrameIdx]->sFrameNumber;
        if (frameNum > (uint32_t)refList[params->CurrReconPic.FrameIdx]->sFrameNumber)
        {
            frameNumWrap = frameNum - slcParams->MaxFrameNum;
        }
        else
        {
            frameNumWrap = frameNum;
        }

        if (CodecHal_PictureIsFrame(params->CurrPic))
        {
            picNum = frameNumWrap;
        }
        else if ((CodecHal_PictureIsTopField(params->CurrPic) &&
                     CodecHal_PictureIsTopField(picture)) ||
                 (CodecHal_PictureIsBottomField(params->CurrPic) &&
                     CodecHal_PictureIsBottomField(picture)))
        {
            // Same polarity
            picNum = (frameNumWrap << 1) + 1;
        }
        else
        {
            picNum = frameNumWrap << 1;
        }
        slcParams->PicOrder[list][i].PicNum = picNum;
        slcParams->PicOrder[list][i].POC =
            refList[picture.FrameIdx]->iFieldOrderCnt[botField];
    }

    return;
}

static MOS_STATUS CodecHal_PackSliceHeader_SetRefPicListParam(
    PCODECHAL_ENCODE_AVC_PACK_SLC_HEADER_PARAMS params,
    uint8_t                                     list)
{
    PCODEC_AVC_ENCODE_SLICE_PARAMS slcParams;
    PCODEC_REF_LIST *              refList;
    PCODEC_PIC_REORDER             picOrder;
    uint8_t                        i, j, idx, picIdx, numReorder, numActiveMinus1, refPolarity;
    uint32_t                       picNumPred, currPicNum, picNumNoWrap, maxPicNum;
    int16_t                        frameNum;
    MOS_STATUS                     eStatus = MOS_STATUS_SUCCESS;

    CODECHAL_ENCODE_FUNCTION_ENTER;

    CODECHAL_ENCODE_CHK_NULL_RETURN(params);
    CODECHAL_ENCODE_CHK_NULL_RETURN(params->pAvcSliceParams);
    CODECHAL_ENCODE_CHK_NULL_RETURN(params->ppRefList);

    slcParams = params->pAvcSliceParams;
    refList   = params->ppRefList;
    frameNum  = refList[params->CurrReconPic.FrameIdx]->sFrameNumber;

    currPicNum = (CodecHal_PictureIsFrame(params->CurrPic)) ? frameNum : 2 * frameNum + 1;
    picNumPred = currPicNum;
    maxPicNum  = (CodecHal_PictureIsFrame(params->CurrPic)) ? slcParams->MaxFrameNum : (2 * slcParams->MaxFrameNum);

    numActiveMinus1 = list ? slcParams->num_ref_idx_l1_active_minus1 : slcParams->num_ref_idx_l0_active_minus1;

    picOrder = &slcParams->PicOrder[list][0];

    idx         = 0;
    picIdx      = picOrder[idx].Picture.FrameIdx;
    refPolarity = (CodecHal_PictureIsBottomField(picOrder[idx].Picture)) ? 1 : 0;
    if (refList[picIdx]->ucFinalIdx[list][refPolarity] ==
        refList[picIdx]->ucInitialIdx[list][refPolarity])
    {
        // Should never happen, something must be wrong in CodecHal_PackSliceHeader_SetInitialRefPicList()
        CODECHAL_ENCODE_ASSERT(false);
        if (list)  // L1
        {
            slcParams->ref_pic_list_reordering_flag_l1 = 0;
        }
        else  // L0
        {
            slcParams->ref_pic_list_reordering_flag_l0 = 0;
        }
        eStatus = MOS_STATUS_UNKNOWN;
        return eStatus;
    }

    numReorder = refList[picIdx]->ucFinalIdx[list][refPolarity] - refList[picIdx]->ucInitialIdx[list][refPolarity];
    if (numReorder > numActiveMinus1)
    {
        numReorder = numActiveMinus1;
    }
    slcParams->NumReorder = numReorder;
    do
    {
        for (i = (idx + 1); i <= numActiveMinus1; i++)
        {
            picIdx      = picOrder[i].Picture.FrameIdx;
            refPolarity = (CodecHal_PictureIsBottomField(picOrder[i].Picture)) ? 1 : 0;
            if (refList[picIdx]->ucFinalIdx[list][refPolarity] == idx)
            {
                break;
            }
        }
        if (i == (numActiveMinus1 + 1))
        {
            // Should never happen, something must be wrong
            CODECHAL_ENCODE_ASSERT(false);
            if (list)  // L1
            {
                slcParams->ref_pic_list_reordering_flag_l1 = 0;
            }
            else  // L0
            {
                slcParams->ref_pic_list_reordering_flag_l0 = 0;
            }
            eStatus = MOS_STATUS_UNKNOWN;
            return eStatus;
        }

        if (picOrder[i].PicNum > picNumPred)
        {
            picOrder[idx].ReorderPicNumIDC = 1;
        }
        else
        {
            picOrder[idx].ReorderPicNumIDC = 0;
        }

        if (picOrder[i].PicNum > currPicNum)
        {
            picNumNoWrap = picOrder[i].PicNum + maxPicNum;
        }
        else
        {
            picNumNoWrap = picOrder[i].PicNum;
        }

        if (picOrder[idx].ReorderPicNumIDC == 0)
        {
            if (picNumPred > picNumNoWrap)
            {
                picOrder[idx].DiffPicNumMinus1 = picNumPred - picNumNoWrap - 1;
            }
            else
            {
                picOrder[idx].DiffPicNumMinus1 = picNumPred + maxPicNum - picNumNoWrap - 1;
            }
        }
        else
        {
            if (picNumNoWrap > picNumPred)
            {
                picOrder[idx].DiffPicNumMinus1 = picNumNoWrap - picNumPred - 1;
            }
            else
            {
                picOrder[idx].DiffPicNumMinus1 = picNumNoWrap + maxPicNum - picNumPred - 1;
            }
        }
        picNumPred = picNumNoWrap;

        for (j = i; j > idx; j--)
        {
            picOrder[j].Picture = picOrder[j - 1].Picture;
            picOrder[j].PicNum  = picOrder[j - 1].PicNum;
            picOrder[j].POC     = picOrder[j - 1].POC;
        }

        idx++;
    } while (--numReorder);
    picOrder[idx].ReorderPicNumIDC = 3;

    return eStatus;
}

static MOS_STATUS CodecHal_PackSliceHeader_PredWeightTable(
    PCODECHAL_ENCODE_AVC_PACK_SLC_HEADER_PARAMS params)
{
    PCODEC_AVC_ENCODE_SLICE_PARAMS slcParams;
    PBSBuffer                      bsbuffer;
    int16_t                        weight, offset, weight2, offset2;
    uint8_t                        i, weight_flag, chromaIDC;
    MOS_STATUS                     eStatus = MOS_STATUS_SUCCESS;

    CODECHAL_ENCODE_CHK_NULL_RETURN(params);
    CODECHAL_ENCODE_CHK_NULL_RETURN(params->pSeqParams);
    CODECHAL_ENCODE_CHK_NULL_RETURN(params->pAvcSliceParams);
    CODECHAL_ENCODE_CHK_NULL_RETURN(params->pBsBuffer);

    bsbuffer  = params->pBsBuffer;
    slcParams = params->pAvcSliceParams;
    chromaIDC = params->pSeqParams->chroma_format_idc;

    PutVLCCode(bsbuffer, slcParams->luma_log2_weight_denom);

    if (chromaIDC)
    {
        PutVLCCode(bsbuffer, slcParams->chroma_log2_weight_denom);
    }

    for (i = 0; i <= slcParams->num_ref_idx_l0_active_minus1; i++)
    {
        // Luma
        weight      = slcParams->Weights[0][i][0][0];
        offset      = slcParams->Weights[0][i][0][1];
        weight_flag = (weight != (1 << slcParams->luma_log2_weight_denom)) || (offset != 0);
        PutBit(bsbuffer, weight_flag);
        if (weight_flag)
        {
            PutVLCCode(bsbuffer, SIGNED(weight));
            PutVLCCode(bsbuffer, SIGNED(offset));
        }

        // Chroma
        if (chromaIDC)
        {
            weight      = slcParams->Weights[0][i][1][0];
            offset      = slcParams->Weights[0][i][1][1];
            weight2     = slcParams->Weights[0][i][2][0];
            offset2     = slcParams->Weights[0][i][2][1];
            weight_flag = (weight != (1 << slcParams->chroma_log2_weight_denom)) ||
                          (weight2 != (1 << slcParams->chroma_log2_weight_denom)) ||
                          (offset != 0) || (offset2 != 0);
            PutBit(bsbuffer, weight_flag);
            if (weight_flag)
            {
                PutVLCCode(bsbuffer, SIGNED(weight));
                PutVLCCode(bsbuffer, SIGNED(offset));
                PutVLCCode(bsbuffer, SIGNED(weight2));
                PutVLCCode(bsbuffer, SIGNED(offset2));
            }
        }
    }

    if (Slice_Type[slcParams->slice_type] == SLICE_B)
    {
        for (i = 0; i <= slcParams->num_ref_idx_l1_active_minus1; i++)
        {
            // Luma
            weight      = slcParams->Weights[1][i][0][0];
            offset      = slcParams->Weights[1][i][0][1];
            weight_flag = (weight != (1 << slcParams->luma_log2_weight_denom)) || (offset != 0);
            PutBit(bsbuffer, weight_flag);
            if (weight_flag)
            {
                PutVLCCode(bsbuffer, SIGNED(weight));
                PutVLCCode(bsbuffer, SIGNED(offset));
            }

            // Chroma
            if (chromaIDC)
            {
                weight      = slcParams->Weights[1][i][1][0];
                offset      = slcParams->Weights[1][i][1][1];
                weight2     = slcParams->Weights[1][i][2][0];
                offset2     = slcParams->Weights[1][i][2][1];
                weight_flag = (weight != (1 << slcParams->chroma_log2_weight_denom)) ||
                              (weight2 != (1 << slcParams->chroma_log2_weight_denom)) ||
                              (offset != 0) || (offset2 != 0);
                PutBit(bsbuffer, weight_flag);
                if (weight_flag)
                {
                    PutVLCCode(bsbuffer, SIGNED(weight));
                    PutVLCCode(bsbuffer, SIGNED(offset));
                    PutVLCCode(bsbuffer, SIGNED(weight2));
                    PutVLCCode(bsbuffer, SIGNED(offset2));
                }
            }
        }
    }

    return eStatus;
}

static MOS_STATUS CodecHal_PackSliceHeader_MMCO(
    PCODECHAL_ENCODE_AVC_PACK_SLC_HEADER_PARAMS params)
{
    PCODEC_AVC_ENCODE_SLICE_PARAMS slcParams;
    PBSBuffer                      bsbuffer;
    MOS_STATUS                     eStatus = MOS_STATUS_SUCCESS;

    CODECHAL_ENCODE_CHK_NULL_RETURN(params);
    CODECHAL_ENCODE_CHK_NULL_RETURN(params->pAvcSliceParams);
    CODECHAL_ENCODE_CHK_NULL_RETURN(params->pBsBuffer);

    bsbuffer  = params->pBsBuffer;
    slcParams = params->pAvcSliceParams;
    
    PCODEC_SLICE_MMCO mmco = &slcParams->MMCO[0];
    do
    {
        PutVLCCode(bsbuffer, mmco->MmcoIDC);
        if (mmco->MmcoIDC == 1 ||
            mmco->MmcoIDC == 3)
            PutVLCCode(bsbuffer, mmco->DiffPicNumMinus1);
        if (mmco->MmcoIDC == 2)
            PutVLCCode(bsbuffer, mmco->LongTermPicNum);
        if (mmco->MmcoIDC == 3 ||
            mmco->MmcoIDC == 6)
            PutVLCCode(bsbuffer, mmco->LongTermFrameIdx);
        if (mmco->MmcoIDC == 4)
            PutVLCCode(bsbuffer, mmco->MaxLongTermFrameIdxPlus1);
    } while ((mmco++)->MmcoIDC != 0);

    return eStatus;
}

//!
//! \brief    Pack AUD parameters
//!
//! \param    [in] params
//!           Pointer to codechal encode Avc pack picture header parameter
//!
//! \return   MOS_STATUS
//!           Return MOS_STATUS_SUCCESS if call success, else fail reason
//!
MOS_STATUS CodecHal_PackPictureHeader_AUDParams(
    PCODECHAL_ENCODE_AVC_PACK_PIC_HEADER_PARAMS params)
{
    uint32_t   picType;
    MOS_STATUS eStatus = MOS_STATUS_SUCCESS;

    CODECHAL_ENCODE_CHK_NULL_RETURN(params);
    CODECHAL_ENCODE_CHK_NULL_RETURN(params->pBsBuffer);

    // refer table 7-5 in H.264 spec on primary_pic_type
    // Here I,P,B types are included
    // According BD Spec 9.5.1.1, 0 - I; 1 - P; 2 - B

    picType = (uint32_t)(params->wPictureCodingType) - 1;
    PutBits(params->pBsBuffer, picType, 3);

    return eStatus;
}

// Refer to H264 picture reordering session
static MOS_STATUS CodecHal_PackSliceHeader_RefPicListReordering(
    PCODECHAL_ENCODE_AVC_PACK_SLC_HEADER_PARAMS params)
{
    PCODEC_AVC_ENCODE_SLICE_PARAMS slcParams;
    PBSBuffer                      bsbuffer;
    CODEC_PIC_REORDER *            picOrder;
    uint8_t                        sliceType;
    MOS_STATUS                     eStatus = MOS_STATUS_SUCCESS;

    CODECHAL_ENCODE_CHK_NULL_RETURN(params);
    CODECHAL_ENCODE_CHK_NULL_RETURN(params->pAvcSliceParams);

    slcParams = params->pAvcSliceParams;
    bsbuffer  = params->pBsBuffer;
    sliceType = Slice_Type[slcParams->slice_type];

    if (!params->UserFlags.bDisableAcceleratorRefPicListReordering)
    {
        // Generate the initial reference list (PicOrder)
        CodecHal_PackSliceHeader_SetInitialRefPicList(params);
    }

    if (sliceType != SLICE_I && sliceType != SLICE_SI)
    {
        if (slcParams->ref_pic_list_reordering_flag_l0)
        {
            if (!params->UserFlags.bDisableAcceleratorRefPicListReordering)
            {
                CODECHAL_ENCODE_CHK_STATUS_RETURN(CodecHal_PackSliceHeader_SetRefPicListParam(params, 0));
            }

            PutBit(bsbuffer, slcParams->ref_pic_list_reordering_flag_l0);

            if (slcParams->ref_pic_list_reordering_flag_l0)
            {
                picOrder = &slcParams->PicOrder[0][0];
                do
                {
                    PutVLCCode(bsbuffer, picOrder->ReorderPicNumIDC);
                    if (picOrder->ReorderPicNumIDC == 0 ||
                        picOrder->ReorderPicNumIDC == 1)
                    {
                        PutVLCCode(bsbuffer, picOrder->DiffPicNumMinus1);
                    } else
                    if (picOrder->ReorderPicNumIDC == 2)
                    {
                        PutVLCCode(bsbuffer, picOrder->LongTermPicNum);
                    }
                } while ((picOrder++)->ReorderPicNumIDC != 3);
            }
        }
        else
        {
            PutBit(bsbuffer, slcParams->ref_pic_list_reordering_flag_l0);
        }
    }
    if (sliceType == SLICE_B)
    {
        if (slcParams->ref_pic_list_reordering_flag_l1)
        {
            if (!params->UserFlags.bDisableAcceleratorRefPicListReordering)
            {
                CodecHal_PackSliceHeader_SetRefPicListParam(params, 1);
            }

            PutBit(bsbuffer, slcParams->ref_pic_list_reordering_flag_l1);

            if (slcParams->ref_pic_list_reordering_flag_l1)
            {
                picOrder = &slcParams->PicOrder[1][0];
                do
                {
                    PutVLCCode(bsbuffer, picOrder->ReorderPicNumIDC);
                    if (picOrder->ReorderPicNumIDC == 0 ||
                        picOrder->ReorderPicNumIDC == 1)
                    {
                        PutVLCCode(bsbuffer, picOrder->DiffPicNumMinus1);
                    } else
                    if (picOrder->ReorderPicNumIDC == 2)
                    {
                        PutVLCCode(bsbuffer, picOrder->PicNum);
                    }
                } while ((picOrder++)->ReorderPicNumIDC != 3);
            }
        }
        else
        {
            PutBit(bsbuffer, slcParams->ref_pic_list_reordering_flag_l1);
        }
    }

    return eStatus;
}

//!
//! \brief    Pack sequence parameters
//!
//! \param    [in] params
//!           Pointer to codechal encode Avc pack picture header parameter
//!
//! \return   MOS_STATUS
//!           Return MOS_STATUS_SUCCESS if call success, else fail reason
//!
MOS_STATUS CodecHal_PackPictureHeader_SeqParams(
    PCODECHAL_ENCODE_AVC_PACK_PIC_HEADER_PARAMS params)
{
    PCODEC_AVC_ENCODE_SEQUENCE_PARAMS seqParams;
    BSBuffer *                        bsbuffer;
    uint8_t                           i;
    MOS_STATUS                        eStatus = MOS_STATUS_SUCCESS;

    CODECHAL_ENCODE_CHK_NULL_RETURN(params);
    CODECHAL_ENCODE_CHK_NULL_RETURN(params->pBsBuffer);
    CODECHAL_ENCODE_CHK_NULL_RETURN(params->pSeqParams);

    seqParams = params->pSeqParams;
    bsbuffer  = params->pBsBuffer;

    PutBits(bsbuffer, seqParams->Profile, 8);

    PutBit(bsbuffer, seqParams->constraint_set0_flag);
    PutBit(bsbuffer, seqParams->constraint_set1_flag);
    PutBit(bsbuffer, seqParams->constraint_set2_flag);
    PutBit(bsbuffer, seqParams->constraint_set3_flag);

    PutBits(bsbuffer, 0, 4);
    PutBits(bsbuffer, seqParams->Level, 8);
    PutVLCCode(bsbuffer, seqParams->seq_parameter_set_id);

    if (seqParams->Profile == CODEC_AVC_HIGH_PROFILE ||
        seqParams->Profile == CODEC_AVC_HIGH10_PROFILE ||
        seqParams->Profile == CODEC_AVC_HIGH422_PROFILE ||
        seqParams->Profile == CODEC_AVC_HIGH444_PROFILE ||
        seqParams->Profile == CODEC_AVC_CAVLC444_INTRA_PROFILE ||
        seqParams->Profile == CODEC_AVC_SCALABLE_BASE_PROFILE ||
        seqParams->Profile == CODEC_AVC_SCALABLE_HIGH_PROFILE)
    {
        PutVLCCode(bsbuffer, seqParams->chroma_format_idc);
        if (seqParams->chroma_format_idc == 3)
        {
            PutBit(bsbuffer, seqParams->separate_colour_plane_flag);
        }
        PutVLCCode(bsbuffer, seqParams->bit_depth_luma_minus8);
        PutVLCCode(bsbuffer, seqParams->bit_depth_chroma_minus8);
        PutBit(bsbuffer, seqParams->qpprime_y_zero_transform_bypass_flag);
        PutBit(bsbuffer, seqParams->seq_scaling_matrix_present_flag);
        if (seqParams->seq_scaling_matrix_present_flag)
        {
            //Iterate thro' the scaling lists. Refer to ITU-T H.264 std. section 7.3.2.1
            for (i = 0; i < 8; i++)
            {
                // scaling list present flag
                PutBit(bsbuffer, seqParams->seq_scaling_list_present_flag[i]);
                if (seqParams->seq_scaling_list_present_flag[i])
                {
                    if (i < 6)
                    {
                        PackScalingList(bsbuffer, &params->pAvcIQMatrixParams->ScalingList4x4[i][0], 16);
                    }
                    else
                    {
                        PackScalingList(bsbuffer, &params->pAvcIQMatrixParams->ScalingList8x8[i - 6][0], 64);
                    }
                }
            }
        }
    }

    PutVLCCode(bsbuffer, seqParams->log2_max_frame_num_minus4);
    PutVLCCode(bsbuffer, seqParams->pic_order_cnt_type);
    if (seqParams->pic_order_cnt_type == 0)
    {
        PutVLCCode(bsbuffer, seqParams->log2_max_pic_order_cnt_lsb_minus4);
    }
    else if (seqParams->pic_order_cnt_type == 1)
    {
        PutBit(bsbuffer, seqParams->delta_pic_order_always_zero_flag);
        PutVLCCode(bsbuffer, SIGNED(seqParams->offset_for_non_ref_pic));
        PutVLCCode(bsbuffer, SIGNED(seqParams->offset_for_top_to_bottom_field));
        PutVLCCode(bsbuffer, seqParams->num_ref_frames_in_pic_order_cnt_cycle);
        for (i = 0; i < seqParams->num_ref_frames_in_pic_order_cnt_cycle; i++)
        {
            PutVLCCode(bsbuffer, SIGNED(seqParams->offset_for_ref_frame[i]));
        }
    }

    PutVLCCode(bsbuffer, seqParams->NumRefFrames);
    PutBit(bsbuffer, seqParams->gaps_in_frame_num_value_allowed_flag);
    PutVLCCode(bsbuffer, seqParams->pic_width_in_mbs_minus1);
    PutVLCCode(bsbuffer, seqParams->pic_height_in_map_units_minus1);
    PutBit(bsbuffer, seqParams->frame_mbs_only_flag);

    if (!seqParams->frame_mbs_only_flag)
    {
        PutBit(bsbuffer, seqParams->mb_adaptive_frame_field_flag);
    }

    PutBit(bsbuffer, seqParams->direct_8x8_inference_flag);

    if ((!seqParams->frame_cropping_flag) &&
        (params->dwFrameHeight != params->dwOriFrameHeight))
    {
        seqParams->frame_cropping_flag = 1;
        seqParams->frame_crop_bottom_offset =
            (int16_t)((params->dwFrameHeight - params->dwOriFrameHeight) >>
                      (2 - seqParams->frame_mbs_only_flag));  // 4:2:0
    }

    PutBit(bsbuffer, seqParams->frame_cropping_flag);

    if (seqParams->frame_cropping_flag)
    {
        PutVLCCode(bsbuffer, seqParams->frame_crop_left_offset);
        PutVLCCode(bsbuffer, seqParams->frame_crop_right_offset);
        PutVLCCode(bsbuffer, seqParams->frame_crop_top_offset);
        PutVLCCode(bsbuffer, seqParams->frame_crop_bottom_offset);
    }

    PutBit(bsbuffer, seqParams->vui_parameters_present_flag);

    if (seqParams->vui_parameters_present_flag)
    {
        CODECHAL_ENCODE_CHK_STATUS_RETURN(CodecHal_PackPictureHeader_VuiParams(params));
    }

    *params->pbNewSeqHeader = 1;

    return eStatus;
}

//!
//! \brief    Pack picture parameters
//!
//! \param    [in] params
//!           Pointer to codechal encode Avc pack picture header parameter
//!
//! \return   MOS_STATUS
//!           Return MOS_STATUS_SUCCESS if call success, else fail reason
//!
MOS_STATUS CodecHal_PackPictureHeader_PicParams(
    PCODECHAL_ENCODE_AVC_PACK_PIC_HEADER_PARAMS params)
{
    PCODEC_AVC_ENCODE_SEQUENCE_PARAMS seqParams;
    PCODEC_AVC_ENCODE_PIC_PARAMS      picParams;
    PBSBuffer                         bsbuffer;
    MOS_STATUS                        eStatus = MOS_STATUS_SUCCESS;

    CODECHAL_ENCODE_CHK_NULL_RETURN(params);
    CODECHAL_ENCODE_CHK_NULL_RETURN(params->pSeqParams);
    CODECHAL_ENCODE_CHK_NULL_RETURN(params->pPicParams);
    CODECHAL_ENCODE_CHK_NULL_RETURN(params->pBsBuffer);

    seqParams = params->pSeqParams;
    picParams = params->pPicParams;
    bsbuffer  = params->pBsBuffer;

    PutVLCCode(bsbuffer, picParams->pic_parameter_set_id);
    PutVLCCode(bsbuffer, picParams->seq_parameter_set_id);

    PutBit(bsbuffer, picParams->entropy_coding_mode_flag);
    PutBit(bsbuffer, picParams->pic_order_present_flag);

    PutVLCCode(bsbuffer, picParams->num_slice_groups_minus1);

    PutVLCCode(bsbuffer, picParams->num_ref_idx_l0_active_minus1);
    PutVLCCode(bsbuffer, picParams->num_ref_idx_l1_active_minus1);

    PutBit(bsbuffer, picParams->weighted_pred_flag);
    PutBits(bsbuffer, picParams->weighted_bipred_idc, 2);

    PutVLCCode(bsbuffer, SIGNED(picParams->pic_init_qp_minus26));
    PutVLCCode(bsbuffer, SIGNED(picParams->pic_init_qs_minus26));
    PutVLCCode(bsbuffer, SIGNED(picParams->chroma_qp_index_offset));

    PutBit(bsbuffer, picParams->deblocking_filter_control_present_flag);
    PutBit(bsbuffer, picParams->constrained_intra_pred_flag);
    PutBit(bsbuffer, picParams->redundant_pic_cnt_present_flag);

    // The syntax elements transform_8x8_mode_flag, pic_scaling_matrix_present_flag, and second_chroma_qp_index_offset
    // shall not be present for main profile
    if (seqParams->Profile == CODEC_AVC_MAIN_PROFILE || seqParams->Profile == CODEC_AVC_BASE_PROFILE)
    {
        return eStatus;
    }

    PutBit(bsbuffer, picParams->transform_8x8_mode_flag);
    PutBit(bsbuffer, picParams->pic_scaling_matrix_present_flag);
    if (picParams->pic_scaling_matrix_present_flag)
    {
        uint8_t i;

        //Iterate thro' the scaling lists. Refer to ITU-T H.264 std. section 7.3.2.2
        for (i = 0; i < 6 + 2 * picParams->transform_8x8_mode_flag; i++)
        {
            //Put scaling list present flag
            PutBit(bsbuffer, picParams->pic_scaling_list_present_flag[i]);
            if (picParams->pic_scaling_list_present_flag[i])
            {
                if (i < 6)
                {
                    PackScalingList(bsbuffer, &params->pAvcIQMatrixParams->ScalingList4x4[i][0], 16);
                }
                else
                {
                    PackScalingList(bsbuffer, &params->pAvcIQMatrixParams->ScalingList8x8[i - 6][0], 64);
                }
            }
        }
    }

    PutVLCCode(bsbuffer, SIGNED(picParams->second_chroma_qp_index_offset));

    *params->pbNewPPSHeader = 1;

    return eStatus;
}

MOS_STATUS CodecHalAvcEncode_PackPictureHeader(
    PCODECHAL_ENCODE_AVC_PACK_PIC_HEADER_PARAMS params)
{
    PBSBuffer  bsbuffer;
    uint32_t   indexNALUnit;
    MOS_STATUS eStatus = MOS_STATUS_SUCCESS;

    CODECHAL_ENCODE_CHK_NULL_RETURN(params);
    CODECHAL_ENCODE_CHK_NULL_RETURN(params->pBsBuffer);
    CODECHAL_ENCODE_CHK_NULL_RETURN(params->pSeqParams);
    CODECHAL_ENCODE_CHK_NULL_RETURN(params->ppNALUnitParams);

    bsbuffer              = params->pBsBuffer;
    *(bsbuffer->pBase)    = 0;  // init first byte to 0
    bsbuffer->pCurrent    = bsbuffer->pBase;
    bsbuffer->SliceOffset = 0;
    bsbuffer->BitOffset   = 0;
    bsbuffer->BitSize     = 0;

    MOS_ZeroMemory(params->ppNALUnitParams[0], sizeof(CODECHAL_NAL_UNIT_PARAMS) * CODECHAL_ENCODE_AVC_MAX_NAL_TYPE);
    indexNALUnit = 0;

    // AU_Delimiter
    // nal_ref_idc to be 0 for all nal_unit_type equal to 6, 9, 10, 11 or12
    params->ppNALUnitParams[indexNALUnit]->uiOffset                  = 0;
    params->ppNALUnitParams[indexNALUnit]->uiNalUnitType             = CODECHAL_ENCODE_AVC_NAL_UT_AUD;
    params->ppNALUnitParams[indexNALUnit]->bInsertEmulationBytes     = true;
    params->ppNALUnitParams[indexNALUnit]->uiSkipEmulationCheckCount = 4;
    SetNalUnit(&bsbuffer->pCurrent, 0, CODECHAL_ENCODE_AVC_NAL_UT_AUD);
    CODECHAL_ENCODE_CHK_STATUS_RETURN(CodecHal_PackPictureHeader_AUDParams(params));
    SetTrailingBits(bsbuffer);
    //NAL unit are byte aligned, bsbuffer->BitOffset should be 0
    params->ppNALUnitParams[indexNALUnit]->uiSize =
        (uint32_t)(bsbuffer->pCurrent -
                   bsbuffer->pBase -
                   params->ppNALUnitParams[indexNALUnit]->uiOffset);
    indexNALUnit++;

    // If this is a new sequence, write the seq set
    if (params->bNewSeq && !params->pSeqParams->bNoAcceleratorSPSInsertion)
    {
        // Pack SPS
        params->ppNALUnitParams[indexNALUnit]->uiOffset                  = (uint32_t)(bsbuffer->pCurrent - bsbuffer->pBase);
        params->ppNALUnitParams[indexNALUnit]->uiNalUnitType             = CODECHAL_ENCODE_AVC_NAL_UT_SPS;
        params->ppNALUnitParams[indexNALUnit]->bInsertEmulationBytes     = true;
        params->ppNALUnitParams[indexNALUnit]->uiSkipEmulationCheckCount = 4;
        SetNalUnit(&bsbuffer->pCurrent, 1, CODECHAL_ENCODE_AVC_NAL_UT_SPS);
        CODECHAL_ENCODE_CHK_STATUS_RETURN(CodecHal_PackPictureHeader_SeqParams(params));
        SetTrailingBits(bsbuffer);
        params->ppNALUnitParams[indexNALUnit]->uiSize =
            (uint32_t)(bsbuffer->pCurrent -
                       bsbuffer->pBase -
                       params->ppNALUnitParams[indexNALUnit]->uiOffset);
        indexNALUnit++;
    }

    // Pack PPS
    params->ppNALUnitParams[indexNALUnit]->uiOffset                  = (uint32_t)(bsbuffer->pCurrent - bsbuffer->pBase);
    params->ppNALUnitParams[indexNALUnit]->uiNalUnitType             = CODECHAL_ENCODE_AVC_NAL_UT_PPS;
    params->ppNALUnitParams[indexNALUnit]->bInsertEmulationBytes     = true;
    params->ppNALUnitParams[indexNALUnit]->uiSkipEmulationCheckCount = 4;
    SetNalUnit(&bsbuffer->pCurrent, 1, CODECHAL_ENCODE_AVC_NAL_UT_PPS);
    CODECHAL_ENCODE_CHK_STATUS_RETURN(CodecHal_PackPictureHeader_PicParams(params));
    SetTrailingBits(bsbuffer);
    params->ppNALUnitParams[indexNALUnit]->uiSize =
        (uint32_t)(bsbuffer->pCurrent -
                   bsbuffer->pBase -
                   params->ppNALUnitParams[indexNALUnit]->uiOffset);
    indexNALUnit++;

    // Pack SEI
    if (params->pSeiData->newSEIData)
    {
        params->ppNALUnitParams[indexNALUnit]->uiOffset                  = (uint32_t)(bsbuffer->pCurrent - bsbuffer->pBase);
        params->ppNALUnitParams[indexNALUnit]->uiNalUnitType             = CODECHAL_ENCODE_AVC_NAL_UT_SEI;
        params->ppNALUnitParams[indexNALUnit]->bInsertEmulationBytes     = false;
        params->ppNALUnitParams[indexNALUnit]->uiSkipEmulationCheckCount = 4;
        eStatus                                                          = MOS_SecureMemcpy(bsbuffer->pCurrent,
            params->pSeiData->dwSEIBufSize,
            params->pSeiData->pSEIBuffer,
            params->pSeiData->dwSEIBufSize);
        if (eStatus != MOS_STATUS_SUCCESS)
        {
            CODECHAL_ENCODE_ASSERTMESSAGE("Failed to copy memory.");
            return eStatus;
        }
        bsbuffer->pCurrent += params->pSeiData->dwSEIDataSize;
        params->pSeiData->newSEIData = false;
        params->ppNALUnitParams[indexNALUnit]->uiSize =
            (uint32_t)(bsbuffer->pCurrent -
                       bsbuffer->pBase -
                       params->ppNALUnitParams[indexNALUnit]->uiOffset);
        indexNALUnit++;
    }

    bsbuffer->SliceOffset = (uint32_t)(bsbuffer->pCurrent - bsbuffer->pBase);

    return eStatus;
}

uint16_t CodecHalAvcEncode_GetMaxNumSlicesAllowed(
    CODEC_AVC_PROFILE_IDC profileIdc,
    CODEC_AVC_LEVEL_IDC   levelIdc,
    uint32_t              framesPer100Sec)
{
    uint16_t maxAllowedNumSlices = 0;

    if ((profileIdc == CODEC_AVC_MAIN_PROFILE) ||
        (profileIdc == CODEC_AVC_HIGH_PROFILE) ||
        (profileIdc == CODEC_AVC_HIGH10_PROFILE) ||
        (profileIdc == CODEC_AVC_HIGH422_PROFILE) ||
        (profileIdc == CODEC_AVC_HIGH444_PROFILE) ||
        (profileIdc == CODEC_AVC_CAVLC444_INTRA_PROFILE))
    {
        switch (levelIdc)
        {
        case CODEC_AVC_LEVEL_3:
            maxAllowedNumSlices = (uint16_t)(40500.0 * 100 / 22.0 / framesPer100Sec);
            break;
        case CODEC_AVC_LEVEL_31:
            maxAllowedNumSlices = (uint16_t)(108000.0 * 100 / 60.0 / framesPer100Sec);
            break;
        case CODEC_AVC_LEVEL_32:
            maxAllowedNumSlices = (uint16_t)(216000.0 * 100 / 60.0 / framesPer100Sec);
            break;
        case CODEC_AVC_LEVEL_4:
        case CODEC_AVC_LEVEL_41:
            maxAllowedNumSlices = (uint16_t)(245760.0 * 100 / 24.0 / framesPer100Sec);
            break;
        case CODEC_AVC_LEVEL_42:
            maxAllowedNumSlices = (uint16_t)(522240.0 * 100 / 24.0 / framesPer100Sec);
            break;
        case CODEC_AVC_LEVEL_5:
            maxAllowedNumSlices = (uint16_t)(589824.0 * 100 / 24.0 / framesPer100Sec);
            break;
        case CODEC_AVC_LEVEL_51:
            maxAllowedNumSlices = (uint16_t)(983040.0 * 100 / 24.0 / framesPer100Sec);
            break;
        case CODEC_AVC_LEVEL_52:
            maxAllowedNumSlices = (uint16_t)(2073600.0 * 100 / 24.0 / framesPer100Sec);
            break;
        default:
            maxAllowedNumSlices = 0;
        }
    }

    return maxAllowedNumSlices;
}

//Pack Slice Header
MOS_STATUS CodecHalAvcEncode_PackSliceHeader(
    PCODECHAL_ENCODE_AVC_PACK_SLC_HEADER_PARAMS params)
{
    PCODEC_AVC_ENCODE_SEQUENCE_PARAMS seqParams;
    PCODEC_AVC_ENCODE_PIC_PARAMS      picParams;
    PCODEC_AVC_ENCODE_SLICE_PARAMS    slcParams;
    PBSBuffer                         bsbuffer;
    uint8_t                           sliceType;
    CODECHAL_ENCODE_AVC_NAL_UNIT_TYPE nalType;
    bool                              ref;
    MOS_STATUS                        eStatus = MOS_STATUS_SUCCESS;

    CODECHAL_ENCODE_CHK_NULL_RETURN(params);
    CODECHAL_ENCODE_CHK_NULL_RETURN(params->pSeqParams);
    CODECHAL_ENCODE_CHK_NULL_RETURN(params->pPicParams);
    CODECHAL_ENCODE_CHK_NULL_RETURN(params->pAvcSliceParams);
    CODECHAL_ENCODE_CHK_NULL_RETURN(params->pBsBuffer);

    slcParams = params->pAvcSliceParams;
    picParams = params->pPicParams;
    seqParams = params->pSeqParams;
    bsbuffer  = params->pBsBuffer;
    sliceType = Slice_Type[slcParams->slice_type];
    nalType   = params->NalUnitType;
    ref       = params->ppRefList[params->CurrReconPic.FrameIdx]->bUsedAsRef;

    // Make slice header uint8_t aligned
    while (bsbuffer->BitOffset)
    {
        PutBit(bsbuffer, 0);
    }

    // zero byte shall exist when the byte stream NAL unit syntax structure contains the first
    // NAL unit of an access unit in decoding order, as specified by subclause 7.4.1.2.3.
    // VDEnc Slice header packing handled by PAK does not need the 0 byte inserted
    if (params->UserFlags.bDisableAcceleratorHeaderPacking && (!params->bVdencEnabled))
    {
        *bsbuffer->pCurrent = 0;
        bsbuffer->pCurrent++;
    }

    SetNalUnit(&bsbuffer->pCurrent, (uint8_t)ref, nalType);

    // In the VDEnc mode, PAK only gets this command at the beginning of the frame for slice position X=0, Y=0
    PutVLCCode(bsbuffer, params->bVdencEnabled ? 0 : slcParams->first_mb_in_slice);
    PutVLCCode(bsbuffer, slcParams->slice_type);
    PutVLCCode(bsbuffer, slcParams->pic_parameter_set_id);

    if (seqParams->separate_colour_plane_flag)
    {
        PutBits(bsbuffer, slcParams->colour_plane_id, 2);
    }

    PutBits(bsbuffer, slcParams->frame_num, seqParams->log2_max_frame_num_minus4 + 4);

    if (!seqParams->frame_mbs_only_flag)
    {
        PutBit(bsbuffer, slcParams->field_pic_flag);
        if (slcParams->field_pic_flag)
        {
            PutBit(bsbuffer, slcParams->bottom_field_flag);
        }
    }

    if (nalType == CODECHAL_ENCODE_AVC_NAL_UT_IDR_SLICE)
    {
        PutVLCCode(bsbuffer, slcParams->idr_pic_id);
    }

    if (seqParams->pic_order_cnt_type == 0)
    {
        PutBits(bsbuffer, slcParams->pic_order_cnt_lsb, seqParams->log2_max_pic_order_cnt_lsb_minus4 + 4);
        if (picParams->pic_order_present_flag && !slcParams->field_pic_flag)
        {
            PutVLCCode(bsbuffer, SIGNED(slcParams->delta_pic_order_cnt_bottom));
        }
    }

    if (seqParams->pic_order_cnt_type == 1 && !seqParams->delta_pic_order_always_zero_flag)
    {
        PutVLCCode(bsbuffer, SIGNED(slcParams->delta_pic_order_cnt[0]));
        if (picParams->pic_order_present_flag && !slcParams->field_pic_flag)
        {
            PutVLCCode(bsbuffer, SIGNED(slcParams->delta_pic_order_cnt[1]));
        }
    }

    if (picParams->redundant_pic_cnt_present_flag)
    {
        PutVLCCode(bsbuffer, slcParams->redundant_pic_cnt);
    }

    if (sliceType == SLICE_B)
    {
        PutBit(bsbuffer, slcParams->direct_spatial_mv_pred_flag);
    }

    if (sliceType == SLICE_P || sliceType == SLICE_SP || sliceType == SLICE_B)
    {
        PutBit(bsbuffer, slcParams->num_ref_idx_active_override_flag);
        if (slcParams->num_ref_idx_active_override_flag)
        {
            PutVLCCode(bsbuffer, slcParams->num_ref_idx_l0_active_minus1);
            if (sliceType == SLICE_B)
            {
                PutVLCCode(bsbuffer, slcParams->num_ref_idx_l1_active_minus1);
            }
        }
    }

    // ref_pic_list_reordering()
    CODECHAL_ENCODE_CHK_STATUS_RETURN(CodecHal_PackSliceHeader_RefPicListReordering(params));

    if ((picParams->weighted_pred_flag &&
            (sliceType == SLICE_P || sliceType == SLICE_SP)) ||
        (picParams->weighted_bipred_idc == EXPLICIT_WEIGHTED_INTER_PRED_MODE &&
            sliceType == SLICE_B))
    {
        CODECHAL_ENCODE_CHK_STATUS_RETURN(CodecHal_PackSliceHeader_PredWeightTable(params));
    }

    if (ref)
    {
        // dec_ref_pic_marking()
        if (nalType == CODECHAL_ENCODE_AVC_NAL_UT_IDR_SLICE)
        {
            PutBit(bsbuffer, slcParams->no_output_of_prior_pics_flag);
            PutBit(bsbuffer, slcParams->long_term_reference_flag);
        }
        else
        {
            PutBit(bsbuffer, slcParams->adaptive_ref_pic_marking_mode_flag);
            if (slcParams->adaptive_ref_pic_marking_mode_flag)
            {
                CODECHAL_ENCODE_CHK_STATUS_RETURN(CodecHal_PackSliceHeader_MMCO(params));
            }
        }
    }

    if (picParams->entropy_coding_mode_flag && sliceType != SLICE_I && sliceType != SLICE_SI)
    {
        PutVLCCode(bsbuffer, slcParams->cabac_init_idc);
    }

    PutVLCCode(bsbuffer, SIGNED(slcParams->slice_qp_delta));

    if (sliceType == SLICE_SP || sliceType == SLICE_SI)
    {
        if (sliceType == SLICE_SP)
        {
            PutBit(bsbuffer, slcParams->sp_for_switch_flag);
        }
        PutVLCCode(bsbuffer, SIGNED(slcParams->slice_qs_delta));
    }

    if (picParams->deblocking_filter_control_present_flag)
    {
        PutVLCCode(bsbuffer, slcParams->disable_deblocking_filter_idc);
        if (slcParams->disable_deblocking_filter_idc != 1)
        {
            PutVLCCode(bsbuffer, SIGNED(slcParams->slice_alpha_c0_offset_div2));
            PutVLCCode(bsbuffer, SIGNED(slcParams->slice_beta_offset_div2));
        }
    }

    bsbuffer->BitSize =
        (uint32_t)((bsbuffer->pCurrent - bsbuffer->SliceOffset - bsbuffer->pBase) * 8 + bsbuffer->BitOffset);
    bsbuffer->SliceOffset =
        (uint32_t)(bsbuffer->pCurrent - bsbuffer->pBase + (bsbuffer->BitOffset != 0));

    return eStatus;
}

MOS_STATUS CodechalEncodeAvcBase::InitMmcState()
{
#ifdef _MMC_SUPPORTED
    m_mmcState = MOS_New(CodechalMmcEncodeAvc, m_hwInterface, this);
    CODECHAL_ENCODE_CHK_NULL_RETURN(m_mmcState);
#endif
    return MOS_STATUS_SUCCESS;
}

CodechalEncodeAvcBase::CodechalEncodeAvcBase(
    CodechalHwInterface *   hwInterface,
    CodechalDebugInterface *debugInterface,
    PCODECHAL_STANDARD_INFO standardInfo) : CodechalEncoderState(hwInterface, debugInterface, standardInfo)
{
    CODECHAL_ENCODE_FUNCTION_ENTER;

    MOS_ZeroMemory(m_avcPicParams, CODEC_AVC_MAX_PPS_NUM * sizeof(PCODEC_AVC_ENCODE_PIC_PARAMS));
    MOS_ZeroMemory(m_avcSeqParams, CODEC_AVC_MAX_SPS_NUM * sizeof(PCODEC_AVC_ENCODE_SEQUENCE_PARAMS));
    MOS_ZeroMemory(&m_userFlags, sizeof(CODEC_AVC_ENCODE_USER_FLAGS));
    MOS_ZeroMemory(m_picIdx, CODEC_AVC_MAX_NUM_REF_FRAME * sizeof(CODEC_PIC_ID));
    MOS_ZeroMemory(m_refList, CODEC_AVC_NUM_UNCOMPRESSED_SURFACE * sizeof(PCODEC_REF_LIST));
    MOS_ZeroMemory(m_avcFrameStoreID, CODEC_AVC_MAX_NUM_REF_FRAME * sizeof(CODEC_AVC_FRAME_STORE_ID));
    MOS_ZeroMemory(&m_nalUnitType, sizeof(CODECHAL_ENCODE_AVC_NAL_UNIT_TYPE));
    MOS_ZeroMemory(&m_trellisQuantParams, sizeof(CODECHAL_ENCODE_AVC_TQ_PARAMS));
    MOS_ZeroMemory(m_distScaleFactorList0, 2 * CODEC_AVC_MAX_NUM_REF_FRAME * sizeof(uint32_t));
    MOS_ZeroMemory(m_batchBufferForVdencImgStat, CODECHAL_ENCODE_RECYCLED_BUFFER_NUM * sizeof(MHW_BATCH_BUFFER));
    MOS_ZeroMemory(&m_4xMeMvDataBuffer, sizeof(MOS_SURFACE));
    MOS_ZeroMemory(&m_16xMeMvDataBuffer, sizeof(MOS_SURFACE));
    MOS_ZeroMemory(&m_32xMeMvDataBuffer, sizeof(MOS_SURFACE));
    MOS_ZeroMemory(&m_4xMeDistortionBuffer, sizeof(MOS_SURFACE));
    MOS_ZeroMemory(&m_intraRowStoreScratchBuffer, sizeof(MOS_RESOURCE));
    MOS_ZeroMemory(m_batchBufferForPakSlices, CODECHAL_ENCODE_RECYCLED_BUFFER_NUM * sizeof(MHW_BATCH_BUFFER));
    MOS_ZeroMemory(&m_pakSliceSizeStreamoutBuffer, sizeof(MOS_RESOURCE));

    m_hwInterface->GetStateHeapSettings()->dwNumSyncTags = CODECHAL_ENCODE_AVC_NUM_SYNC_TAGS;
    m_hwInterface->GetStateHeapSettings()->dwDshSize     = CODECHAL_ENCODE_AVC_INIT_DSH_SIZE;
}

CodechalEncodeAvcBase::~CodechalEncodeAvcBase()
{
    CODECHAL_ENCODE_FUNCTION_ENTER;

    // Release Ref Lists
    CodecHalFreeDataList(m_refList, CODEC_AVC_NUM_UNCOMPRESSED_SURFACE);

    for (uint8_t i = 0; i < CODECHAL_ENCODE_RECYCLED_BUFFER_NUM; i++)
    {
        ReleaseBatchBufferForPakSlices(i);
    }

    m_osInterface->pfnFreeResource(m_osInterface, &m_intraRowStoreScratchBuffer);

    if (m_encEnabled)
    {
        if (m_hmeSupported)
        {
            if (m_hmeKernel)
            {
                MOS_Delete(m_hmeKernel);
            }
            else
            {
                HmeParams hmeParams;

                MOS_ZeroMemory(&hmeParams, sizeof(hmeParams));
                hmeParams.b4xMeDistortionBufferSupported = true;
                hmeParams.ps16xMeMvDataBuffer            = &m_16xMeMvDataBuffer;
                hmeParams.ps32xMeMvDataBuffer            = &m_32xMeMvDataBuffer;
                hmeParams.ps4xMeDistortionBuffer         = &m_4xMeDistortionBuffer;
                hmeParams.ps4xMeMvDataBuffer             = &m_4xMeMvDataBuffer;
                DestroyMeResources(&hmeParams);
            }
        }
    }

    if (m_sliceSizeStreamoutSupported)
    {
        m_osInterface->pfnFreeResource(m_osInterface, &m_pakSliceSizeStreamoutBuffer);
    }
}

MOS_STATUS CodechalEncodeAvcBase::Initialize(CodechalSetting *settings)
{
    CODECHAL_ENCODE_CHK_STATUS_RETURN(InitMmcState());
    return CodechalEncoderState::Initialize(settings);
}

MOS_STATUS CodechalEncodeAvcBase::UserFeatureKeyReport()
{
    return CodechalEncoderState::UserFeatureKeyReport();
}

MOS_STATUS CodechalEncodeAvcBase::Initialize()
{
    MOS_STATUS eStatus = MOS_STATUS_SUCCESS;

    m_hwInterface->GetMfxPrimitiveCommandsDataSize(
        m_mode,
        &m_pakSliceSize,
        &m_pakSlicePatchListSize,
        false);

    // overwrite, must be zero, no patching into second level batch buffer allowed
    m_pakSlicePatchListSize = 0;

    return eStatus;
}

void CodechalEncodeAvcBase::ScalingListFlat()
{
    // 4x4 block
    for (uint8_t idx2 = 0; idx2 < 6; idx2++)
    {
        for (uint8_t idx1 = 0; idx1 < 16; idx1++)
        {
            m_avcIQWeightScaleLists->WeightScale4x4[idx2][idx1] = 16;
        }
    }
    // 8x8 block
    for (uint8_t idx2 = 0; idx2 < 2; idx2++)
    {
        for (uint8_t idx1 = 0; idx1 < 64; idx1++)
        {
            m_avcIQWeightScaleLists->WeightScale8x8[idx2][idx1] = 16;
        }
    }
}

void CodechalEncodeAvcBase::ScalingListFallbackRuleA()
{
    for (uint8_t idx1 = 0; idx1 < 16; idx1++)
    {
        for (uint8_t idx2 = 0; idx2 < 3; idx2++)
        {
            m_avcIQWeightScaleLists->WeightScale4x4[idx2][CODEC_AVC_Qmatrix_scan_4x4[idx1]] =
                CODEC_AVC_Default_4x4_Intra[idx1];
        }
        for (uint8_t idx2 = 3; idx2 < 6; idx2++)
        {
            m_avcIQWeightScaleLists->WeightScale4x4[idx2][CODEC_AVC_Qmatrix_scan_4x4[idx1]] =
                CODEC_AVC_Default_4x4_Inter[idx1];
        }
    }
    // 8x8 block
    for (uint8_t idx1 = 0; idx1 < 64; idx1++)
    {
        m_avcIQWeightScaleLists->WeightScale8x8[0][CODEC_AVC_Qmatrix_scan_8x8[idx1]] =
            CODEC_AVC_Default_8x8_Intra[idx1];
        m_avcIQWeightScaleLists->WeightScale8x8[1][CODEC_AVC_Qmatrix_scan_8x8[idx1]] =
            CODEC_AVC_Default_8x8_Inter[idx1];
    }
}

void CodechalEncodeAvcBase::GetDistScaleFactor()
{
    auto picParams = m_avcPicParam;
    auto refList   = &(m_refList[0]);
    auto picIdx    = &(m_picIdx[0]);

    bool bottom  = CodecHal_PictureIsBottomField(picParams->CurrOriginalPic);
    int  pocCurr = picParams->CurrFieldOrderCnt[bottom];

    MOS_ZeroMemory(m_distScaleFactorList0, sizeof(uint32_t) * CODEC_AVC_MAX_NUM_REF_FRAME * 2);
    for (unsigned int index = 0; index <= m_avcSliceParams->num_ref_idx_l0_active_minus1; index++)
    {
        auto picture = m_avcSliceParams->RefPicList[LIST_0][index];
        if (!CodecHal_PictureIsInvalid(picture))
        {
            auto pictureIdx = picIdx[picture.FrameIdx].ucPicIdx;
            int  pocPic0    = CodecHal_PictureIsBottomField(picture) ? refList[pictureIdx]->iFieldOrderCnt[1] : refList[pictureIdx]->iFieldOrderCnt[0];
            picture         = m_avcSliceParams->RefPicList[LIST_1][0];
            pictureIdx      = picIdx[picture.FrameIdx].ucPicIdx;
            int pocPic1     = CodecHal_PictureIsBottomField(picture) ? refList[pictureIdx]->iFieldOrderCnt[1] : refList[pictureIdx]->iFieldOrderCnt[0];
            int tb          = CodecHal_Clip3(-128, 127, (pocCurr - pocPic0));
            int td          = CodecHal_Clip3(-128, 127, (pocPic1 - pocPic0));
            if (td == 0)
            {
                td = 1;
            }
            int tx = (16384 + ABS(td / 2)) / td;

            m_distScaleFactorList0[index] = CodecHal_Clip3(-1024, 1023, (tb * tx + 32) >> 6);
        }
    }
}

MOS_STATUS CodechalEncodeAvcBase::AllocateBatchBufferForPakSlices(
    uint32_t numSlices,
    uint8_t  numPakPasses,
    uint8_t  currRecycledBufIdx)
{
    CODECHAL_ENCODE_FUNCTION_ENTER;
    MOS_STATUS eStatus = MOS_STATUS_SUCCESS;

    MOS_ZeroMemory(
        &m_batchBufferForPakSlices[currRecycledBufIdx],
        sizeof(MHW_BATCH_BUFFER));

    // Get the slice size
    uint32_t size = (numPakPasses + 1) * numSlices * m_pakSliceSize;

    m_batchBufferForPakSlices[currRecycledBufIdx].bSecondLevel = true;
    CODECHAL_ENCODE_CHK_STATUS_RETURN(Mhw_AllocateBb(
        m_osInterface,
        &m_batchBufferForPakSlices[currRecycledBufIdx],
        nullptr,
        size));

    MOS_LOCK_PARAMS lockFlags;
    MOS_ZeroMemory(&lockFlags, sizeof(MOS_LOCK_PARAMS));
    lockFlags.WriteOnly = 1;
    uint8_t *data       = (uint8_t *)m_osInterface->pfnLockResource(
        m_osInterface,
        &m_batchBufferForPakSlices[currRecycledBufIdx].OsResource,
        &lockFlags);

    CODECHAL_ENCODE_CHK_NULL_RETURN(data);

    MOS_ZeroMemory(data, size);
    m_osInterface->pfnUnlockResource(
        m_osInterface,
        &m_batchBufferForPakSlices[currRecycledBufIdx].OsResource);

    return eStatus;
}

MOS_STATUS CodechalEncodeAvcBase::ReleaseBatchBufferForPakSlices(
    uint8_t currRecycledBufIdx)
{
    CODECHAL_ENCODE_FUNCTION_ENTER;
    MOS_STATUS eStatus = MOS_STATUS_SUCCESS;

    if (m_batchBufferForPakSlices[currRecycledBufIdx].iSize)
    {
        Mhw_FreeBb(m_osInterface, &m_batchBufferForPakSlices[currRecycledBufIdx], nullptr);
    }

    return eStatus;
}

//==<Functions>=======================================================

// Calculate BiWeight for AVC B frame
// for AVC, we cannot use the CodecHal_GetBiWeight function since AVC can use B as reference and
// also supports PAFF
int32_t CodechalEncodeAvcBase::GetBiWeight(
    uint32_t distScaleFactorRefID0List0,
    uint16_t weightedBiPredIdc)
{
    int32_t biWeight = 32;  // default value
    if (weightedBiPredIdc != IMPLICIT_WEIGHTED_INTER_PRED_MODE)
    {
        biWeight = 32;
    }
    else
    {
        biWeight = (distScaleFactorRefID0List0 + 2) >> 2;

        if (biWeight != 16 && biWeight != 21 &&
            biWeight != 32 && biWeight != 43 && biWeight != 48)
        {
            biWeight = 32;  // If # of B-pics between two refs is more than 3. VME does not support it.
        }
    }

    return biWeight;
}

MOS_STATUS CodechalEncodeAvcBase::AllocateEncResources()
{
    CODECHAL_ENCODE_FUNCTION_ENTER;
    MOS_STATUS eStatus = MOS_STATUS_SUCCESS;

    uint32_t fieldNumMBs = m_picWidthInMb * ((m_picHeightInMb + 1) >> 1);

    // to be used in CodecHalEncode_TrackedBuffer_AllocateMbCodeMvDataResources() later
    m_mbCodeSize = MOS_ALIGN_CEIL(fieldNumMBs * 16 * 4, CODECHAL_PAGE_SIZE) + fieldNumMBs * 16 * 4;
    m_mvDataSize = MOS_ALIGN_CEIL(fieldNumMBs * (32 * 4), CODECHAL_PAGE_SIZE) * 2; // top field MV + bottom field MV (both page aligned)

    // allocate 3 + 2 buffers initially
    if ((m_codecFunction == CODECHAL_FUNCTION_ENC_PAK) && (!m_vdencEnabled))
    {
        for (uint8_t j = 0; j < 3; j++)
        {
            CODECHAL_ENCODE_CHK_STATUS_RETURN(m_trackedBuf->AllocateMbCodeResources(j));
            CODECHAL_ENCODE_CHK_STATUS_RETURN(m_trackedBuf->AllocateMvDataResources(j));
        }

        for (uint8_t k = 0; k < 2; k++)
        {
            CODECHAL_ENCODE_CHK_STATUS_RETURN(m_trackedBuf->AllocateMbCodeResources(CODEC_NUM_REF_BUFFERS + k));
            CODECHAL_ENCODE_CHK_STATUS_RETURN(m_trackedBuf->AllocateMvDataResources(CODEC_NUM_REF_BUFFERS + k));
        }
    }

    if (m_encEnabled && m_hmeSupported)
    {
        if (m_hmeKernel)
        {
            CODECHAL_ENCODE_CHK_STATUS_RETURN(m_hmeKernel->AllocateResources());
        }
        else
        {
            HmeParams hmeParams;
            MOS_ZeroMemory(&hmeParams, sizeof(hmeParams));
            hmeParams.b4xMeDistortionBufferSupported = true;
            hmeParams.ps4xMeDistortionBuffer         = &m_4xMeDistortionBuffer;
            hmeParams.ps4xMeMvDataBuffer             = &m_4xMeMvDataBuffer;
            hmeParams.ps16xMeMvDataBuffer            = &m_16xMeMvDataBuffer;
            hmeParams.ps32xMeMvDataBuffer            = &m_32xMeMvDataBuffer;

            CODECHAL_ENCODE_CHK_STATUS_RETURN(AllocateResources4xMe(&hmeParams));
            if (m_16xMeSupported)
            {
                CODECHAL_ENCODE_CHK_STATUS_RETURN(AllocateResources16xMe(&hmeParams));
            }
            if (m_32xMeSupported)
            {
                CODECHAL_ENCODE_CHK_STATUS_RETURN(AllocateResources32xMe(&hmeParams));
            }
        }
    }

    return eStatus;
}

MOS_STATUS CodechalEncodeAvcBase::AllocateResources()
{
    CODECHAL_ENCODE_FUNCTION_ENTER;
    MOS_STATUS eStatus = MOS_STATUS_SUCCESS;

    CODECHAL_ENCODE_CHK_STATUS_RETURN(CodechalEncoderState::AllocateResources());

    // initiate allocation parameters and lock flags
    MOS_ALLOC_GFXRES_PARAMS allocParamsForBufferLinear;
    MOS_ZeroMemory(&allocParamsForBufferLinear, sizeof(MOS_ALLOC_GFXRES_PARAMS));
    allocParamsForBufferLinear.Type     = MOS_GFXRES_BUFFER;
    allocParamsForBufferLinear.TileType = MOS_TILE_LINEAR;
    allocParamsForBufferLinear.Format   = Format_Buffer;

    AllocateEncResources();

    // Allocate Ref Lists
    CodecHalAllocateDataList(
        m_refList,
        CODEC_AVC_NUM_UNCOMPRESSED_SURFACE);

    if (m_pakEnabled && m_mfxInterface->IsIntraRowstoreCacheEnabled() == false)
    {
        // Intra Row Store Scratch buffer
        // 1 cacheline per MB
        allocParamsForBufferLinear.dwBytes  = m_picWidthInMb * CODECHAL_CACHELINE_SIZE;
        allocParamsForBufferLinear.pBufName = "Intra Row Store Scratch Buffer";

        eStatus = (MOS_STATUS)m_osInterface->pfnAllocateResource(
            m_osInterface,
            &allocParamsForBufferLinear,
            &m_intraRowStoreScratchBuffer);

        if (eStatus != MOS_STATUS_SUCCESS)
        {
            CODECHAL_ENCODE_ASSERTMESSAGE("Failed to allocate Intra Row Store Scratch Buffer.");
            return eStatus;
        }
    }

    if (m_sliceSizeStreamoutSupported)
    {
        // PAK Slice Size Streamout Buffer
        allocParamsForBufferLinear.dwBytes  = MOS_ALIGN_CEIL(CODECHAL_ENCODE_SLICESIZE_BUF_SIZE, CODECHAL_PAGE_SIZE);
        allocParamsForBufferLinear.pBufName = "PAK Slice Size Streamout Buffer";

        eStatus = (MOS_STATUS)m_osInterface->pfnAllocateResource(
            m_osInterface,
            &allocParamsForBufferLinear,
            &m_pakSliceSizeStreamoutBuffer);

        if (eStatus != MOS_STATUS_SUCCESS)
        {
            CODECHAL_ENCODE_ASSERTMESSAGE("%s: Failed to allocate Slice Size Streamout Buffer\n", __FUNCTION__);
            return eStatus;
        }
    }

    return eStatus;
}

MOS_STATUS CodechalEncodeAvcBase::SetSequenceStructs()
{
    CODECHAL_ENCODE_FUNCTION_ENTER;
    MOS_STATUS eStatus = MOS_STATUS_SUCCESS;

    auto seqParams = m_avcSeqParam;

    // seq_scaling_matrix_present_flag and chroma_format_idc
    // shall not be present for main profile
    if (seqParams->Profile == CODEC_AVC_MAIN_PROFILE)
    {
        seqParams->seq_scaling_matrix_present_flag = 0;
        for (uint8_t i = 0; i < 12; i++)
        {
            seqParams->seq_scaling_list_present_flag[i] = 0;
        }
        seqParams->chroma_format_idc = 1;
    }
    // high profile chroma_format_idc in the range of 0 to 1 inclusive
    if (seqParams->chroma_format_idc > 1)
    {
        seqParams->chroma_format_idc = 1;
    }

    // main & high profile support only 8bpp
    seqParams->bit_depth_luma_minus8   = 0;
    seqParams->bit_depth_chroma_minus8 = 0;

    // setup parameters corresponding to H264 bit stream definition
    seqParams->pic_height_in_map_units_minus1       = seqParams->frame_mbs_only_flag ? CODECHAL_GET_HEIGHT_IN_MACROBLOCKS(seqParams->FrameHeight) - 1 : (CODECHAL_GET_HEIGHT_IN_MACROBLOCKS(seqParams->FrameHeight) + 1) / 2 - 1;
    seqParams->pic_width_in_mbs_minus1              = CODECHAL_GET_WIDTH_IN_MACROBLOCKS(seqParams->FrameWidth) - 1;
    seqParams->constraint_set0_flag                 = 0;
    seqParams->constraint_set1_flag                 = (seqParams->Profile == CODEC_AVC_BASE_PROFILE) ? 1 : 0;
    seqParams->constraint_set2_flag                 = 0;
    seqParams->constraint_set3_flag                 = 0;
    seqParams->gaps_in_frame_num_value_allowed_flag = 0;
    seqParams->qpprime_y_zero_transform_bypass_flag = 0;
    seqParams->separate_colour_plane_flag           = 0;

    // setup internal parameters
    m_picWidthInMb  = CODECHAL_GET_WIDTH_IN_MACROBLOCKS(seqParams->FrameWidth);
    m_picHeightInMb = CODECHAL_GET_HEIGHT_IN_MACROBLOCKS(seqParams->FrameHeight);
    m_frameWidth    = m_picWidthInMb * CODECHAL_MACROBLOCK_WIDTH;
    m_frameHeight   = m_picHeightInMb * CODECHAL_MACROBLOCK_HEIGHT;

    // HME Scaling WxH
    m_downscaledWidthInMb4x =
        CODECHAL_GET_WIDTH_IN_MACROBLOCKS(m_frameWidth / SCALE_FACTOR_4x);
    m_downscaledHeightInMb4x =
        CODECHAL_GET_HEIGHT_IN_MACROBLOCKS(m_frameHeight / SCALE_FACTOR_4x);
    m_downscaledWidth4x =
        m_downscaledWidthInMb4x * CODECHAL_MACROBLOCK_WIDTH;
    m_downscaledHeight4x =
        m_downscaledHeightInMb4x * CODECHAL_MACROBLOCK_HEIGHT;

    // SuperHME Scaling WxH
    m_downscaledWidthInMb16x =
        CODECHAL_GET_WIDTH_IN_MACROBLOCKS(m_frameWidth / SCALE_FACTOR_16x);
    m_downscaledHeightInMb16x =
        CODECHAL_GET_HEIGHT_IN_MACROBLOCKS(m_frameHeight / SCALE_FACTOR_16x);
    m_downscaledWidth16x =
        m_downscaledWidthInMb16x * CODECHAL_MACROBLOCK_WIDTH;
    m_downscaledHeight16x =
        m_downscaledHeightInMb16x * CODECHAL_MACROBLOCK_HEIGHT;

    // UltraHME Scaling WxH
    m_downscaledWidthInMb32x =
        CODECHAL_GET_WIDTH_IN_MACROBLOCKS(m_frameWidth / SCALE_FACTOR_32x);
    m_downscaledHeightInMb32x =
        CODECHAL_GET_HEIGHT_IN_MACROBLOCKS(m_frameHeight / SCALE_FACTOR_32x);
    m_downscaledWidth32x =
        m_downscaledWidthInMb32x * CODECHAL_MACROBLOCK_WIDTH;
    m_downscaledHeight32x =
        m_downscaledHeightInMb32x * CODECHAL_MACROBLOCK_HEIGHT;

    MotionEstimationDisableCheck();

    m_kernelMode =
        CodecHal_TargetUsageToMode_AVC[seqParams->TargetUsage & 0x7];
    m_targetUsage = seqParams->TargetUsage & 0x7;

    if (!seqParams->frame_cropping_flag)
    {
        // do cropping only when the picture dimension is not MB aligned...
        seqParams->frame_crop_left_offset = 0;
        seqParams->frame_crop_top_offset  = 0;

        if (m_frameWidth != seqParams->FrameWidth ||
            m_frameHeight != seqParams->FrameHeight)
        {
            seqParams->frame_cropping_flag      = 1;
            seqParams->frame_crop_right_offset  = (uint16_t)((m_frameWidth - seqParams->FrameWidth) >> 1);                                       // 4:2:0
            seqParams->frame_crop_bottom_offset = (uint16_t)((m_frameHeight - seqParams->FrameHeight) >> (2 - seqParams->frame_mbs_only_flag));  // 4:2:0
        }
        else
        {
            seqParams->frame_cropping_flag      = 0;
            seqParams->frame_crop_right_offset  = 0;
            seqParams->frame_crop_bottom_offset = 0;
        }
    }

    if (m_mfxInterface->IsRowStoreCachingSupported())
    {
        MHW_VDBOX_ROWSTORE_PARAMS rowstoreParams;
        MOS_ZeroMemory(&rowstoreParams, sizeof(rowstoreParams));
        rowstoreParams.Mode       = CODECHAL_ENCODE_MODE_AVC;
        rowstoreParams.dwPicWidth = m_frameWidth;
        rowstoreParams.bIsFrame   = (seqParams->frame_mbs_only_flag == 1);
        m_hwInterface->SetRowstoreCachingOffsets(&rowstoreParams);
    }

    return eStatus;
}

MOS_STATUS CodechalEncodeAvcBase::SetPictureStructs()
{
    CODECHAL_ENCODE_FUNCTION_ENTER;
    MOS_STATUS eStatus = MOS_STATUS_SUCCESS;

    auto picParams  = m_avcPicParam;
    auto seqParams  = m_avcSeqParam;
    auto avcRefList = &m_refList[0];
    auto avcPicIdx  = &m_picIdx[0];
    auto slcParams  = m_avcSliceParams;

    if (seqParams->Profile == CODEC_AVC_MAIN_PROFILE || seqParams->Profile == CODEC_AVC_BASE_PROFILE)
    {
        picParams->transform_8x8_mode_flag         = 0;
        picParams->pic_scaling_matrix_present_flag = 0;
        for (uint8_t i = 0; i < 12; i++)
        {
            picParams->pic_scaling_list_present_flag[i] = 0;
        }
        picParams->second_chroma_qp_index_offset = picParams->chroma_qp_index_offset;
    }
    if (picParams->QpY < 0)
    {
        picParams->QpY = 25;  // Set to default, recommended value used in simulation.
    }
    else if (picParams->QpY > CODECHAL_ENCODE_AVC_MAX_SLICE_QP)
    {
        picParams->QpY = CODECHAL_ENCODE_AVC_MAX_SLICE_QP;  // Crop to 51 if larger
    }
    picParams->pic_init_qp_minus26 = picParams->QpY - 26;

    if (!seqParams->seq_scaling_matrix_present_flag)
    {
        if (!picParams->pic_scaling_matrix_present_flag)
            ScalingListFlat();
        else if (!picParams->pic_scaling_list_present_flag[0])
            ScalingListFallbackRuleA();
    }
    else if (!seqParams->seq_scaling_list_present_flag[0] &&
             !picParams->pic_scaling_list_present_flag[0])
    {  // fall-back rule A
        ScalingListFallbackRuleA();
    }

    picParams->num_slice_groups_minus1                = 0;  // do not support flexible MB ordering
    picParams->deblocking_filter_control_present_flag = 1;  // always set to 1
    picParams->redundant_pic_cnt_present_flag         = 0;
    picParams->pic_init_qs_minus26                    = 0;  // not used

    m_userFlags       = picParams->UserFlags;
    m_nalUnitType     = picParams->bIdrPic ? CODECHAL_ENCODE_AVC_NAL_UT_IDR_SLICE : CODECHAL_ENCODE_AVC_NAL_UT_SLICE;
    m_frameNum        = picParams->frame_num;
    m_lastPicInSeq    = picParams->bLastPicInSeq;
    m_lastPicInStream = picParams->bLastPicInStream;
    // App handles tail insertion for VDEnc dynamic slice in non-cp case
    if (m_vdencNoTailInsertion)
    {
        m_lastPicInSeq = m_lastPicInStream = 0;
    }
    m_statusReportFeedbackNumber = picParams->StatusReportFeedbackNumber;

    auto prevPic    = m_currOriginalPic;
    auto prevIdx    = prevPic.FrameIdx;
    auto currPic    = picParams->CurrOriginalPic;
    auto currIdx    = currPic.FrameIdx;
    auto prevRefIdx = m_currReconstructedPic.FrameIdx;
    auto currRefIdx = picParams->CurrReconstructedPic.FrameIdx;

    m_prevReconFrameIdx = m_currReconFrameIdx;
    m_currReconFrameIdx = picParams->CurrReconstructedPic.FrameIdx;

    avcRefList[currRefIdx]->sRefReconBuffer = m_reconSurface;
    avcRefList[currRefIdx]->sRefRawBuffer   = m_rawSurface;
    avcRefList[currRefIdx]->sFrameNumber    = picParams->frame_num;
    avcRefList[currRefIdx]->RefPic          = currPic;
    m_currOriginalPic                       = currPic;
    m_currReconstructedPic                  = picParams->CurrReconstructedPic;

    if (picParams->FieldCodingFlag)
    {
        m_frameFieldHeight                  = ((m_frameHeight + 1) >> 1);
        m_frameFieldHeightInMb              = ((m_picHeightInMb + 1) >> 1);
        m_downscaledFrameFieldHeightInMb4x  = ((m_downscaledHeightInMb4x + 1) >> 1);
        m_downscaledFrameFieldHeightInMb16x = ((m_downscaledHeightInMb16x + 1) >> 1);
        m_downscaledFrameFieldHeightInMb32x = ((m_downscaledHeightInMb32x + 1) >> 1);
        m_currEncBbSet                      = MB_ENC_Field_BB;
        if (CodecHal_PictureIsFrame(prevPic) || prevIdx != currIdx ||
            ((prevPic.PicFlags != currPic.PicFlags) && !(slcParams->pic_order_cnt_lsb & 1)))
        {
            m_firstField = 1;
            // Enable self referencing for both IDR and I pics
            m_firstFieldIdrPic = (picParams->CodingType == I_TYPE) ? 1 : 0;
        }
        else
        {
            m_firstField = 0;
        }
    }
    else
    {
        m_frameFieldHeight                  = m_frameHeight;
        m_frameFieldHeightInMb              = m_picHeightInMb;
        m_downscaledFrameFieldHeightInMb4x  = m_downscaledHeightInMb4x;
        m_downscaledFrameFieldHeightInMb16x = m_downscaledHeightInMb16x;
        m_downscaledFrameFieldHeightInMb32x = m_downscaledHeightInMb32x;
        m_firstField                        = 1;
        m_currEncBbSet                      = MB_ENC_Frame_BB;
    }

    if (picParams->FieldFrameCodingFlag)
    {  // Mbaff
        seqParams->mb_adaptive_frame_field_flag = 1;
        m_mbaffEnabled                          = 1;
    }
    else
    {
        seqParams->mb_adaptive_frame_field_flag = 0;
        m_mbaffEnabled                          = 0;
    }

    // P/B frames with empty ref lists are internally encoded as I frames,
    // while picture header packing remains the original value
    m_pictureCodingType = picParams->CodingType;

    bool emptyRefFrmList = true;
    for (uint8_t i = 0; i < CODEC_AVC_MAX_NUM_REF_FRAME; i++)
    {
        if (picParams->RefFrameList[i].PicFlags != PICTURE_INVALID)
        {
            emptyRefFrmList = false;
            break;
        }
    }

    if (emptyRefFrmList && m_pictureCodingType != I_TYPE)
    {
        m_pictureCodingType = I_TYPE;
    }

    avcRefList[currRefIdx]->bUsedAsRef         = picParams->RefPicFlag;
    avcRefList[currRefIdx]->resBitstreamBuffer = m_resBitstreamBuffer;

    for (uint8_t i = 0; i < 16; i++)
    {
        m_avcFrameStoreID[i].inUse = false;
    }

    for (uint8_t i = 0; i < 16; i++)
    {
        avcPicIdx[i].bValid = false;
        if (picParams->RefFrameList[i].PicFlags != PICTURE_INVALID)
        {
            auto    index         = picParams->RefFrameList[i].FrameIdx;
            uint8_t duplicatedIdx = 0;
            for (uint8_t ii = 0; ii < i; ii++)
            {
                if (avcPicIdx[ii].bValid && index == picParams->RefFrameList[ii].FrameIdx)
                {
                    duplicatedIdx = 1;
                    break;
                }
            }
            if (duplicatedIdx)
            {
                continue;
            }

            avcRefList[index]->RefPic.PicFlags =
                CodecHal_CombinePictureFlags(avcRefList[index]->RefPic, picParams->RefFrameList[i]);
            avcRefList[index]->iFieldOrderCnt[0] = picParams->FieldOrderCntList[i][0];
            avcRefList[index]->iFieldOrderCnt[1] = picParams->FieldOrderCntList[i][1];
            avcPicIdx[i].bValid                  = true;
            avcPicIdx[i].ucPicIdx                = index;
            if (prevPic.PicFlags != PICTURE_INVALID)
            {
                uint8_t ii;
                for (ii = 0; ii < avcRefList[prevRefIdx]->ucNumRef; ii++)
                {
                    if (index == avcRefList[prevRefIdx]->RefList[ii].FrameIdx)
                    {
                        if (avcRefList[index]->ucFrameId == 0x1f)
                        {
                            // Should never happen, something must be wrong
                            CODECHAL_ENCODE_ASSERT(false);
                            avcRefList[index]->ucFrameId = 0;
                        }
                        m_avcFrameStoreID[avcRefList[index]->ucFrameId].inUse = true;
                        break;
                    }
                }
                if (ii == avcRefList[prevRefIdx]->ucNumRef)
                {
                    avcRefList[index]->ucFrameId = 0x1f;
                }
            }
        }
    }

    // Save the current RefList
    uint8_t ii = 0;
    for (uint8_t i = 0; i < 16; i++)
    {
        if (avcPicIdx[i].bValid)
        {
            avcRefList[currRefIdx]->RefList[ii] = picParams->RefFrameList[i];
            ii++;
        }
    }
    avcRefList[currRefIdx]->ucNumRef = ii;
    m_currRefList                    = avcRefList[currRefIdx];

    if (m_codecFunction == CODECHAL_FUNCTION_ENC)
    {
        CODECHAL_ENCODE_CHK_NULL_RETURN(m_encodeParams.presMbCodeSurface);
        m_resMbCodeSurface = *(m_encodeParams.presMbCodeSurface);
    }
    else if (m_codecFunction == CODECHAL_FUNCTION_ENC_PAK)
    {
        if (m_encodeParams.presMbCodeSurface == nullptr ||
            Mos_ResourceIsNull(m_encodeParams.presMbCodeSurface))
        {
            // the actual MbCode/MvData surface to be allocated later
            m_trackedBuf->SetAllocationFlag(true);
        }
        else
        {
            m_resMbCodeSurface = *(m_encodeParams.presMbCodeSurface);
            m_resMvDataSurface  = *(m_encodeParams.presMbCodeSurface);
        }
    }
    else if (CodecHalIsFeiEncode(m_codecFunction))
    {
        CodecEncodeAvcFeiPicParams *feiPicParams;

        feiPicParams = (CodecEncodeAvcFeiPicParams *)m_encodeParams.pFeiPicParams;
        CODECHAL_ENCODE_CHK_NULL_RETURN(feiPicParams);

        // Use app provided buffer if available. For FEI_ENC and FEI_PAK, MBCodeMvEnable needs to be set to true
        if (feiPicParams->MbCodeMvEnable)
        {
            m_resMbCodeSurface = feiPicParams->resMBCode;
            m_resMvDataSurface = feiPicParams->resMVData;

            // Inside the AvcRefList, mbCodesurface and mvdatasurface are stored at frame basis,
            // For FEI, mbcode and mv data buffer are provided separately for each field picture and we need to store them separately.
            if (CodecHal_PictureIsTopField(picParams->CurrOriginalPic))
            {
                avcRefList[currRefIdx]->resRefTopFieldMbCodeBuffer = m_resMbCodeSurface;
                avcRefList[currRefIdx]->resRefTopFieldMvDataBuffer = m_resMvDataSurface;
            }
            else if (CodecHal_PictureIsBottomField(picParams->CurrOriginalPic))
            {
                avcRefList[currRefIdx]->resRefBotFieldMbCodeBuffer = m_resMbCodeSurface;
                avcRefList[currRefIdx]->resRefBotFieldMvDataBuffer = m_resMvDataSurface;
            }

            avcRefList[currRefIdx]->resRefMbCodeBuffer = m_resMbCodeSurface;
            avcRefList[currRefIdx]->resRefMvDataBuffer = m_resMvDataSurface;
        }
        else
        {
            // the actual MbCode/MvData surface to be allocated later
            m_trackedBuf->SetAllocationFlag(true);
        }

        if (feiPicParams->DistortionEnable)
        {
            m_resDistortionBuffer = feiPicParams->resDistortion;
        }
    }

    SetFrameStoreIds(currRefIdx);

    avcRefList[currRefIdx]->iFieldOrderCnt[0]     = picParams->CurrFieldOrderCnt[0];
    avcRefList[currRefIdx]->iFieldOrderCnt[1]     = picParams->CurrFieldOrderCnt[1];
    m_refList[currRefIdx]->ucAvcPictureCodingType = (CodecHal_PictureIsFrame(picParams->CurrOriginalPic)) ? CODEC_AVC_PIC_CODING_TYPE_FRAME : ((picParams->CurrFieldOrderCnt[0] < picParams->CurrFieldOrderCnt[1]) ? CODEC_AVC_PIC_CODING_TYPE_TFF_FIELD : CODEC_AVC_PIC_CODING_TYPE_BFF_FIELD);

    m_hmeEnabled   = m_hmeSupported && m_pictureCodingType != I_TYPE;
    m_16xMeEnabled = m_16xMeSupported && m_pictureCodingType != I_TYPE;
    m_32xMeEnabled = m_32xMeSupported && m_pictureCodingType != I_TYPE;

    if (m_pictureCodingType == B_TYPE)
    {
        GetDistScaleFactor();
        m_biWeight = GetBiWeight(
            m_distScaleFactorList0[0],
            m_avcPicParam->weighted_bipred_idc);
    }

    m_verticalLineStride            = CODECHAL_VLINESTRIDE_FRAME;
    m_verticalLineStrideOffset      = CODECHAL_VLINESTRIDEOFFSET_TOP_FIELD;
    m_mbcodeBottomFieldOffset       = 0;
    m_mvBottomFieldOffset           = 0;
    m_meDistortionBottomFieldOffset = 0;
    m_meMvBottomFieldOffset         = 0;
    m_meMv16xBottomFieldOffset      = 0;
    m_meMv32xBottomFieldOffset      = 0;
    m_sliceMapBottomFieldOffset     = 0;
    if (m_hmeKernel)
    {
        m_hmeKernel->Set4xMeMvBottomFieldOffset(0);
        m_hmeKernel->Set16xMeMvBottomFieldOffset(0);
        m_hmeKernel->Set32xMeMvBottomFieldOffset(0);
        m_hmeKernel->SetDistortionBottomFieldOffset(0);
    }

    if (CodecHal_PictureIsField(m_currOriginalPic))
    {
        m_verticalLineStride = CODECHAL_VLINESTRIDE_FIELD;
        m_frameHeight        = m_frameFieldHeightInMb * 2 * 16;
        m_picHeightInMb      = (uint16_t)(m_frameHeight / 16);
        if (CodecHal_PictureIsBottomField(m_currOriginalPic))
        {
            m_sliceMapBottomFieldOffset = MOS_ALIGN_CEIL((m_picWidthInMb + 1) * sizeof(uint32_t), 64) * m_frameFieldHeightInMb;
            m_verticalLineStrideOffset  = CODECHAL_VLINESTRIDEOFFSET_BOT_FIELD;

            if (CodecHalIsFeiEncode(m_codecFunction))
            {
                CodecEncodeAvcFeiPicParams *feiPicParams;

                feiPicParams = (CodecEncodeAvcFeiPicParams *)m_encodeParams.pFeiPicParams;
                CODECHAL_ENCODE_CHK_NULL_RETURN(feiPicParams);

                // for user provided MbCode and Mv data buffer, set BottomFieldOffset to 0
                if (feiPicParams->MbCodeMvEnable)
                {
                    m_mbcodeBottomFieldOffset = 0;
                    m_mvBottomFieldOffset     = 0;
                }
                else
                {
                    m_mbcodeBottomFieldOffset = m_frameFieldHeightInMb * m_picWidthInMb * 64;
                    m_mvBottomFieldOffset =
                        MOS_ALIGN_CEIL(m_frameFieldHeightInMb * m_picWidthInMb * (32 * 4), CODECHAL_PAGE_SIZE);
                }
            }
            else
            {
                m_mbcodeBottomFieldOffset = m_frameFieldHeightInMb * m_picWidthInMb * 64;
                m_mvBottomFieldOffset =
                    MOS_ALIGN_CEIL(m_frameFieldHeightInMb * m_picWidthInMb * (32 * 4), CODECHAL_PAGE_SIZE);
            }

            m_meDistortionBottomFieldOffset =
                MOS_ALIGN_CEIL((m_downscaledWidthInMb4x * 8), 64) *
                MOS_ALIGN_CEIL((m_downscaledFrameFieldHeightInMb4x * 4 * 10), 8);
            m_meMvBottomFieldOffset =
                MOS_ALIGN_CEIL((m_downscaledWidthInMb4x * 32), 64) *
                (m_downscaledFrameFieldHeightInMb4x * 4 * CODECHAL_ENCODE_ME_DATA_SIZE_MULTIPLIER);
            if (m_16xMeEnabled)
            {
                m_meMv16xBottomFieldOffset =
                    MOS_ALIGN_CEIL((m_downscaledWidthInMb16x * 32), 64) *
                    (m_downscaledFrameFieldHeightInMb16x * 4 * CODECHAL_ENCODE_ME_DATA_SIZE_MULTIPLIER);
                if (m_32xMeEnabled)
                {
                    m_meMv32xBottomFieldOffset =
                        MOS_ALIGN_CEIL((m_downscaledWidthInMb32x * 32), 64) *
                        (m_downscaledFrameFieldHeightInMb32x * 4 * CODECHAL_ENCODE_ME_DATA_SIZE_MULTIPLIER);
                }
            }

            if (m_hmeKernel)
            {
                m_hmeKernel->SetDistortionBottomFieldOffset(
                    MOS_ALIGN_CEIL((m_downscaledWidthInMb4x * 8), 64) *
                    MOS_ALIGN_CEIL((m_downscaledFrameFieldHeightInMb4x * 4 * 10), 8));
                m_hmeKernel->Set4xMeMvBottomFieldOffset(
                    MOS_ALIGN_CEIL((m_downscaledWidthInMb4x * 32), 64) *
                    (m_downscaledFrameFieldHeightInMb4x * 4 * CODECHAL_ENCODE_ME_DATA_SIZE_MULTIPLIER));
                if (m_hmeKernel->Is16xMeEnabled())
                {
                    m_hmeKernel->Set16xMeMvBottomFieldOffset(
                        MOS_ALIGN_CEIL((m_downscaledWidthInMb16x * 32), 64) *
                        (m_downscaledFrameFieldHeightInMb16x * 4 * CODECHAL_ENCODE_ME_DATA_SIZE_MULTIPLIER));
                    if (m_hmeKernel->Is32xMeEnabled())
                    {
                        m_hmeKernel->Set32xMeMvBottomFieldOffset(
                            MOS_ALIGN_CEIL((m_downscaledWidthInMb32x * 32), 64) *
                            (m_downscaledFrameFieldHeightInMb32x * 4 * CODECHAL_ENCODE_ME_DATA_SIZE_MULTIPLIER));
                    }
                }
            }
        }
    }

    return eStatus;
}

MOS_STATUS CodechalEncodeAvcBase::EncodeMeKernel(
    EncodeBrcBuffers *brcBuffers,
    HmeLevel          hmeLevel)
{
    MOS_STATUS eStatus = MOS_STATUS_SUCCESS;

    CODECHAL_ENCODE_FUNCTION_ENTER;

    PerfTagSetting perfTag;
    perfTag.Value             = 0;
    perfTag.Mode              = (uint16_t)m_mode & CODECHAL_ENCODE_MODE_BIT_MASK;
    perfTag.CallType          = m_singleTaskPhaseSupported ? CODECHAL_ENCODE_PERFTAG_CALL_SCALING_KERNEL : CODECHAL_ENCODE_PERFTAG_CALL_ME_KERNEL;
    perfTag.PictureCodingType = m_pictureCodingType;
    m_osInterface->pfnSetPerfTag(m_osInterface, perfTag.Value);
    // Each ME kernel buffer counts as a separate perf task
    m_osInterface->pfnResetPerfBufferID(m_osInterface);

    CODECHAL_MEDIA_STATE_TYPE encFunctionType = (hmeLevel == HME_LEVEL_32x) ? CODECHAL_MEDIA_STATE_32X_ME : (hmeLevel == HME_LEVEL_16x) ? CODECHAL_MEDIA_STATE_16X_ME : CODECHAL_MEDIA_STATE_4X_ME;

    bool vdencMeInUse = false;
    if (m_vdencEnabled && (encFunctionType == CODECHAL_MEDIA_STATE_4X_ME))
    {
        vdencMeInUse    = true;
        encFunctionType = CODECHAL_MEDIA_STATE_ME_VDENC_STREAMIN;
    }

    uint32_t krnStateIdx = vdencMeInUse ? CODECHAL_ENCODE_ME_IDX_VDENC : ((m_pictureCodingType == P_TYPE) ? CODECHAL_ENCODE_ME_IDX_P : CODECHAL_ENCODE_ME_IDX_B);
    auto     kernelState = &m_meKernelStates[krnStateIdx];

    // If Single Task Phase is not enabled, use BT count for the kernel state.
    if (m_firstTaskInPhase || !m_singleTaskPhaseSupported)
    {
        uint32_t maxBtCount = m_singleTaskPhaseSupported ? m_maxBtCount : kernelState->KernelParams.iBTCount;
        CODECHAL_ENCODE_CHK_STATUS_RETURN(m_stateHeapInterface->pfnRequestSshSpaceForCmdBuf(
            m_stateHeapInterface,
            maxBtCount));
        m_vmeStatesSize = m_hwInterface->GetKernelLoadCommandSize(maxBtCount);
        CODECHAL_ENCODE_CHK_STATUS_RETURN(VerifySpaceAvailable());
    }

    CODECHAL_ENCODE_CHK_STATUS_RETURN(m_hwInterface->AssignDshAndSshSpace(
        m_stateHeapInterface,
        kernelState,
        false,
        0,
        false,
        m_storeData));

    MHW_INTERFACE_DESCRIPTOR_PARAMS idParams;
    MOS_ZeroMemory(&idParams, sizeof(idParams));
    idParams.pKernelState = kernelState;
    CODECHAL_ENCODE_CHK_STATUS_RETURN(m_stateHeapInterface->pfnSetInterfaceDescriptor(
        m_stateHeapInterface,
        1,
        &idParams));

    // Setup AVC Curbe
    MeCurbeParams meParams;
    MOS_ZeroMemory(&meParams, sizeof(meParams));
    meParams.hmeLvl       = hmeLevel;
    meParams.pKernelState = kernelState;

    if (!m_useCommonKernel)
    {
        CODECHAL_ENCODE_CHK_STATUS_RETURN(SetCurbeMe(&meParams));
    }

    CODECHAL_DEBUG_TOOL(
        CODECHAL_ENCODE_CHK_STATUS_RETURN(m_debugInterface->DumpKernelRegion(
            encFunctionType,
            MHW_DSH_TYPE,
            kernelState));
        CODECHAL_ENCODE_CHK_STATUS_RETURN(m_debugInterface->DumpCurbe(
            encFunctionType,
            kernelState));
        CODECHAL_ENCODE_CHK_STATUS_RETURN(m_debugInterface->DumpKernelRegion(
            encFunctionType,
            MHW_ISH_TYPE,
            kernelState));)

    MOS_COMMAND_BUFFER cmdBuffer;
    CODECHAL_ENCODE_CHK_STATUS_RETURN(m_osInterface->pfnGetCommandBuffer(m_osInterface, &cmdBuffer, 0));

    SendKernelCmdsParams sendKernelCmdsParams = SendKernelCmdsParams();
    sendKernelCmdsParams.EncFunctionType      = encFunctionType;
    sendKernelCmdsParams.pKernelState         = kernelState;

    CODECHAL_ENCODE_CHK_STATUS_RETURN(SendGenericKernelCmds(&cmdBuffer, &sendKernelCmdsParams));

    // Add binding table
    CODECHAL_ENCODE_CHK_STATUS_RETURN(m_stateHeapInterface->pfnSetBindingTable(
        m_stateHeapInterface,
        kernelState));

    //Add surface states
    MeSurfaceParams meSurfaceParams;
    MOS_ZeroMemory(&meSurfaceParams, sizeof(meSurfaceParams));
    meSurfaceParams.dwNumRefIdxL0ActiveMinus1       = m_avcSliceParams->num_ref_idx_l0_active_minus1;
    meSurfaceParams.dwNumRefIdxL1ActiveMinus1       = m_avcSliceParams->num_ref_idx_l1_active_minus1;
    meSurfaceParams.pL0RefFrameList                 = &(m_avcSliceParams->RefPicList[LIST_0][0]);
    meSurfaceParams.pL1RefFrameList                 = &(m_avcSliceParams->RefPicList[LIST_1][0]);
    meSurfaceParams.ppRefList                       = &m_refList[0];
    meSurfaceParams.pPicIdx                         = &m_picIdx[0];
    meSurfaceParams.pCurrOriginalPic                = &m_currOriginalPic;
    meSurfaceParams.ps4xMeMvDataBuffer              = &m_4xMeMvDataBuffer;
    meSurfaceParams.dw4xMeMvBottomFieldOffset       = (uint32_t)m_meMvBottomFieldOffset;
    meSurfaceParams.ps16xMeMvDataBuffer             = &m_16xMeMvDataBuffer;
    meSurfaceParams.dw16xMeMvBottomFieldOffset      = (uint32_t)m_meMv16xBottomFieldOffset;
    meSurfaceParams.ps32xMeMvDataBuffer             = &m_32xMeMvDataBuffer;
    meSurfaceParams.dw32xMeMvBottomFieldOffset      = (uint32_t)m_meMv32xBottomFieldOffset;
    meSurfaceParams.dw4xScaledBottomFieldOffset     = (uint32_t)m_scaledBottomFieldOffset;
    meSurfaceParams.dw16xScaledBottomFieldOffset    = (uint32_t)m_scaled16xBottomFieldOffset;
    meSurfaceParams.dw32xScaledBottomFieldOffset    = (uint32_t)m_scaled32xBottomFieldOffset;
    meSurfaceParams.psMeDistortionBuffer            = &m_4xMeDistortionBuffer;
    meSurfaceParams.dwMeDistortionBottomFieldOffset = (uint32_t)m_meDistortionBottomFieldOffset;
    if (nullptr != brcBuffers)
    {
        meSurfaceParams.psMeBrcDistortionBuffer            = &brcBuffers->sMeBrcDistortionBuffer;
        meSurfaceParams.dwMeBrcDistortionBottomFieldOffset = brcBuffers->dwMeBrcDistortionBottomFieldOffset;
    }
    meSurfaceParams.psMeVdencStreamInBuffer    = &m_resVdencStreamInBuffer[m_currRecycledBufIdx];
    meSurfaceParams.dwDownscaledWidthInMb      = (hmeLevel == HME_LEVEL_32x) ? m_downscaledWidthInMb32x : (hmeLevel == HME_LEVEL_16x) ? m_downscaledWidthInMb16x : m_downscaledWidthInMb4x;
    meSurfaceParams.dwDownscaledHeightInMb     = (hmeLevel == HME_LEVEL_32x) ? m_downscaledFrameFieldHeightInMb32x : (hmeLevel == HME_LEVEL_16x) ? m_downscaledFrameFieldHeightInMb16x : m_downscaledFrameFieldHeightInMb4x;
    meSurfaceParams.dwVerticalLineStride       = m_verticalLineStride;
    meSurfaceParams.dwVerticalLineStrideOffset = m_verticalLineStrideOffset;
    meSurfaceParams.b32xMeInUse                = (hmeLevel == HME_LEVEL_32x) ? true : false;
    meSurfaceParams.b16xMeInUse                = (hmeLevel == HME_LEVEL_16x) ? true : false;
    meSurfaceParams.b32xMeEnabled              = m_32xMeEnabled;
    meSurfaceParams.b16xMeEnabled              = m_16xMeEnabled;
    meSurfaceParams.bVdencStreamInEnabled      = m_vdencEnabled && (m_16xMeSupported || m_staticFrameDetectionInUse);
    meSurfaceParams.pMeBindingTable            = &m_meBindingTable;
    meSurfaceParams.pKernelState               = kernelState;
    meSurfaceParams.dwVDEncStreamInSurfaceSize = MOS_BYTES_TO_DWORDS(m_picHeightInMb * m_picWidthInMb * 64);

    if (!m_useCommonKernel)
    {
        CODECHAL_ENCODE_CHK_STATUS_RETURN(SendMeSurfaces(&cmdBuffer, &meSurfaceParams));
    }

    // Dump SSH for ME kernel
    CODECHAL_DEBUG_TOOL(
        CODECHAL_ENCODE_CHK_STATUS_RETURN(m_debugInterface->DumpKernelRegion(
            encFunctionType,
            MHW_SSH_TYPE,
            kernelState)));

    /* zero out the mv data memory and me distortion buffer for the driver ULT
    kernel only writes out this data used for current frame, in some cases the the data used for
    previous frames would be left in the buffer (for example, the L1 mv for B frame would still show
    in the P frame mv data buffer */

    /* Zeroing out the buffers has perf impact, so zero it out only when dumps are actually enabled */

    CODECHAL_DEBUG_TOOL(
        CODECHAL_ENCODE_CHK_NULL_RETURN(m_debugInterface);
        uint8_t * data;
        uint32_t size;
        bool     driverMeDumpEnabled;

        driverMeDumpEnabled = m_debugInterface->DumpIsEnabled(CodechalDbgKernel::kernel4xMe) ||
                              m_debugInterface->DumpIsEnabled(CodechalDbgKernel::kernel16xMe) ||
                              m_debugInterface->DumpIsEnabled(CodechalDbgKernel::kernel32xMe);

        if (driverMeDumpEnabled) {
            MOS_LOCK_PARAMS lockFlags;
            MOS_ZeroMemory(&lockFlags, sizeof(MOS_LOCK_PARAMS));
            lockFlags.WriteOnly = 1;

            switch (hmeLevel)
            {
            case HME_LEVEL_32x:
                data = (uint8_t *)m_osInterface->pfnLockResource(
                    m_osInterface,
                    &m_32xMeMvDataBuffer.OsResource,
                    &lockFlags);
                CODECHAL_ENCODE_CHK_NULL_RETURN(data);
                size = MOS_ALIGN_CEIL((m_downscaledWidthInMb32x * 32), 64) *
                       (m_downscaledHeightInMb32x * 2 * 4 * CODECHAL_ENCODE_ME_DATA_SIZE_MULTIPLIER);
                MOS_ZeroMemory(data, size);
                m_osInterface->pfnUnlockResource(
                    m_osInterface,
                    &m_32xMeMvDataBuffer.OsResource);
                break;
            case HME_LEVEL_16x:
                data = (uint8_t *)m_osInterface->pfnLockResource(
                    m_osInterface,
                    &m_16xMeMvDataBuffer.OsResource,
                    &lockFlags);
                CODECHAL_ENCODE_CHK_NULL_RETURN(data);
                size = MOS_ALIGN_CEIL((m_downscaledWidthInMb16x * 32), 64) *
                       (m_downscaledHeightInMb16x * 2 * 4 * CODECHAL_ENCODE_ME_DATA_SIZE_MULTIPLIER);
                MOS_ZeroMemory(data, size);
                m_osInterface->pfnUnlockResource(
                    m_osInterface,
                    &m_16xMeMvDataBuffer.OsResource);
                break;
            case HME_LEVEL_4x:
                if (!m_vdencEnabled)
                {
                    data = (uint8_t *)m_osInterface->pfnLockResource(
                        m_osInterface,
                        &m_4xMeMvDataBuffer.OsResource,
                        &lockFlags);
                    CODECHAL_ENCODE_CHK_NULL_RETURN(data);
                    size = MOS_ALIGN_CEIL((m_downscaledWidthInMb4x * 32), 64) *
                           (m_downscaledHeightInMb4x * 2 * 4 * CODECHAL_ENCODE_ME_DATA_SIZE_MULTIPLIER);
                    MOS_ZeroMemory(data, size);
                    m_osInterface->pfnUnlockResource(
                        m_osInterface,
                        &m_4xMeMvDataBuffer.OsResource);
                }
                break;
            default:
                return MOS_STATUS_INVALID_PARAMETER;
            }

            // zeroing out ME dist buffer
            if (m_4xMeDistortionBufferSupported)
            {
                data = (uint8_t *)m_osInterface->pfnLockResource(
                    m_osInterface, &m_4xMeDistortionBuffer.OsResource, &lockFlags);
                CODECHAL_ENCODE_CHK_NULL_RETURN(data);
                size = m_4xMeDistortionBuffer.dwHeight * m_4xMeDistortionBuffer.dwPitch;
                MOS_ZeroMemory(data, size);
                m_osInterface->pfnUnlockResource(
                    m_osInterface,
                    &m_4xMeDistortionBuffer.OsResource);
            }
        });

    uint32_t scalingFactor = (hmeLevel == HME_LEVEL_32x) ? SCALE_FACTOR_32x : (hmeLevel == HME_LEVEL_16x) ? SCALE_FACTOR_16x : SCALE_FACTOR_4x;

    uint32_t resolutionX = CODECHAL_GET_WIDTH_IN_MACROBLOCKS(m_frameWidth / scalingFactor);
    uint32_t resolutionY = CODECHAL_GET_HEIGHT_IN_MACROBLOCKS(m_frameFieldHeight / scalingFactor);

    CODECHAL_WALKER_CODEC_PARAMS walkerCodecParams;
    MOS_ZeroMemory(&walkerCodecParams, sizeof(walkerCodecParams));
    walkerCodecParams.WalkerMode              = m_walkerMode;
    walkerCodecParams.dwResolutionX           = resolutionX;
    walkerCodecParams.dwResolutionY           = resolutionY;
    walkerCodecParams.bNoDependency           = true;
    walkerCodecParams.bMbaff                  = m_mbaffEnabled;
    walkerCodecParams.bGroupIdSelectSupported = m_groupIdSelectSupported;
    walkerCodecParams.ucGroupId               = m_groupId;

    MHW_WALKER_PARAMS walkerParams;
    CODECHAL_ENCODE_CHK_STATUS_RETURN(CodecHalInitMediaObjectWalkerParams(
        m_hwInterface,
        &walkerParams,
        &walkerCodecParams));

    HalOcaInterface::TraceMessage(cmdBuffer, (MOS_CONTEXT_HANDLE)m_osInterface->pOsContext, __FUNCTION__, sizeof(__FUNCTION__));
    HalOcaInterface::OnDispatch(cmdBuffer, *m_osInterface, *m_miInterface, *m_renderEngineInterface->GetMmioRegisters());

    CODECHAL_ENCODE_CHK_STATUS_RETURN(m_renderEngineInterface->AddMediaObjectWalkerCmd(
        &cmdBuffer,
        &walkerParams));

    CODECHAL_ENCODE_CHK_STATUS_RETURN(EndStatusReport(&cmdBuffer, encFunctionType));

    CODECHAL_ENCODE_CHK_STATUS_RETURN(m_stateHeapInterface->pfnSubmitBlocks(
        m_stateHeapInterface,
        kernelState));
    if (!m_singleTaskPhaseSupported || m_lastTaskInPhase)
    {
        CODECHAL_ENCODE_CHK_STATUS_RETURN(m_stateHeapInterface->pfnUpdateGlobalCmdBufId(
            m_stateHeapInterface));
        CODECHAL_ENCODE_CHK_STATUS_RETURN(m_miInterface->AddMiBatchBufferEnd(&cmdBuffer, nullptr));
    }

    CODECHAL_DEBUG_TOOL(CODECHAL_ENCODE_CHK_STATUS_RETURN(m_debugInterface->DumpCmdBuffer(
        &cmdBuffer,
        encFunctionType,
        nullptr)));

    m_hwInterface->UpdateSSEuForCmdBuffer(&cmdBuffer, m_singleTaskPhaseSupported, m_lastTaskInPhase);

    m_osInterface->pfnReturnCommandBuffer(m_osInterface, &cmdBuffer, 0);

    if (!m_singleTaskPhaseSupported || m_lastTaskInPhase)
    {
        HalOcaInterface::On1stLevelBBEnd(cmdBuffer, *m_osInterface);
        m_osInterface->pfnSubmitCommandBuffer(m_osInterface, &cmdBuffer, m_renderContextUsesNullHw);
        m_lastTaskInPhase = false;
    }

    return eStatus;
}

MOS_STATUS CodechalEncodeAvcBase::SetSliceStructs()
{
    MOS_STATUS eStatus = MOS_STATUS_SUCCESS;
    CODECHAL_ENCODE_FUNCTION_ENTER;

    auto slcParams = m_avcSliceParams;
    auto seqParams = m_avcSeqParam;
    auto picParams = m_avcPicParam;

    // Save the QP value
    if (CodecHal_PictureIsBottomField(picParams->CurrOriginalPic))
    {
        m_refList[m_currReconstructedPic.FrameIdx]->ucQPValue[1] =
            picParams->pic_init_qp_minus26 + 26 + slcParams->slice_qp_delta;
    }
    else
    {
        m_refList[m_currReconstructedPic.FrameIdx]->ucQPValue[0] =
            picParams->pic_init_qp_minus26 + 26 + slcParams->slice_qp_delta;
    }

    uint32_t numMbsInPrevSlice = slcParams->NumMbsForSlice;  // Initiailize to num mbs in first slice
    uint32_t numMbsForFirstSlice;
    uint32_t numMbs = 0;

    for (uint32_t sliceCount = 0; sliceCount < m_numSlices; sliceCount++)
    {
        if (m_sliceStructCaps != CODECHAL_SLICE_STRUCT_ARBITRARYMBSLICE)
        {
            if (sliceCount == 0)
            {
                numMbsForFirstSlice = slcParams->NumMbsForSlice;
                // In current kernel, the same MB number in the slice must be number of MB rows.
                if (numMbsForFirstSlice % m_picWidthInMb)
                {
                    eStatus = MOS_STATUS_INVALID_PARAMETER;
                    return eStatus;
                }
                m_sliceHeight = numMbsForFirstSlice / m_picWidthInMb;
                // Slice height should be in power of 2
                if (m_sliceStructCaps == CODECHAL_SLICE_STRUCT_POW2ROWS && (m_sliceHeight & (m_sliceHeight - 1)))
                {
                    // app can only pass orig numMBs in picture for single slice, set slice height to the nearest pow2
                    if (m_numSlices == 1)
                    {
                        uint16_t sliceHeightPow2 = 1;
                        while (sliceHeightPow2 < m_sliceHeight)
                        {
                            sliceHeightPow2 <<= 1;
                        }
                        m_sliceHeight = sliceHeightPow2;
                    }
                    else
                    {
                        eStatus = MOS_STATUS_INVALID_PARAMETER;
                        return eStatus;
                    }
                }
            }
            // VME: In current kernel, all slices should have the same MBs except the last one, the last one should have no more MBs than the previous
            else if (!m_vdencEnabled || (m_vdencEnabled && m_sliceStructCaps == CODECHAL_SLICE_STRUCT_ROWSLICE))
            {
                if ((sliceCount < m_numSlices - 1 && numMbsForFirstSlice != slcParams->NumMbsForSlice) ||
                    (sliceCount == m_numSlices - 1 && numMbsForFirstSlice < slcParams->NumMbsForSlice))
                {
                    eStatus = MOS_STATUS_INVALID_PARAMETER;
                    return eStatus;
                }
            }

            // Gaps between slices are not allowed
            if (slcParams->first_mb_in_slice != numMbs)
            {
                eStatus = MOS_STATUS_INVALID_PARAMETER;
                return eStatus;
            }
            numMbs += slcParams->NumMbsForSlice;
        }
        else  // SLICE_STRUCT_ARBITRARYMBSLICE
        {
            uint8_t ppsIdx          = m_avcSliceParams->pic_parameter_set_id;
            uint8_t refPicListIdx   = m_avcSliceParams[ppsIdx].RefPicList[0][0].FrameIdx;
            uint8_t refFrameListIdx = m_avcPicParam[ppsIdx].RefFrameList[refPicListIdx].FrameIdx;

            bool dirtyRoiEnabled = (m_pictureCodingType == P_TYPE && m_avcPicParams[ppsIdx]->NumDirtyROI > 0 && m_prevReconFrameIdx == refFrameListIdx);

            if (m_mfeEnabled && m_numSlices > 1)
            {
                m_arbitraryNumMbsInSlice = 1;
                if (sliceCount == 0)
                {
                    m_sliceHeight = slcParams->NumMbsForSlice / m_picWidthInMb;
                }
            }
            else if ((slcParams->NumMbsForSlice % m_picWidthInMb) ||                                          // If slice is partial MB row,
                     ((sliceCount < m_numSlices - 1) && (numMbsInPrevSlice != slcParams->NumMbsForSlice)) ||  // OR not the last slice and num mbs is not same as prev slice
                     ((sliceCount == m_numSlices - 1) && ((numMbsInPrevSlice < slcParams->NumMbsForSlice) ||  // OR it is the last slice and num mbs is not less than prev slice
                                                             (MEDIA_IS_WA(m_waTable, WaArbitraryNumMbsInSlice) && (m_numSlices > 16) &&
                                                                 (!m_vdencEnabled) && (!dirtyRoiEnabled)))))
            {
                m_arbitraryNumMbsInSlice = 1;  // then set flag to use sliceMapSurface
                m_sliceHeight            = 1;  // Slice height doesn't matter if using slicemap just set to any non-zero value.
            }
            else if ((m_numSlices == 1) || (sliceCount == 0))
            {
                m_sliceHeight            = slcParams->NumMbsForSlice / m_picWidthInMb;
                m_arbitraryNumMbsInSlice = 0;
            }
            numMbsInPrevSlice = slcParams->NumMbsForSlice;
        }

        if ((picParams->pic_init_qp_minus26 + 26 + slcParams->slice_qp_delta) > CODECHAL_ENCODE_AVC_MAX_SLICE_QP)
        {
            slcParams->slice_qp_delta = CODECHAL_ENCODE_AVC_MAX_SLICE_QP - (picParams->pic_init_qp_minus26 + 26);
        }
        slcParams->redundant_pic_cnt                  = 0;
        slcParams->sp_for_switch_flag                 = 0;
        slcParams->slice_qs_delta                     = 0;
        slcParams->redundant_pic_cnt                  = 0;

        slcParams->MaxFrameNum =
            1 << (seqParams[picParams->seq_parameter_set_id].log2_max_frame_num_minus4 + 4);
        slcParams->frame_num      = m_frameNum;
        slcParams->field_pic_flag = picParams->FieldCodingFlag;
        slcParams->bottom_field_flag =
            (CodecHal_PictureIsBottomField(picParams->CurrOriginalPic)) ? 1 : 0;

        if (m_pictureCodingType != I_TYPE)
        {
            for (uint8_t i = 0; i < (slcParams->num_ref_idx_l0_active_minus1 + 1); i++)
            {
                slcParams->PicOrder[0][i].Picture.FrameIdx =
                    m_picIdx[slcParams->RefPicList[0][i].FrameIdx].ucPicIdx;
                slcParams->PicOrder[0][i].Picture.PicFlags =
                    slcParams->RefPicList[0][i].PicFlags;
            }
        }
        if (m_pictureCodingType == B_TYPE)
        {
            for (uint8_t i = 0; i < (slcParams->num_ref_idx_l1_active_minus1 + 1); i++)
            {
                slcParams->PicOrder[1][i].Picture.FrameIdx =
                    m_picIdx[slcParams->RefPicList[1][i].FrameIdx].ucPicIdx;
                slcParams->PicOrder[1][i].Picture.PicFlags =
                    slcParams->RefPicList[1][i].PicFlags;
            }
        }
        slcParams++;
    }

    if (eStatus == MOS_STATUS_INVALID_PARAMETER)
    {
        CODECHAL_ENCODE_ASSERTMESSAGE("Invalid slice parameters.");
    }
    return eStatus;
}

void CodechalEncodeAvcBase::SetMfxPipeModeSelectParams(
    const CODECHAL_ENCODE_AVC_GENERIC_PICTURE_LEVEL_PARAMS &genericParam,
    MHW_VDBOX_PIPE_MODE_SELECT_PARAMS &                     param)
{
    // set MFX_PIPE_MODE_SELECT values
    param                           = {};
    param.Mode                      = m_mode;
    param.bStreamOutEnabled         = (m_currPass != m_numPasses);  // Disable Stream Out for final pass; its important for multiple passes, because , next pass will take the qp from stream out
    param.bVdencEnabled             = m_vdencEnabled;
    param.bDeblockerStreamOutEnable = genericParam.bDeblockerStreamOutEnable;
    param.bStreamOutEnabledExtEnabled = genericParam.bPerMBStreamOutEnable;
    param.bPostDeblockOutEnable     = genericParam.bPostDeblockOutEnable;
    param.bPreDeblockOutEnable      = genericParam.bPreDeblockOutEnable;
    param.bDynamicSliceEnable       = m_avcSeqParam->EnableSliceLevelRateCtrl;
    param.bVdencStreamInEnable      = m_vdencStreamInEnabled;
    param.bTlbPrefetchEnable        = m_tlbPrefetchEnable;
    param.ChromaType                = m_avcSeqParam->chroma_format_idc;
    param.Format                    = m_rawSurfaceToPak->Format;
}

MOS_STATUS CodechalEncodeAvcBase::SetMfxPipeBufAddrStateParams(
    CODECHAL_ENCODE_AVC_GENERIC_PICTURE_LEVEL_PARAMS genericParam,
    MHW_VDBOX_PIPE_BUF_ADDR_PARAMS &                 param)
{
    MOS_STATUS eStatus = MOS_STATUS_SUCCESS;

    param.Mode                 = m_mode;
    param.psPreDeblockSurface  = genericParam.psPreDeblockSurface;
    param.psPostDeblockSurface = genericParam.psPostDeblockSurface;

    param.psRawSurface                                 = m_rawSurfaceToPak;
    param.presStreamOutBuffer                          = &m_resStreamOutBuffer[m_currRecycledBufIdx];
    param.presMfdDeblockingFilterRowStoreScratchBuffer = &m_resDeblockingFilterRowStoreScratchBuffer;
    param.presMfdIntraRowStoreScratchBuffer            = &m_intraRowStoreScratchBuffer;
    param.bVdencEnabled                                = m_vdencEnabled;
    param.presMacroblockIldbStreamOutBuffer1           = genericParam.presMacroblockIldbStreamOutBuffer1;
    param.presMacroblockIldbStreamOutBuffer2           = genericParam.presMacroblockIldbStreamOutBuffer2;

    CODECHAL_DEBUG_TOOL(
        // PAK Input Raw Surface
        CODECHAL_ENCODE_CHK_STATUS_RETURN(m_debugInterface->DumpYUVSurface(
            m_rawSurfaceToPak,
            CodechalDbgAttr::attrEncodeRawInputSurface,
            "PAK_Input_SrcSurf")););

    auto firstValidFrame = &m_reconSurface.OsResource;

    // Setting invalid entries to nullptr
    for (uint8_t i = 0; i < CODEC_AVC_MAX_NUM_REF_FRAME; i++)
        param.presReferences[i] = nullptr;

    uint8_t firstValidFrameId = CODEC_AVC_MAX_NUM_REF_FRAME;
    uint8_t numrefL0          = m_avcSliceParams->num_ref_idx_l0_active_minus1 + 1;
    uint8_t numrefL1          = m_avcSliceParams->num_ref_idx_l1_active_minus1 + 1;

    for (uint8_t i = 0; i < CODEC_AVC_MAX_NUM_REF_FRAME; i++)
    {
        if (m_picIdx[i].bValid)
        {
            auto picIdx       = m_picIdx[i].ucPicIdx;
            auto frameStoreId = m_refList[picIdx]->ucFrameId;

            CodecHalGetResourceInfo(m_osInterface, &(m_refList[picIdx]->sRefReconBuffer));
            param.presReferences[frameStoreId] = &(m_refList[picIdx]->sRefReconBuffer.OsResource);

            if (picIdx < firstValidFrameId)
            {
                firstValidFrameId = picIdx;
                firstValidFrame   = param.presReferences[picIdx];
            }

        }
    }
CODECHAL_DEBUG_TOOL(
        MOS_SURFACE refSurface;
    for (uint8_t i = 0; i < numrefL0; i++)
    {
        if (m_pictureCodingType != I_TYPE && m_avcSliceParams->RefPicList[0][i].PicFlags != PICTURE_INVALID)
        {
            auto refPic         = m_avcSliceParams->RefPicList[0][i];
            auto picIdx         = m_picIdx[refPic.FrameIdx].ucPicIdx;
            auto frameStoreId   = m_refList[picIdx]->ucFrameId;
                CODECHAL_ENCODE_CHK_NULL_RETURN(m_debugInterface);

                MOS_ZeroMemory(&refSurface, sizeof(refSurface));
                refSurface.Format     = Format_NV12;
                refSurface.OsResource = *(param.presReferences[frameStoreId]);
                CODECHAL_ENCODE_CHK_STATUS_RETURN(CodecHalGetResourceInfo(
                    m_osInterface,
                    &refSurface));
                m_debugInterface->m_refIndex = frameStoreId;
                std::string refSurfName      = "RefSurfL0[" + std::to_string(static_cast<uint32_t>(i)) + "]";
                CODECHAL_ENCODE_CHK_STATUS_RETURN(m_debugInterface->DumpYUVSurface(
                    &refSurface,
                    CodechalDbgAttr::attrReferenceSurfaces,
                    refSurfName.c_str()));
        }
    }
    for (uint8_t i = 0; i < numrefL1; i++)
    {
        if (m_pictureCodingType == B_TYPE && m_avcSliceParams->RefPicList[1][i].PicFlags != PICTURE_INVALID)
        {
            auto refPic       = m_avcSliceParams->RefPicList[1][i];
            auto picIdx       = m_picIdx[refPic.FrameIdx].ucPicIdx;
            auto frameStoreId = m_refList[picIdx]->ucFrameId;
                CODECHAL_ENCODE_CHK_NULL_RETURN(m_debugInterface);
                //MOS_SURFACE refSurface;
                MOS_ZeroMemory(&refSurface, sizeof(refSurface));
                refSurface.Format     = Format_NV12;
                refSurface.OsResource = *(param.presReferences[frameStoreId]);
                CODECHAL_ENCODE_CHK_STATUS_RETURN(CodecHalGetResourceInfo(
                    m_osInterface,
                    &refSurface));
                m_debugInterface->m_refIndex = frameStoreId;
                std::string refSurfName      = "RefSurfL1[" + std::to_string(static_cast<uint32_t>(i)) + "]";
                CODECHAL_ENCODE_CHK_STATUS_RETURN(m_debugInterface->DumpYUVSurface(
                    &refSurface,
                    CodechalDbgAttr::attrReferenceSurfaces,
                    refSurfName.c_str()));
        }
    }

);

    for (uint8_t i = 0; i < CODEC_AVC_MAX_NUM_REF_FRAME; i++)
    {
        // error concealment for the unset reference addresses
        if (!param.presReferences[i])
        {
            param.presReferences[i] = firstValidFrame;
        }
    }

    if (m_sliceSizeStreamoutSupported)
    {
        param.presSliceSizeStreamOutBuffer = &m_pakSliceSizeStreamoutBuffer;
    }
    return eStatus;
}

void CodechalEncodeAvcBase::SetMfxIndObjBaseAddrStateParams(MHW_VDBOX_IND_OBJ_BASE_ADDR_PARAMS &param)
{
    MOS_ZeroMemory(&param, sizeof(param));
    param.Mode                    = CODECHAL_ENCODE_MODE_AVC;
    param.presPakBaseObjectBuffer = &m_resBitstreamBuffer;
    param.dwPakBaseObjectSize     = m_bitstreamUpperBound;
}

void CodechalEncodeAvcBase::SetMfxBspBufBaseAddrStateParams(MHW_VDBOX_BSP_BUF_BASE_ADDR_PARAMS &param)
{
    MOS_ZeroMemory(&param, sizeof(param));
    param.presBsdMpcRowStoreScratchBuffer = &m_resMPCRowStoreScratchBuffer;
}

void CodechalEncodeAvcBase::SetMfxQmStateParams(MHW_VDBOX_QM_PARAMS &qmParams, MHW_VDBOX_QM_PARAMS &fqmParams)
{
    MOS_ZeroMemory(&qmParams, sizeof(qmParams));
    MOS_ZeroMemory(&fqmParams, sizeof(fqmParams));

    qmParams.Standard     = CODECHAL_AVC;
    qmParams.pAvcIqMatrix = (PMHW_VDBOX_AVC_QM_PARAMS)m_avcIQWeightScaleLists;

    fqmParams.Standard     = CODECHAL_AVC;
    fqmParams.pAvcIqMatrix = (PMHW_VDBOX_AVC_QM_PARAMS)m_avcIQWeightScaleLists;
}

void CodechalEncodeAvcBase::SetMfxAvcImgStateParams(MHW_VDBOX_AVC_IMG_PARAMS &param)
{
    param                            = {};
    param.currPass                   = m_currPass;
    param.pEncodeAvcPicParams        = m_avcPicParam;
    param.pEncodeAvcSeqParams        = m_avcSeqParam;
    param.pEncodeAvcSliceParams      = m_avcSliceParams;
    param.wPicWidthInMb              = m_picWidthInMb;
    param.wPicHeightInMb             = m_picHeightInMb;
    param.ppRefList                  = &(m_refList[0]);
    param.pPicIdx                    = &(m_picIdx[0]);
    param.dwTqEnabled                = m_trellisQuantParams.dwTqEnabled;
    param.dwTqRounding               = m_trellisQuantParams.dwTqRounding;
    param.ucKernelMode               = m_kernelMode;
    param.wSlcHeightInMb             = m_sliceHeight;
    param.dwMaxVmvR                  = CodecHalAvcEncode_GetMaxVmvR(m_avcSeqParam->Level);
    param.bVdencStreamInEnabled      = m_vdencStreamInEnabled;
    param.bSliceSizeStreamOutEnabled = m_sliceSizeStreamoutSupported;
    param.bCrePrefetchEnable         = m_crePrefetchEnable;

    if (m_currPass && (m_currPass == m_numPasses) && (!m_vdencBrcEnabled))
    {
        // Enable IPCM pass, excluding VDENC BRC case
        param.bIPCMPass = true;
    }
}

void CodechalEncodeAvcBase::UpdateSSDSliceCount()
{
    m_setRequestedEUSlices = ((m_frameHeight * m_frameWidth) >= m_ssdResolutionThreshold &&
                                 m_targetUsage <= m_ssdTargetUsageThreshold)
                                 ? true
                                 : false;

    m_hwInterface->m_numRequestedEuSlices = (m_setRequestedEUSlices) ? m_sliceShutdownRequestState : m_sliceShutdownDefaultState;
}

MOS_STATUS CodechalEncodeAvcBase::AddIshSize(uint32_t kuid, uint8_t *kernelBase)
{
    uint8_t *kernelBinary;
    uint32_t kernelSize;

    MOS_STATUS status = CodecHalGetKernelBinaryAndSize(kernelBase, kuid, &kernelBinary, &kernelSize);
    CODECHAL_ENCODE_CHK_STATUS_RETURN(status);
    m_hwInterface->GetStateHeapSettings()->dwIshSize += MOS_ALIGN_CEIL(kernelSize, (1 << MHW_KERNEL_OFFSET_SHIFT));
    return status;
}

MOS_STATUS CodechalEncodeAvcBase::StoreNumPasses(
    EncodeStatusBuffer *encodeStatusBuf,
    MhwMiInterface *    miInterface,
    PMOS_COMMAND_BUFFER cmdBuffer,
    uint32_t            currPass)
{
    MHW_MI_STORE_DATA_PARAMS storeDataParams;
    uint32_t                 offset;
    MOS_STATUS               eStatus = MOS_STATUS_SUCCESS;

    CODECHAL_ENCODE_FUNCTION_ENTER;

    CODECHAL_ENCODE_CHK_NULL_RETURN(encodeStatusBuf);
    CODECHAL_ENCODE_CHK_NULL_RETURN(miInterface);
    CODECHAL_ENCODE_CHK_NULL_RETURN(cmdBuffer);

    offset =
        (encodeStatusBuf->wCurrIndex * encodeStatusBuf->dwReportSize) +
        encodeStatusBuf->dwNumPassesOffset +  // Num passes offset
        sizeof(uint32_t) * 2;                 // pEncodeStatus is offset by 2 DWs in the resource

    storeDataParams.pOsResource      = &encodeStatusBuf->resStatusBuffer;
    storeDataParams.dwResourceOffset = offset;
    storeDataParams.dwValue          = currPass + 1;
    CODECHAL_ENCODE_CHK_STATUS_RETURN(miInterface->AddMiStoreDataImmCmd(cmdBuffer, &storeDataParams));

    return MOS_STATUS_SUCCESS;
}

void CodechalEncodeAvcBase::fill_pad_with_value(PMOS_SURFACE psSurface, uint32_t real_height, uint32_t aligned_height)
{
    CODECHAL_ENCODE_CHK_NULL_NO_STATUS_RETURN(psSurface);

    // unaligned surfaces only
    if (aligned_height <= real_height || aligned_height > psSurface->dwHeight)
    {
        return;
    }

    if (psSurface->OsResource.TileType == MOS_TILE_INVALID)
    {
        return;
    }

    if (psSurface->Format == Format_NV12 || psSurface->Format == Format_P010)
    {
        uint32_t pitch         = psSurface->dwPitch;
        uint32_t UVPlaneOffset = psSurface->UPlaneOffset.iSurfaceOffset;
        uint32_t YPlaneOffset  = psSurface->dwOffset;
        uint32_t pad_rows      = aligned_height - real_height;
        uint32_t y_plane_size  = pitch * real_height;
        uint32_t uv_plane_size = pitch * real_height / 2;

        MOS_LOCK_PARAMS lockFlags;
        MOS_ZeroMemory(&lockFlags, sizeof(MOS_LOCK_PARAMS));
        lockFlags.WriteOnly = 1;

        // padding for the linear format buffer.
        if (psSurface->OsResource.TileType == MOS_TILE_LINEAR)
        {
            uint8_t *src_data = (uint8_t *)m_osInterface->pfnLockResource(m_osInterface, &(psSurface->OsResource), &lockFlags);
            CODECHAL_ENCODE_CHK_NULL_NO_STATUS_RETURN(src_data);

            uint8_t *src_data_y     = src_data + YPlaneOffset;
            uint8_t *src_data_y_end = src_data_y + y_plane_size;
            for (uint32_t i = 0; i < pad_rows; i++)
            {
                MOS_SecureMemcpy(src_data_y_end + i * pitch, pitch, src_data_y_end - pitch, pitch);
            }

            uint8_t *src_data_uv     = src_data + UVPlaneOffset;
            uint8_t *src_data_uv_end = src_data_uv + uv_plane_size;
            for (uint32_t i = 0; i < pad_rows / 2; i++)
            {
                MOS_SecureMemcpy(src_data_uv_end + i * pitch, pitch, src_data_uv_end - pitch, pitch);
            }

            m_osInterface->pfnUnlockResource(m_osInterface, &(psSurface->OsResource));
        }
        else
        {
            // we don't copy out the whole tiled buffer to linear and padding on the tiled buffer directly.
            lockFlags.TiledAsTiled = 1;

            uint8_t *src_data = (uint8_t *)m_osInterface->pfnLockResource(m_osInterface, &(psSurface->OsResource), &lockFlags);
            CODECHAL_ENCODE_CHK_NULL_NO_STATUS_RETURN(src_data);

            uint8_t *padding_data = (uint8_t *)MOS_AllocMemory(pitch * pad_rows);
            CODECHAL_ENCODE_CHK_NULL_NO_STATUS_RETURN(padding_data);

            // Copy last Y row data to linear padding data.
            GMM_RES_COPY_BLT gmmResCopyBlt = {0};
            gmmResCopyBlt.Gpu.pData        = src_data;
            gmmResCopyBlt.Gpu.OffsetX      = 0;
            gmmResCopyBlt.Gpu.OffsetY      = (YPlaneOffset + y_plane_size - pitch) / pitch;
            gmmResCopyBlt.Sys.pData        = padding_data;
            gmmResCopyBlt.Sys.RowPitch     = pitch;
            gmmResCopyBlt.Sys.BufferSize   = pitch * pad_rows;
            gmmResCopyBlt.Sys.SlicePitch   = pitch;
            gmmResCopyBlt.Blt.Slices       = 1;
            gmmResCopyBlt.Blt.Upload       = false;
            gmmResCopyBlt.Blt.Width        = psSurface->dwWidth;
            gmmResCopyBlt.Blt.Height       = 1;
            psSurface->OsResource.pGmmResInfo->CpuBlt(&gmmResCopyBlt);
            // Fill the remain padding lines with last Y row data.
            for (uint32_t i = 1; i < pad_rows; i++)
            {
                MOS_SecureMemcpy(padding_data + i * pitch, pitch, padding_data, pitch);
            }
            // Filling the padding for Y.
            gmmResCopyBlt.Gpu.pData      = src_data;
            gmmResCopyBlt.Gpu.OffsetX    = 0;
            gmmResCopyBlt.Gpu.OffsetY    = (YPlaneOffset + y_plane_size) / pitch;
            gmmResCopyBlt.Sys.pData      = padding_data;
            gmmResCopyBlt.Sys.RowPitch   = pitch;
            gmmResCopyBlt.Sys.BufferSize = pitch * pad_rows;
            gmmResCopyBlt.Sys.SlicePitch = pitch;
            gmmResCopyBlt.Blt.Slices     = 1;
            gmmResCopyBlt.Blt.Upload     = true;
            gmmResCopyBlt.Blt.Width      = psSurface->dwWidth;
            gmmResCopyBlt.Blt.Height     = pad_rows;
            psSurface->OsResource.pGmmResInfo->CpuBlt(&gmmResCopyBlt);

            // Copy last UV row data to linear padding data.
            gmmResCopyBlt.Gpu.pData      = src_data;
            gmmResCopyBlt.Gpu.OffsetX    = 0;
            gmmResCopyBlt.Gpu.OffsetY    = (UVPlaneOffset + uv_plane_size - pitch) / pitch;
            gmmResCopyBlt.Sys.pData      = padding_data;
            gmmResCopyBlt.Sys.RowPitch   = pitch;
            gmmResCopyBlt.Sys.BufferSize = pitch * pad_rows / 2;
            gmmResCopyBlt.Sys.SlicePitch = pitch;
            gmmResCopyBlt.Blt.Slices     = 1;
            gmmResCopyBlt.Blt.Upload     = false;
            gmmResCopyBlt.Blt.Width      = psSurface->dwWidth;
            gmmResCopyBlt.Blt.Height     = 1;
            psSurface->OsResource.pGmmResInfo->CpuBlt(&gmmResCopyBlt);
            // Fill the remain padding lines with last UV row data.
            for (uint32_t i = 1; i < pad_rows / 2; i++)
            {
                MOS_SecureMemcpy(padding_data + i * pitch, pitch, padding_data, pitch);
            }
            // Filling the padding for UV.
            gmmResCopyBlt.Gpu.pData      = src_data;
            gmmResCopyBlt.Gpu.OffsetX    = 0;
            gmmResCopyBlt.Gpu.OffsetY    = (UVPlaneOffset + uv_plane_size) / pitch;
            gmmResCopyBlt.Sys.pData      = padding_data;
            gmmResCopyBlt.Sys.RowPitch   = pitch;
            gmmResCopyBlt.Sys.BufferSize = pitch * pad_rows / 2;
            gmmResCopyBlt.Sys.SlicePitch = pitch;
            gmmResCopyBlt.Blt.Slices     = 1;
            gmmResCopyBlt.Blt.Upload     = true;
            gmmResCopyBlt.Blt.Width      = psSurface->dwWidth;
            gmmResCopyBlt.Blt.Height     = pad_rows / 2;
            psSurface->OsResource.pGmmResInfo->CpuBlt(&gmmResCopyBlt);

            MOS_FreeMemory(padding_data);
            padding_data = nullptr;
            m_osInterface->pfnUnlockResource(m_osInterface, &(psSurface->OsResource));
        }
    }
}

#if USE_CODECHAL_DEBUG_TOOL
static MOS_STATUS DumpEncodePicReorder(
    std::ostringstream &oss,
    uint32_t            x,
    uint32_t            y,
    CODEC_PIC_REORDER * picReorder)
{
    uint8_t botField;

    CODECHAL_DEBUG_CHK_NULL(picReorder);

    botField = CodecHal_PictureIsBottomField(picReorder->Picture) ? 1 : 0;

    oss << "# PicOrder[" << std::dec << +x << "][" << std::dec << +y << "] =" << std::endl;
    oss << "# \tPicNum = " << std::dec << +picReorder->PicNum << std::endl;
    oss << "# \tPOC = " << std::dec << +picReorder->POC << std::endl;
    oss << "# \tReorderPicNumIDC = " << std::dec << +picReorder->ReorderPicNumIDC << std::endl;
    oss << "# \tDiffPicNumMinus1 = " << std::dec << +picReorder->DiffPicNumMinus1 << std::endl;
    oss << "# \tFrameIdx = " << std::dec << +picReorder->Picture.FrameIdx << std::endl;
    oss << "# \tBotField = " << std::dec << +botField << std::endl;

    return MOS_STATUS_SUCCESS;
}

MOS_STATUS CodechalEncodeAvcBase::DumpSeqParams(
    PCODEC_AVC_ENCODE_SEQUENCE_PARAMS seqParams,
    PCODEC_AVC_IQ_MATRIX_PARAMS       matrixParams)
{
    CODECHAL_DEBUG_FUNCTION_ENTER;

    if (!m_debugInterface->DumpIsEnabled(CodechalDbgAttr::attrSeqParams))
    {
        return MOS_STATUS_SUCCESS;
    }

    CODECHAL_DEBUG_CHK_NULL(seqParams);

    std::ostringstream oss;
    oss.setf(std::ios::showbase | std::ios::uppercase);

    oss << "# DDI Parameters:" << std::endl;
    oss << "FrameWidth = " << +seqParams->FrameWidth << std::endl;
    oss << "FrameHeight = " << +seqParams->FrameHeight << std::endl;
    oss << "Profile = " << +seqParams->Profile << std::endl;
    oss << "Level = " << +seqParams->Level << std::endl;
    oss << "GopPicSize = " << +seqParams->GopPicSize << std::endl;
    oss << "GopRefDist = " << +seqParams->GopRefDist << std::endl;
    oss << "GopOptFlag = " << +seqParams->GopOptFlag << std::endl;
    oss << "TargetUsage = " << +seqParams->TargetUsage << std::endl;
    oss << "RateControlMethod = " << +seqParams->RateControlMethod << std::endl;
    oss << "TargetBitRate = " << +seqParams->TargetBitRate << std::endl;
    oss << "MaxBitRate = " << +seqParams->MaxBitRate << std::endl;
    oss << "MinBitRate = " << +seqParams->MinBitRate << std::endl;
    oss << "FramesPer100Sec = " << +seqParams->FramesPer100Sec << std::endl;
    oss << "InitVBVBufferFullnessInBit = " << +seqParams->InitVBVBufferFullnessInBit << std::endl;
    oss << "VBVBufferSizeInBit = " << +seqParams->VBVBufferSizeInBit << std::endl;
    oss << "NumRefFrames = " << +seqParams->NumRefFrames / 2 << std::endl;  // this prints the value passed from DDI
    oss << "# NumRefFrames (Actual Value in CodecHal is twice the value passed from DDI) = "
        << +seqParams->NumRefFrames << std::endl;  // this prints the actual value in CodecHal seq param structure
    oss << "seq_parameter_set_id = " << +seqParams->seq_parameter_set_id << std::endl;
    oss << "chroma_format_idc = " << +seqParams->chroma_format_idc << std::endl;
    oss << "bit_depth_luma_minus8 = " << +seqParams->bit_depth_luma_minus8 << std::endl;
    oss << "bit_depth_chroma_minus8 = " << +seqParams->bit_depth_chroma_minus8 << std::endl;
    oss << "log2_max_frame_num_minus4 = " << +seqParams->log2_max_frame_num_minus4 << std::endl;
    oss << "pic_order_cnt_type = " << +seqParams->pic_order_cnt_type << std::endl;
    oss << "log2_max_pic_order_cnt_lsb_minus4 = " << +seqParams->log2_max_pic_order_cnt_lsb_minus4 << std::endl;
    oss << "num_ref_frames_in_pic_order_cnt_cycle = " << +seqParams->num_ref_frames_in_pic_order_cnt_cycle << std::endl;
    oss << "offset_for_non_ref_pic = " << +seqParams->offset_for_non_ref_pic << std::endl;
    oss << "offset_for_top_to_bottom_field = " << +seqParams->offset_for_top_to_bottom_field << std::endl;

    // Conditionally printed (only when pic_order_cnt_type = 1).  Contains 256 elements.
    if (seqParams->pic_order_cnt_type == 1)
    {
        for (uint16_t i = 0; i < 256; ++i)
        {
            oss << "offset_for_ref_frame[" << +i << "] = " << +seqParams->offset_for_ref_frame[i] << std::endl;
        }
    }

    oss << "frame_crop_left_offset = " << +seqParams->frame_crop_left_offset << std::endl;
    oss << "frame_crop_right_offset = " << +seqParams->frame_crop_right_offset << std::endl;
    oss << "frame_crop_top_offset = " << +seqParams->frame_crop_top_offset << std::endl;
    oss << "frame_crop_bottom_offset = " << +seqParams->frame_crop_bottom_offset << std::endl;
    oss << "seq_scaling_matrix_present_flag = " << +seqParams->seq_scaling_matrix_present_flag << std::endl;
    oss << "seq_scaling_list_present_flag = " << +seqParams->seq_scaling_list_present_flag[0] << std::endl;

    // seq_scaling_list_present_flag with 12 elements (only 1 element acknowledged in DDI doc)
    oss << "# seq_scaling_list_present_flag[1-11]:";
    for (uint8_t i = 1; i < 12; i++)
        oss << +seqParams->seq_scaling_list_present_flag[i] << " ";
    oss << std::endl;

    oss << "delta_pic_order_always_zero_flag = " << +seqParams->delta_pic_order_always_zero_flag << std::endl;
    oss << "frame_mbs_only_flag = " << +seqParams->frame_mbs_only_flag << std::endl;
    oss << "direct_8x8_inference_flag = " << +seqParams->direct_8x8_inference_flag << std::endl;
    oss << "vui_parameters_present_flag = " << +seqParams->vui_parameters_present_flag << std::endl;
    oss << "frame_cropping_flag = " << +seqParams->frame_cropping_flag << std::endl;
    oss << "EnableSliceLevelRateCtrl = " << +seqParams->EnableSliceLevelRateCtrl << std::endl;
    oss << "ICQQualityFactor = " << +seqParams->ICQQualityFactor << std::endl;
    oss << "InputColorSpace = " << +seqParams->InputColorSpace << std::endl;

    // begining of union/struct
    oss << "# bResetBRC = " << +seqParams->bResetBRC << std::endl;
    oss << "# bNoAcceleratorSPSInsertion = " << +seqParams->bNoAcceleratorSPSInsertion << std::endl;
    oss << "# GlobalSearch = " << +seqParams->GlobalSearch << std::endl;
    oss << "# LocalSearch = " << +seqParams->LocalSearch << std::endl;
    oss << "# EarlySkip = " << +seqParams->EarlySkip << std::endl;
    oss << "# Trellis = " << +seqParams->Trellis << std::endl;
    oss << "# MBBRC = " << +seqParams->MBBRC << std::endl;
    oss << "# bTemporalScalability = " << +seqParams->bTemporalScalability << std::endl;
    oss << "# ROIValueInDeltaQP = " << +seqParams->ROIValueInDeltaQP << std::endl;
    oss << "# bAutoMaxPBFrameSizeForSceneChange = " << +seqParams->bAutoMaxPBFrameSizeForSceneChange << std::endl;
    oss << "sFlags = " << +seqParams->sFlags << std::endl;

    // end of union/struct
    oss << "UserMaxIFrameSize = " << +seqParams->UserMaxFrameSize << std::endl;
    oss << "UserMaxPBFrameSize = " << +seqParams->UserMaxPBFrameSize << std::endl;

    // Parameters not defined in DDI (Any non-DDI parameters printed should be preceeded by #)
    oss << "# Non-DDI Parameters:" << std::endl;
    oss << "# constraint_set0_flag = " << std::hex << +seqParams->constraint_set0_flag << std::endl;
    oss << "# constraint_set1_flag = " << std::hex << +seqParams->constraint_set1_flag << std::endl;
    oss << "# constraint_set2_flag = " << std::hex << +seqParams->constraint_set2_flag << std::endl;
    oss << "# constraint_set3_flag = " << std::hex << +seqParams->constraint_set3_flag << std::endl;

    oss << "# separate_colour_plane_flag = " << std::hex << +seqParams->separate_colour_plane_flag << std::endl;
    oss << "# qpprime_y_zero_transform_bypass_flag = " << std::hex << +seqParams->qpprime_y_zero_transform_bypass_flag << std::endl;
    oss << "# gaps_in_frame_num_value_allowed_flag = " << std::hex << +seqParams->gaps_in_frame_num_value_allowed_flag << std::endl;
    oss << "# pic_width_in_mbs_minus1 = " << std::hex << +seqParams->pic_width_in_mbs_minus1 << std::endl;
    oss << "# pic_height_in_map_units_minus1 = " << std::hex << +seqParams->pic_height_in_map_units_minus1 << std::endl;
    oss << "# mb_adaptive_frame_field_flag = " << std::hex << +seqParams->mb_adaptive_frame_field_flag << std::endl;

    // Dump ScalingList4x4 (6 x 16)
    for (uint8_t i = 0; i < 16; ++i)
    {
        oss << "# ScalingList4x4[" << std::dec << +i * 6 << "-" << (+i * 6) + 5 << "][" << +i << "]";
        for (uint8_t j = 0; j < 6; j++)
            oss << std::hex << +matrixParams->ScalingList4x4[j][i] << " ";
        oss << std::endl;
    }

    // ScalingList8x8 (2 x 64)
    for (uint8_t i = 0; i < 64; ++i)
    {
        oss << "# ScalingList8x8[0 / 1][ " << std::dec << +i << "] = ";
        oss << +matrixParams->ScalingList8x8[0][i] << " / " << +matrixParams->ScalingList8x8[1][i];
        oss << std::endl;
    }

    const char *fileName = m_debugInterface->CreateFileName(
        "_DDIEnc",
        CodechalDbgBufferType::bufSeqParams,
        CodechalDbgExtType::txt);

    std::ofstream ofs(fileName, std::ios::out);
    ofs << oss.str();
    ofs.close();

    if (m_debugInterface->DumpIsEnabled(CodechalDbgAttr::attrDriverUltDump))
    {
        if (!m_debugInterface->m_ddiFileName.empty())
        {
            std::ofstream ofs(m_debugInterface->m_ddiFileName, std::ios::app);
            ofs << "SeqParamFile"
                << " = \"" << m_debugInterface->m_fileName << "\"" << std::endl;
            ofs.close();
        }
    }

    return MOS_STATUS_SUCCESS;
}

MOS_STATUS CodechalEncodeAvcBase::DumpPicParams(
    PCODEC_AVC_ENCODE_PIC_PARAMS picParams,
    PCODEC_AVC_IQ_MATRIX_PARAMS  matrixParams)
{
    CODECHAL_DEBUG_FUNCTION_ENTER;

    if (!m_debugInterface->DumpIsEnabled(CodechalDbgAttr::attrPicParams))
    {
        return MOS_STATUS_SUCCESS;
    }

    CODECHAL_DEBUG_CHK_NULL(picParams);

    std::ostringstream oss;
    oss.setf(std::ios::showbase | std::ios::uppercase);

    oss << "# DDI Parameters:" << std::endl;
    oss << "TargetFrameSize = " << +picParams->TargetFrameSize << std::endl;
    oss << "CurrOriginalPic = " << +picParams->CurrOriginalPic.PicEntry << std::endl;
    oss << "CurrReconstructedPic = " << +picParams->CurrReconstructedPic.PicEntry << std::endl;
    oss << "CodingType = " << +picParams->CodingType << std::endl;
    oss << "FieldCodingFlag = " << +picParams->FieldCodingFlag << std::endl;
    oss << "FieldFrameCodingFlag = " << +picParams->FieldFrameCodingFlag << std::endl;
    oss << "NumSlice = " << +picParams->NumSlice << std::endl;
    oss << "QpY = " << +picParams->QpY << std::endl;

    for (uint8_t i = 0; i < 16; ++i)
    {
        oss << "RefFrameList[" << +i << "] = " << +picParams->RefFrameList[i].PicEntry << std::endl;
    }

    oss << "UsedForReferenceFlags = " << +picParams->UsedForReferenceFlags << std::endl;
    oss << "CurrFieldOrderCnt[0] = " << +picParams->CurrFieldOrderCnt[0] << std::endl;
    oss << "CurrFieldOrderCnt[1] = " << +picParams->CurrFieldOrderCnt[1] << std::endl;

    for (uint8_t i = 0; i < 16; ++i)
    {
        for (uint8_t j = 0; j < 2; ++j)
        {
            oss << "FieldOrderCntList[" << +i << "]"
                << "[" << +j << "] = " << +picParams->FieldOrderCntList[i][j] << std::endl;
        }
    }

    oss << "frame_num = " << +picParams->frame_num << std::endl;
    oss << "bLastPicInSeq = " << +picParams->bLastPicInSeq << std::endl;
    oss << "bLastPicInStream = " << +picParams->bLastPicInStream << std::endl;

    // User Flags parameters
    oss << "# bUseRawPicForRef = " << +picParams->UserFlags.bUseRawPicForRef << std::endl;
    oss << "# bDisableAcceleratorHeaderPacking = " << +picParams->UserFlags.bDisableAcceleratorHeaderPacking << std::endl;
    oss << "# bDisableSubMBPartition = " << +picParams->UserFlags.bDisableSubMBPartition << std::endl;
    oss << "# bEmulationByteInsertion = " << +picParams->UserFlags.bEmulationByteInsertion << std::endl;
    oss << "# bEnableRollingIntraRefresh = " << +picParams->UserFlags.bEnableRollingIntraRefresh << std::endl;
    oss << "ForceRepartitionCheck = " << +picParams->UserFlags.ForceRepartitionCheck << std::endl;
    oss << "UserFlags = " << +picParams->UserFlags.Value << std::endl;
    oss << "StatusReportFeedbackNumber = " << +picParams->StatusReportFeedbackNumber << std::endl;
    oss << "bIdrPic = " << +picParams->bIdrPic << std::endl;
    oss << "pic_parameter_set_id = " << +picParams->pic_parameter_set_id << std::endl;
    oss << "seq_parameter_set_id = " << +picParams->seq_parameter_set_id << std::endl;
    oss << "num_ref_idx_l0_active_minus1 = " << +picParams->num_ref_idx_l0_active_minus1 << std::endl;
    oss << "num_ref_idx_l1_active_minus1 = " << +picParams->num_ref_idx_l1_active_minus1 << std::endl;
    oss << "chroma_qp_index_offset = " << +picParams->chroma_qp_index_offset << std::endl;
    oss << "second_chroma_qp_index_offset = " << +picParams->second_chroma_qp_index_offset << std::endl;
    oss << "entropy_coding_mode_flag = " << +picParams->entropy_coding_mode_flag << std::endl;
    oss << "pic_order_present_flag = " << +picParams->pic_order_present_flag << std::endl;
    oss << "weighted_pred_flag = " << +picParams->weighted_pred_flag << std::endl;
    oss << "weighted_bipred_idc = " << +picParams->weighted_bipred_idc << std::endl;
    oss << "constrained_intra_pred_flag = " << +picParams->constrained_intra_pred_flag << std::endl;
    oss << "transform_8x8_mode_flag = " << +picParams->transform_8x8_mode_flag << std::endl;
    oss << "pic_scaling_matrix_present_flag = " << +picParams->pic_scaling_matrix_present_flag << std::endl;
    oss << "pic_scaling_list_present_flag = " << +picParams->pic_scaling_list_present_flag[0] << std::endl;

    // pic_scaling_list_present_flag buffer contains 12 elements (only 1 acknowledged DDI document)
    oss << "# pic_scaling_list_present_flag[1-11]:";
    oss << +picParams->pic_scaling_list_present_flag[1] << " ";
    oss << +picParams->pic_scaling_list_present_flag[2] << " ";
    oss << +picParams->pic_scaling_list_present_flag[3] << " ";
    oss << +picParams->pic_scaling_list_present_flag[4] << " ";
    oss << +picParams->pic_scaling_list_present_flag[5] << " ";
    oss << +picParams->pic_scaling_list_present_flag[6] << " ";
    oss << +picParams->pic_scaling_list_present_flag[7] << " ";
    oss << +picParams->pic_scaling_list_present_flag[8] << " ";
    oss << +picParams->pic_scaling_list_present_flag[9] << " ";
    oss << +picParams->pic_scaling_list_present_flag[10] << " ";
    oss << +picParams->pic_scaling_list_present_flag[11] << std::endl;

    oss << "RefPicFlag = " << +picParams->RefPicFlag << std::endl;
    oss << "BRCPrecision = " << +picParams->BRCPrecision << std::endl;
    oss << "bDisplayFormatSwizzle = " << +picParams->bDisplayFormatSwizzle << std::endl;
    oss << "IntraInsertionLocation = " << +picParams->IntraRefreshMBNum << std::endl;
    oss << "IntraInsertionSize = " << +picParams->IntraRefreshUnitinMB << std::endl;
    oss << "QpDeltaForInsertedIntra = " << +picParams->IntraRefreshQPDelta << std::endl;
    oss << "SliceSizeInBytes = " << +picParams->SliceSizeInBytes << std::endl;
    oss << "bDisableRollingIntraRefreshOverlap = " << +picParams->bDisableRollingIntraRefreshOverlap << std::endl;
    oss << "NumROI = " << +picParams->NumROI << std::endl;
    oss << "MinDeltaQp = " << +picParams->MinDeltaQp << std::endl;
    oss << "MaxDeltaQp = " << +picParams->MaxDeltaQp << std::endl;

    // Dump ROI coordinates and PriorityLevelOrDQp
    for (uint16_t i = 0; i < picParams->NumROI; ++i)
    {
        oss << "ROI[" << +i << "] = [";
        oss << +picParams->ROI[i].Top << ",";
        oss << +picParams->ROI[i].Bottom << ",";
        oss << +picParams->ROI[i].Left << ",";
        oss << +picParams->ROI[i].Right << "], ";
        oss << "PriorityLevelOrDQp = " << +picParams->ROI[i].PriorityLevelOrDQp << std::endl;
    }

    oss << "NumDirtyROI = " << +picParams->NumDirtyROI << std::endl;

    // Dump Dirty ROI coordinates and PriorityLevelOrDQp
    for (uint16_t i = 0; i < picParams->NumDirtyROI; ++i)
    {
        oss << "DirtyROI[" << +i << "] = [";
        oss << +picParams->DirtyROI[i].Top << ",";
        oss << +picParams->DirtyROI[i].Bottom << ",";
        oss << +picParams->DirtyROI[i].Left << ",";
        oss << +picParams->DirtyROI[i].Right << "], ";
        oss << "PriorityLevelOrDQp = " << +picParams->DirtyROI[i].PriorityLevelOrDQp << std::endl;
    }

    oss << "SkipFrameFlag = " << +picParams->SkipFrameFlag << std::endl;
    oss << "NumSkipFrames = " << +picParams->NumSkipFrames << std::endl;
    oss << "SizeSkipFrames = " << +picParams->SizeSkipFrames << std::endl;

    // Dump Min/Max QP params
    oss << "BRCMinQp = " << +picParams->ucMinimumQP << std::endl;
    oss << "BRCMaxQp = " << +picParams->ucMaximumQP << std::endl;

    // Dump SFD threshold
    oss << "dwZMvThreshold = " << +picParams->dwZMvThreshold << std::endl;

    // Dump HME offset
    oss << "bEnableHMEOffset = " << +picParams->bEnableHMEOffset << std::endl;

    for (uint8_t i = 0; i < 16; ++i)
    {
        for (uint8_t j = 0; j < 2; ++j)
        {
            for (uint8_t k = 0; k < 2; ++k)
            {
                oss << "HMEOffset[" << +i << "][" << +j << "][" << +k << "] = " << +picParams->HMEOffset[i][j][k] << std::endl;
            }
        }
    }

    oss << "bDisableFrameSkip = " << +picParams->bDisableFrameSkip << std::endl;
    oss << "bEnableSync = " << +picParams->bEnableSync << std::endl;
    oss << "bRepeatFrame = " << +picParams->bRepeatFrame << std::endl;
    oss << "bEnableQpAdjustment = " << +picParams->bEnableQpAdjustment << std::endl;

    oss << "NumDeltaQpForNonRectROI = " << +picParams->NumDeltaQpForNonRectROI << std::endl;
    for (uint16_t i = 0; i < picParams->NumDeltaQpForNonRectROI; ++i)
    {
        oss << "NonRectROIDeltaQpList[" << +i << "] = " << +picParams->NonRectROIDeltaQpList[i] << std::endl;
    }
    
    oss << "SyncMarkerX = " << +picParams->SyncMarkerX << std::endl;
    oss << "SyncMarkerY = " << +picParams->SyncMarkerY << std::endl;
    oss << "SyncMarkerSize = " << +picParams->SyncMarkerSize << std::endl;
    oss << "HierarchLevelPlus1 = " << +picParams->HierarchLevelPlus1 << std::endl;
    oss << "QpModulationStrength = " << +picParams->QpModulationStrength << std::endl;

    // Parameters not defined in DDI (Any non-DDI parameters printed should be preceeded by #)
    oss << "# Non-DDI Parameters:" << std::endl;
    oss << "# num_slice_groups_minus1 = " << +picParams->num_slice_groups_minus1 << std::endl;
    oss << "# pic_init_qp_minus26 = " << +picParams->pic_init_qp_minus26 << std::endl;
    oss << "# pic_init_qs_minus26 = " << +picParams->pic_init_qs_minus26 << std::endl;
    oss << "# deblocking_filter_control_present_flag = " << +picParams->deblocking_filter_control_present_flag << std::endl;
    oss << "# redundant_pic_cnt_present_flag = " << +picParams->redundant_pic_cnt_present_flag << std::endl;
    oss << "# EnableRollingIntraRefresh = " << +picParams->EnableRollingIntraRefresh << std::endl;
    oss << "# IntraRefreshMBx = " << +picParams->IntraRefreshMBx << std::endl;
    oss << "# IntraRefreshMBy = " << +picParams->IntraRefreshMBy << std::endl;
    oss << "# IntraRefreshUnitinMB = " << +picParams->IntraRefreshUnitinMB << std::endl;
    oss << "# IntraRefreshQPDelta = " << +picParams->IntraRefreshQPDelta << std::endl;

    // Dump ScalingList4x4 (6 x 16)
    for (uint8_t i = 0; i < 16; ++i)
    {
        oss << "# ScalingList4x4[" << +i << "] = ";
        oss << +matrixParams->ScalingList4x4[0][i] << " ";
        oss << +matrixParams->ScalingList4x4[1][i] << " ";
        oss << +matrixParams->ScalingList4x4[2][i] << " ";
        oss << +matrixParams->ScalingList4x4[3][i] << " ";
        oss << +matrixParams->ScalingList4x4[4][i] << " ";
        oss << +matrixParams->ScalingList4x4[5][i] << std::endl;
    }

    // ScalingList8x8 (2 x 64)
    for (uint8_t i = 0; i < 64; ++i)
    {
        oss << "# ScalingList8x8[0/1][" << +i << "] = " << +matrixParams->ScalingList8x8[0][i] << " / " << +matrixParams->ScalingList8x8[1][i] << std::endl;
    }

    const char *fileName = m_debugInterface->CreateFileName(
        "_DDIEnc",
        CodechalDbgBufferType::bufPicParams,
        CodechalDbgExtType::txt);

    std::ofstream ofs(fileName, std::ios::out);
    ofs << oss.str();
    ofs.close();

    if (m_debugInterface->DumpIsEnabled(CodechalDbgAttr::attrDriverUltDump))
    {
        if (!m_debugInterface->m_ddiFileName.empty())
        {
            std::ofstream ofs(m_debugInterface->m_ddiFileName, std::ios::app);
            ofs << "PicNum"
                << " = \"" << m_debugInterface->m_bufferDumpFrameNum << "\"" << std::endl;
            ofs << "PicParamFile"
                << " = \"" << m_debugInterface->m_fileName << "\"" << std::endl;
            ofs.close();
        }
    }

    return MOS_STATUS_SUCCESS;
}


MOS_STATUS CodechalEncodeAvcBase::DumpFeiPicParams(
    CodecEncodeAvcFeiPicParams *feiPicParams)
{
    CODECHAL_DEBUG_FUNCTION_ENTER;

    if (!m_debugInterface->DumpIsEnabled(CodechalDbgAttr::attrFeiPicParams))
    {
        return MOS_STATUS_SUCCESS;
    }

    CODECHAL_DEBUG_CHK_NULL(feiPicParams);

    std::ostringstream oss;
    oss.setf(std::ios::showbase | std::ios::uppercase);

    oss << "# DDI Parameters:" << std::endl;
    oss << "SearchPath = " << +feiPicParams->SearchPath << std::endl;
    oss << "LenSP = " << +feiPicParams->LenSP << std::endl;
    oss << "SubMBPartMask = " << +feiPicParams->SubMBPartMask << std::endl;
    oss << "IntraPartMask = " << +feiPicParams->IntraPartMask << std::endl;
    oss << "MultiPredL0 = " << +feiPicParams->MultiPredL0 << std::endl;
    oss << "MultiPredL1 = " << +feiPicParams->MultiPredL1 << std::endl;
    oss << "SubPelMode = " << +feiPicParams->SubPelMode << std::endl;
    oss << "InterSAD = " << +feiPicParams->InterSAD << std::endl;
    oss << "IntraSAD = " << +feiPicParams->IntraSAD << std::endl;
    oss << "NumMVPredictors = " << +feiPicParams->NumMVPredictorsL0 << std::endl;
    oss << "NumMVPredictorsL1 = " << +feiPicParams->NumMVPredictorsL1 << std::endl;
    oss << "DistortionType = " << +feiPicParams->DistortionType << std::endl;
    oss << "DistortionEnable = " << +feiPicParams->DistortionEnable << std::endl;
    oss << "RepartitionCheckEnable = " << +feiPicParams->RepartitionCheckEnable << std::endl;
    oss << "AdaptiveSearch = " << +feiPicParams->AdaptiveSearch << std::endl;
    oss << "MVPredictorEnable = " << +feiPicParams->MVPredictorEnable << std::endl;
    oss << "bMBQp = " << +feiPicParams->bMBQp << std::endl;
    oss << "bPerMBInput = " << +feiPicParams->bPerMBInput << std::endl;
    oss << "bMBSizeCtrl = " << +feiPicParams->bMBSizeCtrl << std::endl;
    oss << "RefWidth = " << +feiPicParams->RefWidth << std::endl;
    oss << "RefHeight = " << +feiPicParams->RefHeight << std::endl;
    oss << "SearchWindow = " << +feiPicParams->SearchWindow << std::endl;

    const char *fileName = m_debugInterface->CreateFileName(
        "_DDIEnc",
        CodechalDbgBufferType::bufFeiPicParams,
        CodechalDbgExtType::txt);

    std::ofstream ofs(fileName, std::ios::out);
    ofs << oss.str();
    ofs.close();

    if (m_debugInterface->DumpIsEnabled(CodechalDbgAttr::attrDriverUltDump))
    {
        if (!m_debugInterface->m_ddiFileName.empty())
        {
            std::ofstream ofs(m_debugInterface->m_ddiFileName, std::ios::app);
            ofs << "PicNum"
                << " = \"" << m_debugInterface->m_bufferDumpFrameNum << "\"" << std::endl;
            ofs << "FeiPicParamFile"
                << " = \"" << m_debugInterface->m_fileName << "\"" << std::endl;
            ofs.close();
        }
    }

    return MOS_STATUS_SUCCESS;
}

MOS_STATUS CodechalEncodeAvcBase::DumpSliceParams(
    PCODEC_AVC_ENCODE_SLICE_PARAMS sliceParams,
    PCODEC_AVC_ENCODE_PIC_PARAMS   picParams)
{
    CODECHAL_DEBUG_FUNCTION_ENTER;

    if (!m_debugInterface->DumpIsEnabled(CodechalDbgAttr::attrSlcParams))
    {
        return MOS_STATUS_SUCCESS;
    }

    CODECHAL_DEBUG_CHK_NULL(sliceParams);

    m_debugInterface->m_sliceId = sliceParams->slice_id;  // set here for constructing debug file name

    std::ostringstream oss;
    oss.setf(std::ios::showbase | std::ios::uppercase);

    oss << "# DDI Parameters:" << std::endl;
    oss << "NumMbsForSlice = " << +sliceParams->NumMbsForSlice << std::endl;

    // RefPicList (2 x 32)
    for (uint8_t i = 0; i < 2; ++i)
    {
        for (uint8_t j = 0; j < 32; ++j)
        {
            oss << "RefPicList[" << +i << "][" << +j << "] = " << +sliceParams->RefPicList[i][j].PicEntry << std::endl;
        }
    }

    // Conditionally printed (only when picture parameters weighted_pred_flag or weighted_bipred_idc are set).
    // Weights contains 192 elements (2 x 32 x 3 x 2).
    if (picParams->weighted_pred_flag || picParams->weighted_bipred_idc)
    {
        for (uint8_t i = 0; i < 2; ++i)
        {
            for (uint8_t j = 0; j < 32; ++j)
            {
                for (uint8_t k = 0; k < 3; ++k)
                {
                    for (uint8_t l = 0; l < 2; ++l)
                    {
                        oss << "Weights[" << +i << "][" << +j << "][" << +k << "][" << +l << "]: " << +sliceParams->Weights[i][j][k][l] << std::endl;
                    }
                }
            }
        }
    }

    oss << "first_mb_in_slice = " << +sliceParams->first_mb_in_slice << std::endl;
    oss << "slice_type = " << +sliceParams->slice_type << std::endl;
    oss << "pic_parameter_set_id = " << +sliceParams->pic_parameter_set_id << std::endl;
    oss << "direct_spatial_mv_pred_flag = " << +sliceParams->direct_spatial_mv_pred_flag << std::endl;
    oss << "num_ref_idx_active_override_flag = " << +sliceParams->num_ref_idx_active_override_flag << std::endl;
    oss << "long_term_reference_flag = " << +sliceParams->long_term_reference_flag << std::endl;
    oss << "idr_pic_id = " << +sliceParams->idr_pic_id << std::endl;
    oss << "pic_order_cnt_lsb = " << +sliceParams->pic_order_cnt_lsb << std::endl;
    oss << "delta_pic_order_cnt_bottom = " << +sliceParams->delta_pic_order_cnt_bottom << std::endl;
    oss << "delta_pic_order_cnt[0] = " << +sliceParams->delta_pic_order_cnt[0] << std::endl;
    oss << "delta_pic_order_cnt[1] = " << +sliceParams->delta_pic_order_cnt[1] << std::endl;
    oss << "num_ref_idx_l0_active_minus1 = " << +sliceParams->num_ref_idx_l0_active_minus1 << std::endl;
    oss << "num_ref_idx_l1_active_minus1 = " << +sliceParams->num_ref_idx_l1_active_minus1 << std::endl;
    oss << "luma_log2_weight_denom = " << +sliceParams->luma_log2_weight_denom << std::endl;
    oss << "chroma_log2_weight_denom = " << +sliceParams->chroma_log2_weight_denom << std::endl;
    oss << "cabac_init_idc = " << +sliceParams->cabac_init_idc << std::endl;
    oss << "slice_qp_delta = " << +sliceParams->slice_qp_delta << std::endl;
    oss << "disable_deblocking_filter_idc = " << +sliceParams->disable_deblocking_filter_idc << std::endl;
    oss << "slice_alpha_c0_offset_div2 = " << +sliceParams->slice_alpha_c0_offset_div2 << std::endl;
    oss << "slice_beta_offset_div2 = " << +sliceParams->slice_beta_offset_div2 << std::endl;
    oss << "slice_id = " << +sliceParams->slice_id << std::endl;
    oss << "luma_weight_flag[0] = " << +sliceParams->luma_weight_flag[0] << std::endl;
    oss << "luma_weight_flag[1] = " << +sliceParams->luma_weight_flag[1] << std::endl;
    oss << "chroma_weight_flag[0] = " << +sliceParams->chroma_weight_flag[0] << std::endl;
    oss << "chroma_weight_flag[1] = " << +sliceParams->chroma_weight_flag[1] << std::endl;

    // Parameters not in DDI (Any non-DDI parameters printed should be preceeded by #)
    oss << "# Non-DDI Parameters:" << std::endl;

    // PicOrder (2 x 32) - Dump in 32 blocks of 2 chunks per line
    for (uint16_t i = 0; i < 32; ++i)
    {
        CODECHAL_DEBUG_CHK_STATUS(DumpEncodePicReorder(
            oss,
            0,
            i,
            &(sliceParams->PicOrder[0][i])));
        CODECHAL_DEBUG_CHK_STATUS(DumpEncodePicReorder(
            oss,
            1,
            i,
            &(sliceParams->PicOrder[1][i])));
    }

    oss << "# colour_plane_id = " << +sliceParams->colour_plane_id << std::endl;
    oss << "# frame_num = " << +sliceParams->frame_num << std::endl;
    oss << "# field_pic_flag = " << std::hex << +sliceParams->field_pic_flag << std::endl;
    oss << "# bottom_field_flag = " << std::hex << +sliceParams->bottom_field_flag << std::endl;
    oss << "# redundant_pic_cnt = " << std::dec << +sliceParams->redundant_pic_cnt << std::endl;
    oss << "# sp_for_switch_flag = " << std::hex << +sliceParams->sp_for_switch_flag << std::endl;
    oss << "# slice_qs_delta = " << std::dec << +sliceParams->slice_qs_delta << std::endl;
    oss << "# ref_pic_list_reordering_flag_l0 = " << std::hex << +sliceParams->ref_pic_list_reordering_flag_l0 << std::endl;
    oss << "# ref_pic_list_reordering_flag_l1 = " << std::hex << +sliceParams->ref_pic_list_reordering_flag_l1 << std::endl;
    oss << "# no_output_of_prior_pics_flag = " << std::hex << +sliceParams->no_output_of_prior_pics_flag << std::endl;
    oss << "# adaptive_ref_pic_marking_mode_flag = " << std::hex << +sliceParams->adaptive_ref_pic_marking_mode_flag << std::endl;
    oss << "# MaxFrameNum = " << std::dec << +sliceParams->MaxFrameNum << std::endl;
    oss << "# NumReorder = " << std::dec << +sliceParams->NumReorder << std::endl;

    const char *fileName = m_debugInterface->CreateFileName(
        "_DDIEnc",
        CodechalDbgBufferType::bufSlcParams,
        CodechalDbgExtType::txt);

    std::ofstream ofs(fileName, std::ios::out);
    ofs << oss.str();
    ofs.close();

    if (m_debugInterface->DumpIsEnabled(CodechalDbgAttr::attrDriverUltDump))
    {
        if (!m_debugInterface->m_ddiFileName.empty())
        {
            std::ofstream ofs(m_debugInterface->m_ddiFileName, std::ios::app);
            ofs << "SlcParamFile"
                << " = \"" << m_debugInterface->m_fileName << "\"" << std::endl;
            ofs.close();
        }
    }

    return MOS_STATUS_SUCCESS;
}

MOS_STATUS CodechalEncodeAvcBase::DumpVuiParams(
    PCODECHAL_ENCODE_AVC_VUI_PARAMS vuiParams)
{
    CODECHAL_DEBUG_FUNCTION_ENTER;

    if (!m_debugInterface->DumpIsEnabled(CodechalDbgAttr::attrVuiParams))
    {
        return MOS_STATUS_SUCCESS;
    }

    CODECHAL_DEBUG_CHK_NULL(vuiParams);

    std::ostringstream oss;
    oss.setf(std::ios::showbase | std::ios::uppercase);

    oss << "# DDI Parameters:" << std::endl;
    oss << "aspect_ratio_info_present_flag = " << +vuiParams->aspect_ratio_info_present_flag << std::endl;
    oss << "overscan_info_present_flag = " << +vuiParams->overscan_info_present_flag << std::endl;
    oss << "overscan_appropriate_flag = " << +vuiParams->overscan_appropriate_flag << std::endl;
    oss << "video_signal_type_present_flag = " << +vuiParams->video_signal_type_present_flag << std::endl;
    oss << "video_full_range_flag = " << +vuiParams->video_full_range_flag << std::endl;
    oss << "colour_description_present_flag = " << +vuiParams->colour_description_present_flag << std::endl;
    oss << "chroma_loc_info_present_flag = " << +vuiParams->chroma_loc_info_present_flag << std::endl;
    oss << "timing_info_present_flag = " << +vuiParams->timing_info_present_flag << std::endl;
    oss << "fixed_frame_rate_flag = " << +vuiParams->fixed_frame_rate_flag << std::endl;
    oss << "nal_hrd_parameters_present_flag = " << +vuiParams->nal_hrd_parameters_present_flag << std::endl;
    oss << "vcl_hrd_parameters_present_flag = " << +vuiParams->vcl_hrd_parameters_present_flag << std::endl;
    oss << "low_delay_hrd_flag = " << +vuiParams->low_delay_hrd_flag << std::endl;
    oss << "pic_struct_present_flag = " << +vuiParams->pic_struct_present_flag << std::endl;
    oss << "bitstream_restriction_flag = " << +vuiParams->bitstream_restriction_flag << std::endl;
    oss << "motion_vectors_over_pic_boundaries_flag = " << +vuiParams->motion_vectors_over_pic_boundaries_flag << std::endl;
    oss << "sar_width = " << +vuiParams->sar_width << std::endl;
    oss << "sar_height = " << +vuiParams->sar_height << std::endl;
    oss << "aspect_ratio_idc = " << +vuiParams->aspect_ratio_idc << std::endl;
    oss << "video_format = " << +vuiParams->video_format << std::endl;
    oss << "colour_primaries = " << +vuiParams->colour_primaries << std::endl;
    oss << "transfer_characteristics = " << +vuiParams->transfer_characteristics << std::endl;
    oss << "matrix_coefficients = " << +vuiParams->matrix_coefficients << std::endl;
    oss << "chroma_sample_loc_type_top_field = " << +vuiParams->chroma_sample_loc_type_top_field << std::endl;
    oss << "chroma_sample_loc_type_bottom_field = " << +vuiParams->chroma_sample_loc_type_bottom_field << std::endl;
    oss << "max_bytes_per_pic_denom = " << +vuiParams->max_bytes_per_pic_denom << std::endl;
    oss << "max_bits_per_mb_denom = " << +vuiParams->max_bits_per_mb_denom << std::endl;
    oss << "log2_max_mv_length_horizontal = " << +vuiParams->log2_max_mv_length_horizontal << std::endl;
    oss << "log2_max_mv_length_vertical = " << +vuiParams->log2_max_mv_length_vertical << std::endl;
    oss << "num_reorder_frames = " << +vuiParams->num_reorder_frames << std::endl;
    oss << "num_units_in_tick = " << +vuiParams->num_units_in_tick << std::endl;
    oss << "time_scale = " << +vuiParams->time_scale << std::endl;
    oss << "max_dec_frame_buffering = " << +vuiParams->max_dec_frame_buffering << std::endl;
    oss << "cpb_cnt_minus1 = " << +vuiParams->cpb_cnt_minus1 << std::endl;
    oss << "bit_rate_scale = " << +vuiParams->bit_rate_scale << std::endl;
    oss << "cpb_size_scale = " << +vuiParams->cpb_size_scale << std::endl;

    // bit_rate_value_minus1 (32 in size)
    for (uint8_t i = 0; i < 32; ++i)
    {
        oss << "bit_rate_value_minus1[" << +i << "] = " << +vuiParams->bit_rate_value_minus1[i] << std::endl;
    }

    // cpb_size_value_minus1 (32 in size)
    for (uint8_t i = 0; i < 32; ++i)
    {
        oss << "cpb_size_value_minus1[" << +i << "] = " << +vuiParams->cpb_size_value_minus1[i] << std::endl;
    }

    oss << "cbr_flag = " << +vuiParams->cbr_flag << std::endl;
    oss << "initial_cpb_removal_delay_length_minus1 = " << +vuiParams->initial_cpb_removal_delay_length_minus1 << std::endl;
    oss << "cpb_removal_delay_length_minus1 = " << +vuiParams->cpb_removal_delay_length_minus1 << std::endl;
    oss << "dpb_output_delay_length_minus1 = " << +vuiParams->dpb_output_delay_length_minus1 << std::endl;
    oss << "time_offset_length = " << +vuiParams->time_offset_length << std::endl;

    const char *fileName = m_debugInterface->CreateFileName(
        "_DDIEnc",
        CodechalDbgBufferType::bufVuiParams,
        CodechalDbgExtType::txt);

    std::ofstream ofs(fileName, std::ios::out);
    ofs << oss.str();
    ofs.close();

    if (m_debugInterface->DumpIsEnabled(CodechalDbgAttr::attrDriverUltDump))
    {
        if (!m_debugInterface->m_ddiFileName.empty())
        {
            std::ofstream ofs(m_debugInterface->m_ddiFileName, std::ios::app);
            ofs << "VuiParamFile"
                << " = \"" << m_debugInterface->m_fileName << "\"" << std::endl;
            ofs.close();
        }
    }

    return MOS_STATUS_SUCCESS;
}

bool SearchNALHeader(
    PMHW_VDBOX_AVC_SLICE_STATE sliceState,
    uint32_t                   startCode)
{
    CODECHAL_DEBUG_FUNCTION_ENTER;

    for (auto i = 0; i < CODECHAL_ENCODE_AVC_MAX_NAL_TYPE; i++)
    {
        if (sliceState->ppNalUnitParams[i]->uiSize > 0)
        {
            uint32_t offset   = 0;
            uint8_t *dataBase = (uint8_t *)(sliceState->pBsBuffer->pBase + sliceState->ppNalUnitParams[i]->uiOffset);

            while (offset < sliceState->ppNalUnitParams[i]->uiSize)
            {
                uint8_t *dataBuf = dataBase + offset;

                if (*dataBuf == 0)
                {
                    uint32_t data = ((*dataBuf) << 24) + ((*(dataBuf + 1)) << 16) + ((*(dataBuf + 2)) << 8) + (*(dataBuf + 3));

                    if ((data & 0xFFFFFF00) == 0x00000100)
                    {
                        if (data == startCode)
                        {
                            return true;
                        }

                        offset += 4;
                    }
                    else
                    {
                        offset++;
                    }
                }
                else
                {
                    offset++;
                }
            }
        }
    }

    return false;
}

MOS_STATUS CodechalEncodeAvcBase::CreateAvcPar()
{
    CODECHAL_DEBUG_FUNCTION_ENTER;

    CODECHAL_DEBUG_CHK_NULL(m_debugInterface);

    if (m_debugInterface->DumpIsEnabled(CodechalDbgAttr::attrDumpEncodePar))
    {
        CODECHAL_DEBUG_CHK_NULL(m_avcPar = MOS_New(EncodeAvcPar));
        MOS_ZeroMemory(m_avcPar, sizeof(EncodeAvcPar));
    }

    return MOS_STATUS_SUCCESS;
}

MOS_STATUS CodechalEncodeAvcBase::DestroyAvcPar()
{
    CODECHAL_DEBUG_FUNCTION_ENTER;

    CODECHAL_ENCODE_CHK_STATUS_RETURN(DumpSeqParFile());
    MOS_Delete(m_avcPar);

    return MOS_STATUS_SUCCESS;
}

MOS_STATUS CodechalEncodeAvcBase::PopulateConstParam()
{
    CODECHAL_DEBUG_FUNCTION_ENTER;

    CODECHAL_DEBUG_CHK_NULL(m_debugInterface);

    if (!m_debugInterface->DumpIsEnabled(CodechalDbgAttr::attrDumpEncodePar))
    {
        return MOS_STATUS_SUCCESS;
    }

    if (m_encodeParState->m_isConstDumped)
    {
        return MOS_STATUS_SUCCESS;
    }

    CODECHAL_ENCODE_CHK_STATUS_RETURN(PopulateTargetUsage());

    std::ostringstream oss;
    oss.setf(std::ios::showbase | std::ios::uppercase);

    // Constant
    oss << "EnableStatistics = 0" << std::endl;
    oss << "KernelDumpEnable = 16" << std::endl;
    oss << "Kernel = 1" << std::endl;
    oss << "StartMB = -1" << std::endl;
    oss << "EndMB = -1" << std::endl;
    oss << "GOPMode = 0" << std::endl;
    oss << "BoxFilter = 1" << std::endl;
    oss << "EnableBpyramid = 0" << std::endl;
    oss << "EnableIPCM = 1" << std::endl;
    oss << "EnableMVUnpacked = 1" << std::endl;
    oss << "EnableNewModeCost = 1" << std::endl;
    oss << "EnablePAFF = 0" << std::endl;
    oss << "EnableSkip = 3" << std::endl;
    oss << "EnableSkipBiasAdjustment = 1" << std::endl;
    oss << "HierarchicalMEFlag = 3" << std::endl;
    oss << "NumRefStartB = 1" << std::endl;
    oss << "PAFFThreshold = 10000" << std::endl;
    oss << "PicScalingList = 0" << std::endl;
    oss << "SeqScalingList = 0" << std::endl;
    oss << "SkipChromaCBPDetection = 1" << std::endl;
    oss << "IdrInterval = 0" << std::endl;
    oss << "AddEoSquenceNAL = 1" << std::endl;
    oss << "AddEoStreamNAL = 1" << std::endl;
    oss << "CabacZeroWordFlag = 0" << std::endl;
    oss << "EncodeFrameSizeTolerance = 0" << std::endl;
    oss << "ForceIntraDC = 0" << std::endl;
    oss << "HMECoarseShape = 2" << std::endl;
    oss << "HMESubPelMode = 3" << std::endl;
    oss << "IntraDirectionBias = 1" << std::endl;
    oss << "InterSADMeasure = 2" << std::endl;
    oss << "IntraSADMeasure = 2" << std::endl;
    oss << "CostingFeature = 3" << std::endl;
    oss << "CostingType = 1" << std::endl;
    oss << "ModeCosting = 1" << std::endl;
    oss << "HighQPMvCostEnable = 1" << std::endl;
    oss << "HighQPHMECostEnable = 1" << std::endl;
    oss << "RefIDCostMode = 0" << std::endl;
    oss << "EnableAdaptiveLambdaOffset = 1" << std::endl;

    m_encodeParState->m_isConstDumped = true;

    const char *fileName = m_debugInterface->CreateFileName(
        "EncodeSequence",
        "EncodePar",
        CodechalDbgExtType::par);

    std::ofstream ofs(fileName, std::ios::app);
    ofs << oss.str();
    ofs.close();

    return MOS_STATUS_SUCCESS;
}

MOS_STATUS CodechalEncodeAvcBase::PopulateTargetUsage()
{
    CODECHAL_DEBUG_FUNCTION_ENTER;

    if (m_populateTargetUsage == false)
    {
        return MOS_STATUS_SUCCESS;
    }

    const char *fileName = m_debugInterface->CreateFileName(
        "EncodeSequence",
        "EncodePar",
        CodechalDbgExtType::par);

    std::ifstream ifs(fileName);
    std::string   str((std::istreambuf_iterator<char>(ifs)), std::istreambuf_iterator<char>());
    ifs.close();
    std::ofstream ofs(fileName, std::ios::trunc);
    ofs << "TargetUsage = " << static_cast<uint32_t>(m_avcSeqParam->TargetUsage) << std::endl;
    ofs << str;
    ofs.close();

    return MOS_STATUS_SUCCESS;
}

MOS_STATUS CodechalEncodeAvcBase::PopulateDdiParam(
    PCODEC_AVC_ENCODE_SEQUENCE_PARAMS avcSeqParams,
    PCODEC_AVC_ENCODE_PIC_PARAMS      avcPicParams,
    PCODEC_AVC_ENCODE_SLICE_PARAMS    avcSlcParams)
{
    CODECHAL_DEBUG_FUNCTION_ENTER;

    CODECHAL_DEBUG_CHK_NULL(m_debugInterface);

    if (!m_debugInterface->DumpIsEnabled(CodechalDbgAttr::attrDumpEncodePar))
    {
        return MOS_STATUS_SUCCESS;
    }

    if (Slice_Type[avcSlcParams->slice_type] == SLICE_I || Slice_Type[avcSlcParams->slice_type] == SLICE_SI)
    {
        m_avcPar->ProfileIDC           = avcSeqParams->Profile;
        m_avcPar->LevelIDC             = avcSeqParams->Level;
        m_avcPar->DisableVUIHeader     = !avcSeqParams->vui_parameters_present_flag;
        m_avcPar->ChromaFormatIDC      = avcSeqParams->chroma_format_idc;
        m_avcPar->ChromaQpOffset       = avcPicParams->chroma_qp_index_offset;
        m_avcPar->SecondChromaQpOffset = avcPicParams->second_chroma_qp_index_offset;

        uint8_t pictureCodingType   = CodecHal_PictureIsFrame(avcPicParams->CurrOriginalPic) ? 0 : (CodecHal_PictureIsTopField(avcPicParams->CurrOriginalPic) ? 1 : 3);
        m_avcPar->PictureCodingType = pictureCodingType;

        uint16_t gopP  = (avcSeqParams->GopRefDist) ? ((avcSeqParams->GopPicSize - 1) / avcSeqParams->GopRefDist) : 0;
        uint16_t gopB  = avcSeqParams->GopPicSize - 1 - gopP;
        m_avcPar->NumP = gopP;
        m_avcPar->NumB = ((gopP > 0) ? (gopB / gopP) : 0);

        if ((avcPicParams->NumSlice * m_sliceHeight) >=
            (uint32_t)(avcSeqParams->pic_height_in_map_units_minus1 + 1 + m_sliceHeight))
        {
            m_avcPar->NumSlices = avcPicParams->NumSlice - 1;
        }
        else
        {
            m_avcPar->NumSlices = avcPicParams->NumSlice;
        }
        m_avcPar->SliceHeight = m_sliceHeight;

        m_avcPar->NumSuperSlices = m_avcPar->NumSlices;
        if (m_avcPar->NumSuperSlices)
        {
            uint32_t sliceIdx = 0;
            for (; sliceIdx < m_avcPar->NumSuperSlices - 1; sliceIdx++)
            {
                m_avcPar->SuperSliceHeight[sliceIdx] = m_sliceHeight;
            }
            m_avcPar->SuperSliceHeight[sliceIdx] = avcSeqParams->pic_height_in_map_units_minus1 + 1 - sliceIdx * m_sliceHeight;
        }

        m_avcPar->ISliceQP   = avcPicParams->QpY + avcSlcParams->slice_qp_delta;
        m_avcPar->FrameRateM = ((avcSeqParams->FramesPer100Sec % 100) == 0) ? (avcSeqParams->FramesPer100Sec / 100) : avcSeqParams->FramesPer100Sec;
        m_avcPar->FrameRateD = ((avcSeqParams->FramesPer100Sec % 100) == 0) ? 1 : 100;

        uint8_t brcMethod = 0;
        uint8_t brcType   = 0;

        if (CodecHalIsRateControlBrc(avcSeqParams->RateControlMethod, CODECHAL_AVC))
        {
            brcMethod = 2;

            switch (avcSeqParams->RateControlMethod)
            {
            case RATECONTROL_ICQ:
                brcMethod = m_vdencEnabled ? 2 : 3;
                brcType   = 16;
                break;
            case RATECONTROL_QVBR:
                brcMethod = m_vdencEnabled ? 2 : 4;
                brcType   = 2;
                break;
            case RATECONTROL_CBR:
                brcType = 1;
                break;
            case RATECONTROL_VBR:
                brcType = 2;
                break;
            case RATECONTROL_VCM:
                brcType = m_vdencEnabled ? 4 : 3;
                break;
            default:
                brcMethod = 0;
                brcType   = 0;
                break;
            }

            if (avcSeqParams->FrameSizeTolerance == EFRAMESIZETOL_EXTREMELY_LOW)
            {
                // low delay mode
                brcType = 8;
            }
        }

        m_avcPar->BRCMethod = brcMethod;
        m_avcPar->BRCType   = brcType;

        m_avcPar->DeblockingIDC         = avcSlcParams->disable_deblocking_filter_idc;
        m_avcPar->DeblockingFilterAlpha = avcSlcParams->slice_alpha_c0_offset_div2 << 1;
        m_avcPar->DeblockingFilterBeta  = avcSlcParams->slice_beta_offset_div2 << 1;
        m_avcPar->EntropyCodingMode     = avcPicParams->entropy_coding_mode_flag;
        m_avcPar->DirectInference       = avcSeqParams->direct_8x8_inference_flag;
        m_avcPar->Transform8x8Mode      = avcPicParams->transform_8x8_mode_flag;
        m_avcPar->CRFQualityFactor      = avcSeqParams->ICQQualityFactor;
        m_avcPar->ConstrainedIntraPred  = avcPicParams->constrained_intra_pred_flag;

        // This is only for header matching although I frame doesn't have references
        if (avcSlcParams->num_ref_idx_active_override_flag)
        {
            m_avcPar->MaxRefIdxL0 = MOS_MAX(m_avcPar->MaxRefIdxL0, avcSlcParams->num_ref_idx_l0_active_minus1);
            m_avcPar->MaxRefIdxL1 = MOS_MAX(m_avcPar->MaxRefIdxL1, avcSlcParams->num_ref_idx_l1_active_minus1);
        }
        else
        {
            m_avcPar->MaxRefIdxL0 = MOS_MAX(m_avcPar->MaxRefIdxL0, avcPicParams->num_ref_idx_l0_active_minus1);
            m_avcPar->MaxRefIdxL1 = MOS_MAX(m_avcPar->MaxRefIdxL1, avcPicParams->num_ref_idx_l1_active_minus1);
        }

        if (m_vdencEnabled)
        {
            m_avcPar->SliceMode = avcSeqParams->EnableSliceLevelRateCtrl ? 2 : 0;
        }
    }
    else if (Slice_Type[avcSlcParams->slice_type] == SLICE_P || Slice_Type[avcSlcParams->slice_type] == SLICE_SP)
    {
        m_avcPar->PSliceQP     = avcPicParams->QpY + avcSlcParams->slice_qp_delta;
        m_avcPar->CabacInitIDC = avcSlcParams->cabac_init_idc;

        if (avcSlcParams->num_ref_idx_active_override_flag)
        {
            m_avcPar->MaxRefIdxL0 = MOS_MAX(m_avcPar->MaxRefIdxL0, avcSlcParams->num_ref_idx_l0_active_minus1);
            m_avcPar->MaxRefIdxL1 = MOS_MAX(m_avcPar->MaxRefIdxL1, avcSlcParams->num_ref_idx_l1_active_minus1);
        }
        else
        {
            m_avcPar->MaxRefIdxL0 = MOS_MAX(m_avcPar->MaxRefIdxL0, avcPicParams->num_ref_idx_l0_active_minus1);
            m_avcPar->MaxRefIdxL1 = MOS_MAX(m_avcPar->MaxRefIdxL1, avcPicParams->num_ref_idx_l1_active_minus1);
        }

        if (m_avcPar->NumB == 0)  // There's no B frame
        {
            m_avcPar->EnableWeightPredictionDetection = avcPicParams->weighted_pred_flag > 0 ? 1 : 0;
        }
        m_avcPar->WeightedPred    = avcPicParams->weighted_pred_flag;
        m_avcPar->UseOrigAsRef    = avcPicParams->UserFlags.bUseRawPicForRef;
        m_avcPar->BiSubMbPartMask = avcPicParams->UserFlags.bDisableSubMBPartition ? (bool)(CODECHAL_ENCODE_AVC_DISABLE_4X4_SUB_MB_PARTITION | CODECHAL_ENCODE_AVC_DISABLE_4X8_SUB_MB_PARTITION | CODECHAL_ENCODE_AVC_DISABLE_8X4_SUB_MB_PARTITION) : 0;

        if (m_vdencEnabled)
        {
            if (m_targetUsage == 1 || m_targetUsage == 2)
            {
                m_avcPar->StaticFrameZMVPercent = avcPicParams->dwZMvThreshold;
            }
            else
            {
                m_avcPar->StaticFrameZMVPercent = 100;
            }

            if (avcPicParams->bEnableHMEOffset)
            {
                m_avcPar->hme0XOffset = MOS_CLAMP_MIN_MAX(avcPicParams->HMEOffset[0][0][0], -128, 127);
                m_avcPar->hme0YOffset = MOS_CLAMP_MIN_MAX(avcPicParams->HMEOffset[0][0][1], -128, 127);
                m_avcPar->hme1XOffset = MOS_CLAMP_MIN_MAX(avcPicParams->HMEOffset[1][0][0], -128, 127);
                m_avcPar->hme1YOffset = MOS_CLAMP_MIN_MAX(avcPicParams->HMEOffset[1][0][1], -128, 127);
            }
        }
    }
    else if (Slice_Type[avcSlcParams->slice_type] == SLICE_B)
    {
        m_avcPar->BSliceQP = avcPicParams->QpY + avcSlcParams->slice_qp_delta;

        if (avcSlcParams->num_ref_idx_active_override_flag)
        {
            m_avcPar->MaxBRefIdxL0 = MOS_MAX(m_avcPar->MaxBRefIdxL0, avcSlcParams->num_ref_idx_l0_active_minus1);
        }
        else
        {
            m_avcPar->MaxBRefIdxL0 = MOS_MAX(m_avcPar->MaxBRefIdxL0, avcPicParams->num_ref_idx_l0_active_minus1);
        }

        m_avcPar->EnableWeightPredictionDetection = (avcPicParams->weighted_bipred_idc | avcPicParams->weighted_pred_flag) > 0 ? 1 : 0;
        m_avcPar->WeightedBiPred                  = avcPicParams->weighted_bipred_idc;
        m_avcPar->BiWeight                        = m_biWeight;
    }

    return MOS_STATUS_SUCCESS;
}

MOS_STATUS CodechalEncodeAvcBase::PopulateSliceStateParam(
    bool                       adaptiveRoundingInterEnable,
    PMHW_VDBOX_AVC_SLICE_STATE sliceState)
{
    CODECHAL_DEBUG_FUNCTION_ENTER;

    CODECHAL_DEBUG_CHK_NULL(m_debugInterface);

    if (!m_debugInterface->DumpIsEnabled(CodechalDbgAttr::attrDumpEncodePar))
    {
        return MOS_STATUS_SUCCESS;
    }

    if (m_pictureCodingType == I_TYPE)
    {
        m_avcPar->RoundingIntraEnabled = true;
        m_avcPar->RoundingIntra        = 5;
        // Set to 1 first, we don't consider 0 case as we only dump I frame param once
        m_avcPar->FrmHdrEncodingFrequency = 1;  // 1: picture header in every IDR frame

        // Search SEI NAL
        m_avcPar->EnableSEI = SearchNALHeader(sliceState, CODECHAL_DEBUG_ENCODE_AVC_NAL_START_CODE_SEI);
    }
    else if (m_pictureCodingType == P_TYPE)
    {
        m_avcPar->EnableAdaptiveRounding = adaptiveRoundingInterEnable;
        m_avcPar->RoundingInterEnabled   = sliceState->bRoundingInterEnable;
        m_avcPar->RoundingInter          = sliceState->dwRoundingValue;

        // Search PPS NAL
        m_avcPar->FrmHdrEncodingFrequency =
            SearchNALHeader(sliceState, CODECHAL_DEBUG_ENCODE_AVC_NAL_START_CODE_PPS) ? 2 : m_avcPar->FrmHdrEncodingFrequency;
    }
    else if (m_pictureCodingType == B_TYPE)
    {
        m_avcPar->RoundingInterB = sliceState->dwRoundingValue;
    }

    return MOS_STATUS_SUCCESS;
}

MOS_STATUS CodechalEncodeAvcBase::PopulateSfdParam(
    void *cmd)
{
    CODECHAL_DEBUG_FUNCTION_ENTER;

    CODECHAL_DEBUG_CHK_NULL(m_debugInterface);

    if (!m_debugInterface->DumpIsEnabled(CodechalDbgAttr::attrDumpEncodePar))
    {
        return MOS_STATUS_SUCCESS;
    }

    CODECHAL_ENCODE_AVC_SFD_CURBE_COMMON *curbe = (CODECHAL_ENCODE_AVC_SFD_CURBE_COMMON *)cmd;

    if (m_pictureCodingType == P_TYPE)
    {
        m_avcPar->EnableIntraCostScalingForStaticFrame = curbe->DW0.EnableIntraCostScalingForStaticFrame;
        m_avcPar->StaticFrameIntraCostScalingRatioP    = 240;
        m_avcPar->AdaptiveMvStreamIn                   = curbe->DW0.EnableAdaptiveMvStreamIn;
        m_avcPar->LargeMvThresh                        = curbe->DW3.LargeMvThresh;
        m_avcPar->LargeMvPctThreshold                  = 1;
    }

    return MOS_STATUS_SUCCESS;
}
#endif

MOS_STATUS CodechalEncodeAvcBase::SetFrameStoreIds(uint8_t frameIdx)
{
    uint8_t invalidFrame = (m_mode == CODECHAL_DECODE_MODE_AVCVLD) ? 0x7f : 0x1f;

    for (uint8_t i = 0; i < m_refList[frameIdx]->ucNumRef; i++)
    {
        uint8_t index;
        index = m_refList[frameIdx]->RefList[i].FrameIdx;
        if (m_refList[index]->ucFrameId == invalidFrame)
        {
            uint8_t j;
            for (j = 0; j < CODEC_AVC_MAX_NUM_REF_FRAME; j++)
            {
                if (!m_avcFrameStoreID[j].inUse)
                {
                    m_refList[index]->ucFrameId = j;
                    m_avcFrameStoreID[j].inUse  = true;
                    break;
                }
            }
            if (j == CODEC_AVC_MAX_NUM_REF_FRAME)
            {
                // should never happen, something must be wrong
                CODECHAL_PUBLIC_ASSERT(false);
                m_refList[index]->ucFrameId = 0;
                m_avcFrameStoreID[0].inUse  = true;
            }
        }
    }
    return MOS_STATUS_SUCCESS;
}

MOS_STATUS CodechalEncodeAvcBase::AddMfxAvcSlice(
    PMOS_COMMAND_BUFFER        cmdBuffer,
    PMHW_BATCH_BUFFER          batchBuffer,
    PMHW_VDBOX_AVC_SLICE_STATE avcSliceState)
{
    CODECHAL_ENCODE_FUNCTION_ENTER;

    CODECHAL_ENCODE_CHK_NULL_RETURN(m_mfxInterface);
    CODECHAL_ENCODE_CHK_STATUS_RETURN(m_mfxInterface->AddMfxAvcSlice(cmdBuffer, batchBuffer, avcSliceState));

    return MOS_STATUS_SUCCESS;
}

MOS_STATUS CodechalEncodeAvcBase::AddVdencSliceStateCmd(
    PMOS_COMMAND_BUFFER        cmdBuffer,
    PMHW_VDBOX_AVC_SLICE_STATE params)
{
    CODECHAL_ENCODE_FUNCTION_ENTER;

    CODECHAL_ENCODE_CHK_NULL_RETURN(m_vdencInterface);
    CODECHAL_ENCODE_CHK_STATUS_RETURN(m_vdencInterface->AddVdencSliceStateCmd(cmdBuffer, params));

    return MOS_STATUS_SUCCESS;
}
MOS_STATUS CodechalEncodeAvcBase::GetStatusReport(
    EncodeStatus* encodeStatus,
    EncodeStatusReport* encodeStatusReport)
{
    MOS_STATUS eStatus = MOS_STATUS_SUCCESS;

    encodeStatusReport->CodecStatus = CODECHAL_STATUS_SUCCESSFUL;
    encodeStatusReport->bitstreamSize =
        encodeStatus->dwMFCBitstreamByteCountPerFrame + encodeStatus->dwHeaderBytesInserted;

    // dwHeaderBytesInserted is for WAAVCSWHeaderInsertion
    // and is 0 otherwise
    encodeStatusReport->QpY = encodeStatus->BrcQPReport.DW0.QPPrimeY;
    encodeStatusReport->SuggestedQpYDelta =
        encodeStatus->ImageStatusCtrl.CumulativeSliceDeltaQP;
    encodeStatusReport->NumberPasses = (uint8_t)encodeStatus->dwNumberPasses;
    ENCODE_VERBOSEMESSAGE("statusReportData->numberPasses: %d\n", encodeStatusReport->NumberPasses);
    encodeStatusReport->SceneChangeDetected =
        (encodeStatus->dwSceneChangedFlag & CODECHAL_ENCODE_SCENE_CHANGE_DETECTED_MASK) ? 1 : 0;

    CODECHAL_ENCODE_CHK_NULL_RETURN(m_skuTable);

    if (m_picWidthInMb != 0 && m_frameFieldHeightInMb != 0)
    {
        encodeStatusReport->AverageQp = (unsigned char)(((uint32_t)encodeStatus->QpStatusCount.cumulativeQP) / (m_picWidthInMb * m_frameFieldHeightInMb));
    }
    encodeStatusReport->PanicMode = encodeStatus->ImageStatusCtrl.Panic;

    // If Num slices is greater than spec limit set NumSlicesNonCompliant to 1 and report error
    PMHW_VDBOX_PAK_NUM_OF_SLICES numSlices = &encodeStatus->NumSlices;
    if (numSlices->NumberOfSlices > m_maxNumSlicesAllowed)
    {
        encodeStatusReport->NumSlicesNonCompliant = 1;
    }
    encodeStatusReport->NumberSlices = numSlices->NumberOfSlices;

    return eStatus;
}