/*
* Copyright (c) 2017-2018, 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_jpeg.cpp
//! \brief    Defines state class for JPEG encoder.
//!

#include "codechal_encode_jpeg.h"
#if USE_CODECHAL_DEBUG_TOOL
#include "codechal_debug.h"
#endif

MOS_STATUS CodechalEncodeJpegState::Initialize(CodechalSetting  *settings)
{
    MOS_STATUS eStatus = MOS_STATUS_SUCCESS;

    CODECHAL_ENCODE_FUNCTION_ENTER;

    CODECHAL_ENCODE_CHK_NULL_RETURN(m_osInterface);
    CODECHAL_ENCODE_CHK_NULL_RETURN(m_miInterface);
    CODECHAL_ENCODE_CHK_NULL_RETURN(settings);

    CODECHAL_ENCODE_CHK_STATUS_RETURN(CodechalEncoderState::Initialize(settings));

    // Picture Level Commands
    CODECHAL_ENCODE_CHK_STATUS_RETURN(
        m_hwInterface->GetMfxStateCommandsDataSize(
            CODECHAL_ENCODE_MODE_JPEG,
            &m_pictureStatesSize,
            &m_picturePatchListSize,
            0));

    // Slice Level Commands (cannot be placed in 2nd level batch)
    CODECHAL_ENCODE_CHK_STATUS_RETURN(
        m_hwInterface->GetMfxPrimitiveCommandsDataSize(
            CODECHAL_ENCODE_MODE_JPEG,
            &m_sliceStatesSize,
            &m_slicePatchListSize,
            0));

    return eStatus;
}

MOS_STATUS CodechalEncodeJpegState::AllocateResources()
{
    MOS_STATUS eStatus = MOS_STATUS_SUCCESS;

    CODECHAL_ENCODE_FUNCTION_ENTER;

    CODECHAL_ENCODE_CHK_STATUS_RETURN(CodechalEncoderState::AllocateResources());

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

    return eStatus;
}

void CodechalEncodeJpegState::FreeResources()
{
    CODECHAL_ENCODE_FUNCTION_ENTER;

    CodechalEncoderState::FreeResources();

    // Release Ref Lists
    CodecHalFreeDataList(m_refList, CODECHAL_NUM_UNCOMPRESSED_SURFACE_JPEG);
}

MOS_STATUS CodechalEncodeJpegState::InitializePicture(const EncoderParams& params)
{
    MOS_STATUS eStatus = MOS_STATUS_SUCCESS;

    CODECHAL_ENCODE_FUNCTION_ENTER;

    m_bitstreamUpperBound = params.dwBitstreamSize;

    m_jpegPicParams         = (CodecEncodeJpegPictureParams *)(params.pPicParams);
    m_jpegScanParams        = (CodecEncodeJpegScanHeader *)(params.pSliceParams);
    m_jpegQuantTables       = (CodecEncodeJpegQuantTable *)(params.pQuantizationTable);
    m_jpegHuffmanTable      = (CodecEncodeJpegHuffmanDataArray *)(params.pHuffmanTable);
    m_applicationData       = params.pApplicationData;
    m_appDataSize           = params.dwAppDataSize;
    m_jpegQuantMatrixSent   = params.bJpegQuantMatrixSent;
    m_fullHeaderInAppData   = params.fullHeaderInAppData;

    CODECHAL_ENCODE_CHK_NULL_RETURN(m_jpegPicParams);
    CODECHAL_ENCODE_CHK_NULL_RETURN(m_jpegScanParams);
    CODECHAL_ENCODE_CHK_NULL_RETURN(m_jpegQuantTables);
    CODECHAL_ENCODE_CHK_NULL_RETURN(m_jpegHuffmanTable);

    // Set Status Report Feedback Number
    m_statusReportFeedbackNumber = m_jpegPicParams->m_statusReportFeedbackNumber;
    m_currRefList                = m_refList[m_currOriginalPic.FrameIdx];

    CODECHAL_ENCODE_CHK_STATUS_RETURN(SetStatusReportParams(m_refList[m_currOriginalPic.FrameIdx]));

    m_currRefList->resBitstreamBuffer = m_resBitstreamBuffer;
    m_currRefList->sRefRawBuffer      = m_rawSurface;

    CODECHAL_DEBUG_TOOL(
        CODECHAL_ENCODE_CHK_NULL_RETURN(m_debugInterface);

         if (m_jpegPicParams)
        {
            CODECHAL_ENCODE_CHK_STATUS_RETURN(DumpPicParams(
                m_jpegPicParams));
        }

        if (m_jpegScanParams)
        {
            CODECHAL_ENCODE_CHK_STATUS_RETURN(DumpScanParams(
                m_jpegScanParams));
        }

        if (m_jpegHuffmanTable)
        {
            CODECHAL_ENCODE_CHK_STATUS_RETURN(DumpHuffmanTable(
                m_jpegHuffmanTable));
        }

        if (m_jpegQuantTables)
        {
            CODECHAL_ENCODE_CHK_STATUS_RETURN(DumpQuantTables(
                m_jpegQuantTables));
        }
    )

    return eStatus;
}

MOS_STATUS CodechalEncodeJpegState::CheckResChangeAndCsc()
{
    return MOS_STATUS_SUCCESS;
}

// Implemented based on table K.5 in JPEG spec
uint8_t CodechalEncodeJpegState::MapHuffValIndex(uint8_t huffValIndex)
{
    CODECHAL_ENCODE_FUNCTION_ENTER;

    uint8_t mappedIndex = 0;

    if (huffValIndex < 0xF0)
    {
        mappedIndex = (((huffValIndex >> 4) & 0x0F) * 0xA) + (huffValIndex & 0x0F);
    }
    else
    {
        mappedIndex = (((huffValIndex >> 4) & 0x0F) * 0xA) + (huffValIndex & 0x0F) + 1;
    }

    return mappedIndex;
}

// Implemented based on Flowchart in figure C.1 in JPEG spec
MOS_STATUS CodechalEncodeJpegState::GenerateSizeTable(
    uint8_t     bits[],
    uint8_t     huffSize[],
    uint8_t&    lastK)
{
    CODECHAL_ENCODE_FUNCTION_ENTER;

    MOS_STATUS eStatus = MOS_STATUS_SUCCESS;

    uint8_t i = 1, j = 1;
    uint8_t k = 0;
    while (i <= 16)
    {
        while (j <= (int8_t)bits[i - 1]) // bits index is from 0 to 15
        {
            huffSize[k] = i;
            k = k + 1;
            j = j + 1;
        }

        i++;
        j = 1;
    };

    huffSize[k] = 0;
    lastK = k;

    return eStatus;
}

// Implemented based on Flowchart in figure C.2 in JPEG spec
MOS_STATUS CodechalEncodeJpegState::GenerateCodeTable(
    uint8_t     huffSize[],
    uint16_t    huffCode[])
{
    CODECHAL_ENCODE_FUNCTION_ENTER;

    MOS_STATUS eStatus = MOS_STATUS_SUCCESS;

    uint8_t    k = 0;
    uint8_t    si = huffSize[0];
    uint16_t   code = 0;
    while (huffSize[k] != 0)
    {
        while (huffSize[k] == si)
        {
            if (code == 0xFFFF)
            {
                // Invalid code generated - replace with all zeroes
                code = 0x0000;
            }

            huffCode[k] = code;
            code = code + 1;
            k = k + 1;
        };

        code <<= 1;
        si = si + 1;
    }

    return eStatus;
}

// Implemented based on Flowchart in figure C.3 in JPEG spec
MOS_STATUS CodechalEncodeJpegState::OrderCodes(
    uint8_t     huffVal[],
    uint8_t     huffSize[],
    uint16_t    huffCode[],
    uint8_t     lastK)
{
    CODECHAL_ENCODE_FUNCTION_ENTER;

    MOS_STATUS eStatus = MOS_STATUS_SUCCESS;

    uint16_t eHuffCo[JPEG_NUM_HUFF_TABLE_AC_HUFFVAL];
    uint8_t  eHuffSi[JPEG_NUM_HUFF_TABLE_AC_HUFFVAL];
    MOS_ZeroMemory(&eHuffCo[0], JPEG_NUM_HUFF_TABLE_AC_HUFFVAL * sizeof(uint16_t));
    MOS_ZeroMemory(&eHuffSi[0], JPEG_NUM_HUFF_TABLE_AC_HUFFVAL * sizeof(uint8_t));

    uint8_t k = 0;
    do
    {
        uint8_t i = MapHuffValIndex((uint8_t)huffVal[k]);
        if (i >= JPEG_NUM_HUFF_TABLE_AC_HUFFVAL)
        {
            CODECHAL_ENCODE_ASSERT(false);
            return MOS_STATUS_UNKNOWN;
        }
        eHuffCo[i] = huffCode[k];
        eHuffSi[i] = huffSize[k];
        k++;
    } while (k < lastK);

    // copy over the first 162 values of reordered arrays to Huffman Code and size arrays
    CODECHAL_ENCODE_CHK_STATUS_RETURN(MOS_SecureMemcpy(&huffCode[0], JPEG_NUM_HUFF_TABLE_AC_HUFFVAL * sizeof(uint16_t), &eHuffCo[0], JPEG_NUM_HUFF_TABLE_AC_HUFFVAL * sizeof(uint16_t)));
    CODECHAL_ENCODE_CHK_STATUS_RETURN(MOS_SecureMemcpy(&huffSize[0], JPEG_NUM_HUFF_TABLE_AC_HUFFVAL * sizeof(uint8_t), &eHuffSi[0], JPEG_NUM_HUFF_TABLE_AC_HUFFVAL * sizeof(uint8_t)));

    return eStatus;
}

MOS_STATUS CodechalEncodeJpegState::ConvertHuffDataToTable(
    CodecEncodeJpegHuffData             huffmanData,
    CodechalEncodeJpegHuffTable         *huffmanTable)
{
    CODECHAL_ENCODE_FUNCTION_ENTER;

    MOS_STATUS eStatus = MOS_STATUS_SUCCESS;

    huffmanTable->m_tableClass = huffmanData.m_tableClass;
    huffmanTable->m_tableID    = huffmanData.m_tableID;

    uint8_t lastK = 0;

    // Step 1 : Generate size table
    CODECHAL_ENCODE_CHK_STATUS_RETURN(GenerateSizeTable(huffmanData.m_bits, huffmanTable->m_huffSize, lastK));

    // Step2: Generate code table
    CODECHAL_ENCODE_CHK_STATUS_RETURN(GenerateCodeTable(huffmanTable->m_huffSize, huffmanTable->m_huffCode));

    // Step 3: Order codes
    CODECHAL_ENCODE_CHK_STATUS_RETURN(OrderCodes(huffmanData.m_huffVal, huffmanTable->m_huffSize, huffmanTable->m_huffCode, lastK));

    return eStatus;
}

MOS_STATUS CodechalEncodeJpegState::PackSOI(BSBuffer *buffer)
{
    CODECHAL_ENCODE_FUNCTION_ENTER;

    MOS_STATUS eStatus = MOS_STATUS_SUCCESS;

    CODECHAL_ENCODE_CHK_NULL_RETURN(buffer);
    // Add SOI = 0xFFD8
    buffer->pBase = (uint8_t*)MOS_AllocAndZeroMemory(2);
    CODECHAL_ENCODE_CHK_NULL_RETURN(buffer->pBase);

    *(buffer->pBase)     = (m_jpegEncodeSoi >> 8) & 0xFF;
    *(buffer->pBase + 1) = (m_jpegEncodeSoi & 0xFF);
    buffer->BitOffset    = 0;
    buffer->BufferSize   = 16;

    return eStatus;
}

MOS_STATUS CodechalEncodeJpegState::PackApplicationData(
    BSBuffer                        *buffer,
    uint8_t                         *appDataChunk,
    uint32_t                           size)
{
    CODECHAL_ENCODE_FUNCTION_ENTER;

    MOS_STATUS eStatus = MOS_STATUS_SUCCESS;

    CODECHAL_ENCODE_CHK_NULL_RETURN(appDataChunk);

    buffer->pBase        = appDataChunk;
    buffer->BitOffset    = 0;
    buffer->BufferSize   = (size * sizeof(uint8_t) * 8);

    return eStatus;
}

MOS_STATUS CodechalEncodeJpegState::PackFrameHeader(
    BSBuffer                        *buffer,
    bool                            useSingleDefaultQuantTable)
{
    CODECHAL_ENCODE_FUNCTION_ENTER;

    MOS_STATUS eStatus = MOS_STATUS_SUCCESS;

    CodechalEncodeJpegFrameHeader *frameHeader = (CodechalEncodeJpegFrameHeader *)MOS_AllocAndZeroMemory(sizeof(CodechalEncodeJpegFrameHeader));
    CODECHAL_ENCODE_CHK_NULL_RETURN(frameHeader);

    frameHeader->m_sof   = 0xC0FF;
    frameHeader->m_nf    = (uint8_t)m_jpegPicParams->m_numComponent;

    // Calculate lf - switch btes to match with simulation
    uint16_t value = 8 + (3 * frameHeader->m_nf); // does not include sof
    frameHeader->m_lf    = ((value & 0xFF) << 8) | ((value & 0xFF00) >> 8);

    frameHeader->m_p     = 8;
    frameHeader->m_y     = ((m_jpegPicParams->m_picHeight & 0xFF) << 8) | ((m_jpegPicParams->m_picHeight & 0xFF00) >> 8);
    frameHeader->m_x     = ((m_jpegPicParams->m_picWidth & 0xFF) << 8) | ((m_jpegPicParams->m_picWidth & 0xFF00) >> 8);

    for (uint8_t i = 0; i < frameHeader->m_nf; i++)
    {
        frameHeader->m_codechalJpegFrameComponent[i].m_ci = (uint8_t)m_jpegPicParams->m_componentID[i];

        if (useSingleDefaultQuantTable)
        {
            frameHeader->m_codechalJpegFrameComponent[i].m_tqi = 0; // 0/1/2 based on Y/U/V
        }
        else
        {
            frameHeader->m_codechalJpegFrameComponent[i].m_tqi = i; // 0/1/2 based on Y/U/V
        }

        // For all supported formats on JPEG encode, U and V vertical and horizontal sampling is 1
        uint32_t horizontalSamplingFactor = 0, verticalSamplingFactor = 0;
        if (i == 0)
        {
            horizontalSamplingFactor    = m_mfxInterface->GetJpegHorizontalSamplingFactorForY((CodecEncodeJpegInputSurfaceFormat)m_jpegPicParams->m_inputSurfaceFormat);
            verticalSamplingFactor      = m_mfxInterface->GetJpegVerticalSamplingFactorForY((CodecEncodeJpegInputSurfaceFormat)m_jpegPicParams->m_inputSurfaceFormat);
        }
        else
        {
            horizontalSamplingFactor    = 1;
            verticalSamplingFactor      = 1;
        }

        frameHeader->m_codechalJpegFrameComponent[i].m_samplingFactori = 0;
        frameHeader->m_codechalJpegFrameComponent[i].m_samplingFactori = ((horizontalSamplingFactor & 0xF) << 4) | (verticalSamplingFactor & 0xF);
    }

    buffer->pBase        = (uint8_t*)frameHeader;
    buffer->BitOffset    = 0;
    buffer->BufferSize   = (2 * sizeof(uint8_t) * 8) + (4 * sizeof(uint16_t) * 8) + (sizeof(frameHeader->m_codechalJpegFrameComponent[0]) * 8 * m_jpegPicParams->m_numComponent);

    return eStatus;
}

MOS_STATUS CodechalEncodeJpegState::PackHuffmanTable(
    BSBuffer                        *buffer,
    uint32_t                        tableIndex)
{
    CODECHAL_ENCODE_FUNCTION_ENTER;

    MOS_STATUS eStatus = MOS_STATUS_SUCCESS;

    CodechalJpegHuffmanHeader *huffmanHeader = (CodechalJpegHuffmanHeader *)MOS_AllocAndZeroMemory(sizeof(CodechalJpegHuffmanHeader));
    CODECHAL_ENCODE_CHK_NULL_RETURN(huffmanHeader);

    huffmanHeader->m_dht = 0xC4FF;
    huffmanHeader->m_tableClassAndDestn =
        ((m_jpegHuffmanTable->m_huffmanData[tableIndex].m_tableClass & 0xF) << 4) | ((tableIndex / 2) & 0xF);

    uint16_t totalHuffValues = 0;
    for (auto i = 0; i < JPEG_NUM_HUFF_TABLE_AC_BITS; i++)
    {
        huffmanHeader->m_li[i] = (uint8_t)m_jpegHuffmanTable->m_huffmanData[tableIndex].m_bits[i];
        totalHuffValues += huffmanHeader->m_li[i];
    }

    uint16_t hdrSize = 19 + totalHuffValues;
    huffmanHeader->m_lh = ((hdrSize & 0xFF) << 8) | ((hdrSize & 0xFF00) >> 8);

    for (auto i = 0; i < totalHuffValues; i++)
    {
        huffmanHeader->m_vij[i] = (uint8_t)m_jpegHuffmanTable->m_huffmanData[tableIndex].m_huffVal[i];
    }

    buffer->pBase = (uint8_t*)huffmanHeader;
    buffer->BitOffset = 0;
    buffer->BufferSize = (2 * sizeof(uint16_t) * 8) + (sizeof(uint8_t) * 8) + (JPEG_NUM_HUFF_TABLE_AC_BITS * 8) + (totalHuffValues * sizeof(uint8_t) * 8);

    return eStatus;
}

MOS_STATUS CodechalEncodeJpegState::PackQuantTable(
    BSBuffer                        *buffer,
    CodecJpegComponents             componentType)
{
    CODECHAL_ENCODE_FUNCTION_ENTER;

    MOS_STATUS eStatus = MOS_STATUS_SUCCESS;

    CodechalEncodeJpegQuantHeader *quantHeader = (CodechalEncodeJpegQuantHeader *)MOS_AllocAndZeroMemory(sizeof(CodechalEncodeJpegQuantHeader));
    CODECHAL_ENCODE_CHK_NULL_RETURN(quantHeader);

    quantHeader->m_dqt = 0xDBFF;
    // Header size including marker
    uint16_t hdrSize = sizeof(uint16_t) * 2 + sizeof(uint8_t) + sizeof(uint8_t) * JPEG_NUM_QUANTMATRIX;
    quantHeader->m_lq = (((hdrSize - 2) & 0xFF) << 8) | (((hdrSize - 2) & 0xFF00) >> 8);
    quantHeader->m_tablePrecisionAndDestination
        = ((m_jpegQuantTables->m_quantTable[componentType].m_precision & 0xF) << 4)
        | (componentType & 0xF);

    for (auto i = 0; i < JPEG_NUM_QUANTMATRIX; i++)
    {
        quantHeader->m_qk[i] = (uint8_t)m_jpegQuantTables->m_quantTable[componentType].m_qm[i];
    }

    buffer->pBase        = (uint8_t*)quantHeader;
    buffer->BitOffset    = 0;
    buffer->BufferSize   = hdrSize * 8;

    return eStatus;
}

MOS_STATUS CodechalEncodeJpegState::PackRestartInterval(
    BSBuffer                        *buffer)
{
    CODECHAL_ENCODE_FUNCTION_ENTER;

    MOS_STATUS eStatus = MOS_STATUS_SUCCESS;

    CodechalEncodeJpegRestartHeader *restartHeader = (CodechalEncodeJpegRestartHeader *)MOS_AllocAndZeroMemory(sizeof(CodechalEncodeJpegRestartHeader));
    CODECHAL_ENCODE_CHK_NULL_RETURN(restartHeader);

    restartHeader->m_dri = 0xDDFF;
    uint16_t hdrSize  = sizeof(uint16_t) * 3;
    restartHeader->m_lr  = (((hdrSize - 2) & 0xFF) << 8) | (((hdrSize - 2) & 0xFF00) >> 8);
    restartHeader->m_ri  = (uint16_t)(((m_jpegScanParams->m_restartInterval & 0xFF) << 8) |
        ((m_jpegScanParams->m_restartInterval & 0xFF00) >> 8));

    buffer->pBase        = (uint8_t*)restartHeader;
    buffer->BitOffset    = 0;
    buffer->BufferSize   = hdrSize * 8;

    return eStatus;
}

MOS_STATUS CodechalEncodeJpegState::PackScanHeader(
    BSBuffer                        *buffer)
{
    CODECHAL_ENCODE_FUNCTION_ENTER;

    MOS_STATUS eStatus = MOS_STATUS_SUCCESS;

    // Size of Scan header in bytes = sos (2 bytes) + ls (2 bytes) + ns (1 byte)
    // + ss (1 byte) + se (1 byte) + ahl (1 byte) + scanComponent (2 bytes) * Number of scan components
    uint16_t hdrSize = 8 + 2 * m_jpegPicParams->m_numComponent;

    uint8_t *scanHeader = (uint8_t*)MOS_AllocAndZeroMemory(hdrSize);
    CODECHAL_ENCODE_CHK_NULL_RETURN(scanHeader);

    buffer->pBase = (uint8_t*)scanHeader;

    // scanHeader->sos
    *scanHeader = (m_jpegEncodeSos >> 8) & 0xFF;
    scanHeader += 1;
    *scanHeader = (m_jpegEncodeSos & 0xFF);
    scanHeader += 1;

    // scanHeader->ls
    *scanHeader = ((hdrSize - 2) >> 8) & 0xFF;
    scanHeader += 1;
    *scanHeader = (hdrSize - 2) & 0xFF;
    scanHeader += 1;

    // scanHeader->ns
    *scanHeader = (uint8_t)m_jpegPicParams->m_numComponent;
    scanHeader += 1;

    for (uint32_t j = 0; j < m_jpegPicParams->m_numComponent; j++)
    {
        *scanHeader = (uint8_t)m_jpegPicParams->m_componentID[j];
        scanHeader += 1;

        // For Y8 image format there is only one scan component, so scanComponent[1] and scanComponent[2] should not be added to the header
        // scanHeader->scanComponent[j].Tdaj
        if (j == 0)
        {
            *scanHeader = (uint8_t)(((m_jpegHuffmanTable->m_huffmanData[0].m_tableID & 0x0F) << 4)
                | ((m_jpegHuffmanTable->m_huffmanData[1].m_tableID & 0x0F)));
            scanHeader += 1;
        }
        else
        {
            *scanHeader = (uint8_t)(((m_jpegHuffmanTable->m_huffmanData[2].m_tableID & 0x0F) << 4)
                | ((m_jpegHuffmanTable->m_huffmanData[3].m_tableID & 0x0F)));
            scanHeader += 1;
        }

    }

    // scanHeader->ss
    *scanHeader = 0;
    scanHeader += 1;
    // scanHeader->se
    *scanHeader = 63;
    scanHeader += 1;
    // scanHeader->ahl
    *scanHeader = 0;
    scanHeader += 1;

    buffer->BitOffset = 0;
    // Buffer size in bits
    buffer->BufferSize = hdrSize * 8;

    return eStatus;
}

MOS_STATUS CodechalEncodeJpegState::ExecutePictureLevel()
{
    MOS_STATUS eStatus = MOS_STATUS_SUCCESS;

    CODECHAL_ENCODE_FUNCTION_ENTER;

    PerfTagSetting perfTag;
    CODECHAL_ENCODE_SET_PERFTAG_INFO(perfTag, CODECHAL_ENCODE_PERFTAG_CALL_PAK_ENGINE);

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

    m_mode = CODECHAL_ENCODE_MODE_JPEG;

    // set MFX_PIPE_MODE_SELECT
    MHW_VDBOX_PIPE_MODE_SELECT_PARAMS pipeModeSelectParams;
    pipeModeSelectParams.Mode                   = m_mode;
    pipeModeSelectParams.bStreamOutEnabled      = false;
    pipeModeSelectParams.bShortFormatInUse      = false;
    pipeModeSelectParams.bPreDeblockOutEnable   = false;
    pipeModeSelectParams.bPostDeblockOutEnable  = false;

    // set MFX_SURFACE_STATE
    MHW_VDBOX_SURFACE_PARAMS surfaceParams;
    MOS_ZeroMemory(&surfaceParams, sizeof(surfaceParams));
    surfaceParams.Mode      = m_mode;
    surfaceParams.psSurface = &m_rawSurface; // original picture to be encoded
    surfaceParams.ucSurfaceStateId = CODECHAL_MFX_SRC_SURFACE_ID;

    // set MFX_PIPE_BUF_ADDR_STATE
    MHW_VDBOX_PIPE_BUF_ADDR_PARAMS pipeBufAddrParams;
    pipeBufAddrParams.Mode          = m_mode;
    pipeBufAddrParams.psRawSurface  = &m_rawSurface; // original picture to be encoded
    pipeBufAddrParams.pRawSurfParam = &surfaceParams;

    CODECHAL_ENCODE_CHK_NULL_RETURN(m_mmcState);
    CODECHAL_ENCODE_CHK_STATUS_RETURN(m_mmcState->SetPipeBufAddr(&pipeBufAddrParams, &cmdBuffer));

    CODECHAL_DEBUG_TOOL(
        CODECHAL_ENCODE_CHK_STATUS_RETURN(m_debugInterface->DumpYUVSurface(
            &m_rawSurface,
            CodechalDbgAttr::attrEncodeRawInputSurface,
            "SrcSurf"))
    );

    // No references for JPEG
    // Setting invalid entries to nullptr
    for (auto i = 0; i < CODEC_MAX_NUM_REF_FRAME; i++)
    {
        pipeBufAddrParams.presReferences[i] = nullptr;
    }

    // set MFX_IND_OBJ_BASE_ADDR_STATE
    MHW_VDBOX_IND_OBJ_BASE_ADDR_PARAMS indObjBaseAddrParams;
    MOS_ZeroMemory(&indObjBaseAddrParams, sizeof(indObjBaseAddrParams));
    indObjBaseAddrParams.Mode                       = m_mode;
    indObjBaseAddrParams.presPakBaseObjectBuffer    = &m_resBitstreamBuffer;
    indObjBaseAddrParams.dwPakBaseObjectSize        = m_bitstreamUpperBound;

    // set MFX_JPEG_PIC_STATE
    MhwVdboxJpegEncodePicState jpegPicState;
    MOS_ZeroMemory(&jpegPicState, sizeof(jpegPicState));
    jpegPicState.pJpegEncodePicParams   = m_jpegPicParams;
    jpegPicState.mode                   = m_mode;

    // Send command buffer header at the beginning (OS dependent)
    CODECHAL_ENCODE_CHK_STATUS_RETURN(SendPrologWithFrameTracking(&cmdBuffer, true));

    CODECHAL_ENCODE_CHK_STATUS_RETURN(StartStatusReport(&cmdBuffer, CODECHAL_NUM_MEDIA_STATES));

    CODECHAL_ENCODE_CHK_STATUS_RETURN(m_mfxInterface->AddMfxPipeModeSelectCmd(&cmdBuffer, &pipeModeSelectParams));

    CODECHAL_ENCODE_CHK_STATUS_RETURN(m_mfxInterface->AddMfxSurfaceCmd(&cmdBuffer, &surfaceParams));

    CODECHAL_ENCODE_CHK_STATUS_RETURN(m_mfxInterface->AddMfxPipeBufAddrCmd(&cmdBuffer, &pipeBufAddrParams));

    CODECHAL_ENCODE_CHK_STATUS_RETURN(m_mfxInterface->AddMfxIndObjBaseAddrCmd(&cmdBuffer, &indObjBaseAddrParams));

    CODECHAL_ENCODE_CHK_STATUS_RETURN(m_mfxInterface->AddMfxJpegEncodePicStateCmd(&cmdBuffer, &jpegPicState));

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

    return eStatus;
}

MOS_STATUS CodechalEncodeJpegState::ExecuteSliceLevel()
{
    MOS_STATUS eStatus = MOS_STATUS_SUCCESS;

    CODECHAL_ENCODE_FUNCTION_ENTER;

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

    if (m_encodeParams.dwNumSlices != 1)
    {
        CODECHAL_ENCODE_ASSERTMESSAGE("JPEG encode only one scan is supported.");
    }

    MOS_SURFACE *surface = &m_rawSurface;

    bool useSingleDefaultQuantTable = (m_jpegQuantMatrixSent == false &&
                                       ((surface->Format == Format_A8R8G8B8) ||
                                        (surface->Format == Format_X8R8G8B8) ||
                                        (surface->Format == Format_A8B8G8R8) ||
                                        (surface->Format == Format_X8B8G8R8)));

    CodecJpegQuantMatrix *tempJpegQuantMatrix = (CodecJpegQuantMatrix *)MOS_AllocAndZeroMemory(sizeof(CodecJpegQuantMatrix));
    CODECHAL_ENCODE_CHK_NULL_RETURN(tempJpegQuantMatrix);

    static_assert(JPEG_MAX_NUM_QUANT_TABLE_INDEX <= JPEG_MAX_NUM_OF_QUANTMATRIX,
        "access to CodecJpegQuantMatrix is controlled by numQuantTables");

    uint32_t numQuantTables = JPEG_MAX_NUM_QUANT_TABLE_INDEX;
    for (uint32_t scanCount = 0; scanCount < m_encodeParams.dwNumSlices; scanCount++)
    {
        MHW_VDBOX_QM_PARAMS fqmParams;
        MOS_ZeroMemory(&fqmParams, sizeof(fqmParams));

        // set MFX_FQM_STATE
        fqmParams.pJpegQuantMatrix = tempJpegQuantMatrix;

        // For monochrome inputs there will be only 1 quantization table and huffman table sent
        if (m_jpegPicParams->m_inputSurfaceFormat == codechalJpegY8)
        {
            numQuantTables = 1;
            m_encodeParams.dwNumHuffBuffers = 2; //for Y8 only 2 huff tables
        }
        // If there is only 1 quantization table copy over the table to 2nd and 3rd table in JPEG state (used for frame header)
        // OR For RGB input surfaces, if the app does not send quantization tables, then use luma quant table for all 3 components
        else if (m_jpegPicParams->m_numQuantTable == 1 || useSingleDefaultQuantTable)
        {
            for (auto i = 1; i < JPEG_MAX_NUM_QUANT_TABLE_INDEX; i++)
            {
                m_jpegQuantTables->m_quantTable[i].m_precision = m_jpegQuantTables->m_quantTable[0].m_precision;
                m_jpegQuantTables->m_quantTable[i].m_tableID = m_jpegQuantTables->m_quantTable[0].m_tableID;

                eStatus = MOS_SecureMemcpy(&m_jpegQuantTables->m_quantTable[i].m_qm[0], JPEG_NUM_QUANTMATRIX * sizeof(uint16_t),
                    &m_jpegQuantTables->m_quantTable[0].m_qm[0], JPEG_NUM_QUANTMATRIX * sizeof(uint16_t));
                if (eStatus != MOS_STATUS_SUCCESS)
                {
                    CODECHAL_ENCODE_ASSERTMESSAGE("Failed to copy memory.");
                    MOS_SafeFreeMemory(tempJpegQuantMatrix);
                    return eStatus;
                }
            }
        }
        // If there are 2 quantization tables copy over the second table to 3rd table in JPEG state since U and V share the same table (used for frame header)
        else if (m_jpegPicParams->m_numQuantTable == 2)
        {
            m_jpegQuantTables->m_quantTable[2].m_precision    = m_jpegQuantTables->m_quantTable[1].m_precision;
            m_jpegQuantTables->m_quantTable[2].m_tableID      = m_jpegQuantTables->m_quantTable[1].m_tableID;

            eStatus = MOS_SecureMemcpy(&m_jpegQuantTables->m_quantTable[2].m_qm[0], JPEG_NUM_QUANTMATRIX * sizeof(uint16_t),
                &m_jpegQuantTables->m_quantTable[1].m_qm[0], JPEG_NUM_QUANTMATRIX * sizeof(uint16_t));
            if (eStatus != MOS_STATUS_SUCCESS)
            {
                CODECHAL_ENCODE_ASSERTMESSAGE("Failed to copy memory.");
                MOS_SafeFreeMemory(tempJpegQuantMatrix);
                return eStatus;
            }

        }
        // else 3 quantization tables are sent by the application for non monochrome input formats. In that case, do nothing.

        for (uint32_t i = 0; i < numQuantTables; i++)
        {
            fqmParams.pJpegQuantMatrix->m_jpegQMTableType[i] = m_jpegQuantTables->m_quantTable[i].m_tableID; // Used to distinguish between Y,U,V quantization tables for the same scan

            for (auto j = 0; j < JPEG_NUM_QUANTMATRIX; j++)
            {
                uint32_t k = jpeg_qm_scan_8x8[j];

                // copy over Quant matrix in raster order from zig zag
                fqmParams.pJpegQuantMatrix->m_quantMatrix[i][k] = (uint8_t)m_jpegQuantTables->m_quantTable[i].m_qm[j];
            }
        }

        eStatus = (MOS_STATUS) m_mfxInterface->AddMfxJpegFqmCmd(&cmdBuffer, &fqmParams, numQuantTables);
        if (eStatus != MOS_STATUS_SUCCESS)
        {
            MOS_SafeFreeMemory(tempJpegQuantMatrix);
            CODECHAL_ENCODE_CHK_STATUS_RETURN(eStatus);
        }

        // set MFC_JPEG_HUFF_TABLE - Convert encoded huffman table to actual table for HW
        // We need a different params struct for JPEG Encode Huffman table because JPEG decode huffman table has Bits and codes,
        // whereas JPEG encode huffman table has huffman code lengths and values
        MHW_VDBOX_ENCODE_HUFF_TABLE_PARAMS huffTableParams[JPEG_MAX_NUM_HUFF_TABLE_INDEX] = {};
        for (uint32_t i = 0; i < m_encodeParams.dwNumHuffBuffers; i++)
        {
            CodechalEncodeJpegHuffTable huffmanTable;// intermediate table for each AC/DC component which will be copied to huffTableParams
            MOS_ZeroMemory(&huffmanTable, sizeof(huffmanTable));

            eStatus = (MOS_STATUS) ConvertHuffDataToTable(m_jpegHuffmanTable->m_huffmanData[i], &huffmanTable);
            if (eStatus != MOS_STATUS_SUCCESS)
            {
                MOS_SafeFreeMemory(tempJpegQuantMatrix);
                CODECHAL_ENCODE_CHK_STATUS_RETURN(eStatus);
            }

            huffTableParams[m_jpegHuffmanTable->m_huffmanData[i].m_tableID].HuffTableID = m_jpegHuffmanTable->m_huffmanData[i].m_tableID;

            if (m_jpegHuffmanTable->m_huffmanData[i].m_tableClass == 0) // DC table
            {
                eStatus = (MOS_STATUS) MOS_SecureMemcpy(
                    huffTableParams[m_jpegHuffmanTable->m_huffmanData[i].m_tableID].pDCCodeValues,
                    JPEG_NUM_HUFF_TABLE_DC_HUFFVAL * sizeof(uint16_t),
                    &huffmanTable.m_huffCode,
                    JPEG_NUM_HUFF_TABLE_DC_HUFFVAL * sizeof(uint16_t));
                if (eStatus != MOS_STATUS_SUCCESS)
                {
                    MOS_SafeFreeMemory(tempJpegQuantMatrix);
                    CODECHAL_ENCODE_CHK_STATUS_RETURN(eStatus);
                }

                eStatus = (MOS_STATUS) MOS_SecureMemcpy(huffTableParams[m_jpegHuffmanTable->m_huffmanData[i].m_tableID].pDCCodeLength,
                    JPEG_NUM_HUFF_TABLE_DC_HUFFVAL * sizeof(uint8_t),
                    &huffmanTable.m_huffSize,
                    JPEG_NUM_HUFF_TABLE_DC_HUFFVAL * sizeof(uint8_t));
                if (eStatus != MOS_STATUS_SUCCESS)
                {
                    MOS_SafeFreeMemory(tempJpegQuantMatrix);
                    CODECHAL_ENCODE_CHK_STATUS_RETURN(eStatus);
                }
            }
            else // AC Table
            {
                eStatus = (MOS_STATUS) MOS_SecureMemcpy(huffTableParams[m_jpegHuffmanTable->m_huffmanData[i].m_tableID].pACCodeValues,
                    JPEG_NUM_HUFF_TABLE_AC_HUFFVAL * sizeof(uint16_t),
                    &huffmanTable.m_huffCode,
                    JPEG_NUM_HUFF_TABLE_AC_HUFFVAL * sizeof(uint16_t));
                if (eStatus != MOS_STATUS_SUCCESS)
                {
                    MOS_SafeFreeMemory(tempJpegQuantMatrix);
                    CODECHAL_ENCODE_CHK_STATUS_RETURN(eStatus);
                }

                eStatus = (MOS_STATUS) MOS_SecureMemcpy(huffTableParams[m_jpegHuffmanTable->m_huffmanData[i].m_tableID].pACCodeLength,
                    JPEG_NUM_HUFF_TABLE_AC_HUFFVAL * sizeof(uint8_t),
                    &huffmanTable.m_huffSize,
                    JPEG_NUM_HUFF_TABLE_AC_HUFFVAL * sizeof(uint8_t));
                if (eStatus != MOS_STATUS_SUCCESS)
                {
                    MOS_SafeFreeMemory(tempJpegQuantMatrix);
                    CODECHAL_ENCODE_CHK_STATUS_RETURN(eStatus);
                }
            }
        }

        // Send 2 huffman table commands - 1 for Luma and one for chroma for non-monchrome input formats
        // If only one table is sent by the app (2 buffers), send the same table for Luma and chroma
        bool repeatHuffTable = false;
        if ((m_encodeParams.dwNumHuffBuffers / 2 < JPEG_MAX_NUM_HUFF_TABLE_INDEX)
            && (m_jpegPicParams->m_inputSurfaceFormat != codechalJpegY8))
        {
            repeatHuffTable = true;

            // Copy over huffman data to the other two data buffers for JPEG picture header
            for (uint32_t i = 0; i < m_encodeParams.dwNumHuffBuffers; i++)
            {
                m_jpegHuffmanTable->m_huffmanData[i + 2].m_tableClass = m_jpegHuffmanTable->m_huffmanData[i].m_tableClass;
                m_jpegHuffmanTable->m_huffmanData[i + 2].m_tableID    = m_jpegHuffmanTable->m_huffmanData[i].m_tableID;

                eStatus = MOS_SecureMemcpy(&m_jpegHuffmanTable->m_huffmanData[i + 2].m_bits[0],
                    sizeof(uint8_t) * JPEG_NUM_HUFF_TABLE_AC_BITS,
                    &m_jpegHuffmanTable->m_huffmanData[i].m_bits[0],
                    sizeof(uint8_t) * JPEG_NUM_HUFF_TABLE_AC_BITS);
                if (eStatus != MOS_STATUS_SUCCESS)
                {
                    CODECHAL_ENCODE_ASSERTMESSAGE("Failed to copy memory.");
                    MOS_SafeFreeMemory(tempJpegQuantMatrix);
                    return eStatus;
                }

                eStatus = MOS_SecureMemcpy(&m_jpegHuffmanTable->m_huffmanData[i + 2].m_huffVal[0],
                    sizeof(uint8_t) * JPEG_NUM_HUFF_TABLE_AC_HUFFVAL,
                    &m_jpegHuffmanTable->m_huffmanData[i].m_huffVal[0],
                    sizeof(uint8_t) * JPEG_NUM_HUFF_TABLE_AC_HUFFVAL);
                if (eStatus != MOS_STATUS_SUCCESS)
                {
                    CODECHAL_ENCODE_ASSERTMESSAGE("Failed to copy memory.");
                    MOS_SafeFreeMemory(tempJpegQuantMatrix);
                    return eStatus;
                }
            }
        }

        // the number of huffman commands is half of the huffman buffers sent by the app, since AC and DC buffers are combined into one command
        for (uint32_t i = 0; i < m_encodeParams.dwNumHuffBuffers / 2; i++)
        {
            if (repeatHuffTable)
            {
                eStatus = (MOS_STATUS) (m_mfxInterface->AddMfcJpegHuffTableStateCmd(&cmdBuffer, &huffTableParams[i]));
                if (eStatus != MOS_STATUS_SUCCESS)
                {
                    MOS_SafeFreeMemory(tempJpegQuantMatrix);
                    CODECHAL_ENCODE_CHK_STATUS_RETURN(eStatus);
                }
            }

            eStatus = (MOS_STATUS) m_mfxInterface->AddMfcJpegHuffTableStateCmd(&cmdBuffer, &huffTableParams[i]);
            if (eStatus != MOS_STATUS_SUCCESS)
            {
                MOS_SafeFreeMemory(tempJpegQuantMatrix);
                CODECHAL_ENCODE_CHK_STATUS_RETURN(eStatus);
            }
        }

        // set MFC_JPEG_SCAN_OBJECT
        MhwVdboxJpegScanParams scanObjectParams;
        scanObjectParams.mode                   = m_mode;
        scanObjectParams.inputSurfaceFormat     = (CodecEncodeJpegInputSurfaceFormat)m_jpegPicParams->m_inputSurfaceFormat;
        scanObjectParams.dwPicWidth             = m_jpegPicParams->m_picWidth;
        scanObjectParams.dwPicHeight            = m_jpegPicParams->m_picHeight;
        scanObjectParams.pJpegEncodeScanParams  = m_jpegScanParams;

        eStatus = (MOS_STATUS) m_mfxInterface->AddMfcJpegScanObjCmd(&cmdBuffer, &scanObjectParams);
        if (eStatus != MOS_STATUS_SUCCESS)
        {
            MOS_SafeFreeMemory(tempJpegQuantMatrix);
            CODECHAL_ENCODE_CHK_STATUS_RETURN(eStatus);
        }
        // set MFC_JPEG_PAK_INSERT_OBJECT
        MHW_VDBOX_PAK_INSERT_PARAMS pakInsertObjectParams;
        MOS_ZeroMemory(&pakInsertObjectParams, sizeof(pakInsertObjectParams));

        // The largest component written through the MFC_JPEG_PAK_INSERT_OBJECT command is Huffman table
        pakInsertObjectParams.pBsBuffer = (BSBuffer *)MOS_AllocAndZeroMemory(sizeof(CodechalEncodeJpegFrameHeader));
        if (pakInsertObjectParams.pBsBuffer == nullptr)
        {
            MOS_SafeFreeMemory(tempJpegQuantMatrix);
            CODECHAL_ENCODE_CHK_NULL_RETURN(nullptr);
        }
        if(!m_fullHeaderInAppData)
        {
            // Add SOI (0xFFD8) (only if it was sent by the application)
            eStatus = (MOS_STATUS)PackSOI(pakInsertObjectParams.pBsBuffer);
            if (eStatus != MOS_STATUS_SUCCESS)
            {
                MOS_SafeFreeMemory(pakInsertObjectParams.pBsBuffer->pBase);
                MOS_SafeFreeMemory(pakInsertObjectParams.pBsBuffer);
                MOS_SafeFreeMemory(tempJpegQuantMatrix);
                CODECHAL_ENCODE_CHK_STATUS_RETURN(eStatus);
            }
            pakInsertObjectParams.dwOffset                      = 0;
            pakInsertObjectParams.dwBitSize                     = pakInsertObjectParams.pBsBuffer->BufferSize;
            pakInsertObjectParams.bLastHeader                   = false;
            pakInsertObjectParams.bEndOfSlice                   = false;
            pakInsertObjectParams.bResetBitstreamStartingPos    = 1; // from discussion with HW Architect
            eStatus = (MOS_STATUS) m_mfxInterface->AddMfxPakInsertObject(&cmdBuffer, nullptr, &pakInsertObjectParams);
            if (eStatus != MOS_STATUS_SUCCESS)
            {
                MOS_SafeFreeMemory(pakInsertObjectParams.pBsBuffer->pBase);
                MOS_SafeFreeMemory(pakInsertObjectParams.pBsBuffer);
                MOS_SafeFreeMemory(tempJpegQuantMatrix);
                CODECHAL_ENCODE_CHK_STATUS_RETURN(eStatus);
            }
            MOS_FreeMemory(pakInsertObjectParams.pBsBuffer->pBase);
        }
        // Add Application data if it was sent by application
        if (m_applicationData != nullptr)
        {
            uint8_t* appDataChunk = nullptr;
            uint32_t appDataChunkSize = m_appDataSize;

            // We can write a maximum of 1020 words per command, so if the size of the app data is
            // more than 1020 we need to send multiple commands for writing out app data
            uint32_t numAppDataCmdsNeeded = 1;
            uint32_t appDataCmdSizeResidue = 0;
            if (m_appDataSize > 1020)
            {
                numAppDataCmdsNeeded  = m_appDataSize / 1020;
                appDataCmdSizeResidue = m_appDataSize % 1020;

                appDataChunkSize = 1020;
            }

            appDataChunk = (uint8_t*)MOS_AllocAndZeroMemory(appDataChunkSize);
            if (appDataChunk == nullptr)
            {
                MOS_SafeFreeMemory(pakInsertObjectParams.pBsBuffer->pBase);
                MOS_SafeFreeMemory(pakInsertObjectParams.pBsBuffer);
                MOS_SafeFreeMemory(tempJpegQuantMatrix);
                CODECHAL_ENCODE_CHK_NULL_RETURN(nullptr);
            }

            for (uint32_t i = 0; i < numAppDataCmdsNeeded; i++)
            {
                uint8_t *copyAddress = (uint8_t*)(m_applicationData) + (i * appDataChunkSize);

                MOS_SecureMemcpy(appDataChunk, appDataChunkSize,
                    copyAddress, appDataChunkSize);

                eStatus = (MOS_STATUS)PackApplicationData(pakInsertObjectParams.pBsBuffer, appDataChunk, appDataChunkSize);
                if (eStatus != MOS_STATUS_SUCCESS)
                {
                    MOS_SafeFreeMemory(pakInsertObjectParams.pBsBuffer->pBase);
                    appDataChunk = nullptr;
                    MOS_SafeFreeMemory(pakInsertObjectParams.pBsBuffer);
                    MOS_SafeFreeMemory(tempJpegQuantMatrix);
                    CODECHAL_ENCODE_CHK_STATUS_RETURN(eStatus);
                }
                pakInsertObjectParams.dwOffset                      = 0;
                pakInsertObjectParams.dwBitSize                     = pakInsertObjectParams.pBsBuffer->BufferSize;
                //if full header is included in application data, it will be the last header to insert and last chunk of it should be marked with EndOfSlice
                if((appDataCmdSizeResidue == 0) && m_fullHeaderInAppData && (i == numAppDataCmdsNeeded - 1))
                {
                    pakInsertObjectParams.bLastHeader                   = true;
                    pakInsertObjectParams.bEndOfSlice                   = true;
                }
                else
                {
                    pakInsertObjectParams.bLastHeader                   = false;
                    pakInsertObjectParams.bEndOfSlice                   = false;
                }
                pakInsertObjectParams.bResetBitstreamStartingPos    = 1; // from discussion with HW Architect
                eStatus = (MOS_STATUS)m_mfxInterface->AddMfxPakInsertObject(&cmdBuffer, nullptr,
                    &pakInsertObjectParams);
                if (eStatus != MOS_STATUS_SUCCESS)
                {
                    MOS_SafeFreeMemory(pakInsertObjectParams.pBsBuffer->pBase);
                    appDataChunk = nullptr;
                    MOS_SafeFreeMemory(pakInsertObjectParams.pBsBuffer);
                    MOS_SafeFreeMemory(tempJpegQuantMatrix);
                    CODECHAL_ENCODE_CHK_STATUS_RETURN(eStatus);
                }
            }

            if (appDataCmdSizeResidue != 0)
            {
                uint8_t* lastAddress = (uint8_t*)(m_applicationData) + (numAppDataCmdsNeeded * appDataChunkSize);
                appDataChunkSize = appDataCmdSizeResidue;

                MOS_SecureMemcpy(appDataChunk, appDataChunkSize,
                    lastAddress,
                    appDataChunkSize);

                eStatus = (MOS_STATUS)PackApplicationData(pakInsertObjectParams.pBsBuffer, appDataChunk, appDataCmdSizeResidue);
                if (eStatus != MOS_STATUS_SUCCESS)
                {
                    MOS_SafeFreeMemory(pakInsertObjectParams.pBsBuffer->pBase);
                    MOS_SafeFreeMemory(pakInsertObjectParams.pBsBuffer);
                    MOS_SafeFreeMemory(tempJpegQuantMatrix);
                    MOS_SafeFreeMemory(appDataChunk);
                    CODECHAL_ENCODE_CHK_STATUS_RETURN(eStatus);
                }
                pakInsertObjectParams.dwOffset                      = 0;
                pakInsertObjectParams.dwBitSize                     = pakInsertObjectParams.pBsBuffer->BufferSize;
                //if full header is included in application data, it will be the last insert headers
                if(m_fullHeaderInAppData)
                {
                    pakInsertObjectParams.bLastHeader                   = true;
                    pakInsertObjectParams.bEndOfSlice                   = true;
                }
                else
                {
                    pakInsertObjectParams.bLastHeader                   = false;
                    pakInsertObjectParams.bEndOfSlice                   = false;
                }
                pakInsertObjectParams.bResetBitstreamStartingPos    = 1; // from discussion with HW Architect
                eStatus = (MOS_STATUS)m_mfxInterface->AddMfxPakInsertObject(&cmdBuffer, nullptr,
                    &pakInsertObjectParams);
                if (eStatus != MOS_STATUS_SUCCESS)
                {
                    MOS_SafeFreeMemory(pakInsertObjectParams.pBsBuffer->pBase);
                    MOS_SafeFreeMemory(pakInsertObjectParams.pBsBuffer);
                    MOS_SafeFreeMemory(tempJpegQuantMatrix);
                    MOS_SafeFreeMemory(appDataChunk);
                    CODECHAL_ENCODE_CHK_STATUS_RETURN(eStatus);
                }
            }

            MOS_FreeMemory(appDataChunk);
        }
        if(!m_fullHeaderInAppData)
        {
        // Add Quant Table for Y
        eStatus = (MOS_STATUS)PackQuantTable(pakInsertObjectParams.pBsBuffer, jpegComponentY);
        if (eStatus != MOS_STATUS_SUCCESS)
        {
            MOS_SafeFreeMemory(pakInsertObjectParams.pBsBuffer->pBase);
            MOS_SafeFreeMemory(pakInsertObjectParams.pBsBuffer);
            MOS_SafeFreeMemory(tempJpegQuantMatrix);
            CODECHAL_ENCODE_CHK_STATUS_RETURN(eStatus);
        }
        pakInsertObjectParams.dwOffset                      = 0;
        pakInsertObjectParams.dwBitSize                     = pakInsertObjectParams.pBsBuffer->BufferSize;
        pakInsertObjectParams.bLastHeader                   = false;
        pakInsertObjectParams.bEndOfSlice                   = false;
        pakInsertObjectParams.bResetBitstreamStartingPos    = 1; // from discussion with HW Architect
        eStatus = (MOS_STATUS)m_mfxInterface->AddMfxPakInsertObject(&cmdBuffer, nullptr,
            &pakInsertObjectParams);
        if (eStatus != MOS_STATUS_SUCCESS)
        {
            MOS_SafeFreeMemory(pakInsertObjectParams.pBsBuffer->pBase);
            MOS_SafeFreeMemory(pakInsertObjectParams.pBsBuffer);
            MOS_SafeFreeMemory(tempJpegQuantMatrix);
            CODECHAL_ENCODE_CHK_STATUS_RETURN(eStatus);
        }
        MOS_FreeMemory(pakInsertObjectParams.pBsBuffer->pBase);

        if (!useSingleDefaultQuantTable)
        {
            // Since there is no U and V in monochrome format, donot add Quantization table header for U and V components
            if (m_jpegPicParams->m_inputSurfaceFormat != codechalJpegY8)
            {
                // Add quant table for U
                eStatus = (MOS_STATUS)PackQuantTable(pakInsertObjectParams.pBsBuffer, jpegComponentU);
                if (eStatus != MOS_STATUS_SUCCESS)
                {
                    MOS_SafeFreeMemory(pakInsertObjectParams.pBsBuffer->pBase);
                    MOS_SafeFreeMemory(pakInsertObjectParams.pBsBuffer);
                    MOS_SafeFreeMemory(tempJpegQuantMatrix);
                    CODECHAL_ENCODE_CHK_STATUS_RETURN(eStatus);
                }
                pakInsertObjectParams.dwOffset                      = 0;
                pakInsertObjectParams.dwBitSize                     = pakInsertObjectParams.pBsBuffer->BufferSize;
                pakInsertObjectParams.bLastHeader                   = false;
                pakInsertObjectParams.bEndOfSlice                   = false;
                pakInsertObjectParams.bResetBitstreamStartingPos    = 1; // from discussion with HW Architect
                eStatus = (MOS_STATUS)m_mfxInterface->AddMfxPakInsertObject(&cmdBuffer, nullptr,
                    &pakInsertObjectParams);
                if (eStatus != MOS_STATUS_SUCCESS)
                {
                    MOS_SafeFreeMemory(pakInsertObjectParams.pBsBuffer->pBase);
                    MOS_SafeFreeMemory(pakInsertObjectParams.pBsBuffer);
                    MOS_SafeFreeMemory(tempJpegQuantMatrix);
                    CODECHAL_ENCODE_CHK_STATUS_RETURN(eStatus);
                }
                MOS_FreeMemory(pakInsertObjectParams.pBsBuffer->pBase);

                // Add quant table for V
                eStatus = (MOS_STATUS)PackQuantTable(pakInsertObjectParams.pBsBuffer, jpegComponentV);
                if (eStatus != MOS_STATUS_SUCCESS)
                {
                    MOS_SafeFreeMemory(pakInsertObjectParams.pBsBuffer->pBase);
                    MOS_SafeFreeMemory(pakInsertObjectParams.pBsBuffer);
                    MOS_SafeFreeMemory(tempJpegQuantMatrix);
                    CODECHAL_ENCODE_CHK_STATUS_RETURN(eStatus);
                }
                pakInsertObjectParams.dwOffset                      = 0;
                pakInsertObjectParams.dwBitSize                     = pakInsertObjectParams.pBsBuffer->BufferSize;
                pakInsertObjectParams.bLastHeader                   = false;
                pakInsertObjectParams.bEndOfSlice                   = false;
                pakInsertObjectParams.bResetBitstreamStartingPos    = 1; // from discussion with HW Architect
                eStatus = (MOS_STATUS)m_mfxInterface->AddMfxPakInsertObject(&cmdBuffer, nullptr,
                    &pakInsertObjectParams);
                if (eStatus != MOS_STATUS_SUCCESS)
                {
                    MOS_SafeFreeMemory(pakInsertObjectParams.pBsBuffer->pBase);
                    MOS_SafeFreeMemory(pakInsertObjectParams.pBsBuffer);
                    MOS_SafeFreeMemory(tempJpegQuantMatrix);
                    CODECHAL_ENCODE_CHK_STATUS_RETURN(eStatus);
                }
                MOS_FreeMemory(pakInsertObjectParams.pBsBuffer->pBase);
            }
        }

        // Add Frame Header
        eStatus = (MOS_STATUS)PackFrameHeader(pakInsertObjectParams.pBsBuffer, useSingleDefaultQuantTable);
        if (eStatus != MOS_STATUS_SUCCESS)
        {
            MOS_SafeFreeMemory(pakInsertObjectParams.pBsBuffer->pBase);
            MOS_SafeFreeMemory(pakInsertObjectParams.pBsBuffer);
            MOS_SafeFreeMemory(tempJpegQuantMatrix);
            CODECHAL_ENCODE_CHK_STATUS_RETURN(eStatus);
        }
        pakInsertObjectParams.dwOffset                      = 0;
        pakInsertObjectParams.dwBitSize                     = pakInsertObjectParams.pBsBuffer->BufferSize;
        pakInsertObjectParams.bLastHeader                   = false;
        pakInsertObjectParams.bEndOfSlice                   = false;
        pakInsertObjectParams.bResetBitstreamStartingPos    = 1; // from discussion with HW Architect
        eStatus = (MOS_STATUS)m_mfxInterface->AddMfxPakInsertObject(&cmdBuffer, nullptr,
            &pakInsertObjectParams);
        if (eStatus != MOS_STATUS_SUCCESS)
        {
            MOS_SafeFreeMemory(pakInsertObjectParams.pBsBuffer->pBase);
            MOS_SafeFreeMemory(pakInsertObjectParams.pBsBuffer);
            MOS_SafeFreeMemory(tempJpegQuantMatrix);
            CODECHAL_ENCODE_CHK_STATUS_RETURN(eStatus);
        }
        MOS_FreeMemory(pakInsertObjectParams.pBsBuffer->pBase);

        // Add Huffman Table for Y - DC table, Y- AC table, U/V - DC table, U/V - AC table
        for (uint32_t i = 0; i < m_encodeParams.dwNumHuffBuffers; i++)
        {
            eStatus = (MOS_STATUS)PackHuffmanTable(pakInsertObjectParams.pBsBuffer, i);
            if (eStatus != MOS_STATUS_SUCCESS)
            {
                MOS_SafeFreeMemory(pakInsertObjectParams.pBsBuffer->pBase);
                MOS_SafeFreeMemory(pakInsertObjectParams.pBsBuffer);
                MOS_SafeFreeMemory(tempJpegQuantMatrix);
                CODECHAL_ENCODE_CHK_STATUS_RETURN(eStatus);
            }
            pakInsertObjectParams.dwOffset                      = 0;
            pakInsertObjectParams.dwBitSize                     = pakInsertObjectParams.pBsBuffer->BufferSize;
            pakInsertObjectParams.bLastHeader                   = false;
            pakInsertObjectParams.bEndOfSlice                   = false;
            pakInsertObjectParams.bResetBitstreamStartingPos    = 1; // from discussion with HW Architect
            eStatus = (MOS_STATUS)m_mfxInterface->AddMfxPakInsertObject(&cmdBuffer, nullptr,
                &pakInsertObjectParams);
            if (eStatus != MOS_STATUS_SUCCESS)
            {
                MOS_SafeFreeMemory(pakInsertObjectParams.pBsBuffer->pBase);
                MOS_SafeFreeMemory(pakInsertObjectParams.pBsBuffer);
                MOS_SafeFreeMemory(tempJpegQuantMatrix);
                CODECHAL_ENCODE_CHK_STATUS_RETURN(eStatus);
            }
            MOS_FreeMemory(pakInsertObjectParams.pBsBuffer->pBase);
        }

        // Restart Interval - Add only if the restart interval is not zero
        if (m_jpegScanParams->m_restartInterval != 0)
        {
            eStatus = (MOS_STATUS)PackRestartInterval(pakInsertObjectParams.pBsBuffer);
            if (eStatus != MOS_STATUS_SUCCESS)
            {
                MOS_SafeFreeMemory(pakInsertObjectParams.pBsBuffer->pBase);
                MOS_SafeFreeMemory(pakInsertObjectParams.pBsBuffer);
                MOS_SafeFreeMemory(tempJpegQuantMatrix);
                CODECHAL_ENCODE_CHK_STATUS_RETURN(eStatus);
            }
            pakInsertObjectParams.dwOffset                      = 0;
            pakInsertObjectParams.dwBitSize                     = pakInsertObjectParams.pBsBuffer->BufferSize;
            pakInsertObjectParams.bLastHeader                   = false;
            pakInsertObjectParams.bEndOfSlice                   = false;
            pakInsertObjectParams.bResetBitstreamStartingPos    = 1; // from discussion with HW Architect
            eStatus = (MOS_STATUS)m_mfxInterface->AddMfxPakInsertObject(&cmdBuffer, nullptr,
                &pakInsertObjectParams);
            if (eStatus != MOS_STATUS_SUCCESS)
            {
                MOS_SafeFreeMemory(pakInsertObjectParams.pBsBuffer->pBase);
                MOS_SafeFreeMemory(pakInsertObjectParams.pBsBuffer);
                MOS_SafeFreeMemory(tempJpegQuantMatrix);
                CODECHAL_ENCODE_CHK_STATUS_RETURN(eStatus);
            }
            MOS_FreeMemory(pakInsertObjectParams.pBsBuffer->pBase);
        }

        // Add scan header
        eStatus = (MOS_STATUS)PackScanHeader(pakInsertObjectParams.pBsBuffer);
        if (eStatus != MOS_STATUS_SUCCESS)
        {
            MOS_SafeFreeMemory(pakInsertObjectParams.pBsBuffer->pBase);
            MOS_SafeFreeMemory(pakInsertObjectParams.pBsBuffer);
            MOS_SafeFreeMemory(tempJpegQuantMatrix);
            CODECHAL_ENCODE_CHK_STATUS_RETURN(eStatus);
        }
        pakInsertObjectParams.dwOffset                      = 0;
        pakInsertObjectParams.dwBitSize                     = pakInsertObjectParams.pBsBuffer->BufferSize;
        pakInsertObjectParams.bLastHeader                   = true;
        pakInsertObjectParams.bEndOfSlice                   = true;
        pakInsertObjectParams.bResetBitstreamStartingPos    = 1; // from discussion with HW Architect
        eStatus = (MOS_STATUS)m_mfxInterface->AddMfxPakInsertObject(&cmdBuffer, nullptr,
            &pakInsertObjectParams);
        if (eStatus != MOS_STATUS_SUCCESS)
        {
            MOS_SafeFreeMemory(pakInsertObjectParams.pBsBuffer->pBase);
            MOS_SafeFreeMemory(pakInsertObjectParams.pBsBuffer);
            MOS_SafeFreeMemory(tempJpegQuantMatrix);
            CODECHAL_ENCODE_CHK_STATUS_RETURN(eStatus);
        }
        MOS_FreeMemory(pakInsertObjectParams.pBsBuffer->pBase);
        }
        MOS_FreeMemory(pakInsertObjectParams.pBsBuffer);
    }

    eStatus = ReadMfcStatus(&cmdBuffer);
    if (eStatus != MOS_STATUS_SUCCESS)
    {
        MOS_SafeFreeMemory(tempJpegQuantMatrix);
        CODECHAL_ENCODE_CHK_STATUS_RETURN(eStatus);
    }

    eStatus = EndStatusReport(&cmdBuffer, CODECHAL_NUM_MEDIA_STATES);
    if (eStatus != MOS_STATUS_SUCCESS)
    {
        MOS_SafeFreeMemory(tempJpegQuantMatrix);
        CODECHAL_ENCODE_CHK_STATUS_RETURN(eStatus);
    }

    eStatus = m_miInterface->AddMiBatchBufferEnd(&cmdBuffer, nullptr);
    if (eStatus != MOS_STATUS_SUCCESS)
    {
        MOS_SafeFreeMemory(tempJpegQuantMatrix);
        CODECHAL_ENCODE_CHK_STATUS_RETURN(eStatus);
    }

    std::string pakPassName = "PAK_PASS" + std::to_string(static_cast<uint32_t>(m_currPass));
    CODECHAL_DEBUG_TOOL(
        eStatus = m_debugInterface->DumpCmdBuffer(
            &cmdBuffer,
            CODECHAL_NUM_MEDIA_STATES,
            pakPassName.data());
        if (eStatus != MOS_STATUS_SUCCESS)
        {
            MOS_SafeFreeMemory(tempJpegQuantMatrix);
            CODECHAL_ENCODE_CHK_STATUS_RETURN(eStatus);
        }

    //CODECHAL_ENCODE_CHK_STATUS_RETURN(CodecHal_DbgReplaceAllCommands(
    //    m_debugInterface,
    //    &cmdBuffer));
    )

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

    eStatus = SubmitCommandBuffer(&cmdBuffer, m_renderContextUsesNullHw);
    if (eStatus != MOS_STATUS_SUCCESS)
    {
        MOS_SafeFreeMemory(tempJpegQuantMatrix);
        CODECHAL_ENCODE_CHK_STATUS_RETURN(eStatus);
    }

    if (tempJpegQuantMatrix != nullptr)
    {
        MOS_FreeMemory(tempJpegQuantMatrix);
        tempJpegQuantMatrix = nullptr;
    }

    return eStatus;
}

uint32_t CodechalEncodeJpegState::CalculateCommandBufferSize()
{
    uint32_t commandBufferSize =
        m_pictureStatesSize        +
        m_extraPictureStatesSize   +
        (m_sliceStatesSize * m_numSlices);

    // For JPEG encoder, add the size of PAK_INSERT_OBJ commands which is also part of command buffer
    if(m_standard == CODECHAL_JPEG)
    {
        // Add PAK_INSERT_OBJ for app data
        // PAK_INSERT_OBJ contains 2 DWORDS + bytes of payload data
        // There is a max of 1024 payload bytes of app data per PAK_INSERT_OBJ command, so adding 2 DWORDS for each of them
        // Total payload data is the same size as app data
        commandBufferSize += (m_encodeParams.dwAppDataSize + (2 * sizeof(uint32_t) * (m_encodeParams.dwAppDataSize / 1020+1)));  //to be consistent with how we split app data into chunks.

        // Add number of bytes of data added through PAK_INSERT_OBJ command
        commandBufferSize += (2 + // SOI = 2 bytes
                // Frame header - add sizes of each component of CodechalEncodeJpegFrameHeader
                (2 * sizeof(uint8_t)) + (4 * sizeof(uint16_t)) + 3 * sizeof(uint8_t)*  jpegNumComponent +
                // AC and DC Huffman tables - 2 Huffman tables for each component, and 3 components
                (2 * 3 * sizeof(CodechalJpegHuffmanHeader)) +
                // Quant tables - 1 for Quant table of each component, so 3 quant tables per frame
                (3 * sizeof(CodechalEncodeJpegQuantHeader)) +
                // Restart interval - 1 per frame
                sizeof(CodechalEncodeJpegRestartHeader) +
                // Scan header - 1 per frame
                sizeof(CodechalEncodeJpegScanHeader));
    }

    if (m_singleTaskPhaseSupported)
    {
        commandBufferSize *= (m_numPasses + 1);
    }

    // 4K align since allocation is in chunks of 4K bytes.
    commandBufferSize = MOS_ALIGN_CEIL(commandBufferSize, 0x1000);

    return commandBufferSize;
}

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

    PMHW_VDBOX_IMAGE_STATUS_CONTROL imgStatusCtrl = &encodeStatus->ImageStatusCtrl;

    // The huffman tables sent by application were incorrect (used only for JPEG encoding)
    if (imgStatusCtrl->MissingHuffmanCode == 1)
    {
        CODECHAL_ENCODE_ASSERTMESSAGE("Error: JPEG standard encoding: missing huffman code");
        encodeStatusReport->CodecStatus = CODECHAL_STATUS_ERROR;
        return eStatus;
    }

    eStatus = GetStatusReportCommon(encodeStatus, encodeStatusReport);

    return eStatus;
}

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

    memset(m_refList, 0, sizeof(m_refList));

    m_codecGetStatusReportDefined = true;
}

#if USE_CODECHAL_DEBUG_TOOL
MOS_STATUS CodechalEncodeJpegState::DumpQuantTables(
    CodecEncodeJpegQuantTable *quantTable)
{
    CODECHAL_DEBUG_FUNCTION_ENTER;

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

    CODECHAL_DEBUG_CHK_NULL(quantTable);

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

    //Dump quantTable[JPEG_MAX_NUM_QUANT_TABLE_INDEX]
    for (uint32_t i = 0; i < JPEG_MAX_NUM_QUANT_TABLE_INDEX; ++i)
    {
        // Dump Table ID
        oss << "TableID: " << +quantTable->m_quantTable[i].m_tableID << std::endl;
        // Dump Precision
        oss << "TableID: " << +quantTable->m_quantTable[i].m_precision << std::endl;
        //Dump usQm[JPEG_NUM_QUANTMATRIX];
        oss << "quantTable[" << +i << "].usQm[0-" << (JPEG_NUM_QUANTMATRIX - 1) << "]: " << std::endl;

        for (uint32_t j = 0; j < JPEG_NUM_QUANTMATRIX; ++j)
        {
            oss << +quantTable->m_quantTable[i].m_qm[j];
            if (j % 6 == 5 || j == JPEG_NUM_QUANTMATRIX - 1)
            {
                oss << std::endl;
            }
        }
    }
    const char *fileName = m_debugInterface->CreateFileName(
        "_ENC",
        CodechalDbgBufferType::bufIqParams,
        CodechalDbgExtType::txt);

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

    return MOS_STATUS_SUCCESS;
}

MOS_STATUS CodechalEncodeJpegState::DumpPicParams(
    CodecEncodeJpegPictureParams *picParams)
{
    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 << "Profile: " << +picParams->m_profile << std::endl;
    oss << "Progressive: " << +picParams->m_progressive << std::endl;
    oss << "Huffman: " << +picParams->m_huffman << std::endl;
    oss << "Interleaved: " << +picParams->m_interleaved << std::endl;
    oss << "Differential: " << +picParams->m_differential << std::endl;
    oss << "PicWidth: " << +picParams->m_picWidth << std::endl;
    oss << "PicHeight: " << +picParams->m_picHeight << std::endl;
    oss << "InputSurfaceFormat: " << +picParams->m_inputSurfaceFormat << std::endl;
    oss << "SampleBitDepth: " << +picParams->m_sampleBitDepth << std::endl;
    oss << "uiNumComponent: " << +picParams->m_numComponent << std::endl;

    //Dump componentIdentifier[jpegNumComponent]
    for (uint32_t i = 0; i < jpegNumComponent; ++i)
    {
        oss << "ComponentIdentifier[" << +i << "]: " << +picParams->m_componentID[i] << std::endl;
    }

    //Dump quantTableSelector[jpegNumComponent]
    for (uint32_t i = 0; i < jpegNumComponent; ++i)
    {
        oss << "QuantTableSelector[" << +i << "]: " << +picParams->m_quantTableSelector[i] << std::endl;
    }
    oss << "Quality: " << +picParams->m_quality << std::endl;
    oss << "NumScan: " << +picParams->m_numScan << std::endl;
    oss << "NumQuantTable: " << +picParams->m_numQuantTable << std::endl;
    oss << "NumCodingTable: " << +picParams->m_numCodingTable << std::endl;
    oss << "StatusReportFeedbackNumber: " << +picParams->m_statusReportFeedbackNumber << std::endl;

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

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

MOS_STATUS CodechalEncodeJpegState::DumpScanParams(
    CodecEncodeJpegScanHeader *scanParams)
{
    CODECHAL_DEBUG_FUNCTION_ENTER;

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

    CODECHAL_DEBUG_CHK_NULL(scanParams);

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

    oss << "RestartInterval: " << +scanParams->m_restartInterval << std::endl;
    oss << "NumComponents: " << +scanParams->m_numComponent << std::endl;

    //Dump ComponentSelector[jpegNumComponent]
    for (uint32_t i = 0; i < jpegNumComponent; ++i)
    {
        oss << "ComponentSelector[" << +i << "]: " << +scanParams->m_componentSelector[i] << std::endl;
    }

    //Dump DcHuffTblSelector[jpegNumComponent]
    for (uint32_t i = 0; i < jpegNumComponent; ++i)
    {
        oss << "DcHuffTblSelector[" << +i << "]: " << +scanParams->m_dcCodingTblSelector[i] << std::endl;
    }

    //Dump AcHuffTblSelector[jpegNumComponent]
    for (uint32_t i = 0; i < jpegNumComponent; ++i)
    {
        oss << "AcHuffTblSelector[" << +i << "]: " << +scanParams->m_acCodingTblSelector[i] << std::endl;
    }

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

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

    return MOS_STATUS_SUCCESS;
}

MOS_STATUS CodechalEncodeJpegState::DumpHuffmanTable(
    CodecEncodeJpegHuffmanDataArray *huffmanTable)
{
    CODECHAL_DEBUG_FUNCTION_ENTER;

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

    CODECHAL_DEBUG_CHK_NULL(huffmanTable);

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

    //Dump HuffTable[JPEG_MAX_NUM_HUFF_TABLE_INDEX]
    for (uint32_t i = 0; i < JPEG_NUM_ENCODE_HUFF_BUFF; ++i)
    {
        // Dump Table Class
        oss << "TableClass: " << +huffmanTable->m_huffmanData[i].m_tableClass << std::endl;
        // Dump Table ID
        oss << "TableID: " << +huffmanTable->m_huffmanData[i].m_tableID << std::endl;
        //Dump ucBits[JPEG_NUM_HUFF_TABLE_AC_BITS]
        oss << "HuffTable[" << +i << "].ucBits[0-" << (JPEG_NUM_HUFF_TABLE_AC_BITS - 1) << "]: " << std::endl;

        for (uint32_t j = 0; j < JPEG_NUM_HUFF_TABLE_AC_BITS; ++j)
        {
            oss << +huffmanTable->m_huffmanData[i].m_bits[j];
            if (j % 6 == 5 || j == JPEG_NUM_HUFF_TABLE_AC_BITS - 1)
            {
                oss << std::endl;
            }
        }

        //Dump ucHuffVal[JPEG_NUM_HUFF_TABLE_AC_HUFFVAL]
        oss << "HuffTable[" << +i << "].ucHuffVal[0-" << (JPEG_NUM_HUFF_TABLE_AC_HUFFVAL - 1) << "]: " << std::endl;

        for (uint32_t j = 0; j < JPEG_NUM_HUFF_TABLE_AC_HUFFVAL; ++j)
        {
            oss << +huffmanTable->m_huffmanData[i].m_huffVal[j];
            if (j % 6 == 5 || j == JPEG_NUM_HUFF_TABLE_AC_HUFFVAL - 1)
            {
                oss << std::endl;
            }
        }
    }

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

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

#endif
